From 7770b4d578bfdeac8cd745a789c05f43deda7808 Mon Sep 17 00:00:00 2001 From: Jonathan Davies Date: Sat, 29 Jul 2023 00:27:42 +0100 Subject: [PATCH 1/2] Implemented --http3 flag for HTTP3/QUIC support. Fixes: #557. --- command/app.go | 5 ++++ go.mod | 21 +++++++++++++--- go.sum | 63 ++++++++++++++++++++++++++++++++++------------ storage/s3.go | 14 +++++++++++ storage/storage.go | 2 ++ 5 files changed, 85 insertions(+), 20 deletions(-) diff --git a/command/app.go b/command/app.go index f77654139..ffbf174c4 100644 --- a/command/app.go +++ b/command/app.go @@ -46,6 +46,10 @@ var app = &cli.App{ Usage: "override default S3 host for custom services", EnvVars: []string{"S3_ENDPOINT_URL"}, }, + &cli.BoolFlag{ + Name: "http3", + Usage: "Enable HTTP3/QUIC support", + }, &cli.BoolFlag{ Name: "no-verify-ssl", Usage: "disable SSL certificate verification", @@ -181,6 +185,7 @@ func NewStorageOpts(c *cli.Context) storage.Options { return storage.Options{ DryRun: c.Bool("dry-run"), Endpoint: c.String("endpoint-url"), + HTTP3: c.Bool("http3"), MaxRetries: c.Int("retry-count"), NoSignRequest: c.Bool("no-sign-request"), NoVerifySSL: c.Bool("no-verify-ssl"), diff --git a/go.mod b/go.mod index ce67e9408..04eb244f5 100644 --- a/go.mod +++ b/go.mod @@ -6,13 +6,14 @@ require ( github.com/aws/aws-sdk-go v1.44.256 github.com/cheggaaa/pb/v3 v3.1.4 github.com/golang/mock v1.6.0 - github.com/google/go-cmp v0.4.0 + github.com/google/go-cmp v0.5.9 github.com/hashicorp/go-multierror v1.0.0 github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 github.com/igungor/gofakes3 v0.0.14 github.com/karrick/godirwalk v1.15.3 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/lanrat/extsort v1.0.0 + github.com/quic-go/quic-go v0.37.0 github.com/termie/go-shutil v0.0.0-20140729215957-bcacb06fecae github.com/urfave/cli/v2 v2.11.2 gotest.tools/v3 v3.0.2 @@ -23,23 +24,35 @@ require ( github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.15.0 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kr/pretty v0.3.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/onsi/ginkgo/v2 v2.9.5 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/quic-go/qpack v0.4.0 // indirect + github.com/quic-go/qtls-go1-19 v0.3.2 // indirect + github.com/quic-go/qtls-go1-20 v0.3.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect github.com/shabbyrobe/gocovmerge v0.0.0-20190829150210-3e036491d500 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.etcd.io/bbolt v1.3.6 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.7.0 // indirect - golang.org/x/tools v0.8.0 // indirect + golang.org/x/crypto v0.4.0 // indirect + golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect + golang.org/x/mod v0.10.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sync v0.2.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + golang.org/x/tools v0.9.1 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index bbf349d54..c6b538e7c 100644 --- a/go.sum +++ b/go.sum @@ -4,41 +4,47 @@ github.com/aws/aws-sdk-go v1.44.256 h1:O8VH+bJqgLDguqkH/xQBFz5o/YheeZqgcOYIgsTVW github.com/aws/aws-sdk-go v1.44.256/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/cheggaaa/pb/v3 v3.1.4 h1:DN8j4TVVdKu3WxVwcRKu0sG00IIU6FewoABZzXbRQeo= github.com/cheggaaa/pb/v3 v3.1.4/go.mod h1:6wVjILNBaXMs8c21qRiaUM8BR82erfgau1DQ4iUXmSA= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 h1:VHgatEHNcBFEB7inlalqfNqw65aNkM1lGX2yt3NmbS8= github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/igungor/gofakes3 v0.0.14 h1:jpKujPDFe6iF3rJ34AyafvK7+LatbSbjRTnmBVPnsuY= github.com/igungor/gofakes3 v0.0.14/go.mod h1:+rwAKRO9RTGCIeE8SRvRPLSj7PVhaMBLlm1zPXzu7Cs= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/karrick/godirwalk v1.15.3 h1:0a2pXOgtB16CqIqXTiT7+K9L73f74n/aNQUnH6Ortew= github.com/karrick/godirwalk v1.15.3/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lanrat/extsort v1.0.0 h1:JjvkCUbD55+gs5s64FHmCU93kWjegEAM5n10XN6GB3c= github.com/lanrat/extsort v1.0.0/go.mod h1:bkDEvem4UnD1h87yKICydXs63mKrIGW3W9OGPMg93Ww= @@ -49,14 +55,28 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= +github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= +github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= +github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U= +github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= +github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E= +github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= +github.com/quic-go/qtls-go1-20 v0.3.0 h1:NrCXmDl8BddZwO67vlvEpBTwT89bJfKYygxv4HQvuDk= +github.com/quic-go/qtls-go1-20 v0.3.0/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/quic-go v0.36.1 h1:WsG73nVtnDy1TiACxFxhQ3TqaW+DipmqzLEtNlAwZyY= +github.com/quic-go/quic-go v0.36.1/go.mod h1:zPetvwDlILVxt15n3hr3Gf/I3mDf7LpLKPhR4Ez0AZQ= +github.com/quic-go/quic-go v0.37.0 h1:wf/Ym2yeWi98oQn4ahiBSqdnaXVxNQGj2oBQFgiVChc= +github.com/quic-go/quic-go v0.37.0/go.mod h1:XtCUOCALTTWbPyd0IxFfHf6h0sEMubRFvEYHl3QxKw8= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -67,6 +87,7 @@ github.com/shabbyrobe/gocovmerge v0.0.0-20190829150210-3e036491d500/go.mod h1:+n github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/termie/go-shutil v0.0.0-20140729215957-bcacb06fecae h1:vgGSvdW5Lqg+I1aZOlG32uyE6xHpLdKhZzcTEktz5wM= github.com/termie/go-shutil v0.0.0-20140729215957-bcacb06fecae/go.mod h1:quDq6Se6jlGwiIKia/itDZxqC5rj6/8OdFyMMAwTxCs= github.com/urfave/cli/v2 v2.11.2 h1:FVfNg4m3vbjbBpLYxW//WjxUoHvJ9TlppXcqY9Q9ZfA= @@ -80,9 +101,14 @@ go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8= +golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80= +golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= +golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -92,15 +118,18 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -112,8 +141,9 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -133,20 +163,21 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= diff --git a/storage/s3.go b/storage/s3.go index a6703ac51..849256a7e 100644 --- a/storage/s3.go +++ b/storage/s3.go @@ -29,6 +29,8 @@ import ( "github.com/aws/aws-sdk-go/service/s3/s3iface" "github.com/aws/aws-sdk-go/service/s3/s3manager" "github.com/aws/aws-sdk-go/service/s3/s3manager/s3manageriface" + "github.com/quic-go/quic-go" + "github.com/quic-go/quic-go/http3" "github.com/peak/s5cmd/v2/log" "github.com/peak/s5cmd/v2/storage/url" @@ -1079,6 +1081,18 @@ func (sc *SessionCache) newSession(ctx context.Context, opts Options) (*session. } var httpClient *http.Client + + if opts.HTTP3 { + var qconf quic.Config + roundTripper := &http3.RoundTripper{ + QuicConfig: &qconf, + } + + httpClient = &http.Client{ + Transport: roundTripper, + } + } + if opts.NoVerifySSL { httpClient = insecureHTTPClient } diff --git a/storage/storage.go b/storage/storage.go index ea340f649..3f30c3ee3 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -64,6 +64,7 @@ func NewRemoteClient(ctx context.Context, url *url.URL, opts Options) (*S3, erro MaxRetries: opts.MaxRetries, NoSuchUploadRetryCount: opts.NoSuchUploadRetryCount, Endpoint: opts.Endpoint, + HTTP3: opts.HTTP3, NoVerifySSL: opts.NoVerifySSL, DryRun: opts.DryRun, NoSignRequest: opts.NoSignRequest, @@ -90,6 +91,7 @@ type Options struct { MaxRetries int NoSuchUploadRetryCount int Endpoint string + HTTP3 bool NoVerifySSL bool DryRun bool NoSignRequest bool From 3394256bd74b243adfcd7c4bc30ac9215326b81e Mon Sep 17 00:00:00 2001 From: Jonathan Davies Date: Sat, 29 Jul 2023 00:28:24 +0100 Subject: [PATCH 2/2] vendor: Updated for HTTP3/QUIC support. --- .../go-task/slim-sprig/.editorconfig | 14 + .../go-task/slim-sprig/.gitattributes | 1 + .../github.com/go-task/slim-sprig/.gitignore | 2 + .../go-task/slim-sprig/CHANGELOG.md | 364 + .../github.com/go-task/slim-sprig/LICENSE.txt | 19 + .../github.com/go-task/slim-sprig/README.md | 73 + .../go-task/slim-sprig/Taskfile.yml | 12 + .../github.com/go-task/slim-sprig/crypto.go | 24 + vendor/github.com/go-task/slim-sprig/date.go | 152 + .../github.com/go-task/slim-sprig/defaults.go | 163 + vendor/github.com/go-task/slim-sprig/dict.go | 118 + vendor/github.com/go-task/slim-sprig/doc.go | 19 + .../go-task/slim-sprig/functions.go | 317 + vendor/github.com/go-task/slim-sprig/list.go | 464 + .../github.com/go-task/slim-sprig/network.go | 12 + .../github.com/go-task/slim-sprig/numeric.go | 228 + .../github.com/go-task/slim-sprig/reflect.go | 28 + vendor/github.com/go-task/slim-sprig/regex.go | 83 + .../github.com/go-task/slim-sprig/strings.go | 189 + vendor/github.com/go-task/slim-sprig/url.go | 66 + .../github.com/golang/mock/mockgen/mockgen.go | 701 + .../golang/mock/mockgen/model/model.go | 495 + .../github.com/golang/mock/mockgen/parse.go | 644 + .../github.com/golang/mock/mockgen/reflect.go | 256 + .../golang/mock/mockgen/version.1.11.go | 26 + .../golang/mock/mockgen/version.1.12.go | 35 + .../google/go-cmp/cmp/cmpopts/equate.go | 10 +- .../google/go-cmp/cmp/cmpopts/ignore.go | 11 +- .../google/go-cmp/cmp/cmpopts/sort.go | 16 +- .../go-cmp/cmp/cmpopts/struct_filter.go | 23 +- .../google/go-cmp/cmp/cmpopts/xform.go | 3 +- .../github.com/google/go-cmp/cmp/compare.go | 166 +- .../google/go-cmp/cmp/export_panic.go | 5 +- .../google/go-cmp/cmp/export_unsafe.go | 23 +- .../go-cmp/cmp/internal/diff/debug_disable.go | 3 +- .../go-cmp/cmp/internal/diff/debug_enable.go | 3 +- .../google/go-cmp/cmp/internal/diff/diff.go | 88 +- .../google/go-cmp/cmp/internal/flags/flags.go | 2 +- .../cmp/internal/flags/toolchain_legacy.go | 10 - .../cmp/internal/flags/toolchain_recent.go | 10 - .../go-cmp/cmp/internal/function/func.go | 2 +- .../google/go-cmp/cmp/internal/value/name.go | 164 + .../cmp/internal/value/pointer_purego.go | 13 +- .../cmp/internal/value/pointer_unsafe.go | 13 +- .../google/go-cmp/cmp/internal/value/sort.go | 2 +- .../google/go-cmp/cmp/internal/value/zero.go | 48 - .../github.com/google/go-cmp/cmp/options.go | 17 +- vendor/github.com/google/go-cmp/cmp/path.go | 31 +- vendor/github.com/google/go-cmp/cmp/report.go | 7 +- .../google/go-cmp/cmp/report_compare.go | 215 +- .../google/go-cmp/cmp/report_references.go | 264 + .../google/go-cmp/cmp/report_reflect.go | 312 +- .../google/go-cmp/cmp/report_slices.go | 365 +- .../google/go-cmp/cmp/report_text.go | 89 +- .../google/go-cmp/cmp/report_value.go | 2 +- vendor/github.com/google/pprof/AUTHORS | 7 + vendor/github.com/google/pprof/CONTRIBUTORS | 16 + vendor/github.com/google/pprof/LICENSE | 202 + .../github.com/google/pprof/profile/encode.go | 567 + .../github.com/google/pprof/profile/filter.go | 270 + .../github.com/google/pprof/profile/index.go | 64 + .../pprof/profile/legacy_java_profile.go | 315 + .../google/pprof/profile/legacy_profile.go | 1225 ++ .../github.com/google/pprof/profile/merge.go | 481 + .../google/pprof/profile/profile.go | 805 ++ .../github.com/google/pprof/profile/proto.go | 370 + .../github.com/google/pprof/profile/prune.go | 178 + vendor/github.com/onsi/ginkgo/v2/LICENSE | 20 + .../onsi/ginkgo/v2/config/deprecated.go | 69 + .../ginkgo/v2/formatter/colorable_others.go | 41 + .../ginkgo/v2/formatter/colorable_windows.go | 809 ++ .../onsi/ginkgo/v2/formatter/formatter.go | 230 + .../ginkgo/v2/ginkgo/build/build_command.go | 63 + .../onsi/ginkgo/v2/ginkgo/command/abort.go | 61 + .../onsi/ginkgo/v2/ginkgo/command/command.go | 50 + .../onsi/ginkgo/v2/ginkgo/command/program.go | 182 + .../ginkgo/generators/boostrap_templates.go | 48 + .../v2/ginkgo/generators/bootstrap_command.go | 133 + .../v2/ginkgo/generators/generate_command.go | 259 + .../ginkgo/generators/generate_templates.go | 41 + .../v2/ginkgo/generators/generators_common.go | 64 + .../onsi/ginkgo/v2/ginkgo/internal/compile.go | 161 + .../ginkgo/internal/profiles_and_reports.go | 237 + .../onsi/ginkgo/v2/ginkgo/internal/run.go | 355 + .../ginkgo/v2/ginkgo/internal/test_suite.go | 283 + .../onsi/ginkgo/v2/ginkgo/internal/utils.go | 86 + .../v2/ginkgo/internal/verify_version.go | 54 + .../ginkgo/v2/ginkgo/labels/labels_command.go | 123 + .../github.com/onsi/ginkgo/v2/ginkgo/main.go | 58 + .../onsi/ginkgo/v2/ginkgo/outline/ginkgo.go | 302 + .../onsi/ginkgo/v2/ginkgo/outline/import.go | 65 + .../onsi/ginkgo/v2/ginkgo/outline/outline.go | 110 + .../v2/ginkgo/outline/outline_command.go | 98 + .../onsi/ginkgo/v2/ginkgo/run/run_command.go | 232 + .../v2/ginkgo/unfocus/unfocus_command.go | 186 + .../onsi/ginkgo/v2/ginkgo/watch/delta.go | 22 + .../ginkgo/v2/ginkgo/watch/delta_tracker.go | 75 + .../ginkgo/v2/ginkgo/watch/dependencies.go | 92 + .../ginkgo/v2/ginkgo/watch/package_hash.go | 108 + .../ginkgo/v2/ginkgo/watch/package_hashes.go | 85 + .../onsi/ginkgo/v2/ginkgo/watch/suite.go | 87 + .../ginkgo/v2/ginkgo/watch/watch_command.go | 192 + .../interrupt_handler/interrupt_handler.go | 177 + .../sigquit_swallower_unix.go | 15 + .../sigquit_swallower_windows.go | 8 + .../parallel_support/client_server.go | 72 + .../internal/parallel_support/http_client.go | 169 + .../internal/parallel_support/http_server.go | 242 + .../internal/parallel_support/rpc_client.go | 136 + .../internal/parallel_support/rpc_server.go | 75 + .../parallel_support/server_handler.go | 234 + .../ginkgo/v2/reporters/default_reporter.go | 759 ++ .../v2/reporters/deprecated_reporter.go | 149 + .../onsi/ginkgo/v2/reporters/json_report.go | 60 + .../onsi/ginkgo/v2/reporters/junit_report.go | 369 + .../onsi/ginkgo/v2/reporters/reporter.go | 29 + .../ginkgo/v2/reporters/teamcity_report.go | 101 + .../onsi/ginkgo/v2/types/code_location.go | 159 + .../github.com/onsi/ginkgo/v2/types/config.go | 757 ++ .../onsi/ginkgo/v2/types/deprecated_types.go | 141 + .../ginkgo/v2/types/deprecation_support.go | 177 + .../onsi/ginkgo/v2/types/enum_support.go | 43 + .../github.com/onsi/ginkgo/v2/types/errors.go | 630 + .../onsi/ginkgo/v2/types/file_filter.go | 106 + .../github.com/onsi/ginkgo/v2/types/flags.go | 489 + .../onsi/ginkgo/v2/types/label_filter.go | 358 + .../onsi/ginkgo/v2/types/report_entry.go | 190 + .../github.com/onsi/ginkgo/v2/types/types.go | 916 ++ .../onsi/ginkgo/v2/types/version.go | 3 + vendor/github.com/quic-go/qpack/.codecov.yml | 7 + vendor/github.com/quic-go/qpack/.gitignore | 6 + vendor/github.com/quic-go/qpack/.gitmodules | 3 + vendor/github.com/quic-go/qpack/.golangci.yml | 27 + vendor/github.com/quic-go/qpack/LICENSE.md | 7 + vendor/github.com/quic-go/qpack/README.md | 20 + vendor/github.com/quic-go/qpack/decoder.go | 271 + vendor/github.com/quic-go/qpack/encoder.go | 95 + .../github.com/quic-go/qpack/header_field.go | 16 + .../github.com/quic-go/qpack/static_table.go | 255 + vendor/github.com/quic-go/qpack/tools.go | 5 + vendor/github.com/quic-go/qpack/varint.go | 66 + .../quic-go/qtls-go1-20}/LICENSE | 2 +- .../github.com/quic-go/qtls-go1-20/README.md | 6 + .../github.com/quic-go/qtls-go1-20/alert.go | 109 + vendor/github.com/quic-go/qtls-go1-20/auth.go | 293 + .../github.com/quic-go/qtls-go1-20/cache.go | 95 + .../quic-go/qtls-go1-20/cipher_suites.go | 691 + .../github.com/quic-go/qtls-go1-20/common.go | 1466 ++ vendor/github.com/quic-go/qtls-go1-20/conn.go | 1643 +++ .../quic-go/qtls-go1-20/handshake_client.go | 1122 ++ .../qtls-go1-20/handshake_client_tls13.go | 782 ++ .../quic-go/qtls-go1-20/handshake_messages.go | 1886 +++ .../quic-go/qtls-go1-20/handshake_server.go | 895 ++ .../qtls-go1-20/handshake_server_tls13.go | 979 ++ .../quic-go/qtls-go1-20/key_agreement.go | 366 + .../quic-go/qtls-go1-20/key_schedule.go | 159 + .../quic-go/qtls-go1-20/notboring.go | 18 + vendor/github.com/quic-go/qtls-go1-20/prf.go | 283 + vendor/github.com/quic-go/qtls-go1-20/quic.go | 412 + .../github.com/quic-go/qtls-go1-20/ticket.go | 203 + vendor/github.com/quic-go/qtls-go1-20/tls.go | 356 + .../github.com/quic-go/qtls-go1-20/tls.test | Bin 0 -> 7881666 bytes .../github.com/quic-go/qtls-go1-20/unsafe.go | 101 + vendor/github.com/quic-go/quic-go/.gitignore | 17 + .../github.com/quic-go/quic-go/.golangci.yml | 44 + .../github.com/quic-go/quic-go/Changelog.md | 109 + vendor/github.com/quic-go/quic-go/LICENSE | 21 + vendor/github.com/quic-go/quic-go/README.md | 228 + vendor/github.com/quic-go/quic-go/SECURITY.md | 19 + .../github.com/quic-go/quic-go/buffer_pool.go | 92 + vendor/github.com/quic-go/quic-go/client.go | 257 + .../github.com/quic-go/quic-go/closed_conn.go | 64 + vendor/github.com/quic-go/quic-go/codecov.yml | 23 + vendor/github.com/quic-go/quic-go/config.go | 135 + .../quic-go/quic-go/conn_id_generator.go | 139 + .../quic-go/quic-go/conn_id_manager.go | 214 + .../github.com/quic-go/quic-go/connection.go | 2339 ++++ .../quic-go/quic-go/connection_timer.go | 51 + .../quic-go/quic-go/crypto_stream.go | 107 + .../quic-go/quic-go/crypto_stream_manager.go | 82 + .../quic-go/quic-go/datagram_queue.go | 126 + vendor/github.com/quic-go/quic-go/errors.go | 63 + .../quic-go/quic-go/frame_sorter.go | 237 + vendor/github.com/quic-go/quic-go/framer.go | 165 + .../github.com/quic-go/quic-go/http3/body.go | 135 + .../quic-go/quic-go/http3/capsule.go | 55 + .../quic-go/quic-go/http3/client.go | 477 + .../quic-go/quic-go/http3/error_codes.go | 73 + .../quic-go/quic-go/http3/frames.go | 164 + .../quic-go/quic-go/http3/gzip_reader.go | 39 + .../quic-go/quic-go/http3/headers.go | 198 + .../quic-go/quic-go/http3/http_stream.go | 124 + .../quic-go/quic-go/http3/mockgen.go | 8 + .../quic-go/quic-go/http3/request_writer.go | 287 + .../quic-go/quic-go/http3/response_writer.go | 183 + .../quic-go/quic-go/http3/roundtrip.go | 301 + .../quic-go/quic-go/http3/server.go | 765 ++ .../github.com/quic-go/quic-go/interface.go | 354 + .../internal/ackhandler/ack_eliciting.go | 20 + .../quic-go/internal/ackhandler/ackhandler.go | 23 + .../quic-go/internal/ackhandler/frame.go | 21 + .../quic-go/internal/ackhandler/interfaces.go | 52 + .../quic-go/internal/ackhandler/mockgen.go | 6 + .../quic-go/internal/ackhandler/packet.go | 55 + .../ackhandler/packet_number_generator.go | 84 + .../ackhandler/received_packet_handler.go | 142 + .../ackhandler/received_packet_history.go | 151 + .../ackhandler/received_packet_tracker.go | 196 + .../quic-go/internal/ackhandler/send_mode.go | 46 + .../ackhandler/sent_packet_handler.go | 887 ++ .../ackhandler/sent_packet_history.go | 177 + .../quic-go/internal/congestion/bandwidth.go | 25 + .../quic-go/internal/congestion/clock.go | 18 + .../quic-go/internal/congestion/cubic.go | 214 + .../internal/congestion/cubic_sender.go | 316 + .../internal/congestion/hybrid_slow_start.go | 113 + .../quic-go/internal/congestion/interface.go | 28 + .../quic-go/internal/congestion/pacer.go | 80 + .../flowcontrol/base_flow_controller.go | 125 + .../flowcontrol/connection_flow_controller.go | 112 + .../quic-go/internal/flowcontrol/interface.go | 42 + .../flowcontrol/stream_flow_controller.go | 149 + .../quic-go/internal/handshake/aead.go | 94 + .../internal/handshake/cipher_suite.go | 104 + .../internal/handshake/crypto_setup.go | 637 + .../internal/handshake/header_protector.go | 135 + .../quic-go/internal/handshake/hkdf.go | 29 + .../internal/handshake/initial_aead.go | 71 + .../quic-go/internal/handshake/interface.go | 116 + .../quic-go/internal/handshake/retry.go | 63 + .../internal/handshake/session_ticket.go | 47 + .../internal/handshake/token_generator.go | 127 + .../internal/handshake/token_protector.go | 89 + .../internal/handshake/updatable_aead.go | 332 + .../quic-go/internal/logutils/frame.go | 50 + .../internal/protocol/connection_id.go | 116 + .../internal/protocol/encryption_level.go | 30 + .../quic-go/internal/protocol/key_phase.go | 36 + .../internal/protocol/packet_number.go | 79 + .../quic-go/internal/protocol/params.go | 196 + .../quic-go/internal/protocol/perspective.go | 26 + .../quic-go/internal/protocol/protocol.go | 103 + .../quic-go/internal/protocol/stream.go | 76 + .../quic-go/internal/protocol/version.go | 105 + .../quic-go/internal/qerr/error_codes.go | 88 + .../quic-go/quic-go/internal/qerr/errors.go | 131 + .../internal/qtls/cipher_suite_go121.go | 66 + .../internal/qtls/client_session_cache.go | 61 + .../quic-go/quic-go/internal/qtls/go120.go | 141 + .../quic-go/quic-go/internal/qtls/go121.go | 154 + .../quic-go/internal/qtls/go_oldversion.go | 5 + .../internal/utils/buffered_write_closer.go | 26 + .../quic-go/internal/utils/byteorder.go | 21 + .../internal/utils/byteorder_big_endian.go | 103 + .../quic-go/quic-go/internal/utils/ip.go | 10 + .../internal/utils/linkedlist/README.md | 6 + .../internal/utils/linkedlist/linkedlist.go | 264 + .../quic-go/quic-go/internal/utils/log.go | 131 + .../quic-go/quic-go/internal/utils/minmax.go | 72 + .../quic-go/quic-go/internal/utils/rand.go | 29 + .../internal/utils/ringbuffer/ringbuffer.go | 86 + .../quic-go/internal/utils/rtt_stats.go | 131 + .../quic-go/quic-go/internal/utils/timer.go | 57 + .../quic-go/internal/wire/ack_frame.go | 266 + .../quic-go/internal/wire/ack_range.go | 14 + .../internal/wire/connection_close_frame.go | 78 + .../quic-go/internal/wire/crypto_frame.go | 98 + .../internal/wire/data_blocked_frame.go | 31 + .../quic-go/internal/wire/datagram_frame.go | 80 + .../quic-go/internal/wire/extended_header.go | 210 + .../quic-go/internal/wire/frame_parser.go | 191 + .../internal/wire/handshake_done_frame.go | 17 + .../quic-go/quic-go/internal/wire/header.go | 296 + .../quic-go/internal/wire/interface.go | 17 + .../quic-go/quic-go/internal/wire/log.go | 72 + .../quic-go/internal/wire/max_data_frame.go | 35 + .../internal/wire/max_stream_data_frame.go | 42 + .../internal/wire/max_streams_frame.go | 50 + .../internal/wire/new_connection_id_frame.go | 73 + .../quic-go/internal/wire/new_token_frame.go | 45 + .../internal/wire/path_challenge_frame.go | 35 + .../internal/wire/path_response_frame.go | 35 + .../quic-go/internal/wire/ping_frame.go | 17 + .../quic-go/quic-go/internal/wire/pool.go | 33 + .../internal/wire/reset_stream_frame.go | 54 + .../wire/retire_connection_id_frame.go | 32 + .../quic-go/internal/wire/short_header.go | 73 + .../internal/wire/stop_sending_frame.go | 44 + .../wire/stream_data_blocked_frame.go | 42 + .../quic-go/internal/wire/stream_frame.go | 184 + .../internal/wire/streams_blocked_frame.go | 50 + .../internal/wire/transport_parameters.go | 504 + .../internal/wire/version_negotiation.go | 53 + .../quic-go/quic-go/logging/frame.go | 66 + .../quic-go/quic-go/logging/interface.go | 139 + .../quic-go/quic-go/logging/mockgen.go | 4 + .../quic-go/quic-go/logging/multiplex.go | 226 + .../quic-go/quic-go/logging/null_tracer.go | 58 + .../quic-go/quic-go/logging/packet_header.go | 24 + .../quic-go/quic-go/logging/types.go | 94 + vendor/github.com/quic-go/quic-go/mockgen.go | 74 + .../quic-go/quic-go/mtu_discoverer.go | 119 + .../github.com/quic-go/quic-go/multiplexer.go | 75 + vendor/github.com/quic-go/quic-go/oss-fuzz.sh | 42 + .../quic-go/quic-go/packet_handler_map.go | 283 + .../quic-go/quic-go/packet_packer.go | 879 ++ .../quic-go/quic-go/packet_unpacker.go | 226 + .../quic-go/quic-go/quicvarint/io.go | 68 + .../quic-go/quic-go/quicvarint/varint.go | 141 + .../quic-go/quic-go/receive_stream.go | 327 + .../quic-go/quic-go/retransmission_queue.go | 180 + .../github.com/quic-go/quic-go/send_conn.go | 80 + .../github.com/quic-go/quic-go/send_queue.go | 102 + .../github.com/quic-go/quic-go/send_stream.go | 492 + vendor/github.com/quic-go/quic-go/server.go | 885 ++ vendor/github.com/quic-go/quic-go/stream.go | 146 + .../github.com/quic-go/quic-go/streams_map.go | 318 + .../quic-go/quic-go/streams_map_incoming.go | 195 + .../quic-go/quic-go/streams_map_outgoing.go | 230 + vendor/github.com/quic-go/quic-go/sys_conn.go | 115 + .../quic-go/quic-go/sys_conn_buffers.go | 68 + .../quic-go/quic-go/sys_conn_buffers_write.go | 70 + .../github.com/quic-go/quic-go/sys_conn_df.go | 22 + .../quic-go/quic-go/sys_conn_df_darwin.go | 74 + .../quic-go/quic-go/sys_conn_df_linux.go | 80 + .../quic-go/quic-go/sys_conn_df_windows.go | 54 + .../quic-go/quic-go/sys_conn_helper_darwin.go | 31 + .../quic-go/sys_conn_helper_freebsd.go | 26 + .../quic-go/quic-go/sys_conn_helper_linux.go | 50 + .../quic-go/sys_conn_helper_nonlinux.go | 6 + .../quic-go/quic-go/sys_conn_no_gso.go | 8 + .../quic-go/quic-go/sys_conn_no_oob.go | 21 + .../quic-go/quic-go/sys_conn_oob.go | 286 + .../quic-go/quic-go/sys_conn_windows.go | 42 + .../github.com/quic-go/quic-go/token_store.go | 117 + vendor/github.com/quic-go/quic-go/tools.go | 8 + .../github.com/quic-go/quic-go/transport.go | 432 + .../quic-go/quic-go/window_update_queue.go | 71 + vendor/golang.org/x/crypto/LICENSE | 27 + .../golang.org/x/{xerrors => crypto}/PATENTS | 0 .../x/crypto/chacha20/chacha_arm64.go | 17 + .../x/crypto/chacha20/chacha_arm64.s | 308 + .../x/crypto/chacha20/chacha_generic.go | 398 + .../x/crypto/chacha20/chacha_noasm.go | 14 + .../x/crypto/chacha20/chacha_ppc64le.go | 17 + .../x/crypto/chacha20/chacha_ppc64le.s | 450 + .../x/crypto/chacha20/chacha_s390x.go | 28 + .../x/crypto/chacha20/chacha_s390x.s | 225 + vendor/golang.org/x/crypto/chacha20/xor.go | 42 + .../chacha20poly1305/chacha20poly1305.go | 98 + .../chacha20poly1305_amd64.go | 87 + .../chacha20poly1305/chacha20poly1305_amd64.s | 2696 ++++ .../chacha20poly1305_generic.go | 81 + .../chacha20poly1305_noasm.go | 16 + .../chacha20poly1305/xchacha20poly1305.go | 86 + vendor/golang.org/x/crypto/cryptobyte/asn1.go | 816 ++ .../x/crypto/cryptobyte/asn1/asn1.go | 46 + .../golang.org/x/crypto/cryptobyte/builder.go | 342 + .../golang.org/x/crypto/cryptobyte/string.go | 172 + vendor/golang.org/x/crypto/hkdf/hkdf.go | 93 + .../x/crypto/internal/alias/alias.go | 32 + .../x/crypto/internal/alias/alias_purego.go | 35 + .../x/crypto/internal/poly1305/bits_compat.go | 40 + .../x/crypto/internal/poly1305/bits_go1.13.go | 22 + .../x/crypto/internal/poly1305/mac_noasm.go | 10 + .../x/crypto/internal/poly1305/poly1305.go | 99 + .../x/crypto/internal/poly1305/sum_amd64.go | 48 + .../x/crypto/internal/poly1305/sum_amd64.s | 109 + .../x/crypto/internal/poly1305/sum_generic.go | 309 + .../x/crypto/internal/poly1305/sum_ppc64le.go | 48 + .../x/crypto/internal/poly1305/sum_ppc64le.s | 182 + .../x/crypto/internal/poly1305/sum_s390x.go | 77 + .../x/crypto/internal/poly1305/sum_s390x.s | 504 + vendor/golang.org/x/exp/LICENSE | 27 + vendor/golang.org/x/exp/PATENTS | 22 + .../x/exp/constraints/constraints.go | 50 + vendor/golang.org/x/mod/LICENSE | 27 + vendor/golang.org/x/mod/PATENTS | 22 + .../x/mod/internal/lazyregexp/lazyre.go | 78 + vendor/golang.org/x/mod/modfile/print.go | 174 + vendor/golang.org/x/mod/modfile/read.go | 958 ++ vendor/golang.org/x/mod/modfile/rule.go | 1559 +++ vendor/golang.org/x/mod/modfile/work.go | 234 + vendor/golang.org/x/mod/module/module.go | 841 ++ vendor/golang.org/x/mod/module/pseudo.go | 250 + vendor/golang.org/x/mod/semver/semver.go | 401 + vendor/golang.org/x/net/LICENSE | 27 + vendor/golang.org/x/net/PATENTS | 22 + vendor/golang.org/x/net/bpf/asm.go | 41 + vendor/golang.org/x/net/bpf/constants.go | 222 + vendor/golang.org/x/net/bpf/doc.go | 80 + vendor/golang.org/x/net/bpf/instructions.go | 726 + vendor/golang.org/x/net/bpf/setter.go | 10 + vendor/golang.org/x/net/bpf/vm.go | 150 + .../golang.org/x/net/bpf/vm_instructions.go | 182 + vendor/golang.org/x/net/http/httpguts/guts.go | 50 + .../golang.org/x/net/http/httpguts/httplex.go | 352 + vendor/golang.org/x/net/http2/hpack/encode.go | 245 + vendor/golang.org/x/net/http2/hpack/hpack.go | 523 + .../golang.org/x/net/http2/hpack/huffman.go | 226 + .../x/net/http2/hpack/static_table.go | 188 + vendor/golang.org/x/net/http2/hpack/tables.go | 403 + vendor/golang.org/x/net/idna/go118.go | 14 + vendor/golang.org/x/net/idna/idna10.0.0.go | 770 ++ vendor/golang.org/x/net/idna/idna9.0.0.go | 718 + vendor/golang.org/x/net/idna/pre_go118.go | 12 + vendor/golang.org/x/net/idna/punycode.go | 217 + vendor/golang.org/x/net/idna/tables10.0.0.go | 4560 +++++++ vendor/golang.org/x/net/idna/tables11.0.0.go | 4654 +++++++ vendor/golang.org/x/net/idna/tables12.0.0.go | 4734 +++++++ vendor/golang.org/x/net/idna/tables13.0.0.go | 4840 +++++++ vendor/golang.org/x/net/idna/tables9.0.0.go | 4487 +++++++ vendor/golang.org/x/net/idna/trie.go | 72 + vendor/golang.org/x/net/idna/trieval.go | 119 + .../golang.org/x/net/internal/iana/const.go | 223 + .../x/net/internal/socket/cmsghdr.go | 12 + .../x/net/internal/socket/cmsghdr_bsd.go | 14 + .../internal/socket/cmsghdr_linux_32bit.go | 15 + .../internal/socket/cmsghdr_linux_64bit.go | 15 + .../internal/socket/cmsghdr_solaris_64bit.go | 14 + .../x/net/internal/socket/cmsghdr_stub.go | 28 + .../x/net/internal/socket/cmsghdr_unix.go | 22 + .../net/internal/socket/cmsghdr_zos_s390x.go | 11 + .../net/internal/socket/complete_dontwait.go | 26 + .../internal/socket/complete_nodontwait.go | 22 + .../internal/socket/empty.s} | 6 +- .../x/net/internal/socket/error_unix.go | 32 + .../x/net/internal/socket/error_windows.go | 26 + .../x/net/internal/socket/iovec_32bit.go | 20 + .../x/net/internal/socket/iovec_64bit.go | 20 + .../internal/socket/iovec_solaris_64bit.go | 19 + .../x/net/internal/socket/iovec_stub.go | 12 + .../x/net/internal/socket/mmsghdr_stub.go | 22 + .../x/net/internal/socket/mmsghdr_unix.go | 196 + .../x/net/internal/socket/msghdr_bsd.go | 40 + .../x/net/internal/socket/msghdr_bsdvar.go | 17 + .../x/net/internal/socket/msghdr_linux.go | 36 + .../net/internal/socket/msghdr_linux_32bit.go | 25 + .../net/internal/socket/msghdr_linux_64bit.go | 25 + .../x/net/internal/socket/msghdr_openbsd.go | 14 + .../internal/socket/msghdr_solaris_64bit.go | 36 + .../x/net/internal/socket/msghdr_stub.go | 15 + .../x/net/internal/socket/msghdr_zos_s390x.go | 36 + .../x/net/internal/socket/norace.go | 13 + .../golang.org/x/net/internal/socket/race.go | 38 + .../x/net/internal/socket/rawconn.go | 91 + .../x/net/internal/socket/rawconn_mmsg.go | 54 + .../x/net/internal/socket/rawconn_msg.go | 60 + .../x/net/internal/socket/rawconn_nommsg.go | 16 + .../x/net/internal/socket/rawconn_nomsg.go | 16 + .../x/net/internal/socket/socket.go | 280 + .../golang.org/x/net/internal/socket/sys.go | 23 + .../x/net/internal/socket/sys_bsd.go | 16 + .../x/net/internal/socket/sys_const_unix.go | 21 + .../x/net/internal/socket/sys_linux.go | 23 + .../x/net/internal/socket/sys_linux_386.go | 28 + .../x/net/internal/socket/sys_linux_386.s | 11 + .../x/net/internal/socket/sys_linux_amd64.go | 10 + .../x/net/internal/socket/sys_linux_arm.go | 10 + .../x/net/internal/socket/sys_linux_arm64.go | 10 + .../net/internal/socket/sys_linux_loong64.go | 13 + .../x/net/internal/socket/sys_linux_mips.go | 10 + .../x/net/internal/socket/sys_linux_mips64.go | 10 + .../net/internal/socket/sys_linux_mips64le.go | 10 + .../x/net/internal/socket/sys_linux_mipsle.go | 10 + .../x/net/internal/socket/sys_linux_ppc.go | 10 + .../x/net/internal/socket/sys_linux_ppc64.go | 10 + .../net/internal/socket/sys_linux_ppc64le.go | 10 + .../net/internal/socket/sys_linux_riscv64.go | 13 + .../x/net/internal/socket/sys_linux_s390x.go | 28 + .../x/net/internal/socket/sys_linux_s390x.s | 11 + .../x/net/internal/socket/sys_netbsd.go | 25 + .../x/net/internal/socket/sys_posix.go | 185 + .../x/net/internal/socket/sys_stub.go | 53 + .../x/net/internal/socket/sys_unix.go | 122 + .../x/net/internal/socket/sys_windows.go | 55 + .../x/net/internal/socket/sys_zos_s390x.go | 66 + .../x/net/internal/socket/sys_zos_s390x.s | 11 + .../x/net/internal/socket/zsys_aix_ppc64.go | 40 + .../net/internal/socket/zsys_darwin_amd64.go | 32 + .../net/internal/socket/zsys_darwin_arm64.go | 32 + .../internal/socket/zsys_dragonfly_amd64.go | 32 + .../x/net/internal/socket/zsys_freebsd_386.go | 30 + .../net/internal/socket/zsys_freebsd_amd64.go | 32 + .../x/net/internal/socket/zsys_freebsd_arm.go | 30 + .../net/internal/socket/zsys_freebsd_arm64.go | 32 + .../internal/socket/zsys_freebsd_riscv64.go | 30 + .../x/net/internal/socket/zsys_linux_386.go | 35 + .../x/net/internal/socket/zsys_linux_amd64.go | 38 + .../x/net/internal/socket/zsys_linux_arm.go | 35 + .../x/net/internal/socket/zsys_linux_arm64.go | 38 + .../net/internal/socket/zsys_linux_loong64.go | 40 + .../x/net/internal/socket/zsys_linux_mips.go | 35 + .../net/internal/socket/zsys_linux_mips64.go | 38 + .../internal/socket/zsys_linux_mips64le.go | 38 + .../net/internal/socket/zsys_linux_mipsle.go | 35 + .../x/net/internal/socket/zsys_linux_ppc.go | 35 + .../x/net/internal/socket/zsys_linux_ppc64.go | 38 + .../net/internal/socket/zsys_linux_ppc64le.go | 38 + .../net/internal/socket/zsys_linux_riscv64.go | 40 + .../x/net/internal/socket/zsys_linux_s390x.go | 38 + .../x/net/internal/socket/zsys_netbsd_386.go | 35 + .../net/internal/socket/zsys_netbsd_amd64.go | 38 + .../x/net/internal/socket/zsys_netbsd_arm.go | 35 + .../net/internal/socket/zsys_netbsd_arm64.go | 38 + .../x/net/internal/socket/zsys_openbsd_386.go | 30 + .../net/internal/socket/zsys_openbsd_amd64.go | 32 + .../x/net/internal/socket/zsys_openbsd_arm.go | 30 + .../net/internal/socket/zsys_openbsd_arm64.go | 32 + .../internal/socket/zsys_openbsd_mips64.go | 30 + .../net/internal/socket/zsys_openbsd_ppc64.go | 30 + .../internal/socket/zsys_openbsd_riscv64.go | 30 + .../net/internal/socket/zsys_solaris_amd64.go | 32 + .../x/net/internal/socket/zsys_zos_s390x.go | 28 + vendor/golang.org/x/net/ipv4/batch.go | 194 + vendor/golang.org/x/net/ipv4/control.go | 144 + vendor/golang.org/x/net/ipv4/control_bsd.go | 44 + .../golang.org/x/net/ipv4/control_pktinfo.go | 42 + vendor/golang.org/x/net/ipv4/control_stub.go | 14 + vendor/golang.org/x/net/ipv4/control_unix.go | 76 + .../golang.org/x/net/ipv4/control_windows.go | 12 + vendor/golang.org/x/net/ipv4/control_zos.go | 88 + vendor/golang.org/x/net/ipv4/dgramopt.go | 264 + vendor/golang.org/x/net/ipv4/doc.go | 240 + vendor/golang.org/x/net/ipv4/endpoint.go | 186 + vendor/golang.org/x/net/ipv4/genericopt.go | 55 + vendor/golang.org/x/net/ipv4/header.go | 172 + vendor/golang.org/x/net/ipv4/helper.go | 77 + vendor/golang.org/x/net/ipv4/iana.go | 38 + vendor/golang.org/x/net/ipv4/icmp.go | 57 + vendor/golang.org/x/net/ipv4/icmp_linux.go | 25 + vendor/golang.org/x/net/ipv4/icmp_stub.go | 26 + vendor/golang.org/x/net/ipv4/packet.go | 117 + vendor/golang.org/x/net/ipv4/payload.go | 23 + vendor/golang.org/x/net/ipv4/payload_cmsg.go | 85 + .../golang.org/x/net/ipv4/payload_nocmsg.go | 40 + vendor/golang.org/x/net/ipv4/sockopt.go | 44 + vendor/golang.org/x/net/ipv4/sockopt_posix.go | 72 + vendor/golang.org/x/net/ipv4/sockopt_stub.go | 43 + vendor/golang.org/x/net/ipv4/sys_aix.go | 44 + vendor/golang.org/x/net/ipv4/sys_asmreq.go | 123 + .../golang.org/x/net/ipv4/sys_asmreq_stub.go | 26 + vendor/golang.org/x/net/ipv4/sys_asmreqn.go | 45 + .../golang.org/x/net/ipv4/sys_asmreqn_stub.go | 22 + vendor/golang.org/x/net/ipv4/sys_bpf.go | 25 + vendor/golang.org/x/net/ipv4/sys_bpf_stub.go | 17 + vendor/golang.org/x/net/ipv4/sys_bsd.go | 42 + vendor/golang.org/x/net/ipv4/sys_darwin.go | 69 + vendor/golang.org/x/net/ipv4/sys_dragonfly.go | 39 + vendor/golang.org/x/net/ipv4/sys_freebsd.go | 80 + vendor/golang.org/x/net/ipv4/sys_linux.go | 61 + vendor/golang.org/x/net/ipv4/sys_solaris.go | 61 + vendor/golang.org/x/net/ipv4/sys_ssmreq.go | 53 + .../golang.org/x/net/ipv4/sys_ssmreq_stub.go | 22 + vendor/golang.org/x/net/ipv4/sys_stub.go | 14 + vendor/golang.org/x/net/ipv4/sys_windows.go | 44 + vendor/golang.org/x/net/ipv4/sys_zos.go | 57 + .../golang.org/x/net/ipv4/zsys_aix_ppc64.go | 17 + vendor/golang.org/x/net/ipv4/zsys_darwin.go | 59 + .../golang.org/x/net/ipv4/zsys_dragonfly.go | 13 + .../golang.org/x/net/ipv4/zsys_freebsd_386.go | 52 + .../x/net/ipv4/zsys_freebsd_amd64.go | 54 + .../golang.org/x/net/ipv4/zsys_freebsd_arm.go | 54 + .../x/net/ipv4/zsys_freebsd_arm64.go | 52 + .../x/net/ipv4/zsys_freebsd_riscv64.go | 52 + .../golang.org/x/net/ipv4/zsys_linux_386.go | 72 + .../golang.org/x/net/ipv4/zsys_linux_amd64.go | 74 + .../golang.org/x/net/ipv4/zsys_linux_arm.go | 72 + .../golang.org/x/net/ipv4/zsys_linux_arm64.go | 74 + .../x/net/ipv4/zsys_linux_loong64.go | 77 + .../golang.org/x/net/ipv4/zsys_linux_mips.go | 72 + .../x/net/ipv4/zsys_linux_mips64.go | 74 + .../x/net/ipv4/zsys_linux_mips64le.go | 74 + .../x/net/ipv4/zsys_linux_mipsle.go | 72 + .../golang.org/x/net/ipv4/zsys_linux_ppc.go | 72 + .../golang.org/x/net/ipv4/zsys_linux_ppc64.go | 74 + .../x/net/ipv4/zsys_linux_ppc64le.go | 74 + .../x/net/ipv4/zsys_linux_riscv64.go | 77 + .../golang.org/x/net/ipv4/zsys_linux_s390x.go | 74 + vendor/golang.org/x/net/ipv4/zsys_netbsd.go | 13 + vendor/golang.org/x/net/ipv4/zsys_openbsd.go | 13 + vendor/golang.org/x/net/ipv4/zsys_solaris.go | 57 + .../golang.org/x/net/ipv4/zsys_zos_s390x.go | 56 + vendor/golang.org/x/net/ipv6/batch.go | 116 + vendor/golang.org/x/net/ipv6/control.go | 187 + .../x/net/ipv6/control_rfc2292_unix.go | 51 + .../x/net/ipv6/control_rfc3542_unix.go | 97 + vendor/golang.org/x/net/ipv6/control_stub.go | 14 + vendor/golang.org/x/net/ipv6/control_unix.go | 56 + .../golang.org/x/net/ipv6/control_windows.go | 12 + vendor/golang.org/x/net/ipv6/dgramopt.go | 301 + vendor/golang.org/x/net/ipv6/doc.go | 239 + vendor/golang.org/x/net/ipv6/endpoint.go | 127 + vendor/golang.org/x/net/ipv6/genericopt.go | 56 + vendor/golang.org/x/net/ipv6/header.go | 55 + vendor/golang.org/x/net/ipv6/helper.go | 58 + vendor/golang.org/x/net/ipv6/iana.go | 86 + vendor/golang.org/x/net/ipv6/icmp.go | 60 + vendor/golang.org/x/net/ipv6/icmp_bsd.go | 30 + vendor/golang.org/x/net/ipv6/icmp_linux.go | 27 + vendor/golang.org/x/net/ipv6/icmp_solaris.go | 27 + vendor/golang.org/x/net/ipv6/icmp_stub.go | 24 + vendor/golang.org/x/net/ipv6/icmp_windows.go | 22 + vendor/golang.org/x/net/ipv6/icmp_zos.go | 29 + vendor/golang.org/x/net/ipv6/payload.go | 23 + vendor/golang.org/x/net/ipv6/payload_cmsg.go | 71 + .../golang.org/x/net/ipv6/payload_nocmsg.go | 39 + vendor/golang.org/x/net/ipv6/sockopt.go | 43 + vendor/golang.org/x/net/ipv6/sockopt_posix.go | 90 + vendor/golang.org/x/net/ipv6/sockopt_stub.go | 47 + vendor/golang.org/x/net/ipv6/sys_aix.go | 80 + vendor/golang.org/x/net/ipv6/sys_asmreq.go | 25 + .../golang.org/x/net/ipv6/sys_asmreq_stub.go | 18 + vendor/golang.org/x/net/ipv6/sys_bpf.go | 25 + vendor/golang.org/x/net/ipv6/sys_bpf_stub.go | 17 + vendor/golang.org/x/net/ipv6/sys_bsd.go | 60 + vendor/golang.org/x/net/ipv6/sys_darwin.go | 80 + vendor/golang.org/x/net/ipv6/sys_freebsd.go | 94 + vendor/golang.org/x/net/ipv6/sys_linux.go | 76 + vendor/golang.org/x/net/ipv6/sys_solaris.go | 76 + vendor/golang.org/x/net/ipv6/sys_ssmreq.go | 55 + .../golang.org/x/net/ipv6/sys_ssmreq_stub.go | 22 + vendor/golang.org/x/net/ipv6/sys_stub.go | 14 + vendor/golang.org/x/net/ipv6/sys_windows.go | 68 + vendor/golang.org/x/net/ipv6/sys_zos.go | 72 + .../golang.org/x/net/ipv6/zsys_aix_ppc64.go | 69 + vendor/golang.org/x/net/ipv6/zsys_darwin.go | 64 + .../golang.org/x/net/ipv6/zsys_dragonfly.go | 42 + .../golang.org/x/net/ipv6/zsys_freebsd_386.go | 64 + .../x/net/ipv6/zsys_freebsd_amd64.go | 66 + .../golang.org/x/net/ipv6/zsys_freebsd_arm.go | 66 + .../x/net/ipv6/zsys_freebsd_arm64.go | 64 + .../x/net/ipv6/zsys_freebsd_riscv64.go | 64 + .../golang.org/x/net/ipv6/zsys_linux_386.go | 72 + .../golang.org/x/net/ipv6/zsys_linux_amd64.go | 74 + .../golang.org/x/net/ipv6/zsys_linux_arm.go | 72 + .../golang.org/x/net/ipv6/zsys_linux_arm64.go | 74 + .../x/net/ipv6/zsys_linux_loong64.go | 77 + .../golang.org/x/net/ipv6/zsys_linux_mips.go | 72 + .../x/net/ipv6/zsys_linux_mips64.go | 74 + .../x/net/ipv6/zsys_linux_mips64le.go | 74 + .../x/net/ipv6/zsys_linux_mipsle.go | 72 + .../golang.org/x/net/ipv6/zsys_linux_ppc.go | 72 + .../golang.org/x/net/ipv6/zsys_linux_ppc64.go | 74 + .../x/net/ipv6/zsys_linux_ppc64le.go | 74 + .../x/net/ipv6/zsys_linux_riscv64.go | 77 + .../golang.org/x/net/ipv6/zsys_linux_s390x.go | 74 + vendor/golang.org/x/net/ipv6/zsys_netbsd.go | 42 + vendor/golang.org/x/net/ipv6/zsys_openbsd.go | 42 + vendor/golang.org/x/net/ipv6/zsys_solaris.go | 63 + .../golang.org/x/net/ipv6/zsys_zos_s390x.go | 62 + vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s | 18 + vendor/golang.org/x/sys/cpu/byteorder.go | 66 + vendor/golang.org/x/sys/cpu/cpu.go | 287 + vendor/golang.org/x/sys/cpu/cpu_aix.go | 34 + vendor/golang.org/x/sys/cpu/cpu_arm.go | 73 + vendor/golang.org/x/sys/cpu/cpu_arm64.go | 172 + vendor/golang.org/x/sys/cpu/cpu_arm64.s | 32 + vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go | 12 + vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go | 22 + vendor/golang.org/x/sys/cpu/cpu_gc_x86.go | 17 + .../golang.org/x/sys/cpu/cpu_gccgo_arm64.go | 12 + .../golang.org/x/sys/cpu/cpu_gccgo_s390x.go | 23 + vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c | 39 + vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go | 33 + vendor/golang.org/x/sys/cpu/cpu_linux.go | 16 + vendor/golang.org/x/sys/cpu/cpu_linux_arm.go | 39 + .../golang.org/x/sys/cpu/cpu_linux_arm64.go | 111 + .../golang.org/x/sys/cpu/cpu_linux_mips64x.go | 24 + .../golang.org/x/sys/cpu/cpu_linux_noinit.go | 10 + .../golang.org/x/sys/cpu/cpu_linux_ppc64x.go | 32 + .../golang.org/x/sys/cpu/cpu_linux_s390x.go | 40 + vendor/golang.org/x/sys/cpu/cpu_loong64.go | 13 + vendor/golang.org/x/sys/cpu/cpu_mips64x.go | 16 + vendor/golang.org/x/sys/cpu/cpu_mipsx.go | 12 + .../golang.org/x/sys/cpu/cpu_netbsd_arm64.go | 173 + .../golang.org/x/sys/cpu/cpu_openbsd_arm64.go | 65 + .../golang.org/x/sys/cpu/cpu_openbsd_arm64.s | 11 + vendor/golang.org/x/sys/cpu/cpu_other_arm.go | 10 + .../golang.org/x/sys/cpu/cpu_other_arm64.go | 10 + .../golang.org/x/sys/cpu/cpu_other_mips64x.go | 13 + .../golang.org/x/sys/cpu/cpu_other_ppc64x.go | 15 + .../golang.org/x/sys/cpu/cpu_other_riscv64.go | 12 + vendor/golang.org/x/sys/cpu/cpu_ppc64x.go | 17 + vendor/golang.org/x/sys/cpu/cpu_riscv64.go | 12 + vendor/golang.org/x/sys/cpu/cpu_s390x.go | 172 + vendor/golang.org/x/sys/cpu/cpu_s390x.s | 58 + vendor/golang.org/x/sys/cpu/cpu_wasm.go | 18 + vendor/golang.org/x/sys/cpu/cpu_x86.go | 145 + vendor/golang.org/x/sys/cpu/cpu_x86.s | 28 + vendor/golang.org/x/sys/cpu/cpu_zos.go | 10 + vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go | 25 + vendor/golang.org/x/sys/cpu/endian_big.go | 11 + vendor/golang.org/x/sys/cpu/endian_little.go | 11 + vendor/golang.org/x/sys/cpu/hwcap_linux.go | 71 + vendor/golang.org/x/sys/cpu/parse.go | 43 + .../x/sys/cpu/proc_cpuinfo_linux.go | 54 + vendor/golang.org/x/sys/cpu/runtime_auxv.go | 16 + .../x/sys/cpu/runtime_auxv_go121.go | 19 + .../golang.org/x/sys/cpu/syscall_aix_gccgo.go | 27 + .../x/sys/cpu/syscall_aix_ppc64_gc.go | 36 + vendor/golang.org/x/sys/execabs/execabs.go | 102 + .../golang.org/x/sys/execabs/execabs_go118.go | 18 + .../golang.org/x/sys/execabs/execabs_go119.go | 21 + vendor/golang.org/x/sys/unix/mkerrors.sh | 3 +- vendor/golang.org/x/sys/unix/zerrors_linux.go | 14 + .../golang.org/x/sys/windows/env_windows.go | 6 +- .../golang.org/x/sys/windows/exec_windows.go | 7 +- vendor/golang.org/x/sys/windows/service.go | 7 + .../golang.org/x/sys/windows/types_windows.go | 6 +- .../x/sys/windows/zsyscall_windows.go | 9 + vendor/golang.org/x/text/LICENSE | 27 + vendor/golang.org/x/text/PATENTS | 22 + .../x/text/secure/bidirule/bidirule.go | 336 + .../x/text/secure/bidirule/bidirule10.0.0.go | 12 + .../x/text/secure/bidirule/bidirule9.0.0.go | 15 + .../golang.org/x/text/transform/transform.go | 709 + vendor/golang.org/x/text/unicode/bidi/bidi.go | 359 + .../golang.org/x/text/unicode/bidi/bracket.go | 335 + vendor/golang.org/x/text/unicode/bidi/core.go | 1071 ++ vendor/golang.org/x/text/unicode/bidi/prop.go | 206 + .../x/text/unicode/bidi/tables10.0.0.go | 1816 +++ .../x/text/unicode/bidi/tables11.0.0.go | 1888 +++ .../x/text/unicode/bidi/tables12.0.0.go | 1924 +++ .../x/text/unicode/bidi/tables13.0.0.go | 1956 +++ .../x/text/unicode/bidi/tables9.0.0.go | 1782 +++ .../golang.org/x/text/unicode/bidi/trieval.go | 48 + .../x/text/unicode/norm/composition.go | 512 + .../x/text/unicode/norm/forminfo.go | 279 + .../golang.org/x/text/unicode/norm/input.go | 109 + vendor/golang.org/x/text/unicode/norm/iter.go | 458 + .../x/text/unicode/norm/normalize.go | 610 + .../x/text/unicode/norm/readwriter.go | 125 + .../x/text/unicode/norm/tables10.0.0.go | 7658 +++++++++++ .../x/text/unicode/norm/tables11.0.0.go | 7694 +++++++++++ .../x/text/unicode/norm/tables12.0.0.go | 7711 +++++++++++ .../x/text/unicode/norm/tables13.0.0.go | 7761 +++++++++++ .../x/text/unicode/norm/tables9.0.0.go | 7638 +++++++++++ .../x/text/unicode/norm/transform.go | 88 + vendor/golang.org/x/text/unicode/norm/trie.go | 54 + .../x/tools/go/ast/astutil/enclosing.go | 636 + .../x/tools/go/ast/astutil/imports.go | 485 + .../x/tools/go/ast/astutil/rewrite.go | 488 + .../golang.org/x/tools/go/ast/astutil/util.go | 18 + .../x/tools/go/ast/inspector/inspector.go | 218 + .../x/tools/go/ast/inspector/typeof.go | 229 + vendor/golang.org/x/tools/imports/forward.go | 77 + .../x/tools/internal/event/core/event.go | 85 + .../x/tools/internal/event/core/export.go | 70 + .../x/tools/internal/event/core/fast.go | 77 + .../golang.org/x/tools/internal/event/doc.go | 7 + .../x/tools/internal/event/event.go | 127 + .../x/tools/internal/event/keys/keys.go | 564 + .../x/tools/internal/event/keys/standard.go | 22 + .../x/tools/internal/event/label/label.go | 215 + .../x/tools/internal/fastwalk/fastwalk.go | 196 + .../internal/fastwalk/fastwalk_darwin.go | 119 + .../fastwalk/fastwalk_dirent_fileno.go | 14 + .../internal/fastwalk/fastwalk_dirent_ino.go | 15 + .../fastwalk/fastwalk_dirent_namlen_bsd.go | 14 + .../fastwalk/fastwalk_dirent_namlen_linux.go | 29 + .../internal/fastwalk/fastwalk_portable.go | 38 + .../tools/internal/fastwalk/fastwalk_unix.go | 153 + .../x/tools/internal/gocommand/invoke.go | 444 + .../x/tools/internal/gocommand/vendor.go | 109 + .../x/tools/internal/gocommand/version.go | 71 + .../x/tools/internal/gopathwalk/walk.go | 254 + .../x/tools/internal/imports/fix.go | 1762 +++ .../x/tools/internal/imports/imports.go | 351 + .../x/tools/internal/imports/mod.go | 716 + .../x/tools/internal/imports/mod_cache.go | 236 + .../x/tools/internal/imports/sortimports.go | 297 + .../x/tools/internal/imports/zstdlib.go | 11115 ++++++++++++++++ .../x/tools/internal/typeparams/common.go | 178 + .../x/tools/internal/typeparams/coretype.go | 122 + .../internal/typeparams/enabled_go117.go | 12 + .../internal/typeparams/enabled_go118.go | 15 + .../x/tools/internal/typeparams/normalize.go | 218 + .../x/tools/internal/typeparams/termlist.go | 163 + .../internal/typeparams/typeparams_go117.go | 197 + .../internal/typeparams/typeparams_go118.go | 151 + .../x/tools/internal/typeparams/typeterm.go | 170 + vendor/golang.org/x/xerrors/README | 2 - vendor/golang.org/x/xerrors/adaptor.go | 193 - vendor/golang.org/x/xerrors/codereview.cfg | 1 - vendor/golang.org/x/xerrors/doc.go | 22 - vendor/golang.org/x/xerrors/errors.go | 33 - vendor/golang.org/x/xerrors/fmt.go | 187 - vendor/golang.org/x/xerrors/format.go | 34 - vendor/golang.org/x/xerrors/frame.go | 56 - vendor/golang.org/x/xerrors/wrap.go | 106 - vendor/modules.txt | 114 +- 792 files changed, 189350 insertions(+), 1081 deletions(-) create mode 100644 vendor/github.com/go-task/slim-sprig/.editorconfig create mode 100644 vendor/github.com/go-task/slim-sprig/.gitattributes create mode 100644 vendor/github.com/go-task/slim-sprig/.gitignore create mode 100644 vendor/github.com/go-task/slim-sprig/CHANGELOG.md create mode 100644 vendor/github.com/go-task/slim-sprig/LICENSE.txt create mode 100644 vendor/github.com/go-task/slim-sprig/README.md create mode 100644 vendor/github.com/go-task/slim-sprig/Taskfile.yml create mode 100644 vendor/github.com/go-task/slim-sprig/crypto.go create mode 100644 vendor/github.com/go-task/slim-sprig/date.go create mode 100644 vendor/github.com/go-task/slim-sprig/defaults.go create mode 100644 vendor/github.com/go-task/slim-sprig/dict.go create mode 100644 vendor/github.com/go-task/slim-sprig/doc.go create mode 100644 vendor/github.com/go-task/slim-sprig/functions.go create mode 100644 vendor/github.com/go-task/slim-sprig/list.go create mode 100644 vendor/github.com/go-task/slim-sprig/network.go create mode 100644 vendor/github.com/go-task/slim-sprig/numeric.go create mode 100644 vendor/github.com/go-task/slim-sprig/reflect.go create mode 100644 vendor/github.com/go-task/slim-sprig/regex.go create mode 100644 vendor/github.com/go-task/slim-sprig/strings.go create mode 100644 vendor/github.com/go-task/slim-sprig/url.go create mode 100644 vendor/github.com/golang/mock/mockgen/mockgen.go create mode 100644 vendor/github.com/golang/mock/mockgen/model/model.go create mode 100644 vendor/github.com/golang/mock/mockgen/parse.go create mode 100644 vendor/github.com/golang/mock/mockgen/reflect.go create mode 100644 vendor/github.com/golang/mock/mockgen/version.1.11.go create mode 100644 vendor/github.com/golang/mock/mockgen/version.1.12.go delete mode 100644 vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go delete mode 100644 vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go create mode 100644 vendor/github.com/google/go-cmp/cmp/internal/value/name.go delete mode 100644 vendor/github.com/google/go-cmp/cmp/internal/value/zero.go create mode 100644 vendor/github.com/google/go-cmp/cmp/report_references.go create mode 100644 vendor/github.com/google/pprof/AUTHORS create mode 100644 vendor/github.com/google/pprof/CONTRIBUTORS create mode 100644 vendor/github.com/google/pprof/LICENSE create mode 100644 vendor/github.com/google/pprof/profile/encode.go create mode 100644 vendor/github.com/google/pprof/profile/filter.go create mode 100644 vendor/github.com/google/pprof/profile/index.go create mode 100644 vendor/github.com/google/pprof/profile/legacy_java_profile.go create mode 100644 vendor/github.com/google/pprof/profile/legacy_profile.go create mode 100644 vendor/github.com/google/pprof/profile/merge.go create mode 100644 vendor/github.com/google/pprof/profile/profile.go create mode 100644 vendor/github.com/google/pprof/profile/proto.go create mode 100644 vendor/github.com/google/pprof/profile/prune.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/LICENSE create mode 100644 vendor/github.com/onsi/ginkgo/v2/config/deprecated.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/formatter/colorable_others.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/formatter/colorable_windows.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/formatter/formatter.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/build/build_command.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/command/abort.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/command/command.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/command/program.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/boostrap_templates.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/bootstrap_command.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generate_command.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generate_templates.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generators_common.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/compile.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/profiles_and_reports.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/run.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/test_suite.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/utils.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/verify_version.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/labels/labels_command.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/main.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/ginkgo.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/import.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/outline.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/outline_command.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/run/run_command.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/unfocus/unfocus_command.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/delta.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/delta_tracker.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/dependencies.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/package_hash.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/package_hashes.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/suite.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/watch_command.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/interrupt_handler.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/sigquit_swallower_unix.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/sigquit_swallower_windows.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/client_server.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/http_client.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/http_server.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/rpc_client.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/rpc_server.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/server_handler.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/reporters/deprecated_reporter.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/reporters/json_report.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/reporters/junit_report.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/reporters/reporter.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/reporters/teamcity_report.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/types/code_location.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/types/config.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/types/deprecated_types.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/types/deprecation_support.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/types/enum_support.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/types/errors.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/types/file_filter.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/types/flags.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/types/label_filter.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/types/report_entry.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/types/types.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/types/version.go create mode 100644 vendor/github.com/quic-go/qpack/.codecov.yml create mode 100644 vendor/github.com/quic-go/qpack/.gitignore create mode 100644 vendor/github.com/quic-go/qpack/.gitmodules create mode 100644 vendor/github.com/quic-go/qpack/.golangci.yml create mode 100644 vendor/github.com/quic-go/qpack/LICENSE.md create mode 100644 vendor/github.com/quic-go/qpack/README.md create mode 100644 vendor/github.com/quic-go/qpack/decoder.go create mode 100644 vendor/github.com/quic-go/qpack/encoder.go create mode 100644 vendor/github.com/quic-go/qpack/header_field.go create mode 100644 vendor/github.com/quic-go/qpack/static_table.go create mode 100644 vendor/github.com/quic-go/qpack/tools.go create mode 100644 vendor/github.com/quic-go/qpack/varint.go rename vendor/{golang.org/x/xerrors => github.com/quic-go/qtls-go1-20}/LICENSE (96%) create mode 100644 vendor/github.com/quic-go/qtls-go1-20/README.md create mode 100644 vendor/github.com/quic-go/qtls-go1-20/alert.go create mode 100644 vendor/github.com/quic-go/qtls-go1-20/auth.go create mode 100644 vendor/github.com/quic-go/qtls-go1-20/cache.go create mode 100644 vendor/github.com/quic-go/qtls-go1-20/cipher_suites.go create mode 100644 vendor/github.com/quic-go/qtls-go1-20/common.go create mode 100644 vendor/github.com/quic-go/qtls-go1-20/conn.go create mode 100644 vendor/github.com/quic-go/qtls-go1-20/handshake_client.go create mode 100644 vendor/github.com/quic-go/qtls-go1-20/handshake_client_tls13.go create mode 100644 vendor/github.com/quic-go/qtls-go1-20/handshake_messages.go create mode 100644 vendor/github.com/quic-go/qtls-go1-20/handshake_server.go create mode 100644 vendor/github.com/quic-go/qtls-go1-20/handshake_server_tls13.go create mode 100644 vendor/github.com/quic-go/qtls-go1-20/key_agreement.go create mode 100644 vendor/github.com/quic-go/qtls-go1-20/key_schedule.go create mode 100644 vendor/github.com/quic-go/qtls-go1-20/notboring.go create mode 100644 vendor/github.com/quic-go/qtls-go1-20/prf.go create mode 100644 vendor/github.com/quic-go/qtls-go1-20/quic.go create mode 100644 vendor/github.com/quic-go/qtls-go1-20/ticket.go create mode 100644 vendor/github.com/quic-go/qtls-go1-20/tls.go create mode 100644 vendor/github.com/quic-go/qtls-go1-20/tls.test create mode 100644 vendor/github.com/quic-go/qtls-go1-20/unsafe.go create mode 100644 vendor/github.com/quic-go/quic-go/.gitignore create mode 100644 vendor/github.com/quic-go/quic-go/.golangci.yml create mode 100644 vendor/github.com/quic-go/quic-go/Changelog.md create mode 100644 vendor/github.com/quic-go/quic-go/LICENSE create mode 100644 vendor/github.com/quic-go/quic-go/README.md create mode 100644 vendor/github.com/quic-go/quic-go/SECURITY.md create mode 100644 vendor/github.com/quic-go/quic-go/buffer_pool.go create mode 100644 vendor/github.com/quic-go/quic-go/client.go create mode 100644 vendor/github.com/quic-go/quic-go/closed_conn.go create mode 100644 vendor/github.com/quic-go/quic-go/codecov.yml create mode 100644 vendor/github.com/quic-go/quic-go/config.go create mode 100644 vendor/github.com/quic-go/quic-go/conn_id_generator.go create mode 100644 vendor/github.com/quic-go/quic-go/conn_id_manager.go create mode 100644 vendor/github.com/quic-go/quic-go/connection.go create mode 100644 vendor/github.com/quic-go/quic-go/connection_timer.go create mode 100644 vendor/github.com/quic-go/quic-go/crypto_stream.go create mode 100644 vendor/github.com/quic-go/quic-go/crypto_stream_manager.go create mode 100644 vendor/github.com/quic-go/quic-go/datagram_queue.go create mode 100644 vendor/github.com/quic-go/quic-go/errors.go create mode 100644 vendor/github.com/quic-go/quic-go/frame_sorter.go create mode 100644 vendor/github.com/quic-go/quic-go/framer.go create mode 100644 vendor/github.com/quic-go/quic-go/http3/body.go create mode 100644 vendor/github.com/quic-go/quic-go/http3/capsule.go create mode 100644 vendor/github.com/quic-go/quic-go/http3/client.go create mode 100644 vendor/github.com/quic-go/quic-go/http3/error_codes.go create mode 100644 vendor/github.com/quic-go/quic-go/http3/frames.go create mode 100644 vendor/github.com/quic-go/quic-go/http3/gzip_reader.go create mode 100644 vendor/github.com/quic-go/quic-go/http3/headers.go create mode 100644 vendor/github.com/quic-go/quic-go/http3/http_stream.go create mode 100644 vendor/github.com/quic-go/quic-go/http3/mockgen.go create mode 100644 vendor/github.com/quic-go/quic-go/http3/request_writer.go create mode 100644 vendor/github.com/quic-go/quic-go/http3/response_writer.go create mode 100644 vendor/github.com/quic-go/quic-go/http3/roundtrip.go create mode 100644 vendor/github.com/quic-go/quic-go/http3/server.go create mode 100644 vendor/github.com/quic-go/quic-go/interface.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/ack_eliciting.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/ackhandler.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/interfaces.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/mockgen.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/packet.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/packet_number_generator.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_handler.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_history.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_tracker.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/send_mode.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_handler.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_history.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/congestion/bandwidth.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/congestion/clock.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/congestion/cubic.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/congestion/cubic_sender.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/congestion/hybrid_slow_start.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/congestion/interface.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/congestion/pacer.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/flowcontrol/base_flow_controller.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/flowcontrol/connection_flow_controller.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/flowcontrol/interface.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/flowcontrol/stream_flow_controller.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/aead.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/cipher_suite.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/crypto_setup.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/header_protector.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/hkdf.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/initial_aead.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/interface.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/retry.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/session_ticket.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/token_generator.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/token_protector.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/updatable_aead.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/logutils/frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/protocol/connection_id.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/protocol/encryption_level.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/protocol/key_phase.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/protocol/packet_number.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/protocol/params.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/protocol/perspective.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/protocol/protocol.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/protocol/stream.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/protocol/version.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/qerr/error_codes.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/qerr/errors.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/qtls/cipher_suite_go121.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/qtls/client_session_cache.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/qtls/go120.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/qtls/go121.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/qtls/go_oldversion.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/buffered_write_closer.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/byteorder.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/byteorder_big_endian.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/ip.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/linkedlist/README.md create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/linkedlist/linkedlist.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/log.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/minmax.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/rand.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/ringbuffer/ringbuffer.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/rtt_stats.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/timer.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/ack_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/ack_range.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/connection_close_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/crypto_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/data_blocked_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/datagram_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/extended_header.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/frame_parser.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/handshake_done_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/header.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/interface.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/log.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/max_data_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/max_stream_data_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/max_streams_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/new_connection_id_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/new_token_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/path_challenge_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/path_response_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/ping_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/pool.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/reset_stream_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/retire_connection_id_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/short_header.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/stop_sending_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/stream_data_blocked_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/stream_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/streams_blocked_frame.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/transport_parameters.go create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/version_negotiation.go create mode 100644 vendor/github.com/quic-go/quic-go/logging/frame.go create mode 100644 vendor/github.com/quic-go/quic-go/logging/interface.go create mode 100644 vendor/github.com/quic-go/quic-go/logging/mockgen.go create mode 100644 vendor/github.com/quic-go/quic-go/logging/multiplex.go create mode 100644 vendor/github.com/quic-go/quic-go/logging/null_tracer.go create mode 100644 vendor/github.com/quic-go/quic-go/logging/packet_header.go create mode 100644 vendor/github.com/quic-go/quic-go/logging/types.go create mode 100644 vendor/github.com/quic-go/quic-go/mockgen.go create mode 100644 vendor/github.com/quic-go/quic-go/mtu_discoverer.go create mode 100644 vendor/github.com/quic-go/quic-go/multiplexer.go create mode 100644 vendor/github.com/quic-go/quic-go/oss-fuzz.sh create mode 100644 vendor/github.com/quic-go/quic-go/packet_handler_map.go create mode 100644 vendor/github.com/quic-go/quic-go/packet_packer.go create mode 100644 vendor/github.com/quic-go/quic-go/packet_unpacker.go create mode 100644 vendor/github.com/quic-go/quic-go/quicvarint/io.go create mode 100644 vendor/github.com/quic-go/quic-go/quicvarint/varint.go create mode 100644 vendor/github.com/quic-go/quic-go/receive_stream.go create mode 100644 vendor/github.com/quic-go/quic-go/retransmission_queue.go create mode 100644 vendor/github.com/quic-go/quic-go/send_conn.go create mode 100644 vendor/github.com/quic-go/quic-go/send_queue.go create mode 100644 vendor/github.com/quic-go/quic-go/send_stream.go create mode 100644 vendor/github.com/quic-go/quic-go/server.go create mode 100644 vendor/github.com/quic-go/quic-go/stream.go create mode 100644 vendor/github.com/quic-go/quic-go/streams_map.go create mode 100644 vendor/github.com/quic-go/quic-go/streams_map_incoming.go create mode 100644 vendor/github.com/quic-go/quic-go/streams_map_outgoing.go create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn.go create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_buffers.go create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_buffers_write.go create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_df.go create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_df_darwin.go create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_df_linux.go create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_df_windows.go create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_helper_darwin.go create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_helper_freebsd.go create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_helper_linux.go create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_helper_nonlinux.go create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_no_gso.go create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_no_oob.go create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_oob.go create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_windows.go create mode 100644 vendor/github.com/quic-go/quic-go/token_store.go create mode 100644 vendor/github.com/quic-go/quic-go/tools.go create mode 100644 vendor/github.com/quic-go/quic-go/transport.go create mode 100644 vendor/github.com/quic-go/quic-go/window_update_queue.go create mode 100644 vendor/golang.org/x/crypto/LICENSE rename vendor/golang.org/x/{xerrors => crypto}/PATENTS (100%) create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_arm64.go create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_arm64.s create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_generic.go create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_noasm.go create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_s390x.go create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_s390x.s create mode 100644 vendor/golang.org/x/crypto/chacha20/xor.go create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go create mode 100644 vendor/golang.org/x/crypto/cryptobyte/asn1.go create mode 100644 vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go create mode 100644 vendor/golang.org/x/crypto/cryptobyte/builder.go create mode 100644 vendor/golang.org/x/crypto/cryptobyte/string.go create mode 100644 vendor/golang.org/x/crypto/hkdf/hkdf.go create mode 100644 vendor/golang.org/x/crypto/internal/alias/alias.go create mode 100644 vendor/golang.org/x/crypto/internal/alias/alias_purego.go create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/poly1305.go create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s create mode 100644 vendor/golang.org/x/exp/LICENSE create mode 100644 vendor/golang.org/x/exp/PATENTS create mode 100644 vendor/golang.org/x/exp/constraints/constraints.go create mode 100644 vendor/golang.org/x/mod/LICENSE create mode 100644 vendor/golang.org/x/mod/PATENTS create mode 100644 vendor/golang.org/x/mod/internal/lazyregexp/lazyre.go create mode 100644 vendor/golang.org/x/mod/modfile/print.go create mode 100644 vendor/golang.org/x/mod/modfile/read.go create mode 100644 vendor/golang.org/x/mod/modfile/rule.go create mode 100644 vendor/golang.org/x/mod/modfile/work.go create mode 100644 vendor/golang.org/x/mod/module/module.go create mode 100644 vendor/golang.org/x/mod/module/pseudo.go create mode 100644 vendor/golang.org/x/mod/semver/semver.go create mode 100644 vendor/golang.org/x/net/LICENSE create mode 100644 vendor/golang.org/x/net/PATENTS create mode 100644 vendor/golang.org/x/net/bpf/asm.go create mode 100644 vendor/golang.org/x/net/bpf/constants.go create mode 100644 vendor/golang.org/x/net/bpf/doc.go create mode 100644 vendor/golang.org/x/net/bpf/instructions.go create mode 100644 vendor/golang.org/x/net/bpf/setter.go create mode 100644 vendor/golang.org/x/net/bpf/vm.go create mode 100644 vendor/golang.org/x/net/bpf/vm_instructions.go create mode 100644 vendor/golang.org/x/net/http/httpguts/guts.go create mode 100644 vendor/golang.org/x/net/http/httpguts/httplex.go create mode 100644 vendor/golang.org/x/net/http2/hpack/encode.go create mode 100644 vendor/golang.org/x/net/http2/hpack/hpack.go create mode 100644 vendor/golang.org/x/net/http2/hpack/huffman.go create mode 100644 vendor/golang.org/x/net/http2/hpack/static_table.go create mode 100644 vendor/golang.org/x/net/http2/hpack/tables.go create mode 100644 vendor/golang.org/x/net/idna/go118.go create mode 100644 vendor/golang.org/x/net/idna/idna10.0.0.go create mode 100644 vendor/golang.org/x/net/idna/idna9.0.0.go create mode 100644 vendor/golang.org/x/net/idna/pre_go118.go create mode 100644 vendor/golang.org/x/net/idna/punycode.go create mode 100644 vendor/golang.org/x/net/idna/tables10.0.0.go create mode 100644 vendor/golang.org/x/net/idna/tables11.0.0.go create mode 100644 vendor/golang.org/x/net/idna/tables12.0.0.go create mode 100644 vendor/golang.org/x/net/idna/tables13.0.0.go create mode 100644 vendor/golang.org/x/net/idna/tables9.0.0.go create mode 100644 vendor/golang.org/x/net/idna/trie.go create mode 100644 vendor/golang.org/x/net/idna/trieval.go create mode 100644 vendor/golang.org/x/net/internal/iana/const.go create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr.go create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_bsd.go create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_linux_32bit.go create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_linux_64bit.go create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_solaris_64bit.go create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_stub.go create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_unix.go create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_zos_s390x.go create mode 100644 vendor/golang.org/x/net/internal/socket/complete_dontwait.go create mode 100644 vendor/golang.org/x/net/internal/socket/complete_nodontwait.go rename vendor/golang.org/x/{xerrors/internal/internal.go => net/internal/socket/empty.s} (57%) create mode 100644 vendor/golang.org/x/net/internal/socket/error_unix.go create mode 100644 vendor/golang.org/x/net/internal/socket/error_windows.go create mode 100644 vendor/golang.org/x/net/internal/socket/iovec_32bit.go create mode 100644 vendor/golang.org/x/net/internal/socket/iovec_64bit.go create mode 100644 vendor/golang.org/x/net/internal/socket/iovec_solaris_64bit.go create mode 100644 vendor/golang.org/x/net/internal/socket/iovec_stub.go create mode 100644 vendor/golang.org/x/net/internal/socket/mmsghdr_stub.go create mode 100644 vendor/golang.org/x/net/internal/socket/mmsghdr_unix.go create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_bsd.go create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_bsdvar.go create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_linux.go create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_linux_32bit.go create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_linux_64bit.go create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_openbsd.go create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_solaris_64bit.go create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_stub.go create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_zos_s390x.go create mode 100644 vendor/golang.org/x/net/internal/socket/norace.go create mode 100644 vendor/golang.org/x/net/internal/socket/race.go create mode 100644 vendor/golang.org/x/net/internal/socket/rawconn.go create mode 100644 vendor/golang.org/x/net/internal/socket/rawconn_mmsg.go create mode 100644 vendor/golang.org/x/net/internal/socket/rawconn_msg.go create mode 100644 vendor/golang.org/x/net/internal/socket/rawconn_nommsg.go create mode 100644 vendor/golang.org/x/net/internal/socket/rawconn_nomsg.go create mode 100644 vendor/golang.org/x/net/internal/socket/socket.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_bsd.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_const_unix.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_386.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_386.s create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_amd64.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_arm.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_arm64.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_loong64.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_mips.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_mips64.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_mips64le.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_mipsle.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_ppc.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_ppc64.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_ppc64le.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_riscv64.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_s390x.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_s390x.s create mode 100644 vendor/golang.org/x/net/internal/socket/sys_netbsd.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_posix.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_stub.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_unix.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_windows.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_zos_s390x.go create mode 100644 vendor/golang.org/x/net/internal/socket/sys_zos_s390x.s create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_aix_ppc64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_darwin_amd64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_darwin_arm64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_dragonfly_amd64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_freebsd_386.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_freebsd_amd64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_freebsd_arm.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_freebsd_arm64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_freebsd_riscv64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_386.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_amd64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_arm.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_arm64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_loong64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_mips.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_mips64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_mips64le.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_mipsle.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_ppc.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_ppc64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_ppc64le.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_riscv64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_s390x.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_netbsd_386.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_netbsd_amd64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_netbsd_arm.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_netbsd_arm64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_openbsd_386.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_openbsd_amd64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_openbsd_arm.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_openbsd_arm64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_openbsd_mips64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_openbsd_ppc64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_openbsd_riscv64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_solaris_amd64.go create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_zos_s390x.go create mode 100644 vendor/golang.org/x/net/ipv4/batch.go create mode 100644 vendor/golang.org/x/net/ipv4/control.go create mode 100644 vendor/golang.org/x/net/ipv4/control_bsd.go create mode 100644 vendor/golang.org/x/net/ipv4/control_pktinfo.go create mode 100644 vendor/golang.org/x/net/ipv4/control_stub.go create mode 100644 vendor/golang.org/x/net/ipv4/control_unix.go create mode 100644 vendor/golang.org/x/net/ipv4/control_windows.go create mode 100644 vendor/golang.org/x/net/ipv4/control_zos.go create mode 100644 vendor/golang.org/x/net/ipv4/dgramopt.go create mode 100644 vendor/golang.org/x/net/ipv4/doc.go create mode 100644 vendor/golang.org/x/net/ipv4/endpoint.go create mode 100644 vendor/golang.org/x/net/ipv4/genericopt.go create mode 100644 vendor/golang.org/x/net/ipv4/header.go create mode 100644 vendor/golang.org/x/net/ipv4/helper.go create mode 100644 vendor/golang.org/x/net/ipv4/iana.go create mode 100644 vendor/golang.org/x/net/ipv4/icmp.go create mode 100644 vendor/golang.org/x/net/ipv4/icmp_linux.go create mode 100644 vendor/golang.org/x/net/ipv4/icmp_stub.go create mode 100644 vendor/golang.org/x/net/ipv4/packet.go create mode 100644 vendor/golang.org/x/net/ipv4/payload.go create mode 100644 vendor/golang.org/x/net/ipv4/payload_cmsg.go create mode 100644 vendor/golang.org/x/net/ipv4/payload_nocmsg.go create mode 100644 vendor/golang.org/x/net/ipv4/sockopt.go create mode 100644 vendor/golang.org/x/net/ipv4/sockopt_posix.go create mode 100644 vendor/golang.org/x/net/ipv4/sockopt_stub.go create mode 100644 vendor/golang.org/x/net/ipv4/sys_aix.go create mode 100644 vendor/golang.org/x/net/ipv4/sys_asmreq.go create mode 100644 vendor/golang.org/x/net/ipv4/sys_asmreq_stub.go create mode 100644 vendor/golang.org/x/net/ipv4/sys_asmreqn.go create mode 100644 vendor/golang.org/x/net/ipv4/sys_asmreqn_stub.go create mode 100644 vendor/golang.org/x/net/ipv4/sys_bpf.go create mode 100644 vendor/golang.org/x/net/ipv4/sys_bpf_stub.go create mode 100644 vendor/golang.org/x/net/ipv4/sys_bsd.go create mode 100644 vendor/golang.org/x/net/ipv4/sys_darwin.go create mode 100644 vendor/golang.org/x/net/ipv4/sys_dragonfly.go create mode 100644 vendor/golang.org/x/net/ipv4/sys_freebsd.go create mode 100644 vendor/golang.org/x/net/ipv4/sys_linux.go create mode 100644 vendor/golang.org/x/net/ipv4/sys_solaris.go create mode 100644 vendor/golang.org/x/net/ipv4/sys_ssmreq.go create mode 100644 vendor/golang.org/x/net/ipv4/sys_ssmreq_stub.go create mode 100644 vendor/golang.org/x/net/ipv4/sys_stub.go create mode 100644 vendor/golang.org/x/net/ipv4/sys_windows.go create mode 100644 vendor/golang.org/x/net/ipv4/sys_zos.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_aix_ppc64.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_darwin.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_dragonfly.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_freebsd_386.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_freebsd_amd64.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_freebsd_arm.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_freebsd_arm64.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_freebsd_riscv64.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_386.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_amd64.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_arm.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_arm64.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_loong64.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_mips.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_mips64.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_mips64le.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_mipsle.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_ppc.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_ppc64.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_ppc64le.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_riscv64.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_s390x.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_netbsd.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_openbsd.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_solaris.go create mode 100644 vendor/golang.org/x/net/ipv4/zsys_zos_s390x.go create mode 100644 vendor/golang.org/x/net/ipv6/batch.go create mode 100644 vendor/golang.org/x/net/ipv6/control.go create mode 100644 vendor/golang.org/x/net/ipv6/control_rfc2292_unix.go create mode 100644 vendor/golang.org/x/net/ipv6/control_rfc3542_unix.go create mode 100644 vendor/golang.org/x/net/ipv6/control_stub.go create mode 100644 vendor/golang.org/x/net/ipv6/control_unix.go create mode 100644 vendor/golang.org/x/net/ipv6/control_windows.go create mode 100644 vendor/golang.org/x/net/ipv6/dgramopt.go create mode 100644 vendor/golang.org/x/net/ipv6/doc.go create mode 100644 vendor/golang.org/x/net/ipv6/endpoint.go create mode 100644 vendor/golang.org/x/net/ipv6/genericopt.go create mode 100644 vendor/golang.org/x/net/ipv6/header.go create mode 100644 vendor/golang.org/x/net/ipv6/helper.go create mode 100644 vendor/golang.org/x/net/ipv6/iana.go create mode 100644 vendor/golang.org/x/net/ipv6/icmp.go create mode 100644 vendor/golang.org/x/net/ipv6/icmp_bsd.go create mode 100644 vendor/golang.org/x/net/ipv6/icmp_linux.go create mode 100644 vendor/golang.org/x/net/ipv6/icmp_solaris.go create mode 100644 vendor/golang.org/x/net/ipv6/icmp_stub.go create mode 100644 vendor/golang.org/x/net/ipv6/icmp_windows.go create mode 100644 vendor/golang.org/x/net/ipv6/icmp_zos.go create mode 100644 vendor/golang.org/x/net/ipv6/payload.go create mode 100644 vendor/golang.org/x/net/ipv6/payload_cmsg.go create mode 100644 vendor/golang.org/x/net/ipv6/payload_nocmsg.go create mode 100644 vendor/golang.org/x/net/ipv6/sockopt.go create mode 100644 vendor/golang.org/x/net/ipv6/sockopt_posix.go create mode 100644 vendor/golang.org/x/net/ipv6/sockopt_stub.go create mode 100644 vendor/golang.org/x/net/ipv6/sys_aix.go create mode 100644 vendor/golang.org/x/net/ipv6/sys_asmreq.go create mode 100644 vendor/golang.org/x/net/ipv6/sys_asmreq_stub.go create mode 100644 vendor/golang.org/x/net/ipv6/sys_bpf.go create mode 100644 vendor/golang.org/x/net/ipv6/sys_bpf_stub.go create mode 100644 vendor/golang.org/x/net/ipv6/sys_bsd.go create mode 100644 vendor/golang.org/x/net/ipv6/sys_darwin.go create mode 100644 vendor/golang.org/x/net/ipv6/sys_freebsd.go create mode 100644 vendor/golang.org/x/net/ipv6/sys_linux.go create mode 100644 vendor/golang.org/x/net/ipv6/sys_solaris.go create mode 100644 vendor/golang.org/x/net/ipv6/sys_ssmreq.go create mode 100644 vendor/golang.org/x/net/ipv6/sys_ssmreq_stub.go create mode 100644 vendor/golang.org/x/net/ipv6/sys_stub.go create mode 100644 vendor/golang.org/x/net/ipv6/sys_windows.go create mode 100644 vendor/golang.org/x/net/ipv6/sys_zos.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_aix_ppc64.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_darwin.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_dragonfly.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_freebsd_386.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_freebsd_amd64.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_freebsd_arm.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_freebsd_arm64.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_freebsd_riscv64.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_386.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_amd64.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_arm.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_arm64.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_loong64.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_mips.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_mips64.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_mips64le.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_mipsle.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_ppc.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_ppc64.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_ppc64le.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_riscv64.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_s390x.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_netbsd.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_openbsd.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_solaris.go create mode 100644 vendor/golang.org/x/net/ipv6/zsys_zos_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s create mode 100644 vendor/golang.org/x/sys/cpu/byteorder.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_aix.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm64.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_arm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_loong64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_mips64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_mipsx.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_arm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_ppc64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_riscv64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_s390x.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_wasm.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_x86.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_x86.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_zos.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go create mode 100644 vendor/golang.org/x/sys/cpu/endian_big.go create mode 100644 vendor/golang.org/x/sys/cpu/endian_little.go create mode 100644 vendor/golang.org/x/sys/cpu/hwcap_linux.go create mode 100644 vendor/golang.org/x/sys/cpu/parse.go create mode 100644 vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go create mode 100644 vendor/golang.org/x/sys/cpu/runtime_auxv.go create mode 100644 vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go create mode 100644 vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go create mode 100644 vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go create mode 100644 vendor/golang.org/x/sys/execabs/execabs.go create mode 100644 vendor/golang.org/x/sys/execabs/execabs_go118.go create mode 100644 vendor/golang.org/x/sys/execabs/execabs_go119.go create mode 100644 vendor/golang.org/x/text/LICENSE create mode 100644 vendor/golang.org/x/text/PATENTS create mode 100644 vendor/golang.org/x/text/secure/bidirule/bidirule.go create mode 100644 vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go create mode 100644 vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go create mode 100644 vendor/golang.org/x/text/transform/transform.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/bidi.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/bracket.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/core.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/prop.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/trieval.go create mode 100644 vendor/golang.org/x/text/unicode/norm/composition.go create mode 100644 vendor/golang.org/x/text/unicode/norm/forminfo.go create mode 100644 vendor/golang.org/x/text/unicode/norm/input.go create mode 100644 vendor/golang.org/x/text/unicode/norm/iter.go create mode 100644 vendor/golang.org/x/text/unicode/norm/normalize.go create mode 100644 vendor/golang.org/x/text/unicode/norm/readwriter.go create mode 100644 vendor/golang.org/x/text/unicode/norm/tables10.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/norm/tables11.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/norm/tables12.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/norm/tables13.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/norm/tables9.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/norm/transform.go create mode 100644 vendor/golang.org/x/text/unicode/norm/trie.go create mode 100644 vendor/golang.org/x/tools/go/ast/astutil/enclosing.go create mode 100644 vendor/golang.org/x/tools/go/ast/astutil/imports.go create mode 100644 vendor/golang.org/x/tools/go/ast/astutil/rewrite.go create mode 100644 vendor/golang.org/x/tools/go/ast/astutil/util.go create mode 100644 vendor/golang.org/x/tools/go/ast/inspector/inspector.go create mode 100644 vendor/golang.org/x/tools/go/ast/inspector/typeof.go create mode 100644 vendor/golang.org/x/tools/imports/forward.go create mode 100644 vendor/golang.org/x/tools/internal/event/core/event.go create mode 100644 vendor/golang.org/x/tools/internal/event/core/export.go create mode 100644 vendor/golang.org/x/tools/internal/event/core/fast.go create mode 100644 vendor/golang.org/x/tools/internal/event/doc.go create mode 100644 vendor/golang.org/x/tools/internal/event/event.go create mode 100644 vendor/golang.org/x/tools/internal/event/keys/keys.go create mode 100644 vendor/golang.org/x/tools/internal/event/keys/standard.go create mode 100644 vendor/golang.org/x/tools/internal/event/label/label.go create mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go create mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_darwin.go create mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go create mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go create mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go create mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go create mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go create mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go create mode 100644 vendor/golang.org/x/tools/internal/gocommand/invoke.go create mode 100644 vendor/golang.org/x/tools/internal/gocommand/vendor.go create mode 100644 vendor/golang.org/x/tools/internal/gocommand/version.go create mode 100644 vendor/golang.org/x/tools/internal/gopathwalk/walk.go create mode 100644 vendor/golang.org/x/tools/internal/imports/fix.go create mode 100644 vendor/golang.org/x/tools/internal/imports/imports.go create mode 100644 vendor/golang.org/x/tools/internal/imports/mod.go create mode 100644 vendor/golang.org/x/tools/internal/imports/mod_cache.go create mode 100644 vendor/golang.org/x/tools/internal/imports/sortimports.go create mode 100644 vendor/golang.org/x/tools/internal/imports/zstdlib.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/common.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/coretype.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/normalize.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/termlist.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/typeterm.go delete mode 100644 vendor/golang.org/x/xerrors/README delete mode 100644 vendor/golang.org/x/xerrors/adaptor.go delete mode 100644 vendor/golang.org/x/xerrors/codereview.cfg delete mode 100644 vendor/golang.org/x/xerrors/doc.go delete mode 100644 vendor/golang.org/x/xerrors/errors.go delete mode 100644 vendor/golang.org/x/xerrors/fmt.go delete mode 100644 vendor/golang.org/x/xerrors/format.go delete mode 100644 vendor/golang.org/x/xerrors/frame.go delete mode 100644 vendor/golang.org/x/xerrors/wrap.go diff --git a/vendor/github.com/go-task/slim-sprig/.editorconfig b/vendor/github.com/go-task/slim-sprig/.editorconfig new file mode 100644 index 000000000..b0c95367e --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/.editorconfig @@ -0,0 +1,14 @@ +# editorconfig.org + +root = true + +[*] +insert_final_newline = true +charset = utf-8 +trim_trailing_whitespace = true +indent_style = tab +indent_size = 8 + +[*.{md,yml,yaml,json}] +indent_style = space +indent_size = 2 diff --git a/vendor/github.com/go-task/slim-sprig/.gitattributes b/vendor/github.com/go-task/slim-sprig/.gitattributes new file mode 100644 index 000000000..176a458f9 --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/.gitattributes @@ -0,0 +1 @@ +* text=auto diff --git a/vendor/github.com/go-task/slim-sprig/.gitignore b/vendor/github.com/go-task/slim-sprig/.gitignore new file mode 100644 index 000000000..5e3002f88 --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/.gitignore @@ -0,0 +1,2 @@ +vendor/ +/.glide diff --git a/vendor/github.com/go-task/slim-sprig/CHANGELOG.md b/vendor/github.com/go-task/slim-sprig/CHANGELOG.md new file mode 100644 index 000000000..61d8ebffc --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/CHANGELOG.md @@ -0,0 +1,364 @@ +# Changelog + +## Release 3.2.0 (2020-12-14) + +### Added + +- #211: Added randInt function (thanks @kochurovro) +- #223: Added fromJson and mustFromJson functions (thanks @mholt) +- #242: Added a bcrypt function (thanks @robbiet480) +- #253: Added randBytes function (thanks @MikaelSmith) +- #254: Added dig function for dicts (thanks @nyarly) +- #257: Added regexQuoteMeta for quoting regex metadata (thanks @rheaton) +- #261: Added filepath functions osBase, osDir, osExt, osClean, osIsAbs (thanks @zugl) +- #268: Added and and all functions for testing conditions (thanks @phuslu) +- #181: Added float64 arithmetic addf, add1f, subf, divf, mulf, maxf, and minf + (thanks @andrewmostello) +- #265: Added chunk function to split array into smaller arrays (thanks @karelbilek) +- #270: Extend certificate functions to handle non-RSA keys + add support for + ed25519 keys (thanks @misberner) + +### Changed + +- Removed testing and support for Go 1.12. ed25519 support requires Go 1.13 or newer +- Using semver 3.1.1 and mergo 0.3.11 + +### Fixed + +- #249: Fix htmlDateInZone example (thanks @spawnia) + +NOTE: The dependency github.com/imdario/mergo reverted the breaking change in +0.3.9 via 0.3.10 release. + +## Release 3.1.0 (2020-04-16) + +NOTE: The dependency github.com/imdario/mergo made a behavior change in 0.3.9 +that impacts sprig functionality. Do not use sprig with a version newer than 0.3.8. + +### Added + +- #225: Added support for generating htpasswd hash (thanks @rustycl0ck) +- #224: Added duration filter (thanks @frebib) +- #205: Added `seq` function (thanks @thadc23) + +### Changed + +- #203: Unlambda functions with correct signature (thanks @muesli) +- #236: Updated the license formatting for GitHub display purposes +- #238: Updated package dependency versions. Note, mergo not updated to 0.3.9 + as it causes a breaking change for sprig. That issue is tracked at + https://github.com/imdario/mergo/issues/139 + +### Fixed + +- #229: Fix `seq` example in docs (thanks @kalmant) + +## Release 3.0.2 (2019-12-13) + +### Fixed + +- #220: Updating to semver v3.0.3 to fix issue with <= ranges +- #218: fix typo elyptical->elliptic in ecdsa key description (thanks @laverya) + +## Release 3.0.1 (2019-12-08) + +### Fixed + +- #212: Updated semver fixing broken constraint checking with ^0.0 + +## Release 3.0.0 (2019-10-02) + +### Added + +- #187: Added durationRound function (thanks @yjp20) +- #189: Added numerous template functions that return errors rather than panic (thanks @nrvnrvn) +- #193: Added toRawJson support (thanks @Dean-Coakley) +- #197: Added get support to dicts (thanks @Dean-Coakley) + +### Changed + +- #186: Moving dependency management to Go modules +- #186: Updated semver to v3. This has changes in the way ^ is handled +- #194: Updated documentation on merging and how it copies. Added example using deepCopy +- #196: trunc now supports negative values (thanks @Dean-Coakley) + +## Release 2.22.0 (2019-10-02) + +### Added + +- #173: Added getHostByName function to resolve dns names to ips (thanks @fcgravalos) +- #195: Added deepCopy function for use with dicts + +### Changed + +- Updated merge and mergeOverwrite documentation to explain copying and how to + use deepCopy with it + +## Release 2.21.0 (2019-09-18) + +### Added + +- #122: Added encryptAES/decryptAES functions (thanks @n0madic) +- #128: Added toDecimal support (thanks @Dean-Coakley) +- #169: Added list contcat (thanks @astorath) +- #174: Added deepEqual function (thanks @bonifaido) +- #170: Added url parse and join functions (thanks @astorath) + +### Changed + +- #171: Updated glide config for Google UUID to v1 and to add ranges to semver and testify + +### Fixed + +- #172: Fix semver wildcard example (thanks @piepmatz) +- #175: Fix dateInZone doc example (thanks @s3than) + +## Release 2.20.0 (2019-06-18) + +### Added + +- #164: Adding function to get unix epoch for a time (@mattfarina) +- #166: Adding tests for date_in_zone (@mattfarina) + +### Changed + +- #144: Fix function comments based on best practices from Effective Go (@CodeLingoTeam) +- #150: Handles pointer type for time.Time in "htmlDate" (@mapreal19) +- #161, #157, #160, #153, #158, #156, #155, #159, #152 documentation updates (@badeadan) + +### Fixed + +## Release 2.19.0 (2019-03-02) + +IMPORTANT: This release reverts a change from 2.18.0 + +In the previous release (2.18), we prematurely merged a partial change to the crypto functions that led to creating two sets of crypto functions (I blame @technosophos -- since that's me). This release rolls back that change, and does what was originally intended: It alters the existing crypto functions to use secure random. + +We debated whether this classifies as a change worthy of major revision, but given the proximity to the last release, we have decided that treating 2.18 as a faulty release is the correct course of action. We apologize for any inconvenience. + +### Changed + +- Fix substr panic 35fb796 (Alexey igrychev) +- Remove extra period 1eb7729 (Matthew Lorimor) +- Make random string functions use crypto by default 6ceff26 (Matthew Lorimor) +- README edits/fixes/suggestions 08fe136 (Lauri Apple) + + +## Release 2.18.0 (2019-02-12) + +### Added + +- Added mergeOverwrite function +- cryptographic functions that use secure random (see fe1de12) + +### Changed + +- Improve documentation of regexMatch function, resolves #139 90b89ce (Jan Tagscherer) +- Handle has for nil list 9c10885 (Daniel Cohen) +- Document behaviour of mergeOverwrite fe0dbe9 (Lukas Rieder) +- doc: adds missing documentation. 4b871e6 (Fernandez Ludovic) +- Replace outdated goutils imports 01893d2 (Matthew Lorimor) +- Surface crypto secure random strings from goutils fe1de12 (Matthew Lorimor) +- Handle untyped nil values as paramters to string functions 2b2ec8f (Morten Torkildsen) + +### Fixed + +- Fix dict merge issue and provide mergeOverwrite .dst .src1 to overwrite from src -> dst 4c59c12 (Lukas Rieder) +- Fix substr var names and comments d581f80 (Dean Coakley) +- Fix substr documentation 2737203 (Dean Coakley) + +## Release 2.17.1 (2019-01-03) + +### Fixed + +The 2.17.0 release did not have a version pinned for xstrings, which caused compilation failures when xstrings < 1.2 was used. This adds the correct version string to glide.yaml. + +## Release 2.17.0 (2019-01-03) + +### Added + +- adds alder32sum function and test 6908fc2 (marshallford) +- Added kebabcase function ca331a1 (Ilyes512) + +### Changed + +- Update goutils to 1.1.0 4e1125d (Matt Butcher) + +### Fixed + +- Fix 'has' documentation e3f2a85 (dean-coakley) +- docs(dict): fix typo in pick example dc424f9 (Dustin Specker) +- fixes spelling errors... not sure how that happened 4cf188a (marshallford) + +## Release 2.16.0 (2018-08-13) + +### Added + +- add splitn function fccb0b0 (Helgi Þorbjörnsson) +- Add slice func df28ca7 (gongdo) +- Generate serial number a3bdffd (Cody Coons) +- Extract values of dict with values function df39312 (Lawrence Jones) + +### Changed + +- Modify panic message for list.slice ae38335 (gongdo) +- Minor improvement in code quality - Removed an unreachable piece of code at defaults.go#L26:6 - Resolve formatting issues. 5834241 (Abhishek Kashyap) +- Remove duplicated documentation 1d97af1 (Matthew Fisher) +- Test on go 1.11 49df809 (Helgi Þormar Þorbjörnsson) + +### Fixed + +- Fix file permissions c5f40b5 (gongdo) +- Fix example for buildCustomCert 7779e0d (Tin Lam) + +## Release 2.15.0 (2018-04-02) + +### Added + +- #68 and #69: Add json helpers to docs (thanks @arunvelsriram) +- #66: Add ternary function (thanks @binoculars) +- #67: Allow keys function to take multiple dicts (thanks @binoculars) +- #89: Added sha1sum to crypto function (thanks @benkeil) +- #81: Allow customizing Root CA that used by genSignedCert (thanks @chenzhiwei) +- #92: Add travis testing for go 1.10 +- #93: Adding appveyor config for windows testing + +### Changed + +- #90: Updating to more recent dependencies +- #73: replace satori/go.uuid with google/uuid (thanks @petterw) + +### Fixed + +- #76: Fixed documentation typos (thanks @Thiht) +- Fixed rounding issue on the `ago` function. Note, the removes support for Go 1.8 and older + +## Release 2.14.1 (2017-12-01) + +### Fixed + +- #60: Fix typo in function name documentation (thanks @neil-ca-moore) +- #61: Removing line with {{ due to blocking github pages genertion +- #64: Update the list functions to handle int, string, and other slices for compatibility + +## Release 2.14.0 (2017-10-06) + +This new version of Sprig adds a set of functions for generating and working with SSL certificates. + +- `genCA` generates an SSL Certificate Authority +- `genSelfSignedCert` generates an SSL self-signed certificate +- `genSignedCert` generates an SSL certificate and key based on a given CA + +## Release 2.13.0 (2017-09-18) + +This release adds new functions, including: + +- `regexMatch`, `regexFindAll`, `regexFind`, `regexReplaceAll`, `regexReplaceAllLiteral`, and `regexSplit` to work with regular expressions +- `floor`, `ceil`, and `round` math functions +- `toDate` converts a string to a date +- `nindent` is just like `indent` but also prepends a new line +- `ago` returns the time from `time.Now` + +### Added + +- #40: Added basic regex functionality (thanks @alanquillin) +- #41: Added ceil floor and round functions (thanks @alanquillin) +- #48: Added toDate function (thanks @andreynering) +- #50: Added nindent function (thanks @binoculars) +- #46: Added ago function (thanks @slayer) + +### Changed + +- #51: Updated godocs to include new string functions (thanks @curtisallen) +- #49: Added ability to merge multiple dicts (thanks @binoculars) + +## Release 2.12.0 (2017-05-17) + +- `snakecase`, `camelcase`, and `shuffle` are three new string functions +- `fail` allows you to bail out of a template render when conditions are not met + +## Release 2.11.0 (2017-05-02) + +- Added `toJson` and `toPrettyJson` +- Added `merge` +- Refactored documentation + +## Release 2.10.0 (2017-03-15) + +- Added `semver` and `semverCompare` for Semantic Versions +- `list` replaces `tuple` +- Fixed issue with `join` +- Added `first`, `last`, `intial`, `rest`, `prepend`, `append`, `toString`, `toStrings`, `sortAlpha`, `reverse`, `coalesce`, `pluck`, `pick`, `compact`, `keys`, `omit`, `uniq`, `has`, `without` + +## Release 2.9.0 (2017-02-23) + +- Added `splitList` to split a list +- Added crypto functions of `genPrivateKey` and `derivePassword` + +## Release 2.8.0 (2016-12-21) + +- Added access to several path functions (`base`, `dir`, `clean`, `ext`, and `abs`) +- Added functions for _mutating_ dictionaries (`set`, `unset`, `hasKey`) + +## Release 2.7.0 (2016-12-01) + +- Added `sha256sum` to generate a hash of an input +- Added functions to convert a numeric or string to `int`, `int64`, `float64` + +## Release 2.6.0 (2016-10-03) + +- Added a `uuidv4` template function for generating UUIDs inside of a template. + +## Release 2.5.0 (2016-08-19) + +- New `trimSuffix`, `trimPrefix`, `hasSuffix`, and `hasPrefix` functions +- New aliases have been added for a few functions that didn't follow the naming conventions (`trimAll` and `abbrevBoth`) +- `trimall` and `abbrevboth` (notice the case) are deprecated and will be removed in 3.0.0 + +## Release 2.4.0 (2016-08-16) + +- Adds two functions: `until` and `untilStep` + +## Release 2.3.0 (2016-06-21) + +- cat: Concatenate strings with whitespace separators. +- replace: Replace parts of a string: `replace " " "-" "Me First"` renders "Me-First" +- plural: Format plurals: `len "foo" | plural "one foo" "many foos"` renders "many foos" +- indent: Indent blocks of text in a way that is sensitive to "\n" characters. + +## Release 2.2.0 (2016-04-21) + +- Added a `genPrivateKey` function (Thanks @bacongobbler) + +## Release 2.1.0 (2016-03-30) + +- `default` now prints the default value when it does not receive a value down the pipeline. It is much safer now to do `{{.Foo | default "bar"}}`. +- Added accessors for "hermetic" functions. These return only functions that, when given the same input, produce the same output. + +## Release 2.0.0 (2016-03-29) + +Because we switched from `int` to `int64` as the return value for all integer math functions, the library's major version number has been incremented. + +- `min` complements `max` (formerly `biggest`) +- `empty` indicates that a value is the empty value for its type +- `tuple` creates a tuple inside of a template: `{{$t := tuple "a", "b" "c"}}` +- `dict` creates a dictionary inside of a template `{{$d := dict "key1" "val1" "key2" "val2"}}` +- Date formatters have been added for HTML dates (as used in `date` input fields) +- Integer math functions can convert from a number of types, including `string` (via `strconv.ParseInt`). + +## Release 1.2.0 (2016-02-01) + +- Added quote and squote +- Added b32enc and b32dec +- add now takes varargs +- biggest now takes varargs + +## Release 1.1.0 (2015-12-29) + +- Added #4: Added contains function. strings.Contains, but with the arguments + switched to simplify common pipelines. (thanks krancour) +- Added Travis-CI testing support + +## Release 1.0.0 (2015-12-23) + +- Initial release diff --git a/vendor/github.com/go-task/slim-sprig/LICENSE.txt b/vendor/github.com/go-task/slim-sprig/LICENSE.txt new file mode 100644 index 000000000..f311b1eaa --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (C) 2013-2020 Masterminds + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/go-task/slim-sprig/README.md b/vendor/github.com/go-task/slim-sprig/README.md new file mode 100644 index 000000000..72579471f --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/README.md @@ -0,0 +1,73 @@ +# Slim-Sprig: Template functions for Go templates [![GoDoc](https://godoc.org/github.com/go-task/slim-sprig?status.svg)](https://godoc.org/github.com/go-task/slim-sprig) [![Go Report Card](https://goreportcard.com/badge/github.com/go-task/slim-sprig)](https://goreportcard.com/report/github.com/go-task/slim-sprig) + +Slim-Sprig is a fork of [Sprig](https://github.com/Masterminds/sprig), but with +all functions that depend on external (non standard library) or crypto packages +removed. +The reason for this is to make this library more lightweight. Most of these +functions (specially crypto ones) are not needed on most apps, but costs a lot +in terms of binary size and compilation time. + +## Usage + +**Template developers**: Please use Slim-Sprig's [function documentation](https://go-task.github.io/slim-sprig/) for +detailed instructions and code snippets for the >100 template functions available. + +**Go developers**: If you'd like to include Slim-Sprig as a library in your program, +our API documentation is available [at GoDoc.org](http://godoc.org/github.com/go-task/slim-sprig). + +For standard usage, read on. + +### Load the Slim-Sprig library + +To load the Slim-Sprig `FuncMap`: + +```go + +import ( + "html/template" + + "github.com/go-task/slim-sprig" +) + +// This example illustrates that the FuncMap *must* be set before the +// templates themselves are loaded. +tpl := template.Must( + template.New("base").Funcs(sprig.FuncMap()).ParseGlob("*.html") +) +``` + +### Calling the functions inside of templates + +By convention, all functions are lowercase. This seems to follow the Go +idiom for template functions (as opposed to template methods, which are +TitleCase). For example, this: + +``` +{{ "hello!" | upper | repeat 5 }} +``` + +produces this: + +``` +HELLO!HELLO!HELLO!HELLO!HELLO! +``` + +## Principles Driving Our Function Selection + +We followed these principles to decide which functions to add and how to implement them: + +- Use template functions to build layout. The following + types of operations are within the domain of template functions: + - Formatting + - Layout + - Simple type conversions + - Utilities that assist in handling common formatting and layout needs (e.g. arithmetic) +- Template functions should not return errors unless there is no way to print + a sensible value. For example, converting a string to an integer should not + produce an error if conversion fails. Instead, it should display a default + value. +- Simple math is necessary for grid layouts, pagers, and so on. Complex math + (anything other than arithmetic) should be done outside of templates. +- Template functions only deal with the data passed into them. They never retrieve + data from a source. +- Finally, do not override core Go template functions. diff --git a/vendor/github.com/go-task/slim-sprig/Taskfile.yml b/vendor/github.com/go-task/slim-sprig/Taskfile.yml new file mode 100644 index 000000000..cdcfd223b --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/Taskfile.yml @@ -0,0 +1,12 @@ +# https://taskfile.dev + +version: '2' + +tasks: + default: + cmds: + - task: test + + test: + cmds: + - go test -v . diff --git a/vendor/github.com/go-task/slim-sprig/crypto.go b/vendor/github.com/go-task/slim-sprig/crypto.go new file mode 100644 index 000000000..d06e516d4 --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/crypto.go @@ -0,0 +1,24 @@ +package sprig + +import ( + "crypto/sha1" + "crypto/sha256" + "encoding/hex" + "fmt" + "hash/adler32" +) + +func sha256sum(input string) string { + hash := sha256.Sum256([]byte(input)) + return hex.EncodeToString(hash[:]) +} + +func sha1sum(input string) string { + hash := sha1.Sum([]byte(input)) + return hex.EncodeToString(hash[:]) +} + +func adler32sum(input string) string { + hash := adler32.Checksum([]byte(input)) + return fmt.Sprintf("%d", hash) +} diff --git a/vendor/github.com/go-task/slim-sprig/date.go b/vendor/github.com/go-task/slim-sprig/date.go new file mode 100644 index 000000000..ed022ddac --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/date.go @@ -0,0 +1,152 @@ +package sprig + +import ( + "strconv" + "time" +) + +// Given a format and a date, format the date string. +// +// Date can be a `time.Time` or an `int, int32, int64`. +// In the later case, it is treated as seconds since UNIX +// epoch. +func date(fmt string, date interface{}) string { + return dateInZone(fmt, date, "Local") +} + +func htmlDate(date interface{}) string { + return dateInZone("2006-01-02", date, "Local") +} + +func htmlDateInZone(date interface{}, zone string) string { + return dateInZone("2006-01-02", date, zone) +} + +func dateInZone(fmt string, date interface{}, zone string) string { + var t time.Time + switch date := date.(type) { + default: + t = time.Now() + case time.Time: + t = date + case *time.Time: + t = *date + case int64: + t = time.Unix(date, 0) + case int: + t = time.Unix(int64(date), 0) + case int32: + t = time.Unix(int64(date), 0) + } + + loc, err := time.LoadLocation(zone) + if err != nil { + loc, _ = time.LoadLocation("UTC") + } + + return t.In(loc).Format(fmt) +} + +func dateModify(fmt string, date time.Time) time.Time { + d, err := time.ParseDuration(fmt) + if err != nil { + return date + } + return date.Add(d) +} + +func mustDateModify(fmt string, date time.Time) (time.Time, error) { + d, err := time.ParseDuration(fmt) + if err != nil { + return time.Time{}, err + } + return date.Add(d), nil +} + +func dateAgo(date interface{}) string { + var t time.Time + + switch date := date.(type) { + default: + t = time.Now() + case time.Time: + t = date + case int64: + t = time.Unix(date, 0) + case int: + t = time.Unix(int64(date), 0) + } + // Drop resolution to seconds + duration := time.Since(t).Round(time.Second) + return duration.String() +} + +func duration(sec interface{}) string { + var n int64 + switch value := sec.(type) { + default: + n = 0 + case string: + n, _ = strconv.ParseInt(value, 10, 64) + case int64: + n = value + } + return (time.Duration(n) * time.Second).String() +} + +func durationRound(duration interface{}) string { + var d time.Duration + switch duration := duration.(type) { + default: + d = 0 + case string: + d, _ = time.ParseDuration(duration) + case int64: + d = time.Duration(duration) + case time.Time: + d = time.Since(duration) + } + + u := uint64(d) + neg := d < 0 + if neg { + u = -u + } + + var ( + year = uint64(time.Hour) * 24 * 365 + month = uint64(time.Hour) * 24 * 30 + day = uint64(time.Hour) * 24 + hour = uint64(time.Hour) + minute = uint64(time.Minute) + second = uint64(time.Second) + ) + switch { + case u > year: + return strconv.FormatUint(u/year, 10) + "y" + case u > month: + return strconv.FormatUint(u/month, 10) + "mo" + case u > day: + return strconv.FormatUint(u/day, 10) + "d" + case u > hour: + return strconv.FormatUint(u/hour, 10) + "h" + case u > minute: + return strconv.FormatUint(u/minute, 10) + "m" + case u > second: + return strconv.FormatUint(u/second, 10) + "s" + } + return "0s" +} + +func toDate(fmt, str string) time.Time { + t, _ := time.ParseInLocation(fmt, str, time.Local) + return t +} + +func mustToDate(fmt, str string) (time.Time, error) { + return time.ParseInLocation(fmt, str, time.Local) +} + +func unixEpoch(date time.Time) string { + return strconv.FormatInt(date.Unix(), 10) +} diff --git a/vendor/github.com/go-task/slim-sprig/defaults.go b/vendor/github.com/go-task/slim-sprig/defaults.go new file mode 100644 index 000000000..b9f979666 --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/defaults.go @@ -0,0 +1,163 @@ +package sprig + +import ( + "bytes" + "encoding/json" + "math/rand" + "reflect" + "strings" + "time" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +// dfault checks whether `given` is set, and returns default if not set. +// +// This returns `d` if `given` appears not to be set, and `given` otherwise. +// +// For numeric types 0 is unset. +// For strings, maps, arrays, and slices, len() = 0 is considered unset. +// For bool, false is unset. +// Structs are never considered unset. +// +// For everything else, including pointers, a nil value is unset. +func dfault(d interface{}, given ...interface{}) interface{} { + + if empty(given) || empty(given[0]) { + return d + } + return given[0] +} + +// empty returns true if the given value has the zero value for its type. +func empty(given interface{}) bool { + g := reflect.ValueOf(given) + if !g.IsValid() { + return true + } + + // Basically adapted from text/template.isTrue + switch g.Kind() { + default: + return g.IsNil() + case reflect.Array, reflect.Slice, reflect.Map, reflect.String: + return g.Len() == 0 + case reflect.Bool: + return !g.Bool() + case reflect.Complex64, reflect.Complex128: + return g.Complex() == 0 + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return g.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return g.Uint() == 0 + case reflect.Float32, reflect.Float64: + return g.Float() == 0 + case reflect.Struct: + return false + } +} + +// coalesce returns the first non-empty value. +func coalesce(v ...interface{}) interface{} { + for _, val := range v { + if !empty(val) { + return val + } + } + return nil +} + +// all returns true if empty(x) is false for all values x in the list. +// If the list is empty, return true. +func all(v ...interface{}) bool { + for _, val := range v { + if empty(val) { + return false + } + } + return true +} + +// any returns true if empty(x) is false for any x in the list. +// If the list is empty, return false. +func any(v ...interface{}) bool { + for _, val := range v { + if !empty(val) { + return true + } + } + return false +} + +// fromJson decodes JSON into a structured value, ignoring errors. +func fromJson(v string) interface{} { + output, _ := mustFromJson(v) + return output +} + +// mustFromJson decodes JSON into a structured value, returning errors. +func mustFromJson(v string) (interface{}, error) { + var output interface{} + err := json.Unmarshal([]byte(v), &output) + return output, err +} + +// toJson encodes an item into a JSON string +func toJson(v interface{}) string { + output, _ := json.Marshal(v) + return string(output) +} + +func mustToJson(v interface{}) (string, error) { + output, err := json.Marshal(v) + if err != nil { + return "", err + } + return string(output), nil +} + +// toPrettyJson encodes an item into a pretty (indented) JSON string +func toPrettyJson(v interface{}) string { + output, _ := json.MarshalIndent(v, "", " ") + return string(output) +} + +func mustToPrettyJson(v interface{}) (string, error) { + output, err := json.MarshalIndent(v, "", " ") + if err != nil { + return "", err + } + return string(output), nil +} + +// toRawJson encodes an item into a JSON string with no escaping of HTML characters. +func toRawJson(v interface{}) string { + output, err := mustToRawJson(v) + if err != nil { + panic(err) + } + return string(output) +} + +// mustToRawJson encodes an item into a JSON string with no escaping of HTML characters. +func mustToRawJson(v interface{}) (string, error) { + buf := new(bytes.Buffer) + enc := json.NewEncoder(buf) + enc.SetEscapeHTML(false) + err := enc.Encode(&v) + if err != nil { + return "", err + } + return strings.TrimSuffix(buf.String(), "\n"), nil +} + +// ternary returns the first value if the last value is true, otherwise returns the second value. +func ternary(vt interface{}, vf interface{}, v bool) interface{} { + if v { + return vt + } + + return vf +} diff --git a/vendor/github.com/go-task/slim-sprig/dict.go b/vendor/github.com/go-task/slim-sprig/dict.go new file mode 100644 index 000000000..77ebc61b1 --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/dict.go @@ -0,0 +1,118 @@ +package sprig + +func get(d map[string]interface{}, key string) interface{} { + if val, ok := d[key]; ok { + return val + } + return "" +} + +func set(d map[string]interface{}, key string, value interface{}) map[string]interface{} { + d[key] = value + return d +} + +func unset(d map[string]interface{}, key string) map[string]interface{} { + delete(d, key) + return d +} + +func hasKey(d map[string]interface{}, key string) bool { + _, ok := d[key] + return ok +} + +func pluck(key string, d ...map[string]interface{}) []interface{} { + res := []interface{}{} + for _, dict := range d { + if val, ok := dict[key]; ok { + res = append(res, val) + } + } + return res +} + +func keys(dicts ...map[string]interface{}) []string { + k := []string{} + for _, dict := range dicts { + for key := range dict { + k = append(k, key) + } + } + return k +} + +func pick(dict map[string]interface{}, keys ...string) map[string]interface{} { + res := map[string]interface{}{} + for _, k := range keys { + if v, ok := dict[k]; ok { + res[k] = v + } + } + return res +} + +func omit(dict map[string]interface{}, keys ...string) map[string]interface{} { + res := map[string]interface{}{} + + omit := make(map[string]bool, len(keys)) + for _, k := range keys { + omit[k] = true + } + + for k, v := range dict { + if _, ok := omit[k]; !ok { + res[k] = v + } + } + return res +} + +func dict(v ...interface{}) map[string]interface{} { + dict := map[string]interface{}{} + lenv := len(v) + for i := 0; i < lenv; i += 2 { + key := strval(v[i]) + if i+1 >= lenv { + dict[key] = "" + continue + } + dict[key] = v[i+1] + } + return dict +} + +func values(dict map[string]interface{}) []interface{} { + values := []interface{}{} + for _, value := range dict { + values = append(values, value) + } + + return values +} + +func dig(ps ...interface{}) (interface{}, error) { + if len(ps) < 3 { + panic("dig needs at least three arguments") + } + dict := ps[len(ps)-1].(map[string]interface{}) + def := ps[len(ps)-2] + ks := make([]string, len(ps)-2) + for i := 0; i < len(ks); i++ { + ks[i] = ps[i].(string) + } + + return digFromDict(dict, def, ks) +} + +func digFromDict(dict map[string]interface{}, d interface{}, ks []string) (interface{}, error) { + k, ns := ks[0], ks[1:len(ks)] + step, has := dict[k] + if !has { + return d, nil + } + if len(ns) == 0 { + return step, nil + } + return digFromDict(step.(map[string]interface{}), d, ns) +} diff --git a/vendor/github.com/go-task/slim-sprig/doc.go b/vendor/github.com/go-task/slim-sprig/doc.go new file mode 100644 index 000000000..aabb9d448 --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/doc.go @@ -0,0 +1,19 @@ +/* +Package sprig provides template functions for Go. + +This package contains a number of utility functions for working with data +inside of Go `html/template` and `text/template` files. + +To add these functions, use the `template.Funcs()` method: + + t := templates.New("foo").Funcs(sprig.FuncMap()) + +Note that you should add the function map before you parse any template files. + + In several cases, Sprig reverses the order of arguments from the way they + appear in the standard library. This is to make it easier to pipe + arguments into functions. + +See http://masterminds.github.io/sprig/ for more detailed documentation on each of the available functions. +*/ +package sprig diff --git a/vendor/github.com/go-task/slim-sprig/functions.go b/vendor/github.com/go-task/slim-sprig/functions.go new file mode 100644 index 000000000..5ea74f899 --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/functions.go @@ -0,0 +1,317 @@ +package sprig + +import ( + "errors" + "html/template" + "math/rand" + "os" + "path" + "path/filepath" + "reflect" + "strconv" + "strings" + ttemplate "text/template" + "time" +) + +// FuncMap produces the function map. +// +// Use this to pass the functions into the template engine: +// +// tpl := template.New("foo").Funcs(sprig.FuncMap())) +// +func FuncMap() template.FuncMap { + return HtmlFuncMap() +} + +// HermeticTxtFuncMap returns a 'text/template'.FuncMap with only repeatable functions. +func HermeticTxtFuncMap() ttemplate.FuncMap { + r := TxtFuncMap() + for _, name := range nonhermeticFunctions { + delete(r, name) + } + return r +} + +// HermeticHtmlFuncMap returns an 'html/template'.Funcmap with only repeatable functions. +func HermeticHtmlFuncMap() template.FuncMap { + r := HtmlFuncMap() + for _, name := range nonhermeticFunctions { + delete(r, name) + } + return r +} + +// TxtFuncMap returns a 'text/template'.FuncMap +func TxtFuncMap() ttemplate.FuncMap { + return ttemplate.FuncMap(GenericFuncMap()) +} + +// HtmlFuncMap returns an 'html/template'.Funcmap +func HtmlFuncMap() template.FuncMap { + return template.FuncMap(GenericFuncMap()) +} + +// GenericFuncMap returns a copy of the basic function map as a map[string]interface{}. +func GenericFuncMap() map[string]interface{} { + gfm := make(map[string]interface{}, len(genericMap)) + for k, v := range genericMap { + gfm[k] = v + } + return gfm +} + +// These functions are not guaranteed to evaluate to the same result for given input, because they +// refer to the environment or global state. +var nonhermeticFunctions = []string{ + // Date functions + "date", + "date_in_zone", + "date_modify", + "now", + "htmlDate", + "htmlDateInZone", + "dateInZone", + "dateModify", + + // Strings + "randAlphaNum", + "randAlpha", + "randAscii", + "randNumeric", + "randBytes", + "uuidv4", + + // OS + "env", + "expandenv", + + // Network + "getHostByName", +} + +var genericMap = map[string]interface{}{ + "hello": func() string { return "Hello!" }, + + // Date functions + "ago": dateAgo, + "date": date, + "date_in_zone": dateInZone, + "date_modify": dateModify, + "dateInZone": dateInZone, + "dateModify": dateModify, + "duration": duration, + "durationRound": durationRound, + "htmlDate": htmlDate, + "htmlDateInZone": htmlDateInZone, + "must_date_modify": mustDateModify, + "mustDateModify": mustDateModify, + "mustToDate": mustToDate, + "now": time.Now, + "toDate": toDate, + "unixEpoch": unixEpoch, + + // Strings + "trunc": trunc, + "trim": strings.TrimSpace, + "upper": strings.ToUpper, + "lower": strings.ToLower, + "title": strings.Title, + "substr": substring, + // Switch order so that "foo" | repeat 5 + "repeat": func(count int, str string) string { return strings.Repeat(str, count) }, + // Deprecated: Use trimAll. + "trimall": func(a, b string) string { return strings.Trim(b, a) }, + // Switch order so that "$foo" | trimall "$" + "trimAll": func(a, b string) string { return strings.Trim(b, a) }, + "trimSuffix": func(a, b string) string { return strings.TrimSuffix(b, a) }, + "trimPrefix": func(a, b string) string { return strings.TrimPrefix(b, a) }, + // Switch order so that "foobar" | contains "foo" + "contains": func(substr string, str string) bool { return strings.Contains(str, substr) }, + "hasPrefix": func(substr string, str string) bool { return strings.HasPrefix(str, substr) }, + "hasSuffix": func(substr string, str string) bool { return strings.HasSuffix(str, substr) }, + "quote": quote, + "squote": squote, + "cat": cat, + "indent": indent, + "nindent": nindent, + "replace": replace, + "plural": plural, + "sha1sum": sha1sum, + "sha256sum": sha256sum, + "adler32sum": adler32sum, + "toString": strval, + + // Wrap Atoi to stop errors. + "atoi": func(a string) int { i, _ := strconv.Atoi(a); return i }, + "int64": toInt64, + "int": toInt, + "float64": toFloat64, + "seq": seq, + "toDecimal": toDecimal, + + //"gt": func(a, b int) bool {return a > b}, + //"gte": func(a, b int) bool {return a >= b}, + //"lt": func(a, b int) bool {return a < b}, + //"lte": func(a, b int) bool {return a <= b}, + + // split "/" foo/bar returns map[int]string{0: foo, 1: bar} + "split": split, + "splitList": func(sep, orig string) []string { return strings.Split(orig, sep) }, + // splitn "/" foo/bar/fuu returns map[int]string{0: foo, 1: bar/fuu} + "splitn": splitn, + "toStrings": strslice, + + "until": until, + "untilStep": untilStep, + + // VERY basic arithmetic. + "add1": func(i interface{}) int64 { return toInt64(i) + 1 }, + "add": func(i ...interface{}) int64 { + var a int64 = 0 + for _, b := range i { + a += toInt64(b) + } + return a + }, + "sub": func(a, b interface{}) int64 { return toInt64(a) - toInt64(b) }, + "div": func(a, b interface{}) int64 { return toInt64(a) / toInt64(b) }, + "mod": func(a, b interface{}) int64 { return toInt64(a) % toInt64(b) }, + "mul": func(a interface{}, v ...interface{}) int64 { + val := toInt64(a) + for _, b := range v { + val = val * toInt64(b) + } + return val + }, + "randInt": func(min, max int) int { return rand.Intn(max-min) + min }, + "biggest": max, + "max": max, + "min": min, + "maxf": maxf, + "minf": minf, + "ceil": ceil, + "floor": floor, + "round": round, + + // string slices. Note that we reverse the order b/c that's better + // for template processing. + "join": join, + "sortAlpha": sortAlpha, + + // Defaults + "default": dfault, + "empty": empty, + "coalesce": coalesce, + "all": all, + "any": any, + "compact": compact, + "mustCompact": mustCompact, + "fromJson": fromJson, + "toJson": toJson, + "toPrettyJson": toPrettyJson, + "toRawJson": toRawJson, + "mustFromJson": mustFromJson, + "mustToJson": mustToJson, + "mustToPrettyJson": mustToPrettyJson, + "mustToRawJson": mustToRawJson, + "ternary": ternary, + + // Reflection + "typeOf": typeOf, + "typeIs": typeIs, + "typeIsLike": typeIsLike, + "kindOf": kindOf, + "kindIs": kindIs, + "deepEqual": reflect.DeepEqual, + + // OS: + "env": os.Getenv, + "expandenv": os.ExpandEnv, + + // Network: + "getHostByName": getHostByName, + + // Paths: + "base": path.Base, + "dir": path.Dir, + "clean": path.Clean, + "ext": path.Ext, + "isAbs": path.IsAbs, + + // Filepaths: + "osBase": filepath.Base, + "osClean": filepath.Clean, + "osDir": filepath.Dir, + "osExt": filepath.Ext, + "osIsAbs": filepath.IsAbs, + + // Encoding: + "b64enc": base64encode, + "b64dec": base64decode, + "b32enc": base32encode, + "b32dec": base32decode, + + // Data Structures: + "tuple": list, // FIXME: with the addition of append/prepend these are no longer immutable. + "list": list, + "dict": dict, + "get": get, + "set": set, + "unset": unset, + "hasKey": hasKey, + "pluck": pluck, + "keys": keys, + "pick": pick, + "omit": omit, + "values": values, + + "append": push, "push": push, + "mustAppend": mustPush, "mustPush": mustPush, + "prepend": prepend, + "mustPrepend": mustPrepend, + "first": first, + "mustFirst": mustFirst, + "rest": rest, + "mustRest": mustRest, + "last": last, + "mustLast": mustLast, + "initial": initial, + "mustInitial": mustInitial, + "reverse": reverse, + "mustReverse": mustReverse, + "uniq": uniq, + "mustUniq": mustUniq, + "without": without, + "mustWithout": mustWithout, + "has": has, + "mustHas": mustHas, + "slice": slice, + "mustSlice": mustSlice, + "concat": concat, + "dig": dig, + "chunk": chunk, + "mustChunk": mustChunk, + + // Flow Control: + "fail": func(msg string) (string, error) { return "", errors.New(msg) }, + + // Regex + "regexMatch": regexMatch, + "mustRegexMatch": mustRegexMatch, + "regexFindAll": regexFindAll, + "mustRegexFindAll": mustRegexFindAll, + "regexFind": regexFind, + "mustRegexFind": mustRegexFind, + "regexReplaceAll": regexReplaceAll, + "mustRegexReplaceAll": mustRegexReplaceAll, + "regexReplaceAllLiteral": regexReplaceAllLiteral, + "mustRegexReplaceAllLiteral": mustRegexReplaceAllLiteral, + "regexSplit": regexSplit, + "mustRegexSplit": mustRegexSplit, + "regexQuoteMeta": regexQuoteMeta, + + // URLs: + "urlParse": urlParse, + "urlJoin": urlJoin, +} diff --git a/vendor/github.com/go-task/slim-sprig/list.go b/vendor/github.com/go-task/slim-sprig/list.go new file mode 100644 index 000000000..ca0fbb789 --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/list.go @@ -0,0 +1,464 @@ +package sprig + +import ( + "fmt" + "math" + "reflect" + "sort" +) + +// Reflection is used in these functions so that slices and arrays of strings, +// ints, and other types not implementing []interface{} can be worked with. +// For example, this is useful if you need to work on the output of regexs. + +func list(v ...interface{}) []interface{} { + return v +} + +func push(list interface{}, v interface{}) []interface{} { + l, err := mustPush(list, v) + if err != nil { + panic(err) + } + + return l +} + +func mustPush(list interface{}, v interface{}) ([]interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + nl := make([]interface{}, l) + for i := 0; i < l; i++ { + nl[i] = l2.Index(i).Interface() + } + + return append(nl, v), nil + + default: + return nil, fmt.Errorf("Cannot push on type %s", tp) + } +} + +func prepend(list interface{}, v interface{}) []interface{} { + l, err := mustPrepend(list, v) + if err != nil { + panic(err) + } + + return l +} + +func mustPrepend(list interface{}, v interface{}) ([]interface{}, error) { + //return append([]interface{}{v}, list...) + + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + nl := make([]interface{}, l) + for i := 0; i < l; i++ { + nl[i] = l2.Index(i).Interface() + } + + return append([]interface{}{v}, nl...), nil + + default: + return nil, fmt.Errorf("Cannot prepend on type %s", tp) + } +} + +func chunk(size int, list interface{}) [][]interface{} { + l, err := mustChunk(size, list) + if err != nil { + panic(err) + } + + return l +} + +func mustChunk(size int, list interface{}) ([][]interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + + cs := int(math.Floor(float64(l-1)/float64(size)) + 1) + nl := make([][]interface{}, cs) + + for i := 0; i < cs; i++ { + clen := size + if i == cs-1 { + clen = int(math.Floor(math.Mod(float64(l), float64(size)))) + if clen == 0 { + clen = size + } + } + + nl[i] = make([]interface{}, clen) + + for j := 0; j < clen; j++ { + ix := i*size + j + nl[i][j] = l2.Index(ix).Interface() + } + } + + return nl, nil + + default: + return nil, fmt.Errorf("Cannot chunk type %s", tp) + } +} + +func last(list interface{}) interface{} { + l, err := mustLast(list) + if err != nil { + panic(err) + } + + return l +} + +func mustLast(list interface{}) (interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + if l == 0 { + return nil, nil + } + + return l2.Index(l - 1).Interface(), nil + default: + return nil, fmt.Errorf("Cannot find last on type %s", tp) + } +} + +func first(list interface{}) interface{} { + l, err := mustFirst(list) + if err != nil { + panic(err) + } + + return l +} + +func mustFirst(list interface{}) (interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + if l == 0 { + return nil, nil + } + + return l2.Index(0).Interface(), nil + default: + return nil, fmt.Errorf("Cannot find first on type %s", tp) + } +} + +func rest(list interface{}) []interface{} { + l, err := mustRest(list) + if err != nil { + panic(err) + } + + return l +} + +func mustRest(list interface{}) ([]interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + if l == 0 { + return nil, nil + } + + nl := make([]interface{}, l-1) + for i := 1; i < l; i++ { + nl[i-1] = l2.Index(i).Interface() + } + + return nl, nil + default: + return nil, fmt.Errorf("Cannot find rest on type %s", tp) + } +} + +func initial(list interface{}) []interface{} { + l, err := mustInitial(list) + if err != nil { + panic(err) + } + + return l +} + +func mustInitial(list interface{}) ([]interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + if l == 0 { + return nil, nil + } + + nl := make([]interface{}, l-1) + for i := 0; i < l-1; i++ { + nl[i] = l2.Index(i).Interface() + } + + return nl, nil + default: + return nil, fmt.Errorf("Cannot find initial on type %s", tp) + } +} + +func sortAlpha(list interface{}) []string { + k := reflect.Indirect(reflect.ValueOf(list)).Kind() + switch k { + case reflect.Slice, reflect.Array: + a := strslice(list) + s := sort.StringSlice(a) + s.Sort() + return s + } + return []string{strval(list)} +} + +func reverse(v interface{}) []interface{} { + l, err := mustReverse(v) + if err != nil { + panic(err) + } + + return l +} + +func mustReverse(v interface{}) ([]interface{}, error) { + tp := reflect.TypeOf(v).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(v) + + l := l2.Len() + // We do not sort in place because the incoming array should not be altered. + nl := make([]interface{}, l) + for i := 0; i < l; i++ { + nl[l-i-1] = l2.Index(i).Interface() + } + + return nl, nil + default: + return nil, fmt.Errorf("Cannot find reverse on type %s", tp) + } +} + +func compact(list interface{}) []interface{} { + l, err := mustCompact(list) + if err != nil { + panic(err) + } + + return l +} + +func mustCompact(list interface{}) ([]interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + nl := []interface{}{} + var item interface{} + for i := 0; i < l; i++ { + item = l2.Index(i).Interface() + if !empty(item) { + nl = append(nl, item) + } + } + + return nl, nil + default: + return nil, fmt.Errorf("Cannot compact on type %s", tp) + } +} + +func uniq(list interface{}) []interface{} { + l, err := mustUniq(list) + if err != nil { + panic(err) + } + + return l +} + +func mustUniq(list interface{}) ([]interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + dest := []interface{}{} + var item interface{} + for i := 0; i < l; i++ { + item = l2.Index(i).Interface() + if !inList(dest, item) { + dest = append(dest, item) + } + } + + return dest, nil + default: + return nil, fmt.Errorf("Cannot find uniq on type %s", tp) + } +} + +func inList(haystack []interface{}, needle interface{}) bool { + for _, h := range haystack { + if reflect.DeepEqual(needle, h) { + return true + } + } + return false +} + +func without(list interface{}, omit ...interface{}) []interface{} { + l, err := mustWithout(list, omit...) + if err != nil { + panic(err) + } + + return l +} + +func mustWithout(list interface{}, omit ...interface{}) ([]interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + res := []interface{}{} + var item interface{} + for i := 0; i < l; i++ { + item = l2.Index(i).Interface() + if !inList(omit, item) { + res = append(res, item) + } + } + + return res, nil + default: + return nil, fmt.Errorf("Cannot find without on type %s", tp) + } +} + +func has(needle interface{}, haystack interface{}) bool { + l, err := mustHas(needle, haystack) + if err != nil { + panic(err) + } + + return l +} + +func mustHas(needle interface{}, haystack interface{}) (bool, error) { + if haystack == nil { + return false, nil + } + tp := reflect.TypeOf(haystack).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(haystack) + var item interface{} + l := l2.Len() + for i := 0; i < l; i++ { + item = l2.Index(i).Interface() + if reflect.DeepEqual(needle, item) { + return true, nil + } + } + + return false, nil + default: + return false, fmt.Errorf("Cannot find has on type %s", tp) + } +} + +// $list := [1, 2, 3, 4, 5] +// slice $list -> list[0:5] = list[:] +// slice $list 0 3 -> list[0:3] = list[:3] +// slice $list 3 5 -> list[3:5] +// slice $list 3 -> list[3:5] = list[3:] +func slice(list interface{}, indices ...interface{}) interface{} { + l, err := mustSlice(list, indices...) + if err != nil { + panic(err) + } + + return l +} + +func mustSlice(list interface{}, indices ...interface{}) (interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + if l == 0 { + return nil, nil + } + + var start, end int + if len(indices) > 0 { + start = toInt(indices[0]) + } + if len(indices) < 2 { + end = l + } else { + end = toInt(indices[1]) + } + + return l2.Slice(start, end).Interface(), nil + default: + return nil, fmt.Errorf("list should be type of slice or array but %s", tp) + } +} + +func concat(lists ...interface{}) interface{} { + var res []interface{} + for _, list := range lists { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + for i := 0; i < l2.Len(); i++ { + res = append(res, l2.Index(i).Interface()) + } + default: + panic(fmt.Sprintf("Cannot concat type %s as list", tp)) + } + } + return res +} diff --git a/vendor/github.com/go-task/slim-sprig/network.go b/vendor/github.com/go-task/slim-sprig/network.go new file mode 100644 index 000000000..108d78a94 --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/network.go @@ -0,0 +1,12 @@ +package sprig + +import ( + "math/rand" + "net" +) + +func getHostByName(name string) string { + addrs, _ := net.LookupHost(name) + //TODO: add error handing when release v3 comes out + return addrs[rand.Intn(len(addrs))] +} diff --git a/vendor/github.com/go-task/slim-sprig/numeric.go b/vendor/github.com/go-task/slim-sprig/numeric.go new file mode 100644 index 000000000..98cbb37a1 --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/numeric.go @@ -0,0 +1,228 @@ +package sprig + +import ( + "fmt" + "math" + "reflect" + "strconv" + "strings" +) + +// toFloat64 converts 64-bit floats +func toFloat64(v interface{}) float64 { + if str, ok := v.(string); ok { + iv, err := strconv.ParseFloat(str, 64) + if err != nil { + return 0 + } + return iv + } + + val := reflect.Indirect(reflect.ValueOf(v)) + switch val.Kind() { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return float64(val.Int()) + case reflect.Uint8, reflect.Uint16, reflect.Uint32: + return float64(val.Uint()) + case reflect.Uint, reflect.Uint64: + return float64(val.Uint()) + case reflect.Float32, reflect.Float64: + return val.Float() + case reflect.Bool: + if val.Bool() { + return 1 + } + return 0 + default: + return 0 + } +} + +func toInt(v interface{}) int { + //It's not optimal. Bud I don't want duplicate toInt64 code. + return int(toInt64(v)) +} + +// toInt64 converts integer types to 64-bit integers +func toInt64(v interface{}) int64 { + if str, ok := v.(string); ok { + iv, err := strconv.ParseInt(str, 10, 64) + if err != nil { + return 0 + } + return iv + } + + val := reflect.Indirect(reflect.ValueOf(v)) + switch val.Kind() { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return val.Int() + case reflect.Uint8, reflect.Uint16, reflect.Uint32: + return int64(val.Uint()) + case reflect.Uint, reflect.Uint64: + tv := val.Uint() + if tv <= math.MaxInt64 { + return int64(tv) + } + // TODO: What is the sensible thing to do here? + return math.MaxInt64 + case reflect.Float32, reflect.Float64: + return int64(val.Float()) + case reflect.Bool: + if val.Bool() { + return 1 + } + return 0 + default: + return 0 + } +} + +func max(a interface{}, i ...interface{}) int64 { + aa := toInt64(a) + for _, b := range i { + bb := toInt64(b) + if bb > aa { + aa = bb + } + } + return aa +} + +func maxf(a interface{}, i ...interface{}) float64 { + aa := toFloat64(a) + for _, b := range i { + bb := toFloat64(b) + aa = math.Max(aa, bb) + } + return aa +} + +func min(a interface{}, i ...interface{}) int64 { + aa := toInt64(a) + for _, b := range i { + bb := toInt64(b) + if bb < aa { + aa = bb + } + } + return aa +} + +func minf(a interface{}, i ...interface{}) float64 { + aa := toFloat64(a) + for _, b := range i { + bb := toFloat64(b) + aa = math.Min(aa, bb) + } + return aa +} + +func until(count int) []int { + step := 1 + if count < 0 { + step = -1 + } + return untilStep(0, count, step) +} + +func untilStep(start, stop, step int) []int { + v := []int{} + + if stop < start { + if step >= 0 { + return v + } + for i := start; i > stop; i += step { + v = append(v, i) + } + return v + } + + if step <= 0 { + return v + } + for i := start; i < stop; i += step { + v = append(v, i) + } + return v +} + +func floor(a interface{}) float64 { + aa := toFloat64(a) + return math.Floor(aa) +} + +func ceil(a interface{}) float64 { + aa := toFloat64(a) + return math.Ceil(aa) +} + +func round(a interface{}, p int, rOpt ...float64) float64 { + roundOn := .5 + if len(rOpt) > 0 { + roundOn = rOpt[0] + } + val := toFloat64(a) + places := toFloat64(p) + + var round float64 + pow := math.Pow(10, places) + digit := pow * val + _, div := math.Modf(digit) + if div >= roundOn { + round = math.Ceil(digit) + } else { + round = math.Floor(digit) + } + return round / pow +} + +// converts unix octal to decimal +func toDecimal(v interface{}) int64 { + result, err := strconv.ParseInt(fmt.Sprint(v), 8, 64) + if err != nil { + return 0 + } + return result +} + +func seq(params ...int) string { + increment := 1 + switch len(params) { + case 0: + return "" + case 1: + start := 1 + end := params[0] + if end < start { + increment = -1 + } + return intArrayToString(untilStep(start, end+increment, increment), " ") + case 3: + start := params[0] + end := params[2] + step := params[1] + if end < start { + increment = -1 + if step > 0 { + return "" + } + } + return intArrayToString(untilStep(start, end+increment, step), " ") + case 2: + start := params[0] + end := params[1] + step := 1 + if end < start { + step = -1 + } + return intArrayToString(untilStep(start, end+step, step), " ") + default: + return "" + } +} + +func intArrayToString(slice []int, delimeter string) string { + return strings.Trim(strings.Join(strings.Fields(fmt.Sprint(slice)), delimeter), "[]") +} diff --git a/vendor/github.com/go-task/slim-sprig/reflect.go b/vendor/github.com/go-task/slim-sprig/reflect.go new file mode 100644 index 000000000..8a65c132f --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/reflect.go @@ -0,0 +1,28 @@ +package sprig + +import ( + "fmt" + "reflect" +) + +// typeIs returns true if the src is the type named in target. +func typeIs(target string, src interface{}) bool { + return target == typeOf(src) +} + +func typeIsLike(target string, src interface{}) bool { + t := typeOf(src) + return target == t || "*"+target == t +} + +func typeOf(src interface{}) string { + return fmt.Sprintf("%T", src) +} + +func kindIs(target string, src interface{}) bool { + return target == kindOf(src) +} + +func kindOf(src interface{}) string { + return reflect.ValueOf(src).Kind().String() +} diff --git a/vendor/github.com/go-task/slim-sprig/regex.go b/vendor/github.com/go-task/slim-sprig/regex.go new file mode 100644 index 000000000..fab551018 --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/regex.go @@ -0,0 +1,83 @@ +package sprig + +import ( + "regexp" +) + +func regexMatch(regex string, s string) bool { + match, _ := regexp.MatchString(regex, s) + return match +} + +func mustRegexMatch(regex string, s string) (bool, error) { + return regexp.MatchString(regex, s) +} + +func regexFindAll(regex string, s string, n int) []string { + r := regexp.MustCompile(regex) + return r.FindAllString(s, n) +} + +func mustRegexFindAll(regex string, s string, n int) ([]string, error) { + r, err := regexp.Compile(regex) + if err != nil { + return []string{}, err + } + return r.FindAllString(s, n), nil +} + +func regexFind(regex string, s string) string { + r := regexp.MustCompile(regex) + return r.FindString(s) +} + +func mustRegexFind(regex string, s string) (string, error) { + r, err := regexp.Compile(regex) + if err != nil { + return "", err + } + return r.FindString(s), nil +} + +func regexReplaceAll(regex string, s string, repl string) string { + r := regexp.MustCompile(regex) + return r.ReplaceAllString(s, repl) +} + +func mustRegexReplaceAll(regex string, s string, repl string) (string, error) { + r, err := regexp.Compile(regex) + if err != nil { + return "", err + } + return r.ReplaceAllString(s, repl), nil +} + +func regexReplaceAllLiteral(regex string, s string, repl string) string { + r := regexp.MustCompile(regex) + return r.ReplaceAllLiteralString(s, repl) +} + +func mustRegexReplaceAllLiteral(regex string, s string, repl string) (string, error) { + r, err := regexp.Compile(regex) + if err != nil { + return "", err + } + return r.ReplaceAllLiteralString(s, repl), nil +} + +func regexSplit(regex string, s string, n int) []string { + r := regexp.MustCompile(regex) + return r.Split(s, n) +} + +func mustRegexSplit(regex string, s string, n int) ([]string, error) { + r, err := regexp.Compile(regex) + if err != nil { + return []string{}, err + } + return r.Split(s, n), nil +} + +func regexQuoteMeta(s string) string { + return regexp.QuoteMeta(s) +} diff --git a/vendor/github.com/go-task/slim-sprig/strings.go b/vendor/github.com/go-task/slim-sprig/strings.go new file mode 100644 index 000000000..3c62d6b6f --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/strings.go @@ -0,0 +1,189 @@ +package sprig + +import ( + "encoding/base32" + "encoding/base64" + "fmt" + "reflect" + "strconv" + "strings" +) + +func base64encode(v string) string { + return base64.StdEncoding.EncodeToString([]byte(v)) +} + +func base64decode(v string) string { + data, err := base64.StdEncoding.DecodeString(v) + if err != nil { + return err.Error() + } + return string(data) +} + +func base32encode(v string) string { + return base32.StdEncoding.EncodeToString([]byte(v)) +} + +func base32decode(v string) string { + data, err := base32.StdEncoding.DecodeString(v) + if err != nil { + return err.Error() + } + return string(data) +} + +func quote(str ...interface{}) string { + out := make([]string, 0, len(str)) + for _, s := range str { + if s != nil { + out = append(out, fmt.Sprintf("%q", strval(s))) + } + } + return strings.Join(out, " ") +} + +func squote(str ...interface{}) string { + out := make([]string, 0, len(str)) + for _, s := range str { + if s != nil { + out = append(out, fmt.Sprintf("'%v'", s)) + } + } + return strings.Join(out, " ") +} + +func cat(v ...interface{}) string { + v = removeNilElements(v) + r := strings.TrimSpace(strings.Repeat("%v ", len(v))) + return fmt.Sprintf(r, v...) +} + +func indent(spaces int, v string) string { + pad := strings.Repeat(" ", spaces) + return pad + strings.Replace(v, "\n", "\n"+pad, -1) +} + +func nindent(spaces int, v string) string { + return "\n" + indent(spaces, v) +} + +func replace(old, new, src string) string { + return strings.Replace(src, old, new, -1) +} + +func plural(one, many string, count int) string { + if count == 1 { + return one + } + return many +} + +func strslice(v interface{}) []string { + switch v := v.(type) { + case []string: + return v + case []interface{}: + b := make([]string, 0, len(v)) + for _, s := range v { + if s != nil { + b = append(b, strval(s)) + } + } + return b + default: + val := reflect.ValueOf(v) + switch val.Kind() { + case reflect.Array, reflect.Slice: + l := val.Len() + b := make([]string, 0, l) + for i := 0; i < l; i++ { + value := val.Index(i).Interface() + if value != nil { + b = append(b, strval(value)) + } + } + return b + default: + if v == nil { + return []string{} + } + + return []string{strval(v)} + } + } +} + +func removeNilElements(v []interface{}) []interface{} { + newSlice := make([]interface{}, 0, len(v)) + for _, i := range v { + if i != nil { + newSlice = append(newSlice, i) + } + } + return newSlice +} + +func strval(v interface{}) string { + switch v := v.(type) { + case string: + return v + case []byte: + return string(v) + case error: + return v.Error() + case fmt.Stringer: + return v.String() + default: + return fmt.Sprintf("%v", v) + } +} + +func trunc(c int, s string) string { + if c < 0 && len(s)+c > 0 { + return s[len(s)+c:] + } + if c >= 0 && len(s) > c { + return s[:c] + } + return s +} + +func join(sep string, v interface{}) string { + return strings.Join(strslice(v), sep) +} + +func split(sep, orig string) map[string]string { + parts := strings.Split(orig, sep) + res := make(map[string]string, len(parts)) + for i, v := range parts { + res["_"+strconv.Itoa(i)] = v + } + return res +} + +func splitn(sep string, n int, orig string) map[string]string { + parts := strings.SplitN(orig, sep, n) + res := make(map[string]string, len(parts)) + for i, v := range parts { + res["_"+strconv.Itoa(i)] = v + } + return res +} + +// substring creates a substring of the given string. +// +// If start is < 0, this calls string[:end]. +// +// If start is >= 0 and end < 0 or end bigger than s length, this calls string[start:] +// +// Otherwise, this calls string[start, end]. +func substring(start, end int, s string) string { + if start < 0 { + return s[:end] + } + if end < 0 || end > len(s) { + return s[start:] + } + return s[start:end] +} diff --git a/vendor/github.com/go-task/slim-sprig/url.go b/vendor/github.com/go-task/slim-sprig/url.go new file mode 100644 index 000000000..b8e120e19 --- /dev/null +++ b/vendor/github.com/go-task/slim-sprig/url.go @@ -0,0 +1,66 @@ +package sprig + +import ( + "fmt" + "net/url" + "reflect" +) + +func dictGetOrEmpty(dict map[string]interface{}, key string) string { + value, ok := dict[key] + if !ok { + return "" + } + tp := reflect.TypeOf(value).Kind() + if tp != reflect.String { + panic(fmt.Sprintf("unable to parse %s key, must be of type string, but %s found", key, tp.String())) + } + return reflect.ValueOf(value).String() +} + +// parses given URL to return dict object +func urlParse(v string) map[string]interface{} { + dict := map[string]interface{}{} + parsedURL, err := url.Parse(v) + if err != nil { + panic(fmt.Sprintf("unable to parse url: %s", err)) + } + dict["scheme"] = parsedURL.Scheme + dict["host"] = parsedURL.Host + dict["hostname"] = parsedURL.Hostname() + dict["path"] = parsedURL.Path + dict["query"] = parsedURL.RawQuery + dict["opaque"] = parsedURL.Opaque + dict["fragment"] = parsedURL.Fragment + if parsedURL.User != nil { + dict["userinfo"] = parsedURL.User.String() + } else { + dict["userinfo"] = "" + } + + return dict +} + +// join given dict to URL string +func urlJoin(d map[string]interface{}) string { + resURL := url.URL{ + Scheme: dictGetOrEmpty(d, "scheme"), + Host: dictGetOrEmpty(d, "host"), + Path: dictGetOrEmpty(d, "path"), + RawQuery: dictGetOrEmpty(d, "query"), + Opaque: dictGetOrEmpty(d, "opaque"), + Fragment: dictGetOrEmpty(d, "fragment"), + } + userinfo := dictGetOrEmpty(d, "userinfo") + var user *url.Userinfo + if userinfo != "" { + tempURL, err := url.Parse(fmt.Sprintf("proto://%s@host", userinfo)) + if err != nil { + panic(fmt.Sprintf("unable to parse userinfo in dict: %s", err)) + } + user = tempURL.User + } + + resURL.User = user + return resURL.String() +} diff --git a/vendor/github.com/golang/mock/mockgen/mockgen.go b/vendor/github.com/golang/mock/mockgen/mockgen.go new file mode 100644 index 000000000..50487070e --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/mockgen.go @@ -0,0 +1,701 @@ +// Copyright 2010 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// MockGen generates mock implementations of Go interfaces. +package main + +// TODO: This does not support recursive embedded interfaces. +// TODO: This does not support embedding package-local interfaces in a separate file. + +import ( + "bytes" + "encoding/json" + "flag" + "fmt" + "go/token" + "io" + "io/ioutil" + "log" + "os" + "os/exec" + "path" + "path/filepath" + "sort" + "strconv" + "strings" + "unicode" + + "github.com/golang/mock/mockgen/model" + + "golang.org/x/mod/modfile" + toolsimports "golang.org/x/tools/imports" +) + +const ( + gomockImportPath = "github.com/golang/mock/gomock" +) + +var ( + version = "" + commit = "none" + date = "unknown" +) + +var ( + source = flag.String("source", "", "(source mode) Input Go source file; enables source mode.") + destination = flag.String("destination", "", "Output file; defaults to stdout.") + mockNames = flag.String("mock_names", "", "Comma-separated interfaceName=mockName pairs of explicit mock names to use. Mock names default to 'Mock'+ interfaceName suffix.") + packageOut = flag.String("package", "", "Package of the generated code; defaults to the package of the input with a 'mock_' prefix.") + selfPackage = flag.String("self_package", "", "The full package import path for the generated code. The purpose of this flag is to prevent import cycles in the generated code by trying to include its own package. This can happen if the mock's package is set to one of its inputs (usually the main one) and the output is stdio so mockgen cannot detect the final output package. Setting this flag will then tell mockgen which import to exclude.") + writePkgComment = flag.Bool("write_package_comment", true, "Writes package documentation comment (godoc) if true.") + copyrightFile = flag.String("copyright_file", "", "Copyright file used to add copyright header") + + debugParser = flag.Bool("debug_parser", false, "Print out parser results only.") + showVersion = flag.Bool("version", false, "Print version.") +) + +func main() { + flag.Usage = usage + flag.Parse() + + if *showVersion { + printVersion() + return + } + + var pkg *model.Package + var err error + var packageName string + if *source != "" { + pkg, err = sourceMode(*source) + } else { + if flag.NArg() != 2 { + usage() + log.Fatal("Expected exactly two arguments") + } + packageName = flag.Arg(0) + interfaces := strings.Split(flag.Arg(1), ",") + if packageName == "." { + dir, err := os.Getwd() + if err != nil { + log.Fatalf("Get current directory failed: %v", err) + } + packageName, err = packageNameOfDir(dir) + if err != nil { + log.Fatalf("Parse package name failed: %v", err) + } + } + pkg, err = reflectMode(packageName, interfaces) + } + if err != nil { + log.Fatalf("Loading input failed: %v", err) + } + + if *debugParser { + pkg.Print(os.Stdout) + return + } + + dst := os.Stdout + if len(*destination) > 0 { + if err := os.MkdirAll(filepath.Dir(*destination), os.ModePerm); err != nil { + log.Fatalf("Unable to create directory: %v", err) + } + f, err := os.Create(*destination) + if err != nil { + log.Fatalf("Failed opening destination file: %v", err) + } + defer f.Close() + dst = f + } + + outputPackageName := *packageOut + if outputPackageName == "" { + // pkg.Name in reflect mode is the base name of the import path, + // which might have characters that are illegal to have in package names. + outputPackageName = "mock_" + sanitize(pkg.Name) + } + + // outputPackagePath represents the fully qualified name of the package of + // the generated code. Its purposes are to prevent the module from importing + // itself and to prevent qualifying type names that come from its own + // package (i.e. if there is a type called X then we want to print "X" not + // "package.X" since "package" is this package). This can happen if the mock + // is output into an already existing package. + outputPackagePath := *selfPackage + if outputPackagePath == "" && *destination != "" { + dstPath, err := filepath.Abs(filepath.Dir(*destination)) + if err == nil { + pkgPath, err := parsePackageImport(dstPath) + if err == nil { + outputPackagePath = pkgPath + } else { + log.Println("Unable to infer -self_package from destination file path:", err) + } + } else { + log.Println("Unable to determine destination file path:", err) + } + } + + g := new(generator) + if *source != "" { + g.filename = *source + } else { + g.srcPackage = packageName + g.srcInterfaces = flag.Arg(1) + } + g.destination = *destination + + if *mockNames != "" { + g.mockNames = parseMockNames(*mockNames) + } + if *copyrightFile != "" { + header, err := ioutil.ReadFile(*copyrightFile) + if err != nil { + log.Fatalf("Failed reading copyright file: %v", err) + } + + g.copyrightHeader = string(header) + } + if err := g.Generate(pkg, outputPackageName, outputPackagePath); err != nil { + log.Fatalf("Failed generating mock: %v", err) + } + if _, err := dst.Write(g.Output()); err != nil { + log.Fatalf("Failed writing to destination: %v", err) + } +} + +func parseMockNames(names string) map[string]string { + mocksMap := make(map[string]string) + for _, kv := range strings.Split(names, ",") { + parts := strings.SplitN(kv, "=", 2) + if len(parts) != 2 || parts[1] == "" { + log.Fatalf("bad mock names spec: %v", kv) + } + mocksMap[parts[0]] = parts[1] + } + return mocksMap +} + +func usage() { + _, _ = io.WriteString(os.Stderr, usageText) + flag.PrintDefaults() +} + +const usageText = `mockgen has two modes of operation: source and reflect. + +Source mode generates mock interfaces from a source file. +It is enabled by using the -source flag. Other flags that +may be useful in this mode are -imports and -aux_files. +Example: + mockgen -source=foo.go [other options] + +Reflect mode generates mock interfaces by building a program +that uses reflection to understand interfaces. It is enabled +by passing two non-flag arguments: an import path, and a +comma-separated list of symbols. +Example: + mockgen database/sql/driver Conn,Driver + +` + +type generator struct { + buf bytes.Buffer + indent string + mockNames map[string]string // may be empty + filename string // may be empty + destination string // may be empty + srcPackage, srcInterfaces string // may be empty + copyrightHeader string + + packageMap map[string]string // map from import path to package name +} + +func (g *generator) p(format string, args ...interface{}) { + fmt.Fprintf(&g.buf, g.indent+format+"\n", args...) +} + +func (g *generator) in() { + g.indent += "\t" +} + +func (g *generator) out() { + if len(g.indent) > 0 { + g.indent = g.indent[0 : len(g.indent)-1] + } +} + +// sanitize cleans up a string to make a suitable package name. +func sanitize(s string) string { + t := "" + for _, r := range s { + if t == "" { + if unicode.IsLetter(r) || r == '_' { + t += string(r) + continue + } + } else { + if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' { + t += string(r) + continue + } + } + t += "_" + } + if t == "_" { + t = "x" + } + return t +} + +func (g *generator) Generate(pkg *model.Package, outputPkgName string, outputPackagePath string) error { + if outputPkgName != pkg.Name && *selfPackage == "" { + // reset outputPackagePath if it's not passed in through -self_package + outputPackagePath = "" + } + + if g.copyrightHeader != "" { + lines := strings.Split(g.copyrightHeader, "\n") + for _, line := range lines { + g.p("// %s", line) + } + g.p("") + } + + g.p("// Code generated by MockGen. DO NOT EDIT.") + if g.filename != "" { + g.p("// Source: %v", g.filename) + } else { + g.p("// Source: %v (interfaces: %v)", g.srcPackage, g.srcInterfaces) + } + g.p("") + + // Get all required imports, and generate unique names for them all. + im := pkg.Imports() + im[gomockImportPath] = true + + // Only import reflect if it's used. We only use reflect in mocked methods + // so only import if any of the mocked interfaces have methods. + for _, intf := range pkg.Interfaces { + if len(intf.Methods) > 0 { + im["reflect"] = true + break + } + } + + // Sort keys to make import alias generation predictable + sortedPaths := make([]string, len(im)) + x := 0 + for pth := range im { + sortedPaths[x] = pth + x++ + } + sort.Strings(sortedPaths) + + packagesName := createPackageMap(sortedPaths) + + g.packageMap = make(map[string]string, len(im)) + localNames := make(map[string]bool, len(im)) + for _, pth := range sortedPaths { + base, ok := packagesName[pth] + if !ok { + base = sanitize(path.Base(pth)) + } + + // Local names for an imported package can usually be the basename of the import path. + // A couple of situations don't permit that, such as duplicate local names + // (e.g. importing "html/template" and "text/template"), or where the basename is + // a keyword (e.g. "foo/case"). + // try base0, base1, ... + pkgName := base + i := 0 + for localNames[pkgName] || token.Lookup(pkgName).IsKeyword() { + pkgName = base + strconv.Itoa(i) + i++ + } + + // Avoid importing package if source pkg == output pkg + if pth == pkg.PkgPath && outputPackagePath == pkg.PkgPath { + continue + } + + g.packageMap[pth] = pkgName + localNames[pkgName] = true + } + + if *writePkgComment { + g.p("// Package %v is a generated GoMock package.", outputPkgName) + } + g.p("package %v", outputPkgName) + g.p("") + g.p("import (") + g.in() + for pkgPath, pkgName := range g.packageMap { + if pkgPath == outputPackagePath { + continue + } + g.p("%v %q", pkgName, pkgPath) + } + for _, pkgPath := range pkg.DotImports { + g.p(". %q", pkgPath) + } + g.out() + g.p(")") + + for _, intf := range pkg.Interfaces { + if err := g.GenerateMockInterface(intf, outputPackagePath); err != nil { + return err + } + } + + return nil +} + +// The name of the mock type to use for the given interface identifier. +func (g *generator) mockName(typeName string) string { + if mockName, ok := g.mockNames[typeName]; ok { + return mockName + } + + return "Mock" + typeName +} + +func (g *generator) GenerateMockInterface(intf *model.Interface, outputPackagePath string) error { + mockType := g.mockName(intf.Name) + + g.p("") + g.p("// %v is a mock of %v interface.", mockType, intf.Name) + g.p("type %v struct {", mockType) + g.in() + g.p("ctrl *gomock.Controller") + g.p("recorder *%vMockRecorder", mockType) + g.out() + g.p("}") + g.p("") + + g.p("// %vMockRecorder is the mock recorder for %v.", mockType, mockType) + g.p("type %vMockRecorder struct {", mockType) + g.in() + g.p("mock *%v", mockType) + g.out() + g.p("}") + g.p("") + + g.p("// New%v creates a new mock instance.", mockType) + g.p("func New%v(ctrl *gomock.Controller) *%v {", mockType, mockType) + g.in() + g.p("mock := &%v{ctrl: ctrl}", mockType) + g.p("mock.recorder = &%vMockRecorder{mock}", mockType) + g.p("return mock") + g.out() + g.p("}") + g.p("") + + // XXX: possible name collision here if someone has EXPECT in their interface. + g.p("// EXPECT returns an object that allows the caller to indicate expected use.") + g.p("func (m *%v) EXPECT() *%vMockRecorder {", mockType, mockType) + g.in() + g.p("return m.recorder") + g.out() + g.p("}") + + g.GenerateMockMethods(mockType, intf, outputPackagePath) + + return nil +} + +type byMethodName []*model.Method + +func (b byMethodName) Len() int { return len(b) } +func (b byMethodName) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b byMethodName) Less(i, j int) bool { return b[i].Name < b[j].Name } + +func (g *generator) GenerateMockMethods(mockType string, intf *model.Interface, pkgOverride string) { + sort.Sort(byMethodName(intf.Methods)) + for _, m := range intf.Methods { + g.p("") + _ = g.GenerateMockMethod(mockType, m, pkgOverride) + g.p("") + _ = g.GenerateMockRecorderMethod(mockType, m) + } +} + +func makeArgString(argNames, argTypes []string) string { + args := make([]string, len(argNames)) + for i, name := range argNames { + // specify the type only once for consecutive args of the same type + if i+1 < len(argTypes) && argTypes[i] == argTypes[i+1] { + args[i] = name + } else { + args[i] = name + " " + argTypes[i] + } + } + return strings.Join(args, ", ") +} + +// GenerateMockMethod generates a mock method implementation. +// If non-empty, pkgOverride is the package in which unqualified types reside. +func (g *generator) GenerateMockMethod(mockType string, m *model.Method, pkgOverride string) error { + argNames := g.getArgNames(m) + argTypes := g.getArgTypes(m, pkgOverride) + argString := makeArgString(argNames, argTypes) + + rets := make([]string, len(m.Out)) + for i, p := range m.Out { + rets[i] = p.Type.String(g.packageMap, pkgOverride) + } + retString := strings.Join(rets, ", ") + if len(rets) > 1 { + retString = "(" + retString + ")" + } + if retString != "" { + retString = " " + retString + } + + ia := newIdentifierAllocator(argNames) + idRecv := ia.allocateIdentifier("m") + + g.p("// %v mocks base method.", m.Name) + g.p("func (%v *%v) %v(%v)%v {", idRecv, mockType, m.Name, argString, retString) + g.in() + g.p("%s.ctrl.T.Helper()", idRecv) + + var callArgs string + if m.Variadic == nil { + if len(argNames) > 0 { + callArgs = ", " + strings.Join(argNames, ", ") + } + } else { + // Non-trivial. The generated code must build a []interface{}, + // but the variadic argument may be any type. + idVarArgs := ia.allocateIdentifier("varargs") + idVArg := ia.allocateIdentifier("a") + g.p("%s := []interface{}{%s}", idVarArgs, strings.Join(argNames[:len(argNames)-1], ", ")) + g.p("for _, %s := range %s {", idVArg, argNames[len(argNames)-1]) + g.in() + g.p("%s = append(%s, %s)", idVarArgs, idVarArgs, idVArg) + g.out() + g.p("}") + callArgs = ", " + idVarArgs + "..." + } + if len(m.Out) == 0 { + g.p(`%v.ctrl.Call(%v, %q%v)`, idRecv, idRecv, m.Name, callArgs) + } else { + idRet := ia.allocateIdentifier("ret") + g.p(`%v := %v.ctrl.Call(%v, %q%v)`, idRet, idRecv, idRecv, m.Name, callArgs) + + // Go does not allow "naked" type assertions on nil values, so we use the two-value form here. + // The value of that is either (x.(T), true) or (Z, false), where Z is the zero value for T. + // Happily, this coincides with the semantics we want here. + retNames := make([]string, len(rets)) + for i, t := range rets { + retNames[i] = ia.allocateIdentifier(fmt.Sprintf("ret%d", i)) + g.p("%s, _ := %s[%d].(%s)", retNames[i], idRet, i, t) + } + g.p("return " + strings.Join(retNames, ", ")) + } + + g.out() + g.p("}") + return nil +} + +func (g *generator) GenerateMockRecorderMethod(mockType string, m *model.Method) error { + argNames := g.getArgNames(m) + + var argString string + if m.Variadic == nil { + argString = strings.Join(argNames, ", ") + } else { + argString = strings.Join(argNames[:len(argNames)-1], ", ") + } + if argString != "" { + argString += " interface{}" + } + + if m.Variadic != nil { + if argString != "" { + argString += ", " + } + argString += fmt.Sprintf("%s ...interface{}", argNames[len(argNames)-1]) + } + + ia := newIdentifierAllocator(argNames) + idRecv := ia.allocateIdentifier("mr") + + g.p("// %v indicates an expected call of %v.", m.Name, m.Name) + g.p("func (%s *%vMockRecorder) %v(%v) *gomock.Call {", idRecv, mockType, m.Name, argString) + g.in() + g.p("%s.mock.ctrl.T.Helper()", idRecv) + + var callArgs string + if m.Variadic == nil { + if len(argNames) > 0 { + callArgs = ", " + strings.Join(argNames, ", ") + } + } else { + if len(argNames) == 1 { + // Easy: just use ... to push the arguments through. + callArgs = ", " + argNames[0] + "..." + } else { + // Hard: create a temporary slice. + idVarArgs := ia.allocateIdentifier("varargs") + g.p("%s := append([]interface{}{%s}, %s...)", + idVarArgs, + strings.Join(argNames[:len(argNames)-1], ", "), + argNames[len(argNames)-1]) + callArgs = ", " + idVarArgs + "..." + } + } + g.p(`return %s.mock.ctrl.RecordCallWithMethodType(%s.mock, "%s", reflect.TypeOf((*%s)(nil).%s)%s)`, idRecv, idRecv, m.Name, mockType, m.Name, callArgs) + + g.out() + g.p("}") + return nil +} + +func (g *generator) getArgNames(m *model.Method) []string { + argNames := make([]string, len(m.In)) + for i, p := range m.In { + name := p.Name + if name == "" || name == "_" { + name = fmt.Sprintf("arg%d", i) + } + argNames[i] = name + } + if m.Variadic != nil { + name := m.Variadic.Name + if name == "" { + name = fmt.Sprintf("arg%d", len(m.In)) + } + argNames = append(argNames, name) + } + return argNames +} + +func (g *generator) getArgTypes(m *model.Method, pkgOverride string) []string { + argTypes := make([]string, len(m.In)) + for i, p := range m.In { + argTypes[i] = p.Type.String(g.packageMap, pkgOverride) + } + if m.Variadic != nil { + argTypes = append(argTypes, "..."+m.Variadic.Type.String(g.packageMap, pkgOverride)) + } + return argTypes +} + +type identifierAllocator map[string]struct{} + +func newIdentifierAllocator(taken []string) identifierAllocator { + a := make(identifierAllocator, len(taken)) + for _, s := range taken { + a[s] = struct{}{} + } + return a +} + +func (o identifierAllocator) allocateIdentifier(want string) string { + id := want + for i := 2; ; i++ { + if _, ok := o[id]; !ok { + o[id] = struct{}{} + return id + } + id = want + "_" + strconv.Itoa(i) + } +} + +// Output returns the generator's output, formatted in the standard Go style. +func (g *generator) Output() []byte { + src, err := toolsimports.Process(g.destination, g.buf.Bytes(), nil) + if err != nil { + log.Fatalf("Failed to format generated source code: %s\n%s", err, g.buf.String()) + } + return src +} + +// createPackageMap returns a map of import path to package name +// for specified importPaths. +func createPackageMap(importPaths []string) map[string]string { + var pkg struct { + Name string + ImportPath string + } + pkgMap := make(map[string]string) + b := bytes.NewBuffer(nil) + args := []string{"list", "-json"} + args = append(args, importPaths...) + cmd := exec.Command("go", args...) + cmd.Stdout = b + cmd.Run() + dec := json.NewDecoder(b) + for dec.More() { + err := dec.Decode(&pkg) + if err != nil { + log.Printf("failed to decode 'go list' output: %v", err) + continue + } + pkgMap[pkg.ImportPath] = pkg.Name + } + return pkgMap +} + +func printVersion() { + if version != "" { + fmt.Printf("v%s\nCommit: %s\nDate: %s\n", version, commit, date) + } else { + printModuleVersion() + } +} + +// parseImportPackage get package import path via source file +// an alternative implementation is to use: +// cfg := &packages.Config{Mode: packages.NeedName, Tests: true, Dir: srcDir} +// pkgs, err := packages.Load(cfg, "file="+source) +// However, it will call "go list" and slow down the performance +func parsePackageImport(srcDir string) (string, error) { + moduleMode := os.Getenv("GO111MODULE") + // trying to find the module + if moduleMode != "off" { + currentDir := srcDir + for { + dat, err := ioutil.ReadFile(filepath.Join(currentDir, "go.mod")) + if os.IsNotExist(err) { + if currentDir == filepath.Dir(currentDir) { + // at the root + break + } + currentDir = filepath.Dir(currentDir) + continue + } else if err != nil { + return "", err + } + modulePath := modfile.ModulePath(dat) + return filepath.ToSlash(filepath.Join(modulePath, strings.TrimPrefix(srcDir, currentDir))), nil + } + } + // fall back to GOPATH mode + goPaths := os.Getenv("GOPATH") + if goPaths == "" { + return "", fmt.Errorf("GOPATH is not set") + } + goPathList := strings.Split(goPaths, string(os.PathListSeparator)) + for _, goPath := range goPathList { + sourceRoot := filepath.Join(goPath, "src") + string(os.PathSeparator) + if strings.HasPrefix(srcDir, sourceRoot) { + return filepath.ToSlash(strings.TrimPrefix(srcDir, sourceRoot)), nil + } + } + return "", errOutsideGoPath +} diff --git a/vendor/github.com/golang/mock/mockgen/model/model.go b/vendor/github.com/golang/mock/mockgen/model/model.go new file mode 100644 index 000000000..2c6a62ceb --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/model/model.go @@ -0,0 +1,495 @@ +// Copyright 2012 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package model contains the data model necessary for generating mock implementations. +package model + +import ( + "encoding/gob" + "fmt" + "io" + "reflect" + "strings" +) + +// pkgPath is the importable path for package model +const pkgPath = "github.com/golang/mock/mockgen/model" + +// Package is a Go package. It may be a subset. +type Package struct { + Name string + PkgPath string + Interfaces []*Interface + DotImports []string +} + +// Print writes the package name and its exported interfaces. +func (pkg *Package) Print(w io.Writer) { + _, _ = fmt.Fprintf(w, "package %s\n", pkg.Name) + for _, intf := range pkg.Interfaces { + intf.Print(w) + } +} + +// Imports returns the imports needed by the Package as a set of import paths. +func (pkg *Package) Imports() map[string]bool { + im := make(map[string]bool) + for _, intf := range pkg.Interfaces { + intf.addImports(im) + } + return im +} + +// Interface is a Go interface. +type Interface struct { + Name string + Methods []*Method +} + +// Print writes the interface name and its methods. +func (intf *Interface) Print(w io.Writer) { + _, _ = fmt.Fprintf(w, "interface %s\n", intf.Name) + for _, m := range intf.Methods { + m.Print(w) + } +} + +func (intf *Interface) addImports(im map[string]bool) { + for _, m := range intf.Methods { + m.addImports(im) + } +} + +// AddMethod adds a new method, de-duplicating by method name. +func (intf *Interface) AddMethod(m *Method) { + for _, me := range intf.Methods { + if me.Name == m.Name { + return + } + } + intf.Methods = append(intf.Methods, m) +} + +// Method is a single method of an interface. +type Method struct { + Name string + In, Out []*Parameter + Variadic *Parameter // may be nil +} + +// Print writes the method name and its signature. +func (m *Method) Print(w io.Writer) { + _, _ = fmt.Fprintf(w, " - method %s\n", m.Name) + if len(m.In) > 0 { + _, _ = fmt.Fprintf(w, " in:\n") + for _, p := range m.In { + p.Print(w) + } + } + if m.Variadic != nil { + _, _ = fmt.Fprintf(w, " ...:\n") + m.Variadic.Print(w) + } + if len(m.Out) > 0 { + _, _ = fmt.Fprintf(w, " out:\n") + for _, p := range m.Out { + p.Print(w) + } + } +} + +func (m *Method) addImports(im map[string]bool) { + for _, p := range m.In { + p.Type.addImports(im) + } + if m.Variadic != nil { + m.Variadic.Type.addImports(im) + } + for _, p := range m.Out { + p.Type.addImports(im) + } +} + +// Parameter is an argument or return parameter of a method. +type Parameter struct { + Name string // may be empty + Type Type +} + +// Print writes a method parameter. +func (p *Parameter) Print(w io.Writer) { + n := p.Name + if n == "" { + n = `""` + } + _, _ = fmt.Fprintf(w, " - %v: %v\n", n, p.Type.String(nil, "")) +} + +// Type is a Go type. +type Type interface { + String(pm map[string]string, pkgOverride string) string + addImports(im map[string]bool) +} + +func init() { + gob.Register(&ArrayType{}) + gob.Register(&ChanType{}) + gob.Register(&FuncType{}) + gob.Register(&MapType{}) + gob.Register(&NamedType{}) + gob.Register(&PointerType{}) + + // Call gob.RegisterName to make sure it has the consistent name registered + // for both gob decoder and encoder. + // + // For a non-pointer type, gob.Register will try to get package full path by + // calling rt.PkgPath() for a name to register. If your project has vendor + // directory, it is possible that PkgPath will get a path like this: + // ../../../vendor/github.com/golang/mock/mockgen/model + gob.RegisterName(pkgPath+".PredeclaredType", PredeclaredType("")) +} + +// ArrayType is an array or slice type. +type ArrayType struct { + Len int // -1 for slices, >= 0 for arrays + Type Type +} + +func (at *ArrayType) String(pm map[string]string, pkgOverride string) string { + s := "[]" + if at.Len > -1 { + s = fmt.Sprintf("[%d]", at.Len) + } + return s + at.Type.String(pm, pkgOverride) +} + +func (at *ArrayType) addImports(im map[string]bool) { at.Type.addImports(im) } + +// ChanType is a channel type. +type ChanType struct { + Dir ChanDir // 0, 1 or 2 + Type Type +} + +func (ct *ChanType) String(pm map[string]string, pkgOverride string) string { + s := ct.Type.String(pm, pkgOverride) + if ct.Dir == RecvDir { + return "<-chan " + s + } + if ct.Dir == SendDir { + return "chan<- " + s + } + return "chan " + s +} + +func (ct *ChanType) addImports(im map[string]bool) { ct.Type.addImports(im) } + +// ChanDir is a channel direction. +type ChanDir int + +// Constants for channel directions. +const ( + RecvDir ChanDir = 1 + SendDir ChanDir = 2 +) + +// FuncType is a function type. +type FuncType struct { + In, Out []*Parameter + Variadic *Parameter // may be nil +} + +func (ft *FuncType) String(pm map[string]string, pkgOverride string) string { + args := make([]string, len(ft.In)) + for i, p := range ft.In { + args[i] = p.Type.String(pm, pkgOverride) + } + if ft.Variadic != nil { + args = append(args, "..."+ft.Variadic.Type.String(pm, pkgOverride)) + } + rets := make([]string, len(ft.Out)) + for i, p := range ft.Out { + rets[i] = p.Type.String(pm, pkgOverride) + } + retString := strings.Join(rets, ", ") + if nOut := len(ft.Out); nOut == 1 { + retString = " " + retString + } else if nOut > 1 { + retString = " (" + retString + ")" + } + return "func(" + strings.Join(args, ", ") + ")" + retString +} + +func (ft *FuncType) addImports(im map[string]bool) { + for _, p := range ft.In { + p.Type.addImports(im) + } + if ft.Variadic != nil { + ft.Variadic.Type.addImports(im) + } + for _, p := range ft.Out { + p.Type.addImports(im) + } +} + +// MapType is a map type. +type MapType struct { + Key, Value Type +} + +func (mt *MapType) String(pm map[string]string, pkgOverride string) string { + return "map[" + mt.Key.String(pm, pkgOverride) + "]" + mt.Value.String(pm, pkgOverride) +} + +func (mt *MapType) addImports(im map[string]bool) { + mt.Key.addImports(im) + mt.Value.addImports(im) +} + +// NamedType is an exported type in a package. +type NamedType struct { + Package string // may be empty + Type string +} + +func (nt *NamedType) String(pm map[string]string, pkgOverride string) string { + if pkgOverride == nt.Package { + return nt.Type + } + prefix := pm[nt.Package] + if prefix != "" { + return prefix + "." + nt.Type + } + + return nt.Type +} + +func (nt *NamedType) addImports(im map[string]bool) { + if nt.Package != "" { + im[nt.Package] = true + } +} + +// PointerType is a pointer to another type. +type PointerType struct { + Type Type +} + +func (pt *PointerType) String(pm map[string]string, pkgOverride string) string { + return "*" + pt.Type.String(pm, pkgOverride) +} +func (pt *PointerType) addImports(im map[string]bool) { pt.Type.addImports(im) } + +// PredeclaredType is a predeclared type such as "int". +type PredeclaredType string + +func (pt PredeclaredType) String(map[string]string, string) string { return string(pt) } +func (pt PredeclaredType) addImports(map[string]bool) {} + +// The following code is intended to be called by the program generated by ../reflect.go. + +// InterfaceFromInterfaceType returns a pointer to an interface for the +// given reflection interface type. +func InterfaceFromInterfaceType(it reflect.Type) (*Interface, error) { + if it.Kind() != reflect.Interface { + return nil, fmt.Errorf("%v is not an interface", it) + } + intf := &Interface{} + + for i := 0; i < it.NumMethod(); i++ { + mt := it.Method(i) + // TODO: need to skip unexported methods? or just raise an error? + m := &Method{ + Name: mt.Name, + } + + var err error + m.In, m.Variadic, m.Out, err = funcArgsFromType(mt.Type) + if err != nil { + return nil, err + } + + intf.AddMethod(m) + } + + return intf, nil +} + +// t's Kind must be a reflect.Func. +func funcArgsFromType(t reflect.Type) (in []*Parameter, variadic *Parameter, out []*Parameter, err error) { + nin := t.NumIn() + if t.IsVariadic() { + nin-- + } + var p *Parameter + for i := 0; i < nin; i++ { + p, err = parameterFromType(t.In(i)) + if err != nil { + return + } + in = append(in, p) + } + if t.IsVariadic() { + p, err = parameterFromType(t.In(nin).Elem()) + if err != nil { + return + } + variadic = p + } + for i := 0; i < t.NumOut(); i++ { + p, err = parameterFromType(t.Out(i)) + if err != nil { + return + } + out = append(out, p) + } + return +} + +func parameterFromType(t reflect.Type) (*Parameter, error) { + tt, err := typeFromType(t) + if err != nil { + return nil, err + } + return &Parameter{Type: tt}, nil +} + +var errorType = reflect.TypeOf((*error)(nil)).Elem() + +var byteType = reflect.TypeOf(byte(0)) + +func typeFromType(t reflect.Type) (Type, error) { + // Hack workaround for https://golang.org/issue/3853. + // This explicit check should not be necessary. + if t == byteType { + return PredeclaredType("byte"), nil + } + + if imp := t.PkgPath(); imp != "" { + return &NamedType{ + Package: impPath(imp), + Type: t.Name(), + }, nil + } + + // only unnamed or predeclared types after here + + // Lots of types have element types. Let's do the parsing and error checking for all of them. + var elemType Type + switch t.Kind() { + case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice: + var err error + elemType, err = typeFromType(t.Elem()) + if err != nil { + return nil, err + } + } + + switch t.Kind() { + case reflect.Array: + return &ArrayType{ + Len: t.Len(), + Type: elemType, + }, nil + case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, + reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.String: + return PredeclaredType(t.Kind().String()), nil + case reflect.Chan: + var dir ChanDir + switch t.ChanDir() { + case reflect.RecvDir: + dir = RecvDir + case reflect.SendDir: + dir = SendDir + } + return &ChanType{ + Dir: dir, + Type: elemType, + }, nil + case reflect.Func: + in, variadic, out, err := funcArgsFromType(t) + if err != nil { + return nil, err + } + return &FuncType{ + In: in, + Out: out, + Variadic: variadic, + }, nil + case reflect.Interface: + // Two special interfaces. + if t.NumMethod() == 0 { + return PredeclaredType("interface{}"), nil + } + if t == errorType { + return PredeclaredType("error"), nil + } + case reflect.Map: + kt, err := typeFromType(t.Key()) + if err != nil { + return nil, err + } + return &MapType{ + Key: kt, + Value: elemType, + }, nil + case reflect.Ptr: + return &PointerType{ + Type: elemType, + }, nil + case reflect.Slice: + return &ArrayType{ + Len: -1, + Type: elemType, + }, nil + case reflect.Struct: + if t.NumField() == 0 { + return PredeclaredType("struct{}"), nil + } + } + + // TODO: Struct, UnsafePointer + return nil, fmt.Errorf("can't yet turn %v (%v) into a model.Type", t, t.Kind()) +} + +// impPath sanitizes the package path returned by `PkgPath` method of a reflect Type so that +// it is importable. PkgPath might return a path that includes "vendor". These paths do not +// compile, so we need to remove everything up to and including "/vendor/". +// See https://github.com/golang/go/issues/12019. +func impPath(imp string) string { + if strings.HasPrefix(imp, "vendor/") { + imp = "/" + imp + } + if i := strings.LastIndex(imp, "/vendor/"); i != -1 { + imp = imp[i+len("/vendor/"):] + } + return imp +} + +// ErrorInterface represent built-in error interface. +var ErrorInterface = Interface{ + Name: "error", + Methods: []*Method{ + { + Name: "Error", + Out: []*Parameter{ + { + Name: "", + Type: PredeclaredType("string"), + }, + }, + }, + }, +} diff --git a/vendor/github.com/golang/mock/mockgen/parse.go b/vendor/github.com/golang/mock/mockgen/parse.go new file mode 100644 index 000000000..bf6902cd5 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/parse.go @@ -0,0 +1,644 @@ +// Copyright 2012 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +// This file contains the model construction by parsing source files. + +import ( + "errors" + "flag" + "fmt" + "go/ast" + "go/build" + "go/importer" + "go/parser" + "go/token" + "go/types" + "io/ioutil" + "log" + "path" + "path/filepath" + "strconv" + "strings" + + "github.com/golang/mock/mockgen/model" +) + +var ( + imports = flag.String("imports", "", "(source mode) Comma-separated name=path pairs of explicit imports to use.") + auxFiles = flag.String("aux_files", "", "(source mode) Comma-separated pkg=path pairs of auxiliary Go source files.") +) + +// sourceMode generates mocks via source file. +func sourceMode(source string) (*model.Package, error) { + srcDir, err := filepath.Abs(filepath.Dir(source)) + if err != nil { + return nil, fmt.Errorf("failed getting source directory: %v", err) + } + + packageImport, err := parsePackageImport(srcDir) + if err != nil { + return nil, err + } + + fs := token.NewFileSet() + file, err := parser.ParseFile(fs, source, nil, 0) + if err != nil { + return nil, fmt.Errorf("failed parsing source file %v: %v", source, err) + } + + p := &fileParser{ + fileSet: fs, + imports: make(map[string]importedPackage), + importedInterfaces: make(map[string]map[string]*ast.InterfaceType), + auxInterfaces: make(map[string]map[string]*ast.InterfaceType), + srcDir: srcDir, + } + + // Handle -imports. + dotImports := make(map[string]bool) + if *imports != "" { + for _, kv := range strings.Split(*imports, ",") { + eq := strings.Index(kv, "=") + k, v := kv[:eq], kv[eq+1:] + if k == "." { + dotImports[v] = true + } else { + p.imports[k] = importedPkg{path: v} + } + } + } + + // Handle -aux_files. + if err := p.parseAuxFiles(*auxFiles); err != nil { + return nil, err + } + p.addAuxInterfacesFromFile(packageImport, file) // this file + + pkg, err := p.parseFile(packageImport, file) + if err != nil { + return nil, err + } + for pkgPath := range dotImports { + pkg.DotImports = append(pkg.DotImports, pkgPath) + } + return pkg, nil +} + +type importedPackage interface { + Path() string + Parser() *fileParser +} + +type importedPkg struct { + path string + parser *fileParser +} + +func (i importedPkg) Path() string { return i.path } +func (i importedPkg) Parser() *fileParser { return i.parser } + +// duplicateImport is a bit of a misnomer. Currently the parser can't +// handle cases of multi-file packages importing different packages +// under the same name. Often these imports would not be problematic, +// so this type lets us defer raising an error unless the package name +// is actually used. +type duplicateImport struct { + name string + duplicates []string +} + +func (d duplicateImport) Error() string { + return fmt.Sprintf("%q is ambiguous because of duplicate imports: %v", d.name, d.duplicates) +} + +func (d duplicateImport) Path() string { log.Fatal(d.Error()); return "" } +func (d duplicateImport) Parser() *fileParser { log.Fatal(d.Error()); return nil } + +type fileParser struct { + fileSet *token.FileSet + imports map[string]importedPackage // package name => imported package + importedInterfaces map[string]map[string]*ast.InterfaceType // package (or "") => name => interface + + auxFiles []*ast.File + auxInterfaces map[string]map[string]*ast.InterfaceType // package (or "") => name => interface + + srcDir string +} + +func (p *fileParser) errorf(pos token.Pos, format string, args ...interface{}) error { + ps := p.fileSet.Position(pos) + format = "%s:%d:%d: " + format + args = append([]interface{}{ps.Filename, ps.Line, ps.Column}, args...) + return fmt.Errorf(format, args...) +} + +func (p *fileParser) parseAuxFiles(auxFiles string) error { + auxFiles = strings.TrimSpace(auxFiles) + if auxFiles == "" { + return nil + } + for _, kv := range strings.Split(auxFiles, ",") { + parts := strings.SplitN(kv, "=", 2) + if len(parts) != 2 { + return fmt.Errorf("bad aux file spec: %v", kv) + } + pkg, fpath := parts[0], parts[1] + + file, err := parser.ParseFile(p.fileSet, fpath, nil, 0) + if err != nil { + return err + } + p.auxFiles = append(p.auxFiles, file) + p.addAuxInterfacesFromFile(pkg, file) + } + return nil +} + +func (p *fileParser) addAuxInterfacesFromFile(pkg string, file *ast.File) { + if _, ok := p.auxInterfaces[pkg]; !ok { + p.auxInterfaces[pkg] = make(map[string]*ast.InterfaceType) + } + for ni := range iterInterfaces(file) { + p.auxInterfaces[pkg][ni.name.Name] = ni.it + } +} + +// parseFile loads all file imports and auxiliary files import into the +// fileParser, parses all file interfaces and returns package model. +func (p *fileParser) parseFile(importPath string, file *ast.File) (*model.Package, error) { + allImports, dotImports := importsOfFile(file) + // Don't stomp imports provided by -imports. Those should take precedence. + for pkg, pkgI := range allImports { + if _, ok := p.imports[pkg]; !ok { + p.imports[pkg] = pkgI + } + } + // Add imports from auxiliary files, which might be needed for embedded interfaces. + // Don't stomp any other imports. + for _, f := range p.auxFiles { + auxImports, _ := importsOfFile(f) + for pkg, pkgI := range auxImports { + if _, ok := p.imports[pkg]; !ok { + p.imports[pkg] = pkgI + } + } + } + + var is []*model.Interface + for ni := range iterInterfaces(file) { + i, err := p.parseInterface(ni.name.String(), importPath, ni.it) + if err != nil { + return nil, err + } + is = append(is, i) + } + return &model.Package{ + Name: file.Name.String(), + PkgPath: importPath, + Interfaces: is, + DotImports: dotImports, + }, nil +} + +// parsePackage loads package specified by path, parses it and returns +// a new fileParser with the parsed imports and interfaces. +func (p *fileParser) parsePackage(path string) (*fileParser, error) { + newP := &fileParser{ + fileSet: token.NewFileSet(), + imports: make(map[string]importedPackage), + importedInterfaces: make(map[string]map[string]*ast.InterfaceType), + auxInterfaces: make(map[string]map[string]*ast.InterfaceType), + srcDir: p.srcDir, + } + + var pkgs map[string]*ast.Package + if imp, err := build.Import(path, newP.srcDir, build.FindOnly); err != nil { + return nil, err + } else if pkgs, err = parser.ParseDir(newP.fileSet, imp.Dir, nil, 0); err != nil { + return nil, err + } + + for _, pkg := range pkgs { + file := ast.MergePackageFiles(pkg, ast.FilterFuncDuplicates|ast.FilterUnassociatedComments|ast.FilterImportDuplicates) + if _, ok := newP.importedInterfaces[path]; !ok { + newP.importedInterfaces[path] = make(map[string]*ast.InterfaceType) + } + for ni := range iterInterfaces(file) { + newP.importedInterfaces[path][ni.name.Name] = ni.it + } + imports, _ := importsOfFile(file) + for pkgName, pkgI := range imports { + newP.imports[pkgName] = pkgI + } + } + return newP, nil +} + +func (p *fileParser) parseInterface(name, pkg string, it *ast.InterfaceType) (*model.Interface, error) { + iface := &model.Interface{Name: name} + for _, field := range it.Methods.List { + switch v := field.Type.(type) { + case *ast.FuncType: + if nn := len(field.Names); nn != 1 { + return nil, fmt.Errorf("expected one name for interface %v, got %d", iface.Name, nn) + } + m := &model.Method{ + Name: field.Names[0].String(), + } + var err error + m.In, m.Variadic, m.Out, err = p.parseFunc(pkg, v) + if err != nil { + return nil, err + } + iface.AddMethod(m) + case *ast.Ident: + // Embedded interface in this package. + embeddedIfaceType := p.auxInterfaces[pkg][v.String()] + if embeddedIfaceType == nil { + embeddedIfaceType = p.importedInterfaces[pkg][v.String()] + } + + var embeddedIface *model.Interface + if embeddedIfaceType != nil { + var err error + embeddedIface, err = p.parseInterface(v.String(), pkg, embeddedIfaceType) + if err != nil { + return nil, err + } + } else { + // This is built-in error interface. + if v.String() == model.ErrorInterface.Name { + embeddedIface = &model.ErrorInterface + } else { + return nil, p.errorf(v.Pos(), "unknown embedded interface %s", v.String()) + } + } + // Copy the methods. + for _, m := range embeddedIface.Methods { + iface.AddMethod(m) + } + case *ast.SelectorExpr: + // Embedded interface in another package. + filePkg, sel := v.X.(*ast.Ident).String(), v.Sel.String() + embeddedPkg, ok := p.imports[filePkg] + if !ok { + return nil, p.errorf(v.X.Pos(), "unknown package %s", filePkg) + } + + var embeddedIface *model.Interface + var err error + embeddedIfaceType := p.auxInterfaces[filePkg][sel] + if embeddedIfaceType != nil { + embeddedIface, err = p.parseInterface(sel, filePkg, embeddedIfaceType) + if err != nil { + return nil, err + } + } else { + path := embeddedPkg.Path() + parser := embeddedPkg.Parser() + if parser == nil { + ip, err := p.parsePackage(path) + if err != nil { + return nil, p.errorf(v.Pos(), "could not parse package %s: %v", path, err) + } + parser = ip + p.imports[filePkg] = importedPkg{ + path: embeddedPkg.Path(), + parser: parser, + } + } + if embeddedIfaceType = parser.importedInterfaces[path][sel]; embeddedIfaceType == nil { + return nil, p.errorf(v.Pos(), "unknown embedded interface %s.%s", path, sel) + } + embeddedIface, err = parser.parseInterface(sel, path, embeddedIfaceType) + if err != nil { + return nil, err + } + } + // Copy the methods. + // TODO: apply shadowing rules. + for _, m := range embeddedIface.Methods { + iface.AddMethod(m) + } + default: + return nil, fmt.Errorf("don't know how to mock method of type %T", field.Type) + } + } + return iface, nil +} + +func (p *fileParser) parseFunc(pkg string, f *ast.FuncType) (inParam []*model.Parameter, variadic *model.Parameter, outParam []*model.Parameter, err error) { + if f.Params != nil { + regParams := f.Params.List + if isVariadic(f) { + n := len(regParams) + varParams := regParams[n-1:] + regParams = regParams[:n-1] + vp, err := p.parseFieldList(pkg, varParams) + if err != nil { + return nil, nil, nil, p.errorf(varParams[0].Pos(), "failed parsing variadic argument: %v", err) + } + variadic = vp[0] + } + inParam, err = p.parseFieldList(pkg, regParams) + if err != nil { + return nil, nil, nil, p.errorf(f.Pos(), "failed parsing arguments: %v", err) + } + } + if f.Results != nil { + outParam, err = p.parseFieldList(pkg, f.Results.List) + if err != nil { + return nil, nil, nil, p.errorf(f.Pos(), "failed parsing returns: %v", err) + } + } + return +} + +func (p *fileParser) parseFieldList(pkg string, fields []*ast.Field) ([]*model.Parameter, error) { + nf := 0 + for _, f := range fields { + nn := len(f.Names) + if nn == 0 { + nn = 1 // anonymous parameter + } + nf += nn + } + if nf == 0 { + return nil, nil + } + ps := make([]*model.Parameter, nf) + i := 0 // destination index + for _, f := range fields { + t, err := p.parseType(pkg, f.Type) + if err != nil { + return nil, err + } + + if len(f.Names) == 0 { + // anonymous arg + ps[i] = &model.Parameter{Type: t} + i++ + continue + } + for _, name := range f.Names { + ps[i] = &model.Parameter{Name: name.Name, Type: t} + i++ + } + } + return ps, nil +} + +func (p *fileParser) parseType(pkg string, typ ast.Expr) (model.Type, error) { + switch v := typ.(type) { + case *ast.ArrayType: + ln := -1 + if v.Len != nil { + var value string + switch val := v.Len.(type) { + case (*ast.BasicLit): + value = val.Value + case (*ast.Ident): + // when the length is a const defined locally + value = val.Obj.Decl.(*ast.ValueSpec).Values[0].(*ast.BasicLit).Value + case (*ast.SelectorExpr): + // when the length is a const defined in an external package + usedPkg, err := importer.Default().Import(fmt.Sprintf("%s", val.X)) + if err != nil { + return nil, p.errorf(v.Len.Pos(), "unknown package in array length: %v", err) + } + ev, err := types.Eval(token.NewFileSet(), usedPkg, token.NoPos, val.Sel.Name) + if err != nil { + return nil, p.errorf(v.Len.Pos(), "unknown constant in array length: %v", err) + } + value = ev.Value.String() + } + + x, err := strconv.Atoi(value) + if err != nil { + return nil, p.errorf(v.Len.Pos(), "bad array size: %v", err) + } + ln = x + } + t, err := p.parseType(pkg, v.Elt) + if err != nil { + return nil, err + } + return &model.ArrayType{Len: ln, Type: t}, nil + case *ast.ChanType: + t, err := p.parseType(pkg, v.Value) + if err != nil { + return nil, err + } + var dir model.ChanDir + if v.Dir == ast.SEND { + dir = model.SendDir + } + if v.Dir == ast.RECV { + dir = model.RecvDir + } + return &model.ChanType{Dir: dir, Type: t}, nil + case *ast.Ellipsis: + // assume we're parsing a variadic argument + return p.parseType(pkg, v.Elt) + case *ast.FuncType: + in, variadic, out, err := p.parseFunc(pkg, v) + if err != nil { + return nil, err + } + return &model.FuncType{In: in, Out: out, Variadic: variadic}, nil + case *ast.Ident: + if v.IsExported() { + // `pkg` may be an aliased imported pkg + // if so, patch the import w/ the fully qualified import + maybeImportedPkg, ok := p.imports[pkg] + if ok { + pkg = maybeImportedPkg.Path() + } + // assume type in this package + return &model.NamedType{Package: pkg, Type: v.Name}, nil + } + + // assume predeclared type + return model.PredeclaredType(v.Name), nil + case *ast.InterfaceType: + if v.Methods != nil && len(v.Methods.List) > 0 { + return nil, p.errorf(v.Pos(), "can't handle non-empty unnamed interface types") + } + return model.PredeclaredType("interface{}"), nil + case *ast.MapType: + key, err := p.parseType(pkg, v.Key) + if err != nil { + return nil, err + } + value, err := p.parseType(pkg, v.Value) + if err != nil { + return nil, err + } + return &model.MapType{Key: key, Value: value}, nil + case *ast.SelectorExpr: + pkgName := v.X.(*ast.Ident).String() + pkg, ok := p.imports[pkgName] + if !ok { + return nil, p.errorf(v.Pos(), "unknown package %q", pkgName) + } + return &model.NamedType{Package: pkg.Path(), Type: v.Sel.String()}, nil + case *ast.StarExpr: + t, err := p.parseType(pkg, v.X) + if err != nil { + return nil, err + } + return &model.PointerType{Type: t}, nil + case *ast.StructType: + if v.Fields != nil && len(v.Fields.List) > 0 { + return nil, p.errorf(v.Pos(), "can't handle non-empty unnamed struct types") + } + return model.PredeclaredType("struct{}"), nil + case *ast.ParenExpr: + return p.parseType(pkg, v.X) + } + + return nil, fmt.Errorf("don't know how to parse type %T", typ) +} + +// importsOfFile returns a map of package name to import path +// of the imports in file. +func importsOfFile(file *ast.File) (normalImports map[string]importedPackage, dotImports []string) { + var importPaths []string + for _, is := range file.Imports { + if is.Name != nil { + continue + } + importPath := is.Path.Value[1 : len(is.Path.Value)-1] // remove quotes + importPaths = append(importPaths, importPath) + } + packagesName := createPackageMap(importPaths) + normalImports = make(map[string]importedPackage) + dotImports = make([]string, 0) + for _, is := range file.Imports { + var pkgName string + importPath := is.Path.Value[1 : len(is.Path.Value)-1] // remove quotes + + if is.Name != nil { + // Named imports are always certain. + if is.Name.Name == "_" { + continue + } + pkgName = is.Name.Name + } else { + pkg, ok := packagesName[importPath] + if !ok { + // Fallback to import path suffix. Note that this is uncertain. + _, last := path.Split(importPath) + // If the last path component has dots, the first dot-delimited + // field is used as the name. + pkgName = strings.SplitN(last, ".", 2)[0] + } else { + pkgName = pkg + } + } + + if pkgName == "." { + dotImports = append(dotImports, importPath) + } else { + if pkg, ok := normalImports[pkgName]; ok { + switch p := pkg.(type) { + case duplicateImport: + normalImports[pkgName] = duplicateImport{ + name: p.name, + duplicates: append([]string{importPath}, p.duplicates...), + } + case importedPkg: + normalImports[pkgName] = duplicateImport{ + name: pkgName, + duplicates: []string{p.path, importPath}, + } + } + } else { + normalImports[pkgName] = importedPkg{path: importPath} + } + } + } + return +} + +type namedInterface struct { + name *ast.Ident + it *ast.InterfaceType +} + +// Create an iterator over all interfaces in file. +func iterInterfaces(file *ast.File) <-chan namedInterface { + ch := make(chan namedInterface) + go func() { + for _, decl := range file.Decls { + gd, ok := decl.(*ast.GenDecl) + if !ok || gd.Tok != token.TYPE { + continue + } + for _, spec := range gd.Specs { + ts, ok := spec.(*ast.TypeSpec) + if !ok { + continue + } + it, ok := ts.Type.(*ast.InterfaceType) + if !ok { + continue + } + + ch <- namedInterface{ts.Name, it} + } + } + close(ch) + }() + return ch +} + +// isVariadic returns whether the function is variadic. +func isVariadic(f *ast.FuncType) bool { + nargs := len(f.Params.List) + if nargs == 0 { + return false + } + _, ok := f.Params.List[nargs-1].Type.(*ast.Ellipsis) + return ok +} + +// packageNameOfDir get package import path via dir +func packageNameOfDir(srcDir string) (string, error) { + files, err := ioutil.ReadDir(srcDir) + if err != nil { + log.Fatal(err) + } + + var goFilePath string + for _, file := range files { + if !file.IsDir() && strings.HasSuffix(file.Name(), ".go") { + goFilePath = file.Name() + break + } + } + if goFilePath == "" { + return "", fmt.Errorf("go source file not found %s", srcDir) + } + + packageImport, err := parsePackageImport(srcDir) + if err != nil { + return "", err + } + return packageImport, nil +} + +var errOutsideGoPath = errors.New("source directory is outside GOPATH") diff --git a/vendor/github.com/golang/mock/mockgen/reflect.go b/vendor/github.com/golang/mock/mockgen/reflect.go new file mode 100644 index 000000000..e24efce0b --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/reflect.go @@ -0,0 +1,256 @@ +// Copyright 2012 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +// This file contains the model construction by reflection. + +import ( + "bytes" + "encoding/gob" + "flag" + "fmt" + "go/build" + "io" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "text/template" + + "github.com/golang/mock/mockgen/model" +) + +var ( + progOnly = flag.Bool("prog_only", false, "(reflect mode) Only generate the reflection program; write it to stdout and exit.") + execOnly = flag.String("exec_only", "", "(reflect mode) If set, execute this reflection program.") + buildFlags = flag.String("build_flags", "", "(reflect mode) Additional flags for go build.") +) + +// reflectMode generates mocks via reflection on an interface. +func reflectMode(importPath string, symbols []string) (*model.Package, error) { + if *execOnly != "" { + return run(*execOnly) + } + + program, err := writeProgram(importPath, symbols) + if err != nil { + return nil, err + } + + if *progOnly { + if _, err := os.Stdout.Write(program); err != nil { + return nil, err + } + os.Exit(0) + } + + wd, _ := os.Getwd() + + // Try to run the reflection program in the current working directory. + if p, err := runInDir(program, wd); err == nil { + return p, nil + } + + // Try to run the program in the same directory as the input package. + if p, err := build.Import(importPath, wd, build.FindOnly); err == nil { + dir := p.Dir + if p, err := runInDir(program, dir); err == nil { + return p, nil + } + } + + // Try to run it in a standard temp directory. + return runInDir(program, "") +} + +func writeProgram(importPath string, symbols []string) ([]byte, error) { + var program bytes.Buffer + data := reflectData{ + ImportPath: importPath, + Symbols: symbols, + } + if err := reflectProgram.Execute(&program, &data); err != nil { + return nil, err + } + return program.Bytes(), nil +} + +// run the given program and parse the output as a model.Package. +func run(program string) (*model.Package, error) { + f, err := ioutil.TempFile("", "") + if err != nil { + return nil, err + } + + filename := f.Name() + defer os.Remove(filename) + if err := f.Close(); err != nil { + return nil, err + } + + // Run the program. + cmd := exec.Command(program, "-output", filename) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return nil, err + } + + f, err = os.Open(filename) + if err != nil { + return nil, err + } + + // Process output. + var pkg model.Package + if err := gob.NewDecoder(f).Decode(&pkg); err != nil { + return nil, err + } + + if err := f.Close(); err != nil { + return nil, err + } + + return &pkg, nil +} + +// runInDir writes the given program into the given dir, runs it there, and +// parses the output as a model.Package. +func runInDir(program []byte, dir string) (*model.Package, error) { + // We use TempDir instead of TempFile so we can control the filename. + tmpDir, err := ioutil.TempDir(dir, "gomock_reflect_") + if err != nil { + return nil, err + } + defer func() { + if err := os.RemoveAll(tmpDir); err != nil { + log.Printf("failed to remove temp directory: %s", err) + } + }() + const progSource = "prog.go" + var progBinary = "prog.bin" + if runtime.GOOS == "windows" { + // Windows won't execute a program unless it has a ".exe" suffix. + progBinary += ".exe" + } + + if err := ioutil.WriteFile(filepath.Join(tmpDir, progSource), program, 0600); err != nil { + return nil, err + } + + cmdArgs := []string{} + cmdArgs = append(cmdArgs, "build") + if *buildFlags != "" { + cmdArgs = append(cmdArgs, strings.Split(*buildFlags, " ")...) + } + cmdArgs = append(cmdArgs, "-o", progBinary, progSource) + + // Build the program. + buf := bytes.NewBuffer(nil) + cmd := exec.Command("go", cmdArgs...) + cmd.Dir = tmpDir + cmd.Stdout = os.Stdout + cmd.Stderr = io.MultiWriter(os.Stderr, buf) + if err := cmd.Run(); err != nil { + sErr := buf.String() + if strings.Contains(sErr, `cannot find package "."`) && + strings.Contains(sErr, "github.com/golang/mock/mockgen/model") { + fmt.Fprint(os.Stderr, "Please reference the steps in the README to fix this error:\n\thttps://github.com/golang/mock#reflect-vendoring-error.") + return nil, err + } + return nil, err + } + + return run(filepath.Join(tmpDir, progBinary)) +} + +type reflectData struct { + ImportPath string + Symbols []string +} + +// This program reflects on an interface value, and prints the +// gob encoding of a model.Package to standard output. +// JSON doesn't work because of the model.Type interface. +var reflectProgram = template.Must(template.New("program").Parse(` +package main + +import ( + "encoding/gob" + "flag" + "fmt" + "os" + "path" + "reflect" + + "github.com/golang/mock/mockgen/model" + + pkg_ {{printf "%q" .ImportPath}} +) + +var output = flag.String("output", "", "The output file name, or empty to use stdout.") + +func main() { + flag.Parse() + + its := []struct{ + sym string + typ reflect.Type + }{ + {{range .Symbols}} + { {{printf "%q" .}}, reflect.TypeOf((*pkg_.{{.}})(nil)).Elem()}, + {{end}} + } + pkg := &model.Package{ + // NOTE: This behaves contrary to documented behaviour if the + // package name is not the final component of the import path. + // The reflect package doesn't expose the package name, though. + Name: path.Base({{printf "%q" .ImportPath}}), + } + + for _, it := range its { + intf, err := model.InterfaceFromInterfaceType(it.typ) + if err != nil { + fmt.Fprintf(os.Stderr, "Reflection: %v\n", err) + os.Exit(1) + } + intf.Name = it.sym + pkg.Interfaces = append(pkg.Interfaces, intf) + } + + outfile := os.Stdout + if len(*output) != 0 { + var err error + outfile, err = os.Create(*output) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to open output file %q", *output) + } + defer func() { + if err := outfile.Close(); err != nil { + fmt.Fprintf(os.Stderr, "failed to close output file %q", *output) + os.Exit(1) + } + }() + } + + if err := gob.NewEncoder(outfile).Encode(pkg); err != nil { + fmt.Fprintf(os.Stderr, "gob encode: %v\n", err) + os.Exit(1) + } +} +`)) diff --git a/vendor/github.com/golang/mock/mockgen/version.1.11.go b/vendor/github.com/golang/mock/mockgen/version.1.11.go new file mode 100644 index 000000000..e6b25db23 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/version.1.11.go @@ -0,0 +1,26 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !go1.12 + +package main + +import ( + "log" +) + +func printModuleVersion() { + log.Printf("No version information is available for Mockgen compiled with " + + "version 1.11") +} diff --git a/vendor/github.com/golang/mock/mockgen/version.1.12.go b/vendor/github.com/golang/mock/mockgen/version.1.12.go new file mode 100644 index 000000000..ad121ae63 --- /dev/null +++ b/vendor/github.com/golang/mock/mockgen/version.1.12.go @@ -0,0 +1,35 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// +build go1.12 + +package main + +import ( + "fmt" + "log" + "runtime/debug" +) + +func printModuleVersion() { + if bi, exists := debug.ReadBuildInfo(); exists { + fmt.Println(bi.Main.Version) + } else { + log.Printf("No version information found. Make sure to use " + + "GO111MODULE=on when running 'go get' in order to use specific " + + "version of the binary.") + } + +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go index e102849b0..e54a76c7e 100644 --- a/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go @@ -1,17 +1,17 @@ // Copyright 2017, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. // Package cmpopts provides common options for the cmp package. package cmpopts import ( + "errors" "math" "reflect" "time" "github.com/google/go-cmp/cmp" - "golang.org/x/xerrors" ) func equateAlways(_, _ interface{}) bool { return true } @@ -42,6 +42,7 @@ func isEmpty(x, y interface{}) bool { // The fraction and margin must be non-negative. // // The mathematical expression used is equivalent to: +// // |x-y| ≤ max(fraction*min(|x|, |y|), margin) // // EquateApprox can be used in conjunction with EquateNaNs. @@ -112,7 +113,7 @@ type timeApproximator struct { func (a timeApproximator) compare(x, y time.Time) bool { // Avoid subtracting times to avoid overflow when the - // difference is larger than the largest representible duration. + // difference is larger than the largest representable duration. if x.After(y) { // Ensure x is always before y x, y = y, x @@ -151,6 +152,5 @@ func areConcreteErrors(x, y interface{}) bool { func compareErrors(x, y interface{}) bool { xe := x.(error) ye := y.(error) - // TODO: Use errors.Is when go1.13 is the minimally supported version of Go. - return xerrors.Is(xe, ye) || xerrors.Is(ye, xe) + return errors.Is(xe, ye) || errors.Is(ye, xe) } diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go index ff8e785d4..80c60617e 100644 --- a/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go @@ -1,6 +1,6 @@ // Copyright 2017, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. package cmpopts @@ -14,14 +14,13 @@ import ( "github.com/google/go-cmp/cmp/internal/function" ) -// IgnoreFields returns an Option that ignores exported fields of the -// given names on a single struct type. +// IgnoreFields returns an Option that ignores fields of the +// given names on a single struct type. It respects the names of exported fields +// that are forwarded due to struct embedding. // The struct type is specified by passing in a value of that type. // // The name may be a dot-delimited string (e.g., "Foo.Bar") to ignore a // specific sub-field that is embedded or nested within the parent struct. -// -// This does not handle unexported fields; use IgnoreUnexported instead. func IgnoreFields(typ interface{}, names ...string) cmp.Option { sf := newStructFilter(typ, names...) return cmp.FilterPath(sf.filter, cmp.Ignore()) @@ -129,7 +128,7 @@ func newUnexportedFilter(typs ...interface{}) unexportedFilter { for _, typ := range typs { t := reflect.TypeOf(typ) if t == nil || t.Kind() != reflect.Struct { - panic(fmt.Sprintf("invalid struct type: %T", typ)) + panic(fmt.Sprintf("%T must be a non-pointer struct", typ)) } ux.m[t] = true } diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go index 3a4804621..0eb2a758c 100644 --- a/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go @@ -1,6 +1,6 @@ // Copyright 2017, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. package cmpopts @@ -18,9 +18,9 @@ import ( // sort any slice with element type V that is assignable to T. // // The less function must be: -// • Deterministic: less(x, y) == less(x, y) -// • Irreflexive: !less(x, x) -// • Transitive: if !less(x, y) and !less(y, z), then !less(x, z) +// - Deterministic: less(x, y) == less(x, y) +// - Irreflexive: !less(x, x) +// - Transitive: if !less(x, y) and !less(y, z), then !less(x, z) // // The less function does not have to be "total". That is, if !less(x, y) and // !less(y, x) for two elements x and y, their relative order is maintained. @@ -91,10 +91,10 @@ func (ss sliceSorter) less(v reflect.Value, i, j int) bool { // use Comparers on K or the K.Equal method if it exists. // // The less function must be: -// • Deterministic: less(x, y) == less(x, y) -// • Irreflexive: !less(x, x) -// • Transitive: if !less(x, y) and !less(y, z), then !less(x, z) -// • Total: if x != y, then either less(x, y) or less(y, x) +// - Deterministic: less(x, y) == less(x, y) +// - Irreflexive: !less(x, x) +// - Transitive: if !less(x, y) and !less(y, z), then !less(x, z) +// - Total: if x != y, then either less(x, y) or less(y, x) // // SortMaps can be used in conjunction with EquateEmpty. func SortMaps(lessFunc interface{}) cmp.Option { diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go index 97f707983..ca11a4024 100644 --- a/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go @@ -1,6 +1,6 @@ // Copyright 2017, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. package cmpopts @@ -42,7 +42,7 @@ func newStructFilter(typ interface{}, names ...string) structFilter { t := reflect.TypeOf(typ) if t == nil || t.Kind() != reflect.Struct { - panic(fmt.Sprintf("%T must be a struct", typ)) + panic(fmt.Sprintf("%T must be a non-pointer struct", typ)) } var ft fieldTree for _, name := range names { @@ -67,12 +67,14 @@ func (sf structFilter) filter(p cmp.Path) bool { // fieldTree represents a set of dot-separated identifiers. // // For example, inserting the following selectors: +// // Foo // Foo.Bar.Baz // Foo.Buzz // Nuka.Cola.Quantum // // Results in a tree of the form: +// // {sub: { // "Foo": {ok: true, sub: { // "Bar": {sub: { @@ -160,14 +162,19 @@ func canonicalName(t reflect.Type, sel string) ([]string, error) { // Find the canonical name for this current field name. // If the field exists in an embedded struct, then it will be expanded. + sf, _ := t.FieldByName(name) if !isExported(name) { - // Disallow unexported fields: - // * To discourage people from actually touching unexported fields - // * FieldByName is buggy (https://golang.org/issue/4876) - return []string{name}, fmt.Errorf("name must be exported") + // Avoid using reflect.Type.FieldByName for unexported fields due to + // buggy behavior with regard to embeddeding and unexported fields. + // See https://golang.org/issue/4876 for details. + sf = reflect.StructField{} + for i := 0; i < t.NumField() && sf.Name == ""; i++ { + if t.Field(i).Name == name { + sf = t.Field(i) + } + } } - sf, ok := t.FieldByName(name) - if !ok { + if sf.Name == "" { return []string{name}, fmt.Errorf("does not exist") } var ss []string diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go index 9d651553d..8812443a2 100644 --- a/vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go @@ -1,6 +1,6 @@ // Copyright 2018, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. package cmpopts @@ -23,6 +23,7 @@ func (xf xformFilter) filter(p cmp.Path) bool { // that the transformer cannot be recursively applied upon its own output. // // An example use case is a transformer that splits a string by lines: +// // AcyclicTransformer("SplitLines", func(s string) []string{ // return strings.Split(s, "\n") // }) diff --git a/vendor/github.com/google/go-cmp/cmp/compare.go b/vendor/github.com/google/go-cmp/cmp/compare.go index c9a63ceda..087320da7 100644 --- a/vendor/github.com/google/go-cmp/cmp/compare.go +++ b/vendor/github.com/google/go-cmp/cmp/compare.go @@ -1,29 +1,33 @@ // Copyright 2017, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. // Package cmp determines equality of values. // // This package is intended to be a more powerful and safer alternative to // reflect.DeepEqual for comparing whether two values are semantically equal. +// It is intended to only be used in tests, as performance is not a goal and +// it may panic if it cannot compare the values. Its propensity towards +// panicking means that its unsuitable for production environments where a +// spurious panic may be fatal. // // The primary features of cmp are: // -// • When the default behavior of equality does not suit the needs of the test, -// custom equality functions can override the equality operation. -// For example, an equality function may report floats as equal so long as they -// are within some tolerance of each other. +// - When the default behavior of equality does not suit the test's needs, +// custom equality functions can override the equality operation. +// For example, an equality function may report floats as equal so long as +// they are within some tolerance of each other. // -// • Types that have an Equal method may use that method to determine equality. -// This allows package authors to determine the equality operation for the types -// that they define. +// - Types with an Equal method may use that method to determine equality. +// This allows package authors to determine the equality operation +// for the types that they define. // -// • If no custom equality functions are used and no Equal method is defined, -// equality is determined by recursively comparing the primitive kinds on both -// values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, unexported -// fields are not compared by default; they result in panics unless suppressed -// by using an Ignore option (see cmpopts.IgnoreUnexported) or explicitly -// compared using the Exporter option. +// - If no custom equality functions are used and no Equal method is defined, +// equality is determined by recursively comparing the primitive kinds on +// both values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, +// unexported fields are not compared by default; they result in panics +// unless suppressed by using an Ignore option (see cmpopts.IgnoreUnexported) +// or explicitly compared using the Exporter option. package cmp import ( @@ -32,33 +36,34 @@ import ( "strings" "github.com/google/go-cmp/cmp/internal/diff" - "github.com/google/go-cmp/cmp/internal/flags" "github.com/google/go-cmp/cmp/internal/function" "github.com/google/go-cmp/cmp/internal/value" ) +// TODO(≥go1.18): Use any instead of interface{}. + // Equal reports whether x and y are equal by recursively applying the // following rules in the given order to x and y and all of their sub-values: // -// • Let S be the set of all Ignore, Transformer, and Comparer options that -// remain after applying all path filters, value filters, and type filters. -// If at least one Ignore exists in S, then the comparison is ignored. -// If the number of Transformer and Comparer options in S is greater than one, -// then Equal panics because it is ambiguous which option to use. -// If S contains a single Transformer, then use that to transform the current -// values and recursively call Equal on the output values. -// If S contains a single Comparer, then use that to compare the current values. -// Otherwise, evaluation proceeds to the next rule. +// - Let S be the set of all Ignore, Transformer, and Comparer options that +// remain after applying all path filters, value filters, and type filters. +// If at least one Ignore exists in S, then the comparison is ignored. +// If the number of Transformer and Comparer options in S is non-zero, +// then Equal panics because it is ambiguous which option to use. +// If S contains a single Transformer, then use that to transform +// the current values and recursively call Equal on the output values. +// If S contains a single Comparer, then use that to compare the current values. +// Otherwise, evaluation proceeds to the next rule. // -// • If the values have an Equal method of the form "(T) Equal(T) bool" or -// "(T) Equal(I) bool" where T is assignable to I, then use the result of -// x.Equal(y) even if x or y is nil. Otherwise, no such method exists and -// evaluation proceeds to the next rule. +// - If the values have an Equal method of the form "(T) Equal(T) bool" or +// "(T) Equal(I) bool" where T is assignable to I, then use the result of +// x.Equal(y) even if x or y is nil. Otherwise, no such method exists and +// evaluation proceeds to the next rule. // -// • Lastly, try to compare x and y based on their basic kinds. -// Simple kinds like booleans, integers, floats, complex numbers, strings, and -// channels are compared using the equivalent of the == operator in Go. -// Functions are only equal if they are both nil, otherwise they are unequal. +// - Lastly, try to compare x and y based on their basic kinds. +// Simple kinds like booleans, integers, floats, complex numbers, strings, +// and channels are compared using the equivalent of the == operator in Go. +// Functions are only equal if they are both nil, otherwise they are unequal. // // Structs are equal if recursively calling Equal on all fields report equal. // If a struct contains unexported fields, Equal panics unless an Ignore option @@ -86,6 +91,52 @@ import ( // If there is a cycle, then the pointed at values are considered equal // only if both addresses were previously visited in the same path step. func Equal(x, y interface{}, opts ...Option) bool { + s := newState(opts) + s.compareAny(rootStep(x, y)) + return s.result.Equal() +} + +// Diff returns a human-readable report of the differences between two values: +// y - x. It returns an empty string if and only if Equal returns true for the +// same input values and options. +// +// The output is displayed as a literal in pseudo-Go syntax. +// At the start of each line, a "-" prefix indicates an element removed from x, +// a "+" prefix to indicates an element added from y, and the lack of a prefix +// indicates an element common to both x and y. If possible, the output +// uses fmt.Stringer.String or error.Error methods to produce more humanly +// readable outputs. In such cases, the string is prefixed with either an +// 's' or 'e' character, respectively, to indicate that the method was called. +// +// Do not depend on this output being stable. If you need the ability to +// programmatically interpret the difference, consider using a custom Reporter. +func Diff(x, y interface{}, opts ...Option) string { + s := newState(opts) + + // Optimization: If there are no other reporters, we can optimize for the + // common case where the result is equal (and thus no reported difference). + // This avoids the expensive construction of a difference tree. + if len(s.reporters) == 0 { + s.compareAny(rootStep(x, y)) + if s.result.Equal() { + return "" + } + s.result = diff.Result{} // Reset results + } + + r := new(defaultReporter) + s.reporters = append(s.reporters, reporter{r}) + s.compareAny(rootStep(x, y)) + d := r.String() + if (d == "") != s.result.Equal() { + panic("inconsistent difference and equality results") + } + return d +} + +// rootStep constructs the first path step. If x and y have differing types, +// then they are stored within an empty interface type. +func rootStep(x, y interface{}) PathStep { vx := reflect.ValueOf(x) vy := reflect.ValueOf(y) @@ -93,7 +144,7 @@ func Equal(x, y interface{}, opts ...Option) bool { // so that they have the same parent type. var t reflect.Type if !vx.IsValid() || !vy.IsValid() || vx.Type() != vy.Type() { - t = reflect.TypeOf((*interface{})(nil)).Elem() + t = anyType if vx.IsValid() { vvx := reflect.New(t).Elem() vvx.Set(vx) @@ -108,33 +159,7 @@ func Equal(x, y interface{}, opts ...Option) bool { t = vx.Type() } - s := newState(opts) - s.compareAny(&pathStep{t, vx, vy}) - return s.result.Equal() -} - -// Diff returns a human-readable report of the differences between two values. -// It returns an empty string if and only if Equal returns true for the same -// input values and options. -// -// The output is displayed as a literal in pseudo-Go syntax. -// At the start of each line, a "-" prefix indicates an element removed from x, -// a "+" prefix to indicates an element added to y, and the lack of a prefix -// indicates an element common to both x and y. If possible, the output -// uses fmt.Stringer.String or error.Error methods to produce more humanly -// readable outputs. In such cases, the string is prefixed with either an -// 's' or 'e' character, respectively, to indicate that the method was called. -// -// Do not depend on this output being stable. If you need the ability to -// programmatically interpret the difference, consider using a custom Reporter. -func Diff(x, y interface{}, opts ...Option) string { - r := new(defaultReporter) - eq := Equal(x, y, Options(opts), Reporter(r)) - d := r.String() - if (d == "") != eq { - panic("inconsistent difference and equality results") - } - return d + return &pathStep{t, vx, vy} } type state struct { @@ -295,7 +320,6 @@ func (s *state) tryMethod(t reflect.Type, vx, vy reflect.Value) bool { } func (s *state) callTRFunc(f, v reflect.Value, step Transform) reflect.Value { - v = sanitizeValue(v, f.Type().In(0)) if !s.dynChecker.Next() { return f.Call([]reflect.Value{v})[0] } @@ -319,8 +343,6 @@ func (s *state) callTRFunc(f, v reflect.Value, step Transform) reflect.Value { } func (s *state) callTTBFunc(f, x, y reflect.Value) bool { - x = sanitizeValue(x, f.Type().In(0)) - y = sanitizeValue(y, f.Type().In(1)) if !s.dynChecker.Next() { return f.Call([]reflect.Value{x, y})[0].Bool() } @@ -348,20 +370,8 @@ func detectRaces(c chan<- reflect.Value, f reflect.Value, vs ...reflect.Value) { ret = f.Call(vs)[0] } -// sanitizeValue converts nil interfaces of type T to those of type R, -// assuming that T is assignable to R. -// Otherwise, it returns the input value as is. -func sanitizeValue(v reflect.Value, t reflect.Type) reflect.Value { - // TODO(dsnet): Workaround for reflect bug (https://golang.org/issue/22143). - if !flags.AtLeastGo110 { - if v.Kind() == reflect.Interface && v.IsNil() && v.Type() != t { - return reflect.New(t).Elem() - } - } - return v -} - func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) { + var addr bool var vax, vay reflect.Value // Addressable versions of vx and vy var mayForce, mayForceInit bool @@ -383,6 +393,7 @@ func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) { // For retrieveUnexportedField to work, the parent struct must // be addressable. Create a new copy of the values if // necessary to make them addressable. + addr = vx.CanAddr() || vy.CanAddr() vax = makeAddressable(vx) vay = makeAddressable(vy) } @@ -393,6 +404,7 @@ func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) { mayForceInit = true } step.mayForce = mayForce + step.paddr = addr step.pvx = vax step.pvy = vay step.field = t.Field(i) @@ -627,7 +639,9 @@ type dynChecker struct{ curr, next int } // Next increments the state and reports whether a check should be performed. // // Checks occur every Nth function call, where N is a triangular number: +// // 0 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 ... +// // See https://en.wikipedia.org/wiki/Triangular_number // // This sequence ensures that the cost of checks drops significantly as diff --git a/vendor/github.com/google/go-cmp/cmp/export_panic.go b/vendor/github.com/google/go-cmp/cmp/export_panic.go index dd032354f..ae851fe53 100644 --- a/vendor/github.com/google/go-cmp/cmp/export_panic.go +++ b/vendor/github.com/google/go-cmp/cmp/export_panic.go @@ -1,7 +1,8 @@ // Copyright 2017, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. +//go:build purego // +build purego package cmp @@ -10,6 +11,6 @@ import "reflect" const supportExporters = false -func retrieveUnexportedField(reflect.Value, reflect.StructField) reflect.Value { +func retrieveUnexportedField(reflect.Value, reflect.StructField, bool) reflect.Value { panic("no support for forcibly accessing unexported fields") } diff --git a/vendor/github.com/google/go-cmp/cmp/export_unsafe.go b/vendor/github.com/google/go-cmp/cmp/export_unsafe.go index 57020e26c..e2c0f74e8 100644 --- a/vendor/github.com/google/go-cmp/cmp/export_unsafe.go +++ b/vendor/github.com/google/go-cmp/cmp/export_unsafe.go @@ -1,7 +1,8 @@ // Copyright 2017, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. +//go:build !purego // +build !purego package cmp @@ -17,9 +18,19 @@ const supportExporters = true // a struct such that the value has read-write permissions. // // The parent struct, v, must be addressable, while f must be a StructField -// describing the field to retrieve. -func retrieveUnexportedField(v reflect.Value, f reflect.StructField) reflect.Value { - // See https://github.com/google/go-cmp/issues/167 for discussion of the - // following expression. - return reflect.NewAt(f.Type, unsafe.Pointer(uintptr(unsafe.Pointer(v.UnsafeAddr()))+f.Offset)).Elem() +// describing the field to retrieve. If addr is false, +// then the returned value will be shallowed copied to be non-addressable. +func retrieveUnexportedField(v reflect.Value, f reflect.StructField, addr bool) reflect.Value { + ve := reflect.NewAt(f.Type, unsafe.Pointer(uintptr(unsafe.Pointer(v.UnsafeAddr()))+f.Offset)).Elem() + if !addr { + // A field is addressable if and only if the struct is addressable. + // If the original parent value was not addressable, shallow copy the + // value to make it non-addressable to avoid leaking an implementation + // detail of how forcibly exporting a field works. + if ve.Kind() == reflect.Interface && ve.IsNil() { + return reflect.Zero(f.Type) + } + return reflect.ValueOf(ve.Interface()).Convert(f.Type) + } + return ve } diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go index fe98dcc67..36062a604 100644 --- a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go +++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go @@ -1,7 +1,8 @@ // Copyright 2017, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. +//go:build !cmp_debug // +build !cmp_debug package diff diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go index 597b6ae56..a3b97a1ad 100644 --- a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go +++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go @@ -1,7 +1,8 @@ // Copyright 2017, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. +//go:build cmp_debug // +build cmp_debug package diff diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go index 3d2e42662..a248e5436 100644 --- a/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go +++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go @@ -1,6 +1,6 @@ // Copyright 2017, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. // Package diff implements an algorithm for producing edit-scripts. // The edit-script is a sequence of operations needed to transform one list @@ -12,6 +12,13 @@ // is more important than obtaining a minimal Levenshtein distance. package diff +import ( + "math/rand" + "time" + + "github.com/google/go-cmp/cmp/internal/flags" +) + // EditType represents a single operation within an edit-script. type EditType uint8 @@ -112,15 +119,17 @@ func (r Result) Similar() bool { return r.NumSame+1 >= r.NumDiff } +var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0 + // Difference reports whether two lists of lengths nx and ny are equal // given the definition of equality provided as f. // // This function returns an edit-script, which is a sequence of operations // needed to convert one list into the other. The following invariants for // the edit-script are maintained: -// • eq == (es.Dist()==0) -// • nx == es.LenX() -// • ny == es.LenY() +// - eq == (es.Dist()==0) +// - nx == es.LenX() +// - ny == es.LenY() // // This algorithm is not guaranteed to be an optimal solution (i.e., one that // produces an edit-script with a minimal Levenshtein distance). This algorithm @@ -160,12 +169,13 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) { // A diagonal edge is equivalent to a matching symbol between both X and Y. // Invariants: - // • 0 ≤ fwdPath.X ≤ (fwdFrontier.X, revFrontier.X) ≤ revPath.X ≤ nx - // • 0 ≤ fwdPath.Y ≤ (fwdFrontier.Y, revFrontier.Y) ≤ revPath.Y ≤ ny + // - 0 ≤ fwdPath.X ≤ (fwdFrontier.X, revFrontier.X) ≤ revPath.X ≤ nx + // - 0 ≤ fwdPath.Y ≤ (fwdFrontier.Y, revFrontier.Y) ≤ revPath.Y ≤ ny // // In general: - // • fwdFrontier.X < revFrontier.X - // • fwdFrontier.Y < revFrontier.Y + // - fwdFrontier.X < revFrontier.X + // - fwdFrontier.Y < revFrontier.Y + // // Unless, it is time for the algorithm to terminate. fwdPath := path{+1, point{0, 0}, make(EditScript, 0, (nx+ny)/2)} revPath := path{-1, point{nx, ny}, make(EditScript, 0)} @@ -177,37 +187,50 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) { // approximately the square-root of the search budget. searchBudget := 4 * (nx + ny) // O(n) + // Running the tests with the "cmp_debug" build tag prints a visualization + // of the algorithm running in real-time. This is educational for + // understanding how the algorithm works. See debug_enable.go. + f = debug.Begin(nx, ny, f, &fwdPath.es, &revPath.es) + // The algorithm below is a greedy, meet-in-the-middle algorithm for // computing sub-optimal edit-scripts between two lists. // // The algorithm is approximately as follows: - // • Searching for differences switches back-and-forth between - // a search that starts at the beginning (the top-left corner), and - // a search that starts at the end (the bottom-right corner). The goal of - // the search is connect with the search from the opposite corner. - // • As we search, we build a path in a greedy manner, where the first - // match seen is added to the path (this is sub-optimal, but provides a - // decent result in practice). When matches are found, we try the next pair - // of symbols in the lists and follow all matches as far as possible. - // • When searching for matches, we search along a diagonal going through - // through the "frontier" point. If no matches are found, we advance the - // frontier towards the opposite corner. - // • This algorithm terminates when either the X coordinates or the - // Y coordinates of the forward and reverse frontier points ever intersect. - // + // - Searching for differences switches back-and-forth between + // a search that starts at the beginning (the top-left corner), and + // a search that starts at the end (the bottom-right corner). + // The goal of the search is connect with the search + // from the opposite corner. + // - As we search, we build a path in a greedy manner, + // where the first match seen is added to the path (this is sub-optimal, + // but provides a decent result in practice). When matches are found, + // we try the next pair of symbols in the lists and follow all matches + // as far as possible. + // - When searching for matches, we search along a diagonal going through + // through the "frontier" point. If no matches are found, + // we advance the frontier towards the opposite corner. + // - This algorithm terminates when either the X coordinates or the + // Y coordinates of the forward and reverse frontier points ever intersect. + // This algorithm is correct even if searching only in the forward direction // or in the reverse direction. We do both because it is commonly observed // that two lists commonly differ because elements were added to the front // or end of the other list. // - // Running the tests with the "cmp_debug" build tag prints a visualization - // of the algorithm running in real-time. This is educational for - // understanding how the algorithm works. See debug_enable.go. - f = debug.Begin(nx, ny, f, &fwdPath.es, &revPath.es) - for { + // Non-deterministically start with either the forward or reverse direction + // to introduce some deliberate instability so that we have the flexibility + // to change this algorithm in the future. + if flags.Deterministic || randBool { + goto forwardSearch + } else { + goto reverseSearch + } + +forwardSearch: + { // Forward search from the beginning. if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 { - break + goto finishSearch } for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ { // Search in a diagonal pattern for a match. @@ -242,10 +265,14 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) { } else { fwdFrontier.Y++ } + goto reverseSearch + } +reverseSearch: + { // Reverse search from the end. if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 { - break + goto finishSearch } for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ { // Search in a diagonal pattern for a match. @@ -280,8 +307,10 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) { } else { revFrontier.Y-- } + goto forwardSearch } +finishSearch: // Join the forward and reverse paths and then append the reverse path. fwdPath.connect(revPath.point, f) for i := len(revPath.es) - 1; i >= 0; i-- { @@ -363,6 +392,7 @@ type point struct{ X, Y int } func (p *point) add(dx, dy int) { p.X += dx; p.Y += dy } // zigzag maps a consecutive sequence of integers to a zig-zag sequence. +// // [0 1 2 3 4 5 ...] => [0 -1 +1 -2 +2 ...] func zigzag(x int) int { if x&1 != 0 { diff --git a/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go b/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go index a9e7fc0b5..d8e459c9b 100644 --- a/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go +++ b/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go @@ -1,6 +1,6 @@ // Copyright 2019, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. package flags diff --git a/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go b/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go deleted file mode 100644 index 01aed0a15..000000000 --- a/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_legacy.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2019, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -// +build !go1.10 - -package flags - -// AtLeastGo110 reports whether the Go toolchain is at least Go 1.10. -const AtLeastGo110 = false diff --git a/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go b/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go deleted file mode 100644 index c0b667f58..000000000 --- a/vendor/github.com/google/go-cmp/cmp/internal/flags/toolchain_recent.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2019, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -// +build go1.10 - -package flags - -// AtLeastGo110 reports whether the Go toolchain is at least Go 1.10. -const AtLeastGo110 = true diff --git a/vendor/github.com/google/go-cmp/cmp/internal/function/func.go b/vendor/github.com/google/go-cmp/cmp/internal/function/func.go index ace1dbe86..d127d4362 100644 --- a/vendor/github.com/google/go-cmp/cmp/internal/function/func.go +++ b/vendor/github.com/google/go-cmp/cmp/internal/function/func.go @@ -1,6 +1,6 @@ // Copyright 2017, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. // Package function provides functionality for identifying function types. package function diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/name.go b/vendor/github.com/google/go-cmp/cmp/internal/value/name.go new file mode 100644 index 000000000..7b498bb2c --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/name.go @@ -0,0 +1,164 @@ +// Copyright 2020, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package value + +import ( + "reflect" + "strconv" +) + +var anyType = reflect.TypeOf((*interface{})(nil)).Elem() + +// TypeString is nearly identical to reflect.Type.String, +// but has an additional option to specify that full type names be used. +func TypeString(t reflect.Type, qualified bool) string { + return string(appendTypeName(nil, t, qualified, false)) +} + +func appendTypeName(b []byte, t reflect.Type, qualified, elideFunc bool) []byte { + // BUG: Go reflection provides no way to disambiguate two named types + // of the same name and within the same package, + // but declared within the namespace of different functions. + + // Use the "any" alias instead of "interface{}" for better readability. + if t == anyType { + return append(b, "any"...) + } + + // Named type. + if t.Name() != "" { + if qualified && t.PkgPath() != "" { + b = append(b, '"') + b = append(b, t.PkgPath()...) + b = append(b, '"') + b = append(b, '.') + b = append(b, t.Name()...) + } else { + b = append(b, t.String()...) + } + return b + } + + // Unnamed type. + switch k := t.Kind(); k { + case reflect.Bool, reflect.String, reflect.UnsafePointer, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, + reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: + b = append(b, k.String()...) + case reflect.Chan: + if t.ChanDir() == reflect.RecvDir { + b = append(b, "<-"...) + } + b = append(b, "chan"...) + if t.ChanDir() == reflect.SendDir { + b = append(b, "<-"...) + } + b = append(b, ' ') + b = appendTypeName(b, t.Elem(), qualified, false) + case reflect.Func: + if !elideFunc { + b = append(b, "func"...) + } + b = append(b, '(') + for i := 0; i < t.NumIn(); i++ { + if i > 0 { + b = append(b, ", "...) + } + if i == t.NumIn()-1 && t.IsVariadic() { + b = append(b, "..."...) + b = appendTypeName(b, t.In(i).Elem(), qualified, false) + } else { + b = appendTypeName(b, t.In(i), qualified, false) + } + } + b = append(b, ')') + switch t.NumOut() { + case 0: + // Do nothing + case 1: + b = append(b, ' ') + b = appendTypeName(b, t.Out(0), qualified, false) + default: + b = append(b, " ("...) + for i := 0; i < t.NumOut(); i++ { + if i > 0 { + b = append(b, ", "...) + } + b = appendTypeName(b, t.Out(i), qualified, false) + } + b = append(b, ')') + } + case reflect.Struct: + b = append(b, "struct{ "...) + for i := 0; i < t.NumField(); i++ { + if i > 0 { + b = append(b, "; "...) + } + sf := t.Field(i) + if !sf.Anonymous { + if qualified && sf.PkgPath != "" { + b = append(b, '"') + b = append(b, sf.PkgPath...) + b = append(b, '"') + b = append(b, '.') + } + b = append(b, sf.Name...) + b = append(b, ' ') + } + b = appendTypeName(b, sf.Type, qualified, false) + if sf.Tag != "" { + b = append(b, ' ') + b = strconv.AppendQuote(b, string(sf.Tag)) + } + } + if b[len(b)-1] == ' ' { + b = b[:len(b)-1] + } else { + b = append(b, ' ') + } + b = append(b, '}') + case reflect.Slice, reflect.Array: + b = append(b, '[') + if k == reflect.Array { + b = strconv.AppendUint(b, uint64(t.Len()), 10) + } + b = append(b, ']') + b = appendTypeName(b, t.Elem(), qualified, false) + case reflect.Map: + b = append(b, "map["...) + b = appendTypeName(b, t.Key(), qualified, false) + b = append(b, ']') + b = appendTypeName(b, t.Elem(), qualified, false) + case reflect.Ptr: + b = append(b, '*') + b = appendTypeName(b, t.Elem(), qualified, false) + case reflect.Interface: + b = append(b, "interface{ "...) + for i := 0; i < t.NumMethod(); i++ { + if i > 0 { + b = append(b, "; "...) + } + m := t.Method(i) + if qualified && m.PkgPath != "" { + b = append(b, '"') + b = append(b, m.PkgPath...) + b = append(b, '"') + b = append(b, '.') + } + b = append(b, m.Name...) + b = appendTypeName(b, m.Type, qualified, true) + } + if b[len(b)-1] == ' ' { + b = b[:len(b)-1] + } else { + b = append(b, ' ') + } + b = append(b, '}') + default: + panic("invalid kind: " + k.String()) + } + return b +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go index 0a01c4796..1a71bfcbd 100644 --- a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go @@ -1,7 +1,8 @@ // Copyright 2018, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. +//go:build purego // +build purego package value @@ -21,3 +22,13 @@ func PointerOf(v reflect.Value) Pointer { // assumes that the GC implementation does not use a moving collector. return Pointer{v.Pointer(), v.Type()} } + +// IsNil reports whether the pointer is nil. +func (p Pointer) IsNil() bool { + return p.p == 0 +} + +// Uintptr returns the pointer as a uintptr. +func (p Pointer) Uintptr() uintptr { + return p.p +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go index da134ae2a..16e6860af 100644 --- a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go @@ -1,7 +1,8 @@ // Copyright 2018, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. +//go:build !purego // +build !purego package value @@ -24,3 +25,13 @@ func PointerOf(v reflect.Value) Pointer { // which is necessary if the GC ever uses a moving collector. return Pointer{unsafe.Pointer(v.Pointer()), v.Type()} } + +// IsNil reports whether the pointer is nil. +func (p Pointer) IsNil() bool { + return p.p == nil +} + +// Uintptr returns the pointer as a uintptr. +func (p Pointer) Uintptr() uintptr { + return uintptr(p.p) +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go b/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go index 24fbae6e3..98533b036 100644 --- a/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go @@ -1,6 +1,6 @@ // Copyright 2017, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. package value diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go b/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go deleted file mode 100644 index 06a8ffd03..000000000 --- a/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2017, The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. - -package value - -import ( - "math" - "reflect" -) - -// IsZero reports whether v is the zero value. -// This does not rely on Interface and so can be used on unexported fields. -func IsZero(v reflect.Value) bool { - switch v.Kind() { - case reflect.Bool: - return v.Bool() == false - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return v.Uint() == 0 - case reflect.Float32, reflect.Float64: - return math.Float64bits(v.Float()) == 0 - case reflect.Complex64, reflect.Complex128: - return math.Float64bits(real(v.Complex())) == 0 && math.Float64bits(imag(v.Complex())) == 0 - case reflect.String: - return v.String() == "" - case reflect.UnsafePointer: - return v.Pointer() == 0 - case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: - return v.IsNil() - case reflect.Array: - for i := 0; i < v.Len(); i++ { - if !IsZero(v.Index(i)) { - return false - } - } - return true - case reflect.Struct: - for i := 0; i < v.NumField(); i++ { - if !IsZero(v.Field(i)) { - return false - } - } - return true - } - return false -} diff --git a/vendor/github.com/google/go-cmp/cmp/options.go b/vendor/github.com/google/go-cmp/cmp/options.go index abbd2a63b..1f9ca9c48 100644 --- a/vendor/github.com/google/go-cmp/cmp/options.go +++ b/vendor/github.com/google/go-cmp/cmp/options.go @@ -1,6 +1,6 @@ // Copyright 2017, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. package cmp @@ -33,6 +33,7 @@ type Option interface { } // applicableOption represents the following types: +// // Fundamental: ignore | validator | *comparer | *transformer // Grouping: Options type applicableOption interface { @@ -43,6 +44,7 @@ type applicableOption interface { } // coreOption represents the following types: +// // Fundamental: ignore | validator | *comparer | *transformer // Filters: *pathFilter | *valuesFilter type coreOption interface { @@ -225,11 +227,14 @@ func (validator) apply(s *state, vx, vy reflect.Value) { // Unable to Interface implies unexported field without visibility access. if !vx.CanInterface() || !vy.CanInterface() { - const help = "consider using a custom Comparer; if you control the implementation of type, you can also consider using an Exporter, AllowUnexported, or cmpopts.IgnoreUnexported" + help := "consider using a custom Comparer; if you control the implementation of type, you can also consider using an Exporter, AllowUnexported, or cmpopts.IgnoreUnexported" var name string if t := s.curPath.Index(-2).Type(); t.Name() != "" { // Named type with unexported fields. name = fmt.Sprintf("%q.%v", t.PkgPath(), t.Name()) // e.g., "path/to/package".MyType + if _, ok := reflect.New(t).Interface().(error); ok { + help = "consider using cmpopts.EquateErrors to compare error values" + } } else { // Unnamed type with unexported fields. Derive PkgPath from field. var pkgPath string @@ -333,9 +338,9 @@ func (tr transformer) String() string { // both implement T. // // The equality function must be: -// • Symmetric: equal(x, y) == equal(y, x) -// • Deterministic: equal(x, y) == equal(x, y) -// • Pure: equal(x, y) does not modify x or y +// - Symmetric: equal(x, y) == equal(y, x) +// - Deterministic: equal(x, y) == equal(x, y) +// - Pure: equal(x, y) does not modify x or y func Comparer(f interface{}) Option { v := reflect.ValueOf(f) if !function.IsType(v.Type(), function.Equal) || v.IsNil() { @@ -427,7 +432,7 @@ func AllowUnexported(types ...interface{}) Option { } // Result represents the comparison result for a single node and -// is provided by cmp when calling Result (see Reporter). +// is provided by cmp when calling Report (see Reporter). type Result struct { _ [0]func() // Make Result incomparable flags resultFlags diff --git a/vendor/github.com/google/go-cmp/cmp/path.go b/vendor/github.com/google/go-cmp/cmp/path.go index 509d6b852..a0a588502 100644 --- a/vendor/github.com/google/go-cmp/cmp/path.go +++ b/vendor/github.com/google/go-cmp/cmp/path.go @@ -1,6 +1,6 @@ // Copyright 2017, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. package cmp @@ -41,13 +41,13 @@ type PathStep interface { // The type of each valid value is guaranteed to be identical to Type. // // In some cases, one or both may be invalid or have restrictions: - // • For StructField, both are not interface-able if the current field - // is unexported and the struct type is not explicitly permitted by - // an Exporter to traverse unexported fields. - // • For SliceIndex, one may be invalid if an element is missing from - // either the x or y slice. - // • For MapIndex, one may be invalid if an entry is missing from - // either the x or y map. + // - For StructField, both are not interface-able if the current field + // is unexported and the struct type is not explicitly permitted by + // an Exporter to traverse unexported fields. + // - For SliceIndex, one may be invalid if an element is missing from + // either the x or y slice. + // - For MapIndex, one may be invalid if an entry is missing from + // either the x or y map. // // The provided values must not be mutated. Values() (vx, vy reflect.Value) @@ -94,6 +94,7 @@ func (pa Path) Index(i int) PathStep { // The simplified path only contains struct field accesses. // // For example: +// // MyMap.MySlices.MyField func (pa Path) String() string { var ss []string @@ -108,6 +109,7 @@ func (pa Path) String() string { // GoString returns the path to a specific node using Go syntax. // // For example: +// // (*root.MyMap["key"].(*mypkg.MyStruct).MySlices)[2][3].MyField func (pa Path) GoString() string { var ssPre, ssPost []string @@ -159,7 +161,7 @@ func (ps pathStep) String() string { if ps.typ == nil { return "" } - s := ps.typ.String() + s := value.TypeString(ps.typ, false) if s == "" || strings.ContainsAny(s, "{}\n") { return "root" // Type too simple or complex to print } @@ -177,7 +179,8 @@ type structField struct { // pvx, pvy, and field are only valid if unexported is true. unexported bool mayForce bool // Forcibly allow visibility - pvx, pvy reflect.Value // Parent values + paddr bool // Was parent addressable? + pvx, pvy reflect.Value // Parent values (always addressable) field reflect.StructField // Field information } @@ -189,8 +192,8 @@ func (sf StructField) Values() (vx, vy reflect.Value) { // Forcibly obtain read-write access to an unexported struct field. if sf.mayForce { - vx = retrieveUnexportedField(sf.pvx, sf.field) - vy = retrieveUnexportedField(sf.pvy, sf.field) + vx = retrieveUnexportedField(sf.pvx, sf.field, sf.paddr) + vy = retrieveUnexportedField(sf.pvy, sf.field, sf.paddr) return vx, vy // CanInterface reports true } return sf.vx, sf.vy // CanInterface reports false @@ -281,7 +284,7 @@ type typeAssertion struct { func (ta TypeAssertion) Type() reflect.Type { return ta.typ } func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy } -func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", ta.typ) } +func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", value.TypeString(ta.typ, false)) } // Transform is a transformation from the parent type to the current type. type Transform struct{ *transform } @@ -314,7 +317,7 @@ func (tf Transform) Option() Option { return tf.trans } // pops the address from the stack. Thus, when traversing into a pointer from // reflect.Ptr, reflect.Slice element, or reflect.Map, we can detect cycles // by checking whether the pointer has already been visited. The cycle detection -// uses a seperate stack for the x and y values. +// uses a separate stack for the x and y values. // // If a cycle is detected we need to determine whether the two pointers // should be considered equal. The definition of equality chosen by Equal diff --git a/vendor/github.com/google/go-cmp/cmp/report.go b/vendor/github.com/google/go-cmp/cmp/report.go index 6ddf29993..f43cd12eb 100644 --- a/vendor/github.com/google/go-cmp/cmp/report.go +++ b/vendor/github.com/google/go-cmp/cmp/report.go @@ -1,6 +1,6 @@ // Copyright 2017, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. package cmp @@ -41,7 +41,10 @@ func (r *defaultReporter) String() string { if r.root.NumDiff == 0 { return "" } - return formatOptions{}.FormatDiff(r.root).String() + ptrs := new(pointerReferences) + text := formatOptions{}.FormatDiff(r.root, ptrs) + resolveReferences(text) + return text.String() } func assert(ok bool) { diff --git a/vendor/github.com/google/go-cmp/cmp/report_compare.go b/vendor/github.com/google/go-cmp/cmp/report_compare.go index 17a05eede..2050bf6b4 100644 --- a/vendor/github.com/google/go-cmp/cmp/report_compare.go +++ b/vendor/github.com/google/go-cmp/cmp/report_compare.go @@ -1,24 +1,14 @@ // Copyright 2019, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. package cmp import ( "fmt" "reflect" - - "github.com/google/go-cmp/cmp/internal/value" ) -// TODO: Enforce limits? -// * Enforce maximum number of records to print per node? -// * Enforce maximum size in bytes allowed? -// * As a heuristic, use less verbosity for equal nodes than unequal nodes. -// TODO: Enforce unique outputs? -// * Avoid Stringer methods if it results in same output? -// * Print pointer address if outputs still equal? - // numContextRecords is the number of surrounding equal records to print. const numContextRecords = 2 @@ -71,24 +61,69 @@ func (opts formatOptions) WithTypeMode(t typeMode) formatOptions { opts.TypeMode = t return opts } +func (opts formatOptions) WithVerbosity(level int) formatOptions { + opts.VerbosityLevel = level + opts.LimitVerbosity = true + return opts +} +func (opts formatOptions) verbosity() uint { + switch { + case opts.VerbosityLevel < 0: + return 0 + case opts.VerbosityLevel > 16: + return 16 // some reasonable maximum to avoid shift overflow + default: + return uint(opts.VerbosityLevel) + } +} + +const maxVerbosityPreset = 6 + +// verbosityPreset modifies the verbosity settings given an index +// between 0 and maxVerbosityPreset, inclusive. +func verbosityPreset(opts formatOptions, i int) formatOptions { + opts.VerbosityLevel = int(opts.verbosity()) + 2*i + if i > 0 { + opts.AvoidStringer = true + } + if i >= maxVerbosityPreset { + opts.PrintAddresses = true + opts.QualifiedNames = true + } + return opts +} // FormatDiff converts a valueNode tree into a textNode tree, where the later // is a textual representation of the differences detected in the former. -func (opts formatOptions) FormatDiff(v *valueNode) textNode { +func (opts formatOptions) FormatDiff(v *valueNode, ptrs *pointerReferences) (out textNode) { + if opts.DiffMode == diffIdentical { + opts = opts.WithVerbosity(1) + } else if opts.verbosity() < 3 { + opts = opts.WithVerbosity(3) + } + // Check whether we have specialized formatting for this node. // This is not necessary, but helpful for producing more readable outputs. if opts.CanFormatDiffSlice(v) { return opts.FormatDiffSlice(v) } + var parentKind reflect.Kind + if v.parent != nil && v.parent.TransformerName == "" { + parentKind = v.parent.Type.Kind() + } + // For leaf nodes, format the value based on the reflect.Values alone. - if v.MaxDepth == 0 { + // As a special case, treat equal []byte as a leaf nodes. + isBytes := v.Type.Kind() == reflect.Slice && v.Type.Elem() == byteType + isEqualBytes := isBytes && v.NumDiff+v.NumIgnored+v.NumTransformed == 0 + if v.MaxDepth == 0 || isEqualBytes { switch opts.DiffMode { case diffUnknown, diffIdentical: // Format Equal. if v.NumDiff == 0 { - outx := opts.FormatValue(v.ValueX, visitedPointers{}) - outy := opts.FormatValue(v.ValueY, visitedPointers{}) + outx := opts.FormatValue(v.ValueX, parentKind, ptrs) + outy := opts.FormatValue(v.ValueY, parentKind, ptrs) if v.NumIgnored > 0 && v.NumSame == 0 { return textEllipsis } else if outx.Len() < outy.Len() { @@ -101,8 +136,13 @@ func (opts formatOptions) FormatDiff(v *valueNode) textNode { // Format unequal. assert(opts.DiffMode == diffUnknown) var list textList - outx := opts.WithTypeMode(elideType).FormatValue(v.ValueX, visitedPointers{}) - outy := opts.WithTypeMode(elideType).FormatValue(v.ValueY, visitedPointers{}) + outx := opts.WithTypeMode(elideType).FormatValue(v.ValueX, parentKind, ptrs) + outy := opts.WithTypeMode(elideType).FormatValue(v.ValueY, parentKind, ptrs) + for i := 0; i <= maxVerbosityPreset && outx != nil && outy != nil && outx.Equal(outy); i++ { + opts2 := verbosityPreset(opts, i).WithTypeMode(elideType) + outx = opts2.FormatValue(v.ValueX, parentKind, ptrs) + outy = opts2.FormatValue(v.ValueY, parentKind, ptrs) + } if outx != nil { list = append(list, textRecord{Diff: '-', Value: outx}) } @@ -111,34 +151,57 @@ func (opts formatOptions) FormatDiff(v *valueNode) textNode { } return opts.WithTypeMode(emitType).FormatType(v.Type, list) case diffRemoved: - return opts.FormatValue(v.ValueX, visitedPointers{}) + return opts.FormatValue(v.ValueX, parentKind, ptrs) case diffInserted: - return opts.FormatValue(v.ValueY, visitedPointers{}) + return opts.FormatValue(v.ValueY, parentKind, ptrs) default: panic("invalid diff mode") } } + // Register slice element to support cycle detection. + if parentKind == reflect.Slice { + ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, true) + defer ptrs.Pop() + defer func() { out = wrapTrunkReferences(ptrRefs, out) }() + } + // Descend into the child value node. if v.TransformerName != "" { - out := opts.WithTypeMode(emitType).FormatDiff(v.Value) - out = textWrap{"Inverse(" + v.TransformerName + ", ", out, ")"} + out := opts.WithTypeMode(emitType).FormatDiff(v.Value, ptrs) + out = &textWrap{Prefix: "Inverse(" + v.TransformerName + ", ", Value: out, Suffix: ")"} return opts.FormatType(v.Type, out) } else { switch k := v.Type.Kind(); k { - case reflect.Struct, reflect.Array, reflect.Slice, reflect.Map: - return opts.FormatType(v.Type, opts.formatDiffList(v.Records, k)) + case reflect.Struct, reflect.Array, reflect.Slice: + out = opts.formatDiffList(v.Records, k, ptrs) + out = opts.FormatType(v.Type, out) + case reflect.Map: + // Register map to support cycle detection. + ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, false) + defer ptrs.Pop() + + out = opts.formatDiffList(v.Records, k, ptrs) + out = wrapTrunkReferences(ptrRefs, out) + out = opts.FormatType(v.Type, out) case reflect.Ptr: - return textWrap{"&", opts.FormatDiff(v.Value), ""} + // Register pointer to support cycle detection. + ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, false) + defer ptrs.Pop() + + out = opts.FormatDiff(v.Value, ptrs) + out = wrapTrunkReferences(ptrRefs, out) + out = &textWrap{Prefix: "&", Value: out} case reflect.Interface: - return opts.WithTypeMode(emitType).FormatDiff(v.Value) + out = opts.WithTypeMode(emitType).FormatDiff(v.Value, ptrs) default: panic(fmt.Sprintf("%v cannot have children", k)) } + return out } } -func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) textNode { +func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind, ptrs *pointerReferences) textNode { // Derive record name based on the data structure kind. var name string var formatKey func(reflect.Value) string @@ -154,7 +217,17 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) te case reflect.Map: name = "entry" opts = opts.WithTypeMode(elideType) - formatKey = formatMapKey + formatKey = func(v reflect.Value) string { return formatMapKey(v, false, ptrs) } + } + + maxLen := -1 + if opts.LimitVerbosity { + if opts.DiffMode == diffIdentical { + maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc... + } else { + maxLen = (1 << opts.verbosity()) << 1 // 2, 4, 8, 16, 32, 64, etc... + } + opts.VerbosityLevel-- } // Handle unification. @@ -163,16 +236,21 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) te var list textList var deferredEllipsis bool // Add final "..." to indicate records were dropped for _, r := range recs { + if len(list) == maxLen { + deferredEllipsis = true + break + } + // Elide struct fields that are zero value. if k == reflect.Struct { var isZero bool switch opts.DiffMode { case diffIdentical: - isZero = value.IsZero(r.Value.ValueX) || value.IsZero(r.Value.ValueY) + isZero = r.Value.ValueX.IsZero() || r.Value.ValueY.IsZero() case diffRemoved: - isZero = value.IsZero(r.Value.ValueX) + isZero = r.Value.ValueX.IsZero() case diffInserted: - isZero = value.IsZero(r.Value.ValueY) + isZero = r.Value.ValueY.IsZero() } if isZero { continue @@ -186,23 +264,31 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) te } continue } - if out := opts.FormatDiff(r.Value); out != nil { + if out := opts.FormatDiff(r.Value, ptrs); out != nil { list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) } } if deferredEllipsis { list.AppendEllipsis(diffStats{}) } - return textWrap{"{", list, "}"} + return &textWrap{Prefix: "{", Value: list, Suffix: "}"} case diffUnknown: default: panic("invalid diff mode") } // Handle differencing. + var numDiffs int var list textList + var keys []reflect.Value // invariant: len(list) == len(keys) groups := coalesceAdjacentRecords(name, recs) + maxGroup := diffStats{Name: name} for i, ds := range groups { + if maxLen >= 0 && numDiffs >= maxLen { + maxGroup = maxGroup.Append(ds) + continue + } + // Handle equal records. if ds.NumDiff() == 0 { // Compute the number of leading and trailing records to print. @@ -226,16 +312,21 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) te // Format the equal values. for _, r := range recs[:numLo] { - out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value) + out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value, ptrs) list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) + keys = append(keys, r.Key) } if numEqual > numLo+numHi { ds.NumIdentical -= numLo + numHi list.AppendEllipsis(ds) + for len(keys) < len(list) { + keys = append(keys, reflect.Value{}) + } } for _, r := range recs[numEqual-numHi : numEqual] { - out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value) + out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value, ptrs) list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) + keys = append(keys, r.Key) } recs = recs[numEqual:] continue @@ -247,24 +338,70 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) te case opts.CanFormatDiffSlice(r.Value): out := opts.FormatDiffSlice(r.Value) list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) + keys = append(keys, r.Key) case r.Value.NumChildren == r.Value.MaxDepth: - outx := opts.WithDiffMode(diffRemoved).FormatDiff(r.Value) - outy := opts.WithDiffMode(diffInserted).FormatDiff(r.Value) + outx := opts.WithDiffMode(diffRemoved).FormatDiff(r.Value, ptrs) + outy := opts.WithDiffMode(diffInserted).FormatDiff(r.Value, ptrs) + for i := 0; i <= maxVerbosityPreset && outx != nil && outy != nil && outx.Equal(outy); i++ { + opts2 := verbosityPreset(opts, i) + outx = opts2.WithDiffMode(diffRemoved).FormatDiff(r.Value, ptrs) + outy = opts2.WithDiffMode(diffInserted).FormatDiff(r.Value, ptrs) + } if outx != nil { list = append(list, textRecord{Diff: diffRemoved, Key: formatKey(r.Key), Value: outx}) + keys = append(keys, r.Key) } if outy != nil { list = append(list, textRecord{Diff: diffInserted, Key: formatKey(r.Key), Value: outy}) + keys = append(keys, r.Key) } default: - out := opts.FormatDiff(r.Value) + out := opts.FormatDiff(r.Value, ptrs) list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) + keys = append(keys, r.Key) } } recs = recs[ds.NumDiff():] + numDiffs += ds.NumDiff() + } + if maxGroup.IsZero() { + assert(len(recs) == 0) + } else { + list.AppendEllipsis(maxGroup) + for len(keys) < len(list) { + keys = append(keys, reflect.Value{}) + } } - assert(len(recs) == 0) - return textWrap{"{", list, "}"} + assert(len(list) == len(keys)) + + // For maps, the default formatting logic uses fmt.Stringer which may + // produce ambiguous output. Avoid calling String to disambiguate. + if k == reflect.Map { + var ambiguous bool + seenKeys := map[string]reflect.Value{} + for i, currKey := range keys { + if currKey.IsValid() { + strKey := list[i].Key + prevKey, seen := seenKeys[strKey] + if seen && prevKey.CanInterface() && currKey.CanInterface() { + ambiguous = prevKey.Interface() != currKey.Interface() + if ambiguous { + break + } + } + seenKeys[strKey] = currKey + } + } + if ambiguous { + for i, k := range keys { + if k.IsValid() { + list[i].Key = formatMapKey(k, true, ptrs) + } + } + } + } + + return &textWrap{Prefix: "{", Value: list, Suffix: "}"} } // coalesceAdjacentRecords coalesces the list of records into groups of diff --git a/vendor/github.com/google/go-cmp/cmp/report_references.go b/vendor/github.com/google/go-cmp/cmp/report_references.go new file mode 100644 index 000000000..be31b33a9 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/report_references.go @@ -0,0 +1,264 @@ +// Copyright 2020, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cmp + +import ( + "fmt" + "reflect" + "strings" + + "github.com/google/go-cmp/cmp/internal/flags" + "github.com/google/go-cmp/cmp/internal/value" +) + +const ( + pointerDelimPrefix = "⟪" + pointerDelimSuffix = "⟫" +) + +// formatPointer prints the address of the pointer. +func formatPointer(p value.Pointer, withDelims bool) string { + v := p.Uintptr() + if flags.Deterministic { + v = 0xdeadf00f // Only used for stable testing purposes + } + if withDelims { + return pointerDelimPrefix + formatHex(uint64(v)) + pointerDelimSuffix + } + return formatHex(uint64(v)) +} + +// pointerReferences is a stack of pointers visited so far. +type pointerReferences [][2]value.Pointer + +func (ps *pointerReferences) PushPair(vx, vy reflect.Value, d diffMode, deref bool) (pp [2]value.Pointer) { + if deref && vx.IsValid() { + vx = vx.Addr() + } + if deref && vy.IsValid() { + vy = vy.Addr() + } + switch d { + case diffUnknown, diffIdentical: + pp = [2]value.Pointer{value.PointerOf(vx), value.PointerOf(vy)} + case diffRemoved: + pp = [2]value.Pointer{value.PointerOf(vx), value.Pointer{}} + case diffInserted: + pp = [2]value.Pointer{value.Pointer{}, value.PointerOf(vy)} + } + *ps = append(*ps, pp) + return pp +} + +func (ps *pointerReferences) Push(v reflect.Value) (p value.Pointer, seen bool) { + p = value.PointerOf(v) + for _, pp := range *ps { + if p == pp[0] || p == pp[1] { + return p, true + } + } + *ps = append(*ps, [2]value.Pointer{p, p}) + return p, false +} + +func (ps *pointerReferences) Pop() { + *ps = (*ps)[:len(*ps)-1] +} + +// trunkReferences is metadata for a textNode indicating that the sub-tree +// represents the value for either pointer in a pair of references. +type trunkReferences struct{ pp [2]value.Pointer } + +// trunkReference is metadata for a textNode indicating that the sub-tree +// represents the value for the given pointer reference. +type trunkReference struct{ p value.Pointer } + +// leafReference is metadata for a textNode indicating that the value is +// truncated as it refers to another part of the tree (i.e., a trunk). +type leafReference struct{ p value.Pointer } + +func wrapTrunkReferences(pp [2]value.Pointer, s textNode) textNode { + switch { + case pp[0].IsNil(): + return &textWrap{Value: s, Metadata: trunkReference{pp[1]}} + case pp[1].IsNil(): + return &textWrap{Value: s, Metadata: trunkReference{pp[0]}} + case pp[0] == pp[1]: + return &textWrap{Value: s, Metadata: trunkReference{pp[0]}} + default: + return &textWrap{Value: s, Metadata: trunkReferences{pp}} + } +} +func wrapTrunkReference(p value.Pointer, printAddress bool, s textNode) textNode { + var prefix string + if printAddress { + prefix = formatPointer(p, true) + } + return &textWrap{Prefix: prefix, Value: s, Metadata: trunkReference{p}} +} +func makeLeafReference(p value.Pointer, printAddress bool) textNode { + out := &textWrap{Prefix: "(", Value: textEllipsis, Suffix: ")"} + var prefix string + if printAddress { + prefix = formatPointer(p, true) + } + return &textWrap{Prefix: prefix, Value: out, Metadata: leafReference{p}} +} + +// resolveReferences walks the textNode tree searching for any leaf reference +// metadata and resolves each against the corresponding trunk references. +// Since pointer addresses in memory are not particularly readable to the user, +// it replaces each pointer value with an arbitrary and unique reference ID. +func resolveReferences(s textNode) { + var walkNodes func(textNode, func(textNode)) + walkNodes = func(s textNode, f func(textNode)) { + f(s) + switch s := s.(type) { + case *textWrap: + walkNodes(s.Value, f) + case textList: + for _, r := range s { + walkNodes(r.Value, f) + } + } + } + + // Collect all trunks and leaves with reference metadata. + var trunks, leaves []*textWrap + walkNodes(s, func(s textNode) { + if s, ok := s.(*textWrap); ok { + switch s.Metadata.(type) { + case leafReference: + leaves = append(leaves, s) + case trunkReference, trunkReferences: + trunks = append(trunks, s) + } + } + }) + + // No leaf references to resolve. + if len(leaves) == 0 { + return + } + + // Collect the set of all leaf references to resolve. + leafPtrs := make(map[value.Pointer]bool) + for _, leaf := range leaves { + leafPtrs[leaf.Metadata.(leafReference).p] = true + } + + // Collect the set of trunk pointers that are always paired together. + // This allows us to assign a single ID to both pointers for brevity. + // If a pointer in a pair ever occurs by itself or as a different pair, + // then the pair is broken. + pairedTrunkPtrs := make(map[value.Pointer]value.Pointer) + unpair := func(p value.Pointer) { + if !pairedTrunkPtrs[p].IsNil() { + pairedTrunkPtrs[pairedTrunkPtrs[p]] = value.Pointer{} // invalidate other half + } + pairedTrunkPtrs[p] = value.Pointer{} // invalidate this half + } + for _, trunk := range trunks { + switch p := trunk.Metadata.(type) { + case trunkReference: + unpair(p.p) // standalone pointer cannot be part of a pair + case trunkReferences: + p0, ok0 := pairedTrunkPtrs[p.pp[0]] + p1, ok1 := pairedTrunkPtrs[p.pp[1]] + switch { + case !ok0 && !ok1: + // Register the newly seen pair. + pairedTrunkPtrs[p.pp[0]] = p.pp[1] + pairedTrunkPtrs[p.pp[1]] = p.pp[0] + case ok0 && ok1 && p0 == p.pp[1] && p1 == p.pp[0]: + // Exact pair already seen; do nothing. + default: + // Pair conflicts with some other pair; break all pairs. + unpair(p.pp[0]) + unpair(p.pp[1]) + } + } + } + + // Correlate each pointer referenced by leaves to a unique identifier, + // and print the IDs for each trunk that matches those pointers. + var nextID uint + ptrIDs := make(map[value.Pointer]uint) + newID := func() uint { + id := nextID + nextID++ + return id + } + for _, trunk := range trunks { + switch p := trunk.Metadata.(type) { + case trunkReference: + if print := leafPtrs[p.p]; print { + id, ok := ptrIDs[p.p] + if !ok { + id = newID() + ptrIDs[p.p] = id + } + trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id)) + } + case trunkReferences: + print0 := leafPtrs[p.pp[0]] + print1 := leafPtrs[p.pp[1]] + if print0 || print1 { + id0, ok0 := ptrIDs[p.pp[0]] + id1, ok1 := ptrIDs[p.pp[1]] + isPair := pairedTrunkPtrs[p.pp[0]] == p.pp[1] && pairedTrunkPtrs[p.pp[1]] == p.pp[0] + if isPair { + var id uint + assert(ok0 == ok1) // must be seen together or not at all + if ok0 { + assert(id0 == id1) // must have the same ID + id = id0 + } else { + id = newID() + ptrIDs[p.pp[0]] = id + ptrIDs[p.pp[1]] = id + } + trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id)) + } else { + if print0 && !ok0 { + id0 = newID() + ptrIDs[p.pp[0]] = id0 + } + if print1 && !ok1 { + id1 = newID() + ptrIDs[p.pp[1]] = id1 + } + switch { + case print0 && print1: + trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id0)+","+formatReference(id1)) + case print0: + trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id0)) + case print1: + trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id1)) + } + } + } + } + } + + // Update all leaf references with the unique identifier. + for _, leaf := range leaves { + if id, ok := ptrIDs[leaf.Metadata.(leafReference).p]; ok { + leaf.Prefix = updateReferencePrefix(leaf.Prefix, formatReference(id)) + } + } +} + +func formatReference(id uint) string { + return fmt.Sprintf("ref#%d", id) +} + +func updateReferencePrefix(prefix, ref string) string { + if prefix == "" { + return pointerDelimPrefix + ref + pointerDelimSuffix + } + suffix := strings.TrimPrefix(prefix, pointerDelimPrefix) + return pointerDelimPrefix + ref + ": " + suffix +} diff --git a/vendor/github.com/google/go-cmp/cmp/report_reflect.go b/vendor/github.com/google/go-cmp/cmp/report_reflect.go index 2761b6289..2ab41fad3 100644 --- a/vendor/github.com/google/go-cmp/cmp/report_reflect.go +++ b/vendor/github.com/google/go-cmp/cmp/report_reflect.go @@ -1,33 +1,49 @@ // Copyright 2019, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. package cmp import ( + "bytes" "fmt" "reflect" "strconv" "strings" "unicode" + "unicode/utf8" - "github.com/google/go-cmp/cmp/internal/flags" "github.com/google/go-cmp/cmp/internal/value" ) +var ( + anyType = reflect.TypeOf((*interface{})(nil)).Elem() + stringType = reflect.TypeOf((*string)(nil)).Elem() + bytesType = reflect.TypeOf((*[]byte)(nil)).Elem() + byteType = reflect.TypeOf((*byte)(nil)).Elem() +) + type formatValueOptions struct { // AvoidStringer controls whether to avoid calling custom stringer // methods like error.Error or fmt.Stringer.String. AvoidStringer bool - // ShallowPointers controls whether to avoid descending into pointers. - // Useful when printing map keys, where pointer comparison is performed - // on the pointer address rather than the pointed-at value. - ShallowPointers bool - // PrintAddresses controls whether to print the address of all pointers, // slice elements, and maps. PrintAddresses bool + + // QualifiedNames controls whether FormatType uses the fully qualified name + // (including the full package path as opposed to just the package name). + QualifiedNames bool + + // VerbosityLevel controls the amount of output to produce. + // A higher value produces more output. A value of zero or lower produces + // no output (represented using an ellipsis). + // If LimitVerbosity is false, then the level is treated as infinite. + VerbosityLevel int + + // LimitVerbosity specifies that formatting should respect VerbosityLevel. + LimitVerbosity bool } // FormatType prints the type as if it were wrapping s. @@ -44,12 +60,15 @@ func (opts formatOptions) FormatType(t reflect.Type, s textNode) textNode { default: return s } + if opts.DiffMode == diffIdentical { + return s // elide type for identical nodes + } case elideType: return s } // Determine the type label, applying special handling for unnamed types. - typeName := t.String() + typeName := value.TypeString(t, opts.QualifiedNames) if t.Name() == "" { // According to Go grammar, certain type literals contain symbols that // do not strongly bind to the next lexicographical token (e.g., *T). @@ -57,39 +76,77 @@ func (opts formatOptions) FormatType(t reflect.Type, s textNode) textNode { case reflect.Chan, reflect.Func, reflect.Ptr: typeName = "(" + typeName + ")" } - typeName = strings.Replace(typeName, "struct {", "struct{", -1) - typeName = strings.Replace(typeName, "interface {", "interface{", -1) } + return &textWrap{Prefix: typeName, Value: wrapParens(s)} +} + +// wrapParens wraps s with a set of parenthesis, but avoids it if the +// wrapped node itself is already surrounded by a pair of parenthesis or braces. +// It handles unwrapping one level of pointer-reference nodes. +func wrapParens(s textNode) textNode { + var refNode *textWrap + if s2, ok := s.(*textWrap); ok { + // Unwrap a single pointer reference node. + switch s2.Metadata.(type) { + case leafReference, trunkReference, trunkReferences: + refNode = s2 + if s3, ok := refNode.Value.(*textWrap); ok { + s2 = s3 + } + } - // Avoid wrap the value in parenthesis if unnecessary. - if s, ok := s.(textWrap); ok { - hasParens := strings.HasPrefix(s.Prefix, "(") && strings.HasSuffix(s.Suffix, ")") - hasBraces := strings.HasPrefix(s.Prefix, "{") && strings.HasSuffix(s.Suffix, "}") + // Already has delimiters that make parenthesis unnecessary. + hasParens := strings.HasPrefix(s2.Prefix, "(") && strings.HasSuffix(s2.Suffix, ")") + hasBraces := strings.HasPrefix(s2.Prefix, "{") && strings.HasSuffix(s2.Suffix, "}") if hasParens || hasBraces { - return textWrap{typeName, s, ""} + return s } } - return textWrap{typeName + "(", s, ")"} + if refNode != nil { + refNode.Value = &textWrap{Prefix: "(", Value: refNode.Value, Suffix: ")"} + return s + } + return &textWrap{Prefix: "(", Value: s, Suffix: ")"} } // FormatValue prints the reflect.Value, taking extra care to avoid descending -// into pointers already in m. As pointers are visited, m is also updated. -func (opts formatOptions) FormatValue(v reflect.Value, m visitedPointers) (out textNode) { +// into pointers already in ptrs. As pointers are visited, ptrs is also updated. +func (opts formatOptions) FormatValue(v reflect.Value, parentKind reflect.Kind, ptrs *pointerReferences) (out textNode) { if !v.IsValid() { return nil } t := v.Type() + // Check slice element for cycles. + if parentKind == reflect.Slice { + ptrRef, visited := ptrs.Push(v.Addr()) + if visited { + return makeLeafReference(ptrRef, false) + } + defer ptrs.Pop() + defer func() { out = wrapTrunkReference(ptrRef, false, out) }() + } + // Check whether there is an Error or String method to call. if !opts.AvoidStringer && v.CanInterface() { // Avoid calling Error or String methods on nil receivers since many // implementations crash when doing so. if (t.Kind() != reflect.Ptr && t.Kind() != reflect.Interface) || !v.IsNil() { - switch v := v.Interface().(type) { - case error: - return textLine("e" + formatString(v.Error())) - case fmt.Stringer: - return textLine("s" + formatString(v.String())) + var prefix, strVal string + func() { + // Swallow and ignore any panics from String or Error. + defer func() { recover() }() + switch v := v.Interface().(type) { + case error: + strVal = v.Error() + prefix = "e" + case fmt.Stringer: + strVal = v.String() + prefix = "s" + } + }() + if prefix != "" { + return opts.formatString(prefix, strVal) } } } @@ -102,114 +159,213 @@ func (opts formatOptions) FormatValue(v reflect.Value, m visitedPointers) (out t } }() - var ptr string switch t.Kind() { case reflect.Bool: return textLine(fmt.Sprint(v.Bool())) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return textLine(fmt.Sprint(v.Int())) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - // Unnamed uints are usually bytes or words, so use hexadecimal. - if t.PkgPath() == "" || t.Kind() == reflect.Uintptr { + case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return textLine(fmt.Sprint(v.Uint())) + case reflect.Uint8: + if parentKind == reflect.Slice || parentKind == reflect.Array { return textLine(formatHex(v.Uint())) } return textLine(fmt.Sprint(v.Uint())) + case reflect.Uintptr: + return textLine(formatHex(v.Uint())) case reflect.Float32, reflect.Float64: return textLine(fmt.Sprint(v.Float())) case reflect.Complex64, reflect.Complex128: return textLine(fmt.Sprint(v.Complex())) case reflect.String: - return textLine(formatString(v.String())) + return opts.formatString("", v.String()) case reflect.UnsafePointer, reflect.Chan, reflect.Func: - return textLine(formatPointer(v)) + return textLine(formatPointer(value.PointerOf(v), true)) case reflect.Struct: var list textList + v := makeAddressable(v) // needed for retrieveUnexportedField + maxLen := v.NumField() + if opts.LimitVerbosity { + maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc... + opts.VerbosityLevel-- + } for i := 0; i < v.NumField(); i++ { vv := v.Field(i) - if value.IsZero(vv) { + if vv.IsZero() { continue // Elide fields with zero values } - s := opts.WithTypeMode(autoType).FormatValue(vv, m) - list = append(list, textRecord{Key: t.Field(i).Name, Value: s}) + if len(list) == maxLen { + list.AppendEllipsis(diffStats{}) + break + } + sf := t.Field(i) + if supportExporters && !isExported(sf.Name) { + vv = retrieveUnexportedField(v, sf, true) + } + s := opts.WithTypeMode(autoType).FormatValue(vv, t.Kind(), ptrs) + list = append(list, textRecord{Key: sf.Name, Value: s}) } - return textWrap{"{", list, "}"} + return &textWrap{Prefix: "{", Value: list, Suffix: "}"} case reflect.Slice: if v.IsNil() { return textNil } - if opts.PrintAddresses { - ptr = formatPointer(v) + + // Check whether this is a []byte of text data. + if t.Elem() == byteType { + b := v.Bytes() + isPrintSpace := func(r rune) bool { return unicode.IsPrint(r) || unicode.IsSpace(r) } + if len(b) > 0 && utf8.Valid(b) && len(bytes.TrimFunc(b, isPrintSpace)) == 0 { + out = opts.formatString("", string(b)) + skipType = true + return opts.FormatType(t, out) + } } + fallthrough case reflect.Array: + maxLen := v.Len() + if opts.LimitVerbosity { + maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc... + opts.VerbosityLevel-- + } var list textList for i := 0; i < v.Len(); i++ { - vi := v.Index(i) - if vi.CanAddr() { // Check for cyclic elements - p := vi.Addr() - if m.Visit(p) { - var out textNode - out = textLine(formatPointer(p)) - out = opts.WithTypeMode(emitType).FormatType(p.Type(), out) - out = textWrap{"*", out, ""} - list = append(list, textRecord{Value: out}) - continue - } + if len(list) == maxLen { + list.AppendEllipsis(diffStats{}) + break } - s := opts.WithTypeMode(elideType).FormatValue(vi, m) + s := opts.WithTypeMode(elideType).FormatValue(v.Index(i), t.Kind(), ptrs) list = append(list, textRecord{Value: s}) } - return textWrap{ptr + "{", list, "}"} + + out = &textWrap{Prefix: "{", Value: list, Suffix: "}"} + if t.Kind() == reflect.Slice && opts.PrintAddresses { + header := fmt.Sprintf("ptr:%v, len:%d, cap:%d", formatPointer(value.PointerOf(v), false), v.Len(), v.Cap()) + out = &textWrap{Prefix: pointerDelimPrefix + header + pointerDelimSuffix, Value: out} + } + return out case reflect.Map: if v.IsNil() { return textNil } - if m.Visit(v) { - return textLine(formatPointer(v)) + + // Check pointer for cycles. + ptrRef, visited := ptrs.Push(v) + if visited { + return makeLeafReference(ptrRef, opts.PrintAddresses) } + defer ptrs.Pop() + maxLen := v.Len() + if opts.LimitVerbosity { + maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc... + opts.VerbosityLevel-- + } var list textList for _, k := range value.SortKeys(v.MapKeys()) { - sk := formatMapKey(k) - sv := opts.WithTypeMode(elideType).FormatValue(v.MapIndex(k), m) + if len(list) == maxLen { + list.AppendEllipsis(diffStats{}) + break + } + sk := formatMapKey(k, false, ptrs) + sv := opts.WithTypeMode(elideType).FormatValue(v.MapIndex(k), t.Kind(), ptrs) list = append(list, textRecord{Key: sk, Value: sv}) } - if opts.PrintAddresses { - ptr = formatPointer(v) - } - return textWrap{ptr + "{", list, "}"} + + out = &textWrap{Prefix: "{", Value: list, Suffix: "}"} + out = wrapTrunkReference(ptrRef, opts.PrintAddresses, out) + return out case reflect.Ptr: if v.IsNil() { return textNil } - if m.Visit(v) || opts.ShallowPointers { - return textLine(formatPointer(v)) + + // Check pointer for cycles. + ptrRef, visited := ptrs.Push(v) + if visited { + out = makeLeafReference(ptrRef, opts.PrintAddresses) + return &textWrap{Prefix: "&", Value: out} } - if opts.PrintAddresses { - ptr = formatPointer(v) + defer ptrs.Pop() + + // Skip the name only if this is an unnamed pointer type. + // Otherwise taking the address of a value does not reproduce + // the named pointer type. + if v.Type().Name() == "" { + skipType = true // Let the underlying value print the type instead } - skipType = true // Let the underlying value print the type instead - return textWrap{"&" + ptr, opts.FormatValue(v.Elem(), m), ""} + out = opts.FormatValue(v.Elem(), t.Kind(), ptrs) + out = wrapTrunkReference(ptrRef, opts.PrintAddresses, out) + out = &textWrap{Prefix: "&", Value: out} + return out case reflect.Interface: if v.IsNil() { return textNil } // Interfaces accept different concrete types, // so configure the underlying value to explicitly print the type. - skipType = true // Print the concrete type instead - return opts.WithTypeMode(emitType).FormatValue(v.Elem(), m) + return opts.WithTypeMode(emitType).FormatValue(v.Elem(), t.Kind(), ptrs) default: panic(fmt.Sprintf("%v kind not handled", v.Kind())) } } +func (opts formatOptions) formatString(prefix, s string) textNode { + maxLen := len(s) + maxLines := strings.Count(s, "\n") + 1 + if opts.LimitVerbosity { + maxLen = (1 << opts.verbosity()) << 5 // 32, 64, 128, 256, etc... + maxLines = (1 << opts.verbosity()) << 2 // 4, 8, 16, 32, 64, etc... + } + + // For multiline strings, use the triple-quote syntax, + // but only use it when printing removed or inserted nodes since + // we only want the extra verbosity for those cases. + lines := strings.Split(strings.TrimSuffix(s, "\n"), "\n") + isTripleQuoted := len(lines) >= 4 && (opts.DiffMode == '-' || opts.DiffMode == '+') + for i := 0; i < len(lines) && isTripleQuoted; i++ { + lines[i] = strings.TrimPrefix(strings.TrimSuffix(lines[i], "\r"), "\r") // trim leading/trailing carriage returns for legacy Windows endline support + isPrintable := func(r rune) bool { + return unicode.IsPrint(r) || r == '\t' // specially treat tab as printable + } + line := lines[i] + isTripleQuoted = !strings.HasPrefix(strings.TrimPrefix(line, prefix), `"""`) && !strings.HasPrefix(line, "...") && strings.TrimFunc(line, isPrintable) == "" && len(line) <= maxLen + } + if isTripleQuoted { + var list textList + list = append(list, textRecord{Diff: opts.DiffMode, Value: textLine(prefix + `"""`), ElideComma: true}) + for i, line := range lines { + if numElided := len(lines) - i; i == maxLines-1 && numElided > 1 { + comment := commentString(fmt.Sprintf("%d elided lines", numElided)) + list = append(list, textRecord{Diff: opts.DiffMode, Value: textEllipsis, ElideComma: true, Comment: comment}) + break + } + list = append(list, textRecord{Diff: opts.DiffMode, Value: textLine(line), ElideComma: true}) + } + list = append(list, textRecord{Diff: opts.DiffMode, Value: textLine(prefix + `"""`), ElideComma: true}) + return &textWrap{Prefix: "(", Value: list, Suffix: ")"} + } + + // Format the string as a single-line quoted string. + if len(s) > maxLen+len(textEllipsis) { + return textLine(prefix + formatString(s[:maxLen]) + string(textEllipsis)) + } + return textLine(prefix + formatString(s)) +} + // formatMapKey formats v as if it were a map key. // The result is guaranteed to be a single line. -func formatMapKey(v reflect.Value) string { +func formatMapKey(v reflect.Value, disambiguate bool, ptrs *pointerReferences) string { var opts formatOptions + opts.DiffMode = diffIdentical opts.TypeMode = elideType - opts.ShallowPointers = true - s := opts.FormatValue(v, visitedPointers{}).String() + opts.PrintAddresses = disambiguate + opts.AvoidStringer = disambiguate + opts.QualifiedNames = disambiguate + opts.VerbosityLevel = maxVerbosityPreset + opts.LimitVerbosity = true + s := opts.FormatValue(v, reflect.Map, ptrs).String() return strings.TrimSpace(s) } @@ -227,7 +383,7 @@ func formatString(s string) string { rawInvalid := func(r rune) bool { return r == '`' || r == '\n' || !(unicode.IsPrint(r) || r == '\t') } - if strings.IndexFunc(s, rawInvalid) < 0 { + if utf8.ValidString(s) && strings.IndexFunc(s, rawInvalid) < 0 { return "`" + s + "`" } return qs @@ -256,23 +412,3 @@ func formatHex(u uint64) string { } return fmt.Sprintf(f, u) } - -// formatPointer prints the address of the pointer. -func formatPointer(v reflect.Value) string { - p := v.Pointer() - if flags.Deterministic { - p = 0xdeadf00f // Only used for stable testing purposes - } - return fmt.Sprintf("⟪0x%x⟫", p) -} - -type visitedPointers map[value.Pointer]struct{} - -// Visit inserts pointer v into the visited map and reports whether it had -// already been visited before. -func (m visitedPointers) Visit(v reflect.Value) bool { - p := value.PointerOf(v) - _, visited := m[p] - m[p] = struct{}{} - return visited -} diff --git a/vendor/github.com/google/go-cmp/cmp/report_slices.go b/vendor/github.com/google/go-cmp/cmp/report_slices.go index eafcf2e4c..23e444f62 100644 --- a/vendor/github.com/google/go-cmp/cmp/report_slices.go +++ b/vendor/github.com/google/go-cmp/cmp/report_slices.go @@ -1,13 +1,15 @@ // Copyright 2019, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. package cmp import ( "bytes" "fmt" + "math" "reflect" + "strconv" "strings" "unicode" "unicode/utf8" @@ -23,14 +25,35 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { return false // Must be formatting in diff mode case v.NumDiff == 0: return false // No differences detected - case v.NumIgnored+v.NumCompared+v.NumTransformed > 0: - // TODO: Handle the case where someone uses bytes.Equal on a large slice. - return false // Some custom option was used to determined equality case !v.ValueX.IsValid() || !v.ValueY.IsValid(): return false // Both values must be valid + case v.NumIgnored > 0: + return false // Some ignore option was used + case v.NumTransformed > 0: + return false // Some transform option was used + case v.NumCompared > 1: + return false // More than one comparison was used + case v.NumCompared == 1 && v.Type.Name() != "": + // The need for cmp to check applicability of options on every element + // in a slice is a significant performance detriment for large []byte. + // The workaround is to specify Comparer(bytes.Equal), + // which enables cmp to compare []byte more efficiently. + // If they differ, we still want to provide batched diffing. + // The logic disallows named types since they tend to have their own + // String method, with nicer formatting than what this provides. + return false + } + + // Check whether this is an interface with the same concrete types. + t := v.Type + vx, vy := v.ValueX, v.ValueY + if t.Kind() == reflect.Interface && !vx.IsNil() && !vy.IsNil() && vx.Elem().Type() == vy.Elem().Type() { + vx, vy = vx.Elem(), vy.Elem() + t = vx.Type() } - switch t := v.Type; t.Kind() { + // Check whether we provide specialized diffing for this type. + switch t.Kind() { case reflect.String: case reflect.Array, reflect.Slice: // Only slices of primitive types have specialized handling. @@ -42,6 +65,11 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { return false } + // Both slice values have to be non-empty. + if t.Kind() == reflect.Slice && (vx.Len() == 0 || vy.Len() == 0) { + return false + } + // If a sufficient number of elements already differ, // use specialized formatting even if length requirement is not met. if v.NumDiff > v.NumSame { @@ -52,8 +80,8 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { } // Use specialized string diffing for longer slices or strings. - const minLength = 64 - return v.ValueX.Len() >= minLength && v.ValueY.Len() >= minLength + const minLength = 32 + return vx.Len() >= minLength && vy.Len() >= minLength } // FormatDiffSlice prints a diff for the slices (or strings) represented by v. @@ -62,17 +90,23 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { assert(opts.DiffMode == diffUnknown) t, vx, vy := v.Type, v.ValueX, v.ValueY + if t.Kind() == reflect.Interface { + vx, vy = vx.Elem(), vy.Elem() + t = vx.Type() + opts = opts.WithTypeMode(emitType) + } // Auto-detect the type of the data. - var isLinedText, isText, isBinary bool var sx, sy string + var ssx, ssy []string + var isString, isMostlyText, isPureLinedText, isBinary bool switch { case t.Kind() == reflect.String: sx, sy = vx.String(), vy.String() - isText = true // Initial estimate, verify later - case t.Kind() == reflect.Slice && t.Elem() == reflect.TypeOf(byte(0)): + isString = true + case t.Kind() == reflect.Slice && t.Elem() == byteType: sx, sy = string(vx.Bytes()), string(vy.Bytes()) - isBinary = true // Initial estimate, verify later + isString = true case t.Kind() == reflect.Array: // Arrays need to be addressable for slice operations to work. vx2, vy2 := reflect.New(t).Elem(), reflect.New(t).Elem() @@ -80,13 +114,12 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { vy2.Set(vy) vx, vy = vx2, vy2 } - if isText || isBinary { - var numLines, lastLineIdx, maxLineLen int - isBinary = false + if isString { + var numTotalRunes, numValidRunes, numLines, lastLineIdx, maxLineLen int for i, r := range sx + sy { - if !(unicode.IsPrint(r) || unicode.IsSpace(r)) || r == utf8.RuneError { - isBinary = true - break + numTotalRunes++ + if (unicode.IsPrint(r) || unicode.IsSpace(r)) && r != utf8.RuneError { + numValidRunes++ } if r == '\n' { if maxLineLen < i-lastLineIdx { @@ -96,8 +129,29 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { numLines++ } } - isText = !isBinary - isLinedText = isText && numLines >= 4 && maxLineLen <= 256 + isPureText := numValidRunes == numTotalRunes + isMostlyText = float64(numValidRunes) > math.Floor(0.90*float64(numTotalRunes)) + isPureLinedText = isPureText && numLines >= 4 && maxLineLen <= 1024 + isBinary = !isMostlyText + + // Avoid diffing by lines if it produces a significantly more complex + // edit script than diffing by bytes. + if isPureLinedText { + ssx = strings.Split(sx, "\n") + ssy = strings.Split(sy, "\n") + esLines := diff.Difference(len(ssx), len(ssy), func(ix, iy int) diff.Result { + return diff.BoolResult(ssx[ix] == ssy[iy]) + }) + esBytes := diff.Difference(len(sx), len(sy), func(ix, iy int) diff.Result { + return diff.BoolResult(sx[ix] == sy[iy]) + }) + efficiencyLines := float64(esLines.Dist()) / float64(len(esLines)) + efficiencyBytes := float64(esBytes.Dist()) / float64(len(esBytes)) + quotedLength := len(strconv.Quote(sx + sy)) + unquotedLength := len(sx) + len(sy) + escapeExpansionRatio := float64(quotedLength) / float64(unquotedLength) + isPureLinedText = efficiencyLines < 4*efficiencyBytes || escapeExpansionRatio > 1.1 + } } // Format the string into printable records. @@ -106,9 +160,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { switch { // If the text appears to be multi-lined text, // then perform differencing across individual lines. - case isLinedText: - ssx := strings.Split(sx, "\n") - ssy := strings.Split(sy, "\n") + case isPureLinedText: list = opts.formatDiffSlice( reflect.ValueOf(ssx), reflect.ValueOf(ssy), 1, "line", func(v reflect.Value, d diffMode) textRecord { @@ -117,10 +169,88 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { }, ) delim = "\n" + + // If possible, use a custom triple-quote (""") syntax for printing + // differences in a string literal. This format is more readable, + // but has edge-cases where differences are visually indistinguishable. + // This format is avoided under the following conditions: + // - A line starts with `"""` + // - A line starts with "..." + // - A line contains non-printable characters + // - Adjacent different lines differ only by whitespace + // + // For example: + // + // """ + // ... // 3 identical lines + // foo + // bar + // - baz + // + BAZ + // """ + isTripleQuoted := true + prevRemoveLines := map[string]bool{} + prevInsertLines := map[string]bool{} + var list2 textList + list2 = append(list2, textRecord{Value: textLine(`"""`), ElideComma: true}) + for _, r := range list { + if !r.Value.Equal(textEllipsis) { + line, _ := strconv.Unquote(string(r.Value.(textLine))) + line = strings.TrimPrefix(strings.TrimSuffix(line, "\r"), "\r") // trim leading/trailing carriage returns for legacy Windows endline support + normLine := strings.Map(func(r rune) rune { + if unicode.IsSpace(r) { + return -1 // drop whitespace to avoid visually indistinguishable output + } + return r + }, line) + isPrintable := func(r rune) bool { + return unicode.IsPrint(r) || r == '\t' // specially treat tab as printable + } + isTripleQuoted = !strings.HasPrefix(line, `"""`) && !strings.HasPrefix(line, "...") && strings.TrimFunc(line, isPrintable) == "" + switch r.Diff { + case diffRemoved: + isTripleQuoted = isTripleQuoted && !prevInsertLines[normLine] + prevRemoveLines[normLine] = true + case diffInserted: + isTripleQuoted = isTripleQuoted && !prevRemoveLines[normLine] + prevInsertLines[normLine] = true + } + if !isTripleQuoted { + break + } + r.Value = textLine(line) + r.ElideComma = true + } + if !(r.Diff == diffRemoved || r.Diff == diffInserted) { // start a new non-adjacent difference group + prevRemoveLines = map[string]bool{} + prevInsertLines = map[string]bool{} + } + list2 = append(list2, r) + } + if r := list2[len(list2)-1]; r.Diff == diffIdentical && len(r.Value.(textLine)) == 0 { + list2 = list2[:len(list2)-1] // elide single empty line at the end + } + list2 = append(list2, textRecord{Value: textLine(`"""`), ElideComma: true}) + if isTripleQuoted { + var out textNode = &textWrap{Prefix: "(", Value: list2, Suffix: ")"} + switch t.Kind() { + case reflect.String: + if t != stringType { + out = opts.FormatType(t, out) + } + case reflect.Slice: + // Always emit type for slices since the triple-quote syntax + // looks like a string (not a slice). + opts = opts.WithTypeMode(emitType) + out = opts.FormatType(t, out) + } + return out + } + // If the text appears to be single-lined text, // then perform differencing in approximately fixed-sized chunks. // The output is printed as quoted strings. - case isText: + case isMostlyText: list = opts.formatDiffSlice( reflect.ValueOf(sx), reflect.ValueOf(sy), 64, "byte", func(v reflect.Value, d diffMode) textRecord { @@ -128,7 +258,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { return textRecord{Diff: d, Value: textLine(s)} }, ) - delim = "" + // If the text appears to be binary data, // then perform differencing in approximately fixed-sized chunks. // The output is inspired by hexdump. @@ -145,6 +275,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { return textRecord{Diff: d, Value: textLine(s), Comment: comment} }, ) + // For all other slices of primitive types, // then perform differencing in approximately fixed-sized chunks. // The size of each chunk depends on the width of the element kind. @@ -172,7 +303,9 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { switch t.Elem().Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: ss = append(ss, fmt.Sprint(v.Index(i).Int())) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64: + ss = append(ss, fmt.Sprint(v.Index(i).Uint())) + case reflect.Uint8, reflect.Uintptr: ss = append(ss, formatHex(v.Index(i).Uint())) case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: ss = append(ss, fmt.Sprint(v.Index(i).Interface())) @@ -185,8 +318,8 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { } // Wrap the output with appropriate type information. - var out textNode = textWrap{"{", list, "}"} - if !isText { + var out textNode = &textWrap{Prefix: "{", Value: list, Suffix: "}"} + if !isMostlyText { // The "{...}" byte-sequence literal is not valid Go syntax for strings. // Emit the type for extra clarity (e.g. "string{...}"). if t.Kind() == reflect.String { @@ -196,13 +329,13 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { } switch t.Kind() { case reflect.String: - out = textWrap{"strings.Join(", out, fmt.Sprintf(", %q)", delim)} - if t != reflect.TypeOf(string("")) { + out = &textWrap{Prefix: "strings.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)} + if t != stringType { out = opts.FormatType(t, out) } case reflect.Slice: - out = textWrap{"bytes.Join(", out, fmt.Sprintf(", %q)", delim)} - if t != reflect.TypeOf([]byte(nil)) { + out = &textWrap{Prefix: "bytes.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)} + if t != bytesType { out = opts.FormatType(t, out) } } @@ -225,8 +358,11 @@ func (opts formatOptions) formatDiffSlice( vx, vy reflect.Value, chunkSize int, name string, makeRec func(reflect.Value, diffMode) textRecord, ) (list textList) { - es := diff.Difference(vx.Len(), vy.Len(), func(ix int, iy int) diff.Result { - return diff.BoolResult(vx.Index(ix).Interface() == vy.Index(iy).Interface()) + eq := func(ix, iy int) bool { + return vx.Index(ix).Interface() == vy.Index(iy).Interface() + } + es := diff.Difference(vx.Len(), vy.Len(), func(ix, iy int) diff.Result { + return diff.BoolResult(eq(ix, iy)) }) appendChunks := func(v reflect.Value, d diffMode) int { @@ -242,9 +378,23 @@ func (opts formatOptions) formatDiffSlice( return n0 - v.Len() } + var numDiffs int + maxLen := -1 + if opts.LimitVerbosity { + maxLen = (1 << opts.verbosity()) << 2 // 4, 8, 16, 32, 64, etc... + opts.VerbosityLevel-- + } + groups := coalesceAdjacentEdits(name, es) groups = coalesceInterveningIdentical(groups, chunkSize/4) + groups = cleanupSurroundingIdentical(groups, eq) + maxGroup := diffStats{Name: name} for i, ds := range groups { + if maxLen >= 0 && numDiffs >= maxLen { + maxGroup = maxGroup.Append(ds) + continue + } + // Print equal. if ds.NumDiff() == 0 { // Compute the number of leading and trailing equal bytes to print. @@ -273,36 +423,52 @@ func (opts formatOptions) formatDiffSlice( } // Print unequal. + len0 := len(list) nx := appendChunks(vx.Slice(0, ds.NumIdentical+ds.NumRemoved+ds.NumModified), diffRemoved) vx = vx.Slice(nx, vx.Len()) ny := appendChunks(vy.Slice(0, ds.NumIdentical+ds.NumInserted+ds.NumModified), diffInserted) vy = vy.Slice(ny, vy.Len()) + numDiffs += len(list) - len0 + } + if maxGroup.IsZero() { + assert(vx.Len() == 0 && vy.Len() == 0) + } else { + list.AppendEllipsis(maxGroup) } - assert(vx.Len() == 0 && vy.Len() == 0) return list } // coalesceAdjacentEdits coalesces the list of edits into groups of adjacent // equal or unequal counts. +// +// Example: +// +// Input: "..XXY...Y" +// Output: [ +// {NumIdentical: 2}, +// {NumRemoved: 2, NumInserted 1}, +// {NumIdentical: 3}, +// {NumInserted: 1}, +// ] func coalesceAdjacentEdits(name string, es diff.EditScript) (groups []diffStats) { - var prevCase int // Arbitrary index into which case last occurred - lastStats := func(i int) *diffStats { - if prevCase != i { + var prevMode byte + lastStats := func(mode byte) *diffStats { + if prevMode != mode { groups = append(groups, diffStats{Name: name}) - prevCase = i + prevMode = mode } return &groups[len(groups)-1] } for _, e := range es { switch e { case diff.Identity: - lastStats(1).NumIdentical++ + lastStats('=').NumIdentical++ case diff.UniqueX: - lastStats(2).NumRemoved++ + lastStats('!').NumRemoved++ case diff.UniqueY: - lastStats(2).NumInserted++ + lastStats('!').NumInserted++ case diff.Modified: - lastStats(2).NumModified++ + lastStats('!').NumModified++ } } return groups @@ -312,6 +478,34 @@ func coalesceAdjacentEdits(name string, es diff.EditScript) (groups []diffStats) // equal groups into adjacent unequal groups that currently result in a // dual inserted/removed printout. This acts as a high-pass filter to smooth // out high-frequency changes within the windowSize. +// +// Example: +// +// WindowSize: 16, +// Input: [ +// {NumIdentical: 61}, // group 0 +// {NumRemoved: 3, NumInserted: 1}, // group 1 +// {NumIdentical: 6}, // ├── coalesce +// {NumInserted: 2}, // ├── coalesce +// {NumIdentical: 1}, // ├── coalesce +// {NumRemoved: 9}, // └── coalesce +// {NumIdentical: 64}, // group 2 +// {NumRemoved: 3, NumInserted: 1}, // group 3 +// {NumIdentical: 6}, // ├── coalesce +// {NumInserted: 2}, // ├── coalesce +// {NumIdentical: 1}, // ├── coalesce +// {NumRemoved: 7}, // ├── coalesce +// {NumIdentical: 1}, // ├── coalesce +// {NumRemoved: 2}, // └── coalesce +// {NumIdentical: 63}, // group 4 +// ] +// Output: [ +// {NumIdentical: 61}, +// {NumIdentical: 7, NumRemoved: 12, NumInserted: 3}, +// {NumIdentical: 64}, +// {NumIdentical: 8, NumRemoved: 12, NumInserted: 3}, +// {NumIdentical: 63}, +// ] func coalesceInterveningIdentical(groups []diffStats, windowSize int) []diffStats { groups, groupsOrig := groups[:0], groups for i, ds := range groupsOrig { @@ -331,3 +525,90 @@ func coalesceInterveningIdentical(groups []diffStats, windowSize int) []diffStat } return groups } + +// cleanupSurroundingIdentical scans through all unequal groups, and +// moves any leading sequence of equal elements to the preceding equal group and +// moves and trailing sequence of equal elements to the succeeding equal group. +// +// This is necessary since coalesceInterveningIdentical may coalesce edit groups +// together such that leading/trailing spans of equal elements becomes possible. +// Note that this can occur even with an optimal diffing algorithm. +// +// Example: +// +// Input: [ +// {NumIdentical: 61}, +// {NumIdentical: 1 , NumRemoved: 11, NumInserted: 2}, // assume 3 leading identical elements +// {NumIdentical: 67}, +// {NumIdentical: 7, NumRemoved: 12, NumInserted: 3}, // assume 10 trailing identical elements +// {NumIdentical: 54}, +// ] +// Output: [ +// {NumIdentical: 64}, // incremented by 3 +// {NumRemoved: 9}, +// {NumIdentical: 67}, +// {NumRemoved: 9}, +// {NumIdentical: 64}, // incremented by 10 +// ] +func cleanupSurroundingIdentical(groups []diffStats, eq func(i, j int) bool) []diffStats { + var ix, iy int // indexes into sequence x and y + for i, ds := range groups { + // Handle equal group. + if ds.NumDiff() == 0 { + ix += ds.NumIdentical + iy += ds.NumIdentical + continue + } + + // Handle unequal group. + nx := ds.NumIdentical + ds.NumRemoved + ds.NumModified + ny := ds.NumIdentical + ds.NumInserted + ds.NumModified + var numLeadingIdentical, numTrailingIdentical int + for j := 0; j < nx && j < ny && eq(ix+j, iy+j); j++ { + numLeadingIdentical++ + } + for j := 0; j < nx && j < ny && eq(ix+nx-1-j, iy+ny-1-j); j++ { + numTrailingIdentical++ + } + if numIdentical := numLeadingIdentical + numTrailingIdentical; numIdentical > 0 { + if numLeadingIdentical > 0 { + // Remove leading identical span from this group and + // insert it into the preceding group. + if i-1 >= 0 { + groups[i-1].NumIdentical += numLeadingIdentical + } else { + // No preceding group exists, so prepend a new group, + // but do so after we finish iterating over all groups. + defer func() { + groups = append([]diffStats{{Name: groups[0].Name, NumIdentical: numLeadingIdentical}}, groups...) + }() + } + // Increment indexes since the preceding group would have handled this. + ix += numLeadingIdentical + iy += numLeadingIdentical + } + if numTrailingIdentical > 0 { + // Remove trailing identical span from this group and + // insert it into the succeeding group. + if i+1 < len(groups) { + groups[i+1].NumIdentical += numTrailingIdentical + } else { + // No succeeding group exists, so append a new group, + // but do so after we finish iterating over all groups. + defer func() { + groups = append(groups, diffStats{Name: groups[len(groups)-1].Name, NumIdentical: numTrailingIdentical}) + }() + } + // Do not increment indexes since the succeeding group will handle this. + } + + // Update this group since some identical elements were removed. + nx -= numIdentical + ny -= numIdentical + groups[i] = diffStats{Name: ds.Name, NumRemoved: nx, NumInserted: ny} + } + ix += nx + iy += ny + } + return groups +} diff --git a/vendor/github.com/google/go-cmp/cmp/report_text.go b/vendor/github.com/google/go-cmp/cmp/report_text.go index 8b8fcab7b..388fcf571 100644 --- a/vendor/github.com/google/go-cmp/cmp/report_text.go +++ b/vendor/github.com/google/go-cmp/cmp/report_text.go @@ -1,6 +1,6 @@ // Copyright 2019, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. package cmp @@ -10,12 +10,15 @@ import ( "math/rand" "strings" "time" + "unicode/utf8" "github.com/google/go-cmp/cmp/internal/flags" ) var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0 +const maxColumnLength = 80 + type indentMode int func (n indentMode) appendIndent(b []byte, d diffMode) []byte { @@ -91,21 +94,22 @@ type textNode interface { // textWrap is a wrapper that concatenates a prefix and/or a suffix // to the underlying node. type textWrap struct { - Prefix string // e.g., "bytes.Buffer{" - Value textNode // textWrap | textList | textLine - Suffix string // e.g., "}" + Prefix string // e.g., "bytes.Buffer{" + Value textNode // textWrap | textList | textLine + Suffix string // e.g., "}" + Metadata interface{} // arbitrary metadata; has no effect on formatting } -func (s textWrap) Len() int { +func (s *textWrap) Len() int { return len(s.Prefix) + s.Value.Len() + len(s.Suffix) } -func (s1 textWrap) Equal(s2 textNode) bool { - if s2, ok := s2.(textWrap); ok { +func (s1 *textWrap) Equal(s2 textNode) bool { + if s2, ok := s2.(*textWrap); ok { return s1.Prefix == s2.Prefix && s1.Value.Equal(s2.Value) && s1.Suffix == s2.Suffix } return false } -func (s textWrap) String() string { +func (s *textWrap) String() string { var d diffMode var n indentMode _, s2 := s.formatCompactTo(nil, d) @@ -114,7 +118,7 @@ func (s textWrap) String() string { b = append(b, '\n') // Trailing newline return string(b) } -func (s textWrap) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { +func (s *textWrap) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { n0 := len(b) // Original buffer length b = append(b, s.Prefix...) b, s.Value = s.Value.formatCompactTo(b, d) @@ -124,7 +128,7 @@ func (s textWrap) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { } return b, s } -func (s textWrap) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte { +func (s *textWrap) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte { b = append(b, s.Prefix...) b = s.Value.formatExpandedTo(b, d, n) b = append(b, s.Suffix...) @@ -136,22 +140,23 @@ func (s textWrap) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte { // of the textList.formatCompactTo method. type textList []textRecord type textRecord struct { - Diff diffMode // e.g., 0 or '-' or '+' - Key string // e.g., "MyField" - Value textNode // textWrap | textLine - Comment fmt.Stringer // e.g., "6 identical fields" + Diff diffMode // e.g., 0 or '-' or '+' + Key string // e.g., "MyField" + Value textNode // textWrap | textLine + ElideComma bool // avoid trailing comma + Comment fmt.Stringer // e.g., "6 identical fields" } // AppendEllipsis appends a new ellipsis node to the list if none already // exists at the end. If cs is non-zero it coalesces the statistics with the // previous diffStats. func (s *textList) AppendEllipsis(ds diffStats) { - hasStats := ds != diffStats{} + hasStats := !ds.IsZero() if len(*s) == 0 || !(*s)[len(*s)-1].Value.Equal(textEllipsis) { if hasStats { - *s = append(*s, textRecord{Value: textEllipsis, Comment: ds}) + *s = append(*s, textRecord{Value: textEllipsis, ElideComma: true, Comment: ds}) } else { - *s = append(*s, textRecord{Value: textEllipsis}) + *s = append(*s, textRecord{Value: textEllipsis, ElideComma: true}) } return } @@ -191,7 +196,7 @@ func (s1 textList) Equal(s2 textNode) bool { } func (s textList) String() string { - return textWrap{"{", s, "}"}.String() + return (&textWrap{Prefix: "{", Value: s, Suffix: "}"}).String() } func (s textList) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { @@ -221,7 +226,7 @@ func (s textList) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { } // Force multi-lined output when printing a removed/inserted node that // is sufficiently long. - if (d == diffInserted || d == diffRemoved) && len(b[n0:]) > 80 { + if (d == diffInserted || d == diffRemoved) && len(b[n0:]) > maxColumnLength { multiLine = true } if !multiLine { @@ -236,16 +241,50 @@ func (s textList) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte { _, isLine := r.Value.(textLine) return r.Key == "" || !isLine }, - func(r textRecord) int { return len(r.Key) }, + func(r textRecord) int { return utf8.RuneCountInString(r.Key) }, ) alignValueLens := s.alignLens( func(r textRecord) bool { _, isLine := r.Value.(textLine) return !isLine || r.Value.Equal(textEllipsis) || r.Comment == nil }, - func(r textRecord) int { return len(r.Value.(textLine)) }, + func(r textRecord) int { return utf8.RuneCount(r.Value.(textLine)) }, ) + // Format lists of simple lists in a batched form. + // If the list is sequence of only textLine values, + // then batch multiple values on a single line. + var isSimple bool + for _, r := range s { + _, isLine := r.Value.(textLine) + isSimple = r.Diff == 0 && r.Key == "" && isLine && r.Comment == nil + if !isSimple { + break + } + } + if isSimple { + n++ + var batch []byte + emitBatch := func() { + if len(batch) > 0 { + b = n.appendIndent(append(b, '\n'), d) + b = append(b, bytes.TrimRight(batch, " ")...) + batch = batch[:0] + } + } + for _, r := range s { + line := r.Value.(textLine) + if len(batch)+len(line)+len(", ") > maxColumnLength { + emitBatch() + } + batch = append(batch, line...) + batch = append(batch, ", "...) + } + emitBatch() + n-- + return n.appendIndent(append(b, '\n'), d) + } + // Format the list as a multi-lined output. n++ for i, r := range s { @@ -256,7 +295,7 @@ func (s textList) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte { b = alignKeyLens[i].appendChar(b, ' ') b = r.Value.formatExpandedTo(b, d|r.Diff, n) - if !r.Value.Equal(textEllipsis) { + if !r.ElideComma { b = append(b, ',') } b = alignValueLens[i].appendChar(b, ' ') @@ -332,6 +371,11 @@ type diffStats struct { NumModified int } +func (s diffStats) IsZero() bool { + s.Name = "" + return s == diffStats{} +} + func (s diffStats) NumDiff() int { return s.NumRemoved + s.NumInserted + s.NumModified } @@ -349,6 +393,7 @@ func (s diffStats) Append(ds diffStats) diffStats { // String prints a humanly-readable summary of coalesced records. // // Example: +// // diffStats{Name: "Field", NumIgnored: 5}.String() => "5 ignored fields" func (s diffStats) String() string { var ss []string diff --git a/vendor/github.com/google/go-cmp/cmp/report_value.go b/vendor/github.com/google/go-cmp/cmp/report_value.go index 83031a7f5..668d470fd 100644 --- a/vendor/github.com/google/go-cmp/cmp/report_value.go +++ b/vendor/github.com/google/go-cmp/cmp/report_value.go @@ -1,6 +1,6 @@ // Copyright 2019, The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE.md file. +// license that can be found in the LICENSE file. package cmp diff --git a/vendor/github.com/google/pprof/AUTHORS b/vendor/github.com/google/pprof/AUTHORS new file mode 100644 index 000000000..fd736cb1c --- /dev/null +++ b/vendor/github.com/google/pprof/AUTHORS @@ -0,0 +1,7 @@ +# This is the official list of pprof authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. +# Names should be added to this file as: +# Name or Organization +# The email address is not required for organizations. +Google Inc. \ No newline at end of file diff --git a/vendor/github.com/google/pprof/CONTRIBUTORS b/vendor/github.com/google/pprof/CONTRIBUTORS new file mode 100644 index 000000000..8c8c37d2c --- /dev/null +++ b/vendor/github.com/google/pprof/CONTRIBUTORS @@ -0,0 +1,16 @@ +# People who have agreed to one of the CLAs and can contribute patches. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# +# https://developers.google.com/open-source/cla/individual +# https://developers.google.com/open-source/cla/corporate +# +# Names should be added to this file as: +# Name +Raul Silvera +Tipp Moseley +Hyoun Kyu Cho +Martin Spier +Taco de Wolff +Andrew Hunter diff --git a/vendor/github.com/google/pprof/LICENSE b/vendor/github.com/google/pprof/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/vendor/github.com/google/pprof/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/google/pprof/profile/encode.go b/vendor/github.com/google/pprof/profile/encode.go new file mode 100644 index 000000000..ab7f03ae2 --- /dev/null +++ b/vendor/github.com/google/pprof/profile/encode.go @@ -0,0 +1,567 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package profile + +import ( + "errors" + "sort" +) + +func (p *Profile) decoder() []decoder { + return profileDecoder +} + +// preEncode populates the unexported fields to be used by encode +// (with suffix X) from the corresponding exported fields. The +// exported fields are cleared up to facilitate testing. +func (p *Profile) preEncode() { + strings := make(map[string]int) + addString(strings, "") + + for _, st := range p.SampleType { + st.typeX = addString(strings, st.Type) + st.unitX = addString(strings, st.Unit) + } + + for _, s := range p.Sample { + s.labelX = nil + var keys []string + for k := range s.Label { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + vs := s.Label[k] + for _, v := range vs { + s.labelX = append(s.labelX, + label{ + keyX: addString(strings, k), + strX: addString(strings, v), + }, + ) + } + } + var numKeys []string + for k := range s.NumLabel { + numKeys = append(numKeys, k) + } + sort.Strings(numKeys) + for _, k := range numKeys { + keyX := addString(strings, k) + vs := s.NumLabel[k] + units := s.NumUnit[k] + for i, v := range vs { + var unitX int64 + if len(units) != 0 { + unitX = addString(strings, units[i]) + } + s.labelX = append(s.labelX, + label{ + keyX: keyX, + numX: v, + unitX: unitX, + }, + ) + } + } + s.locationIDX = make([]uint64, len(s.Location)) + for i, loc := range s.Location { + s.locationIDX[i] = loc.ID + } + } + + for _, m := range p.Mapping { + m.fileX = addString(strings, m.File) + m.buildIDX = addString(strings, m.BuildID) + } + + for _, l := range p.Location { + for i, ln := range l.Line { + if ln.Function != nil { + l.Line[i].functionIDX = ln.Function.ID + } else { + l.Line[i].functionIDX = 0 + } + } + if l.Mapping != nil { + l.mappingIDX = l.Mapping.ID + } else { + l.mappingIDX = 0 + } + } + for _, f := range p.Function { + f.nameX = addString(strings, f.Name) + f.systemNameX = addString(strings, f.SystemName) + f.filenameX = addString(strings, f.Filename) + } + + p.dropFramesX = addString(strings, p.DropFrames) + p.keepFramesX = addString(strings, p.KeepFrames) + + if pt := p.PeriodType; pt != nil { + pt.typeX = addString(strings, pt.Type) + pt.unitX = addString(strings, pt.Unit) + } + + p.commentX = nil + for _, c := range p.Comments { + p.commentX = append(p.commentX, addString(strings, c)) + } + + p.defaultSampleTypeX = addString(strings, p.DefaultSampleType) + + p.stringTable = make([]string, len(strings)) + for s, i := range strings { + p.stringTable[i] = s + } +} + +func (p *Profile) encode(b *buffer) { + for _, x := range p.SampleType { + encodeMessage(b, 1, x) + } + for _, x := range p.Sample { + encodeMessage(b, 2, x) + } + for _, x := range p.Mapping { + encodeMessage(b, 3, x) + } + for _, x := range p.Location { + encodeMessage(b, 4, x) + } + for _, x := range p.Function { + encodeMessage(b, 5, x) + } + encodeStrings(b, 6, p.stringTable) + encodeInt64Opt(b, 7, p.dropFramesX) + encodeInt64Opt(b, 8, p.keepFramesX) + encodeInt64Opt(b, 9, p.TimeNanos) + encodeInt64Opt(b, 10, p.DurationNanos) + if pt := p.PeriodType; pt != nil && (pt.typeX != 0 || pt.unitX != 0) { + encodeMessage(b, 11, p.PeriodType) + } + encodeInt64Opt(b, 12, p.Period) + encodeInt64s(b, 13, p.commentX) + encodeInt64(b, 14, p.defaultSampleTypeX) +} + +var profileDecoder = []decoder{ + nil, // 0 + // repeated ValueType sample_type = 1 + func(b *buffer, m message) error { + x := new(ValueType) + pp := m.(*Profile) + pp.SampleType = append(pp.SampleType, x) + return decodeMessage(b, x) + }, + // repeated Sample sample = 2 + func(b *buffer, m message) error { + x := new(Sample) + pp := m.(*Profile) + pp.Sample = append(pp.Sample, x) + return decodeMessage(b, x) + }, + // repeated Mapping mapping = 3 + func(b *buffer, m message) error { + x := new(Mapping) + pp := m.(*Profile) + pp.Mapping = append(pp.Mapping, x) + return decodeMessage(b, x) + }, + // repeated Location location = 4 + func(b *buffer, m message) error { + x := new(Location) + x.Line = make([]Line, 0, 8) // Pre-allocate Line buffer + pp := m.(*Profile) + pp.Location = append(pp.Location, x) + err := decodeMessage(b, x) + var tmp []Line + x.Line = append(tmp, x.Line...) // Shrink to allocated size + return err + }, + // repeated Function function = 5 + func(b *buffer, m message) error { + x := new(Function) + pp := m.(*Profile) + pp.Function = append(pp.Function, x) + return decodeMessage(b, x) + }, + // repeated string string_table = 6 + func(b *buffer, m message) error { + err := decodeStrings(b, &m.(*Profile).stringTable) + if err != nil { + return err + } + if m.(*Profile).stringTable[0] != "" { + return errors.New("string_table[0] must be ''") + } + return nil + }, + // int64 drop_frames = 7 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).dropFramesX) }, + // int64 keep_frames = 8 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).keepFramesX) }, + // int64 time_nanos = 9 + func(b *buffer, m message) error { + if m.(*Profile).TimeNanos != 0 { + return errConcatProfile + } + return decodeInt64(b, &m.(*Profile).TimeNanos) + }, + // int64 duration_nanos = 10 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).DurationNanos) }, + // ValueType period_type = 11 + func(b *buffer, m message) error { + x := new(ValueType) + pp := m.(*Profile) + pp.PeriodType = x + return decodeMessage(b, x) + }, + // int64 period = 12 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).Period) }, + // repeated int64 comment = 13 + func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Profile).commentX) }, + // int64 defaultSampleType = 14 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).defaultSampleTypeX) }, +} + +// postDecode takes the unexported fields populated by decode (with +// suffix X) and populates the corresponding exported fields. +// The unexported fields are cleared up to facilitate testing. +func (p *Profile) postDecode() error { + var err error + mappings := make(map[uint64]*Mapping, len(p.Mapping)) + mappingIds := make([]*Mapping, len(p.Mapping)+1) + for _, m := range p.Mapping { + m.File, err = getString(p.stringTable, &m.fileX, err) + m.BuildID, err = getString(p.stringTable, &m.buildIDX, err) + if m.ID < uint64(len(mappingIds)) { + mappingIds[m.ID] = m + } else { + mappings[m.ID] = m + } + } + + functions := make(map[uint64]*Function, len(p.Function)) + functionIds := make([]*Function, len(p.Function)+1) + for _, f := range p.Function { + f.Name, err = getString(p.stringTable, &f.nameX, err) + f.SystemName, err = getString(p.stringTable, &f.systemNameX, err) + f.Filename, err = getString(p.stringTable, &f.filenameX, err) + if f.ID < uint64(len(functionIds)) { + functionIds[f.ID] = f + } else { + functions[f.ID] = f + } + } + + locations := make(map[uint64]*Location, len(p.Location)) + locationIds := make([]*Location, len(p.Location)+1) + for _, l := range p.Location { + if id := l.mappingIDX; id < uint64(len(mappingIds)) { + l.Mapping = mappingIds[id] + } else { + l.Mapping = mappings[id] + } + l.mappingIDX = 0 + for i, ln := range l.Line { + if id := ln.functionIDX; id != 0 { + l.Line[i].functionIDX = 0 + if id < uint64(len(functionIds)) { + l.Line[i].Function = functionIds[id] + } else { + l.Line[i].Function = functions[id] + } + } + } + if l.ID < uint64(len(locationIds)) { + locationIds[l.ID] = l + } else { + locations[l.ID] = l + } + } + + for _, st := range p.SampleType { + st.Type, err = getString(p.stringTable, &st.typeX, err) + st.Unit, err = getString(p.stringTable, &st.unitX, err) + } + + for _, s := range p.Sample { + labels := make(map[string][]string, len(s.labelX)) + numLabels := make(map[string][]int64, len(s.labelX)) + numUnits := make(map[string][]string, len(s.labelX)) + for _, l := range s.labelX { + var key, value string + key, err = getString(p.stringTable, &l.keyX, err) + if l.strX != 0 { + value, err = getString(p.stringTable, &l.strX, err) + labels[key] = append(labels[key], value) + } else if l.numX != 0 || l.unitX != 0 { + numValues := numLabels[key] + units := numUnits[key] + if l.unitX != 0 { + var unit string + unit, err = getString(p.stringTable, &l.unitX, err) + units = padStringArray(units, len(numValues)) + numUnits[key] = append(units, unit) + } + numLabels[key] = append(numLabels[key], l.numX) + } + } + if len(labels) > 0 { + s.Label = labels + } + if len(numLabels) > 0 { + s.NumLabel = numLabels + for key, units := range numUnits { + if len(units) > 0 { + numUnits[key] = padStringArray(units, len(numLabels[key])) + } + } + s.NumUnit = numUnits + } + s.Location = make([]*Location, len(s.locationIDX)) + for i, lid := range s.locationIDX { + if lid < uint64(len(locationIds)) { + s.Location[i] = locationIds[lid] + } else { + s.Location[i] = locations[lid] + } + } + s.locationIDX = nil + } + + p.DropFrames, err = getString(p.stringTable, &p.dropFramesX, err) + p.KeepFrames, err = getString(p.stringTable, &p.keepFramesX, err) + + if pt := p.PeriodType; pt == nil { + p.PeriodType = &ValueType{} + } + + if pt := p.PeriodType; pt != nil { + pt.Type, err = getString(p.stringTable, &pt.typeX, err) + pt.Unit, err = getString(p.stringTable, &pt.unitX, err) + } + + for _, i := range p.commentX { + var c string + c, err = getString(p.stringTable, &i, err) + p.Comments = append(p.Comments, c) + } + + p.commentX = nil + p.DefaultSampleType, err = getString(p.stringTable, &p.defaultSampleTypeX, err) + p.stringTable = nil + return err +} + +// padStringArray pads arr with enough empty strings to make arr +// length l when arr's length is less than l. +func padStringArray(arr []string, l int) []string { + if l <= len(arr) { + return arr + } + return append(arr, make([]string, l-len(arr))...) +} + +func (p *ValueType) decoder() []decoder { + return valueTypeDecoder +} + +func (p *ValueType) encode(b *buffer) { + encodeInt64Opt(b, 1, p.typeX) + encodeInt64Opt(b, 2, p.unitX) +} + +var valueTypeDecoder = []decoder{ + nil, // 0 + // optional int64 type = 1 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).typeX) }, + // optional int64 unit = 2 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).unitX) }, +} + +func (p *Sample) decoder() []decoder { + return sampleDecoder +} + +func (p *Sample) encode(b *buffer) { + encodeUint64s(b, 1, p.locationIDX) + encodeInt64s(b, 2, p.Value) + for _, x := range p.labelX { + encodeMessage(b, 3, x) + } +} + +var sampleDecoder = []decoder{ + nil, // 0 + // repeated uint64 location = 1 + func(b *buffer, m message) error { return decodeUint64s(b, &m.(*Sample).locationIDX) }, + // repeated int64 value = 2 + func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Sample).Value) }, + // repeated Label label = 3 + func(b *buffer, m message) error { + s := m.(*Sample) + n := len(s.labelX) + s.labelX = append(s.labelX, label{}) + return decodeMessage(b, &s.labelX[n]) + }, +} + +func (p label) decoder() []decoder { + return labelDecoder +} + +func (p label) encode(b *buffer) { + encodeInt64Opt(b, 1, p.keyX) + encodeInt64Opt(b, 2, p.strX) + encodeInt64Opt(b, 3, p.numX) + encodeInt64Opt(b, 4, p.unitX) +} + +var labelDecoder = []decoder{ + nil, // 0 + // optional int64 key = 1 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).keyX) }, + // optional int64 str = 2 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).strX) }, + // optional int64 num = 3 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).numX) }, + // optional int64 num = 4 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).unitX) }, +} + +func (p *Mapping) decoder() []decoder { + return mappingDecoder +} + +func (p *Mapping) encode(b *buffer) { + encodeUint64Opt(b, 1, p.ID) + encodeUint64Opt(b, 2, p.Start) + encodeUint64Opt(b, 3, p.Limit) + encodeUint64Opt(b, 4, p.Offset) + encodeInt64Opt(b, 5, p.fileX) + encodeInt64Opt(b, 6, p.buildIDX) + encodeBoolOpt(b, 7, p.HasFunctions) + encodeBoolOpt(b, 8, p.HasFilenames) + encodeBoolOpt(b, 9, p.HasLineNumbers) + encodeBoolOpt(b, 10, p.HasInlineFrames) +} + +var mappingDecoder = []decoder{ + nil, // 0 + func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).ID) }, // optional uint64 id = 1 + func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Start) }, // optional uint64 memory_offset = 2 + func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Limit) }, // optional uint64 memory_limit = 3 + func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Offset) }, // optional uint64 file_offset = 4 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).fileX) }, // optional int64 filename = 5 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).buildIDX) }, // optional int64 build_id = 6 + func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFunctions) }, // optional bool has_functions = 7 + func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFilenames) }, // optional bool has_filenames = 8 + func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasLineNumbers) }, // optional bool has_line_numbers = 9 + func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasInlineFrames) }, // optional bool has_inline_frames = 10 +} + +func (p *Location) decoder() []decoder { + return locationDecoder +} + +func (p *Location) encode(b *buffer) { + encodeUint64Opt(b, 1, p.ID) + encodeUint64Opt(b, 2, p.mappingIDX) + encodeUint64Opt(b, 3, p.Address) + for i := range p.Line { + encodeMessage(b, 4, &p.Line[i]) + } + encodeBoolOpt(b, 5, p.IsFolded) +} + +var locationDecoder = []decoder{ + nil, // 0 + func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).ID) }, // optional uint64 id = 1; + func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).mappingIDX) }, // optional uint64 mapping_id = 2; + func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).Address) }, // optional uint64 address = 3; + func(b *buffer, m message) error { // repeated Line line = 4 + pp := m.(*Location) + n := len(pp.Line) + pp.Line = append(pp.Line, Line{}) + return decodeMessage(b, &pp.Line[n]) + }, + func(b *buffer, m message) error { return decodeBool(b, &m.(*Location).IsFolded) }, // optional bool is_folded = 5; +} + +func (p *Line) decoder() []decoder { + return lineDecoder +} + +func (p *Line) encode(b *buffer) { + encodeUint64Opt(b, 1, p.functionIDX) + encodeInt64Opt(b, 2, p.Line) +} + +var lineDecoder = []decoder{ + nil, // 0 + // optional uint64 function_id = 1 + func(b *buffer, m message) error { return decodeUint64(b, &m.(*Line).functionIDX) }, + // optional int64 line = 2 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Line) }, +} + +func (p *Function) decoder() []decoder { + return functionDecoder +} + +func (p *Function) encode(b *buffer) { + encodeUint64Opt(b, 1, p.ID) + encodeInt64Opt(b, 2, p.nameX) + encodeInt64Opt(b, 3, p.systemNameX) + encodeInt64Opt(b, 4, p.filenameX) + encodeInt64Opt(b, 5, p.StartLine) +} + +var functionDecoder = []decoder{ + nil, // 0 + // optional uint64 id = 1 + func(b *buffer, m message) error { return decodeUint64(b, &m.(*Function).ID) }, + // optional int64 function_name = 2 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).nameX) }, + // optional int64 function_system_name = 3 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).systemNameX) }, + // repeated int64 filename = 4 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).filenameX) }, + // optional int64 start_line = 5 + func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).StartLine) }, +} + +func addString(strings map[string]int, s string) int64 { + i, ok := strings[s] + if !ok { + i = len(strings) + strings[s] = i + } + return int64(i) +} + +func getString(strings []string, strng *int64, err error) (string, error) { + if err != nil { + return "", err + } + s := int(*strng) + if s < 0 || s >= len(strings) { + return "", errMalformed + } + *strng = 0 + return strings[s], nil +} diff --git a/vendor/github.com/google/pprof/profile/filter.go b/vendor/github.com/google/pprof/profile/filter.go new file mode 100644 index 000000000..ea8e66c68 --- /dev/null +++ b/vendor/github.com/google/pprof/profile/filter.go @@ -0,0 +1,270 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package profile + +// Implements methods to filter samples from profiles. + +import "regexp" + +// FilterSamplesByName filters the samples in a profile and only keeps +// samples where at least one frame matches focus but none match ignore. +// Returns true is the corresponding regexp matched at least one sample. +func (p *Profile) FilterSamplesByName(focus, ignore, hide, show *regexp.Regexp) (fm, im, hm, hnm bool) { + focusOrIgnore := make(map[uint64]bool) + hidden := make(map[uint64]bool) + for _, l := range p.Location { + if ignore != nil && l.matchesName(ignore) { + im = true + focusOrIgnore[l.ID] = false + } else if focus == nil || l.matchesName(focus) { + fm = true + focusOrIgnore[l.ID] = true + } + + if hide != nil && l.matchesName(hide) { + hm = true + l.Line = l.unmatchedLines(hide) + if len(l.Line) == 0 { + hidden[l.ID] = true + } + } + if show != nil { + l.Line = l.matchedLines(show) + if len(l.Line) == 0 { + hidden[l.ID] = true + } else { + hnm = true + } + } + } + + s := make([]*Sample, 0, len(p.Sample)) + for _, sample := range p.Sample { + if focusedAndNotIgnored(sample.Location, focusOrIgnore) { + if len(hidden) > 0 { + var locs []*Location + for _, loc := range sample.Location { + if !hidden[loc.ID] { + locs = append(locs, loc) + } + } + if len(locs) == 0 { + // Remove sample with no locations (by not adding it to s). + continue + } + sample.Location = locs + } + s = append(s, sample) + } + } + p.Sample = s + + return +} + +// ShowFrom drops all stack frames above the highest matching frame and returns +// whether a match was found. If showFrom is nil it returns false and does not +// modify the profile. +// +// Example: consider a sample with frames [A, B, C, B], where A is the root. +// ShowFrom(nil) returns false and has frames [A, B, C, B]. +// ShowFrom(A) returns true and has frames [A, B, C, B]. +// ShowFrom(B) returns true and has frames [B, C, B]. +// ShowFrom(C) returns true and has frames [C, B]. +// ShowFrom(D) returns false and drops the sample because no frames remain. +func (p *Profile) ShowFrom(showFrom *regexp.Regexp) (matched bool) { + if showFrom == nil { + return false + } + // showFromLocs stores location IDs that matched ShowFrom. + showFromLocs := make(map[uint64]bool) + // Apply to locations. + for _, loc := range p.Location { + if filterShowFromLocation(loc, showFrom) { + showFromLocs[loc.ID] = true + matched = true + } + } + // For all samples, strip locations after the highest matching one. + s := make([]*Sample, 0, len(p.Sample)) + for _, sample := range p.Sample { + for i := len(sample.Location) - 1; i >= 0; i-- { + if showFromLocs[sample.Location[i].ID] { + sample.Location = sample.Location[:i+1] + s = append(s, sample) + break + } + } + } + p.Sample = s + return matched +} + +// filterShowFromLocation tests a showFrom regex against a location, removes +// lines after the last match and returns whether a match was found. If the +// mapping is matched, then all lines are kept. +func filterShowFromLocation(loc *Location, showFrom *regexp.Regexp) bool { + if m := loc.Mapping; m != nil && showFrom.MatchString(m.File) { + return true + } + if i := loc.lastMatchedLineIndex(showFrom); i >= 0 { + loc.Line = loc.Line[:i+1] + return true + } + return false +} + +// lastMatchedLineIndex returns the index of the last line that matches a regex, +// or -1 if no match is found. +func (loc *Location) lastMatchedLineIndex(re *regexp.Regexp) int { + for i := len(loc.Line) - 1; i >= 0; i-- { + if fn := loc.Line[i].Function; fn != nil { + if re.MatchString(fn.Name) || re.MatchString(fn.Filename) { + return i + } + } + } + return -1 +} + +// FilterTagsByName filters the tags in a profile and only keeps +// tags that match show and not hide. +func (p *Profile) FilterTagsByName(show, hide *regexp.Regexp) (sm, hm bool) { + matchRemove := func(name string) bool { + matchShow := show == nil || show.MatchString(name) + matchHide := hide != nil && hide.MatchString(name) + + if matchShow { + sm = true + } + if matchHide { + hm = true + } + return !matchShow || matchHide + } + for _, s := range p.Sample { + for lab := range s.Label { + if matchRemove(lab) { + delete(s.Label, lab) + } + } + for lab := range s.NumLabel { + if matchRemove(lab) { + delete(s.NumLabel, lab) + } + } + } + return +} + +// matchesName returns whether the location matches the regular +// expression. It checks any available function names, file names, and +// mapping object filename. +func (loc *Location) matchesName(re *regexp.Regexp) bool { + for _, ln := range loc.Line { + if fn := ln.Function; fn != nil { + if re.MatchString(fn.Name) || re.MatchString(fn.Filename) { + return true + } + } + } + if m := loc.Mapping; m != nil && re.MatchString(m.File) { + return true + } + return false +} + +// unmatchedLines returns the lines in the location that do not match +// the regular expression. +func (loc *Location) unmatchedLines(re *regexp.Regexp) []Line { + if m := loc.Mapping; m != nil && re.MatchString(m.File) { + return nil + } + var lines []Line + for _, ln := range loc.Line { + if fn := ln.Function; fn != nil { + if re.MatchString(fn.Name) || re.MatchString(fn.Filename) { + continue + } + } + lines = append(lines, ln) + } + return lines +} + +// matchedLines returns the lines in the location that match +// the regular expression. +func (loc *Location) matchedLines(re *regexp.Regexp) []Line { + if m := loc.Mapping; m != nil && re.MatchString(m.File) { + return loc.Line + } + var lines []Line + for _, ln := range loc.Line { + if fn := ln.Function; fn != nil { + if !re.MatchString(fn.Name) && !re.MatchString(fn.Filename) { + continue + } + } + lines = append(lines, ln) + } + return lines +} + +// focusedAndNotIgnored looks up a slice of ids against a map of +// focused/ignored locations. The map only contains locations that are +// explicitly focused or ignored. Returns whether there is at least +// one focused location but no ignored locations. +func focusedAndNotIgnored(locs []*Location, m map[uint64]bool) bool { + var f bool + for _, loc := range locs { + if focus, focusOrIgnore := m[loc.ID]; focusOrIgnore { + if focus { + // Found focused location. Must keep searching in case there + // is an ignored one as well. + f = true + } else { + // Found ignored location. Can return false right away. + return false + } + } + } + return f +} + +// TagMatch selects tags for filtering +type TagMatch func(s *Sample) bool + +// FilterSamplesByTag removes all samples from the profile, except +// those that match focus and do not match the ignore regular +// expression. +func (p *Profile) FilterSamplesByTag(focus, ignore TagMatch) (fm, im bool) { + samples := make([]*Sample, 0, len(p.Sample)) + for _, s := range p.Sample { + focused, ignored := true, false + if focus != nil { + focused = focus(s) + } + if ignore != nil { + ignored = ignore(s) + } + fm = fm || focused + im = im || ignored + if focused && !ignored { + samples = append(samples, s) + } + } + p.Sample = samples + return +} diff --git a/vendor/github.com/google/pprof/profile/index.go b/vendor/github.com/google/pprof/profile/index.go new file mode 100644 index 000000000..bef1d6046 --- /dev/null +++ b/vendor/github.com/google/pprof/profile/index.go @@ -0,0 +1,64 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package profile + +import ( + "fmt" + "strconv" + "strings" +) + +// SampleIndexByName returns the appropriate index for a value of sample index. +// If numeric, it returns the number, otherwise it looks up the text in the +// profile sample types. +func (p *Profile) SampleIndexByName(sampleIndex string) (int, error) { + if sampleIndex == "" { + if dst := p.DefaultSampleType; dst != "" { + for i, t := range sampleTypes(p) { + if t == dst { + return i, nil + } + } + } + // By default select the last sample value + return len(p.SampleType) - 1, nil + } + if i, err := strconv.Atoi(sampleIndex); err == nil { + if i < 0 || i >= len(p.SampleType) { + return 0, fmt.Errorf("sample_index %s is outside the range [0..%d]", sampleIndex, len(p.SampleType)-1) + } + return i, nil + } + + // Remove the inuse_ prefix to support legacy pprof options + // "inuse_space" and "inuse_objects" for profiles containing types + // "space" and "objects". + noInuse := strings.TrimPrefix(sampleIndex, "inuse_") + for i, t := range p.SampleType { + if t.Type == sampleIndex || t.Type == noInuse { + return i, nil + } + } + + return 0, fmt.Errorf("sample_index %q must be one of: %v", sampleIndex, sampleTypes(p)) +} + +func sampleTypes(p *Profile) []string { + types := make([]string, len(p.SampleType)) + for i, t := range p.SampleType { + types[i] = t.Type + } + return types +} diff --git a/vendor/github.com/google/pprof/profile/legacy_java_profile.go b/vendor/github.com/google/pprof/profile/legacy_java_profile.go new file mode 100644 index 000000000..91f45e53c --- /dev/null +++ b/vendor/github.com/google/pprof/profile/legacy_java_profile.go @@ -0,0 +1,315 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file implements parsers to convert java legacy profiles into +// the profile.proto format. + +package profile + +import ( + "bytes" + "fmt" + "io" + "path/filepath" + "regexp" + "strconv" + "strings" +) + +var ( + attributeRx = regexp.MustCompile(`([\w ]+)=([\w ]+)`) + javaSampleRx = regexp.MustCompile(` *(\d+) +(\d+) +@ +([ x0-9a-f]*)`) + javaLocationRx = regexp.MustCompile(`^\s*0x([[:xdigit:]]+)\s+(.*)\s*$`) + javaLocationFileLineRx = regexp.MustCompile(`^(.*)\s+\((.+):(-?[[:digit:]]+)\)$`) + javaLocationPathRx = regexp.MustCompile(`^(.*)\s+\((.*)\)$`) +) + +// javaCPUProfile returns a new Profile from profilez data. +// b is the profile bytes after the header, period is the profiling +// period, and parse is a function to parse 8-byte chunks from the +// profile in its native endianness. +func javaCPUProfile(b []byte, period int64, parse func(b []byte) (uint64, []byte)) (*Profile, error) { + p := &Profile{ + Period: period * 1000, + PeriodType: &ValueType{Type: "cpu", Unit: "nanoseconds"}, + SampleType: []*ValueType{{Type: "samples", Unit: "count"}, {Type: "cpu", Unit: "nanoseconds"}}, + } + var err error + var locs map[uint64]*Location + if b, locs, err = parseCPUSamples(b, parse, false, p); err != nil { + return nil, err + } + + if err = parseJavaLocations(b, locs, p); err != nil { + return nil, err + } + + // Strip out addresses for better merge. + if err = p.Aggregate(true, true, true, true, false); err != nil { + return nil, err + } + + return p, nil +} + +// parseJavaProfile returns a new profile from heapz or contentionz +// data. b is the profile bytes after the header. +func parseJavaProfile(b []byte) (*Profile, error) { + h := bytes.SplitAfterN(b, []byte("\n"), 2) + if len(h) < 2 { + return nil, errUnrecognized + } + + p := &Profile{ + PeriodType: &ValueType{}, + } + header := string(bytes.TrimSpace(h[0])) + + var err error + var pType string + switch header { + case "--- heapz 1 ---": + pType = "heap" + case "--- contentionz 1 ---": + pType = "contention" + default: + return nil, errUnrecognized + } + + if b, err = parseJavaHeader(pType, h[1], p); err != nil { + return nil, err + } + var locs map[uint64]*Location + if b, locs, err = parseJavaSamples(pType, b, p); err != nil { + return nil, err + } + if err = parseJavaLocations(b, locs, p); err != nil { + return nil, err + } + + // Strip out addresses for better merge. + if err = p.Aggregate(true, true, true, true, false); err != nil { + return nil, err + } + + return p, nil +} + +// parseJavaHeader parses the attribute section on a java profile and +// populates a profile. Returns the remainder of the buffer after all +// attributes. +func parseJavaHeader(pType string, b []byte, p *Profile) ([]byte, error) { + nextNewLine := bytes.IndexByte(b, byte('\n')) + for nextNewLine != -1 { + line := string(bytes.TrimSpace(b[0:nextNewLine])) + if line != "" { + h := attributeRx.FindStringSubmatch(line) + if h == nil { + // Not a valid attribute, exit. + return b, nil + } + + attribute, value := strings.TrimSpace(h[1]), strings.TrimSpace(h[2]) + var err error + switch pType + "/" + attribute { + case "heap/format", "cpu/format", "contention/format": + if value != "java" { + return nil, errUnrecognized + } + case "heap/resolution": + p.SampleType = []*ValueType{ + {Type: "inuse_objects", Unit: "count"}, + {Type: "inuse_space", Unit: value}, + } + case "contention/resolution": + p.SampleType = []*ValueType{ + {Type: "contentions", Unit: "count"}, + {Type: "delay", Unit: value}, + } + case "contention/sampling period": + p.PeriodType = &ValueType{ + Type: "contentions", Unit: "count", + } + if p.Period, err = strconv.ParseInt(value, 0, 64); err != nil { + return nil, fmt.Errorf("failed to parse attribute %s: %v", line, err) + } + case "contention/ms since reset": + millis, err := strconv.ParseInt(value, 0, 64) + if err != nil { + return nil, fmt.Errorf("failed to parse attribute %s: %v", line, err) + } + p.DurationNanos = millis * 1000 * 1000 + default: + return nil, errUnrecognized + } + } + // Grab next line. + b = b[nextNewLine+1:] + nextNewLine = bytes.IndexByte(b, byte('\n')) + } + return b, nil +} + +// parseJavaSamples parses the samples from a java profile and +// populates the Samples in a profile. Returns the remainder of the +// buffer after the samples. +func parseJavaSamples(pType string, b []byte, p *Profile) ([]byte, map[uint64]*Location, error) { + nextNewLine := bytes.IndexByte(b, byte('\n')) + locs := make(map[uint64]*Location) + for nextNewLine != -1 { + line := string(bytes.TrimSpace(b[0:nextNewLine])) + if line != "" { + sample := javaSampleRx.FindStringSubmatch(line) + if sample == nil { + // Not a valid sample, exit. + return b, locs, nil + } + + // Java profiles have data/fields inverted compared to other + // profile types. + var err error + value1, value2, value3 := sample[2], sample[1], sample[3] + addrs, err := parseHexAddresses(value3) + if err != nil { + return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err) + } + + var sloc []*Location + for _, addr := range addrs { + loc := locs[addr] + if locs[addr] == nil { + loc = &Location{ + Address: addr, + } + p.Location = append(p.Location, loc) + locs[addr] = loc + } + sloc = append(sloc, loc) + } + s := &Sample{ + Value: make([]int64, 2), + Location: sloc, + } + + if s.Value[0], err = strconv.ParseInt(value1, 0, 64); err != nil { + return nil, nil, fmt.Errorf("parsing sample %s: %v", line, err) + } + if s.Value[1], err = strconv.ParseInt(value2, 0, 64); err != nil { + return nil, nil, fmt.Errorf("parsing sample %s: %v", line, err) + } + + switch pType { + case "heap": + const javaHeapzSamplingRate = 524288 // 512K + if s.Value[0] == 0 { + return nil, nil, fmt.Errorf("parsing sample %s: second value must be non-zero", line) + } + s.NumLabel = map[string][]int64{"bytes": {s.Value[1] / s.Value[0]}} + s.Value[0], s.Value[1] = scaleHeapSample(s.Value[0], s.Value[1], javaHeapzSamplingRate) + case "contention": + if period := p.Period; period != 0 { + s.Value[0] = s.Value[0] * p.Period + s.Value[1] = s.Value[1] * p.Period + } + } + p.Sample = append(p.Sample, s) + } + // Grab next line. + b = b[nextNewLine+1:] + nextNewLine = bytes.IndexByte(b, byte('\n')) + } + return b, locs, nil +} + +// parseJavaLocations parses the location information in a java +// profile and populates the Locations in a profile. It uses the +// location addresses from the profile as both the ID of each +// location. +func parseJavaLocations(b []byte, locs map[uint64]*Location, p *Profile) error { + r := bytes.NewBuffer(b) + fns := make(map[string]*Function) + for { + line, err := r.ReadString('\n') + if err != nil { + if err != io.EOF { + return err + } + if line == "" { + break + } + } + + if line = strings.TrimSpace(line); line == "" { + continue + } + + jloc := javaLocationRx.FindStringSubmatch(line) + if len(jloc) != 3 { + continue + } + addr, err := strconv.ParseUint(jloc[1], 16, 64) + if err != nil { + return fmt.Errorf("parsing sample %s: %v", line, err) + } + loc := locs[addr] + if loc == nil { + // Unused/unseen + continue + } + var lineFunc, lineFile string + var lineNo int64 + + if fileLine := javaLocationFileLineRx.FindStringSubmatch(jloc[2]); len(fileLine) == 4 { + // Found a line of the form: "function (file:line)" + lineFunc, lineFile = fileLine[1], fileLine[2] + if n, err := strconv.ParseInt(fileLine[3], 10, 64); err == nil && n > 0 { + lineNo = n + } + } else if filePath := javaLocationPathRx.FindStringSubmatch(jloc[2]); len(filePath) == 3 { + // If there's not a file:line, it's a shared library path. + // The path isn't interesting, so just give the .so. + lineFunc, lineFile = filePath[1], filepath.Base(filePath[2]) + } else if strings.Contains(jloc[2], "generated stub/JIT") { + lineFunc = "STUB" + } else { + // Treat whole line as the function name. This is used by the + // java agent for internal states such as "GC" or "VM". + lineFunc = jloc[2] + } + fn := fns[lineFunc] + + if fn == nil { + fn = &Function{ + Name: lineFunc, + SystemName: lineFunc, + Filename: lineFile, + } + fns[lineFunc] = fn + p.Function = append(p.Function, fn) + } + loc.Line = []Line{ + { + Function: fn, + Line: lineNo, + }, + } + loc.Address = 0 + } + + p.remapLocationIDs() + p.remapFunctionIDs() + p.remapMappingIDs() + + return nil +} diff --git a/vendor/github.com/google/pprof/profile/legacy_profile.go b/vendor/github.com/google/pprof/profile/legacy_profile.go new file mode 100644 index 000000000..0c8f3bb5b --- /dev/null +++ b/vendor/github.com/google/pprof/profile/legacy_profile.go @@ -0,0 +1,1225 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file implements parsers to convert legacy profiles into the +// profile.proto format. + +package profile + +import ( + "bufio" + "bytes" + "fmt" + "io" + "math" + "regexp" + "strconv" + "strings" +) + +var ( + countStartRE = regexp.MustCompile(`\A(\S+) profile: total \d+\z`) + countRE = regexp.MustCompile(`\A(\d+) @(( 0x[0-9a-f]+)+)\z`) + + heapHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] *@ *(heap[_a-z0-9]*)/?(\d*)`) + heapSampleRE = regexp.MustCompile(`(-?\d+): *(-?\d+) *\[ *(\d+): *(\d+) *] @([ x0-9a-f]*)`) + + contentionSampleRE = regexp.MustCompile(`(\d+) *(\d+) @([ x0-9a-f]*)`) + + hexNumberRE = regexp.MustCompile(`0x[0-9a-f]+`) + + growthHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ growthz?`) + + fragmentationHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ fragmentationz?`) + + threadzStartRE = regexp.MustCompile(`--- threadz \d+ ---`) + threadStartRE = regexp.MustCompile(`--- Thread ([[:xdigit:]]+) \(name: (.*)/(\d+)\) stack: ---`) + + // Regular expressions to parse process mappings. Support the format used by Linux /proc/.../maps and other tools. + // Recommended format: + // Start End object file name offset(optional) linker build id + // 0x40000-0x80000 /path/to/binary (@FF00) abc123456 + spaceDigits = `\s+[[:digit:]]+` + hexPair = `\s+[[:xdigit:]]+:[[:xdigit:]]+` + oSpace = `\s*` + // Capturing expressions. + cHex = `(?:0x)?([[:xdigit:]]+)` + cHexRange = `\s*` + cHex + `[\s-]?` + oSpace + cHex + `:?` + cSpaceString = `(?:\s+(\S+))?` + cSpaceHex = `(?:\s+([[:xdigit:]]+))?` + cSpaceAtOffset = `(?:\s+\(@([[:xdigit:]]+)\))?` + cPerm = `(?:\s+([-rwxp]+))?` + + procMapsRE = regexp.MustCompile(`^` + cHexRange + cPerm + cSpaceHex + hexPair + spaceDigits + cSpaceString) + briefMapsRE = regexp.MustCompile(`^` + cHexRange + cPerm + cSpaceString + cSpaceAtOffset + cSpaceHex) + + // Regular expression to parse log data, of the form: + // ... file:line] msg... + logInfoRE = regexp.MustCompile(`^[^\[\]]+:[0-9]+]\s`) +) + +func isSpaceOrComment(line string) bool { + trimmed := strings.TrimSpace(line) + return len(trimmed) == 0 || trimmed[0] == '#' +} + +// parseGoCount parses a Go count profile (e.g., threadcreate or +// goroutine) and returns a new Profile. +func parseGoCount(b []byte) (*Profile, error) { + s := bufio.NewScanner(bytes.NewBuffer(b)) + // Skip comments at the beginning of the file. + for s.Scan() && isSpaceOrComment(s.Text()) { + } + if err := s.Err(); err != nil { + return nil, err + } + m := countStartRE.FindStringSubmatch(s.Text()) + if m == nil { + return nil, errUnrecognized + } + profileType := m[1] + p := &Profile{ + PeriodType: &ValueType{Type: profileType, Unit: "count"}, + Period: 1, + SampleType: []*ValueType{{Type: profileType, Unit: "count"}}, + } + locations := make(map[uint64]*Location) + for s.Scan() { + line := s.Text() + if isSpaceOrComment(line) { + continue + } + if strings.HasPrefix(line, "---") { + break + } + m := countRE.FindStringSubmatch(line) + if m == nil { + return nil, errMalformed + } + n, err := strconv.ParseInt(m[1], 0, 64) + if err != nil { + return nil, errMalformed + } + fields := strings.Fields(m[2]) + locs := make([]*Location, 0, len(fields)) + for _, stk := range fields { + addr, err := strconv.ParseUint(stk, 0, 64) + if err != nil { + return nil, errMalformed + } + // Adjust all frames by -1 to land on top of the call instruction. + addr-- + loc := locations[addr] + if loc == nil { + loc = &Location{ + Address: addr, + } + locations[addr] = loc + p.Location = append(p.Location, loc) + } + locs = append(locs, loc) + } + p.Sample = append(p.Sample, &Sample{ + Location: locs, + Value: []int64{n}, + }) + } + if err := s.Err(); err != nil { + return nil, err + } + + if err := parseAdditionalSections(s, p); err != nil { + return nil, err + } + return p, nil +} + +// remapLocationIDs ensures there is a location for each address +// referenced by a sample, and remaps the samples to point to the new +// location ids. +func (p *Profile) remapLocationIDs() { + seen := make(map[*Location]bool, len(p.Location)) + var locs []*Location + + for _, s := range p.Sample { + for _, l := range s.Location { + if seen[l] { + continue + } + l.ID = uint64(len(locs) + 1) + locs = append(locs, l) + seen[l] = true + } + } + p.Location = locs +} + +func (p *Profile) remapFunctionIDs() { + seen := make(map[*Function]bool, len(p.Function)) + var fns []*Function + + for _, l := range p.Location { + for _, ln := range l.Line { + fn := ln.Function + if fn == nil || seen[fn] { + continue + } + fn.ID = uint64(len(fns) + 1) + fns = append(fns, fn) + seen[fn] = true + } + } + p.Function = fns +} + +// remapMappingIDs matches location addresses with existing mappings +// and updates them appropriately. This is O(N*M), if this ever shows +// up as a bottleneck, evaluate sorting the mappings and doing a +// binary search, which would make it O(N*log(M)). +func (p *Profile) remapMappingIDs() { + // Some profile handlers will incorrectly set regions for the main + // executable if its section is remapped. Fix them through heuristics. + + if len(p.Mapping) > 0 { + // Remove the initial mapping if named '/anon_hugepage' and has a + // consecutive adjacent mapping. + if m := p.Mapping[0]; strings.HasPrefix(m.File, "/anon_hugepage") { + if len(p.Mapping) > 1 && m.Limit == p.Mapping[1].Start { + p.Mapping = p.Mapping[1:] + } + } + } + + // Subtract the offset from the start of the main mapping if it + // ends up at a recognizable start address. + if len(p.Mapping) > 0 { + const expectedStart = 0x400000 + if m := p.Mapping[0]; m.Start-m.Offset == expectedStart { + m.Start = expectedStart + m.Offset = 0 + } + } + + // Associate each location with an address to the corresponding + // mapping. Create fake mapping if a suitable one isn't found. + var fake *Mapping +nextLocation: + for _, l := range p.Location { + a := l.Address + if l.Mapping != nil || a == 0 { + continue + } + for _, m := range p.Mapping { + if m.Start <= a && a < m.Limit { + l.Mapping = m + continue nextLocation + } + } + // Work around legacy handlers failing to encode the first + // part of mappings split into adjacent ranges. + for _, m := range p.Mapping { + if m.Offset != 0 && m.Start-m.Offset <= a && a < m.Start { + m.Start -= m.Offset + m.Offset = 0 + l.Mapping = m + continue nextLocation + } + } + // If there is still no mapping, create a fake one. + // This is important for the Go legacy handler, which produced + // no mappings. + if fake == nil { + fake = &Mapping{ + ID: 1, + Limit: ^uint64(0), + } + p.Mapping = append(p.Mapping, fake) + } + l.Mapping = fake + } + + // Reset all mapping IDs. + for i, m := range p.Mapping { + m.ID = uint64(i + 1) + } +} + +var cpuInts = []func([]byte) (uint64, []byte){ + get32l, + get32b, + get64l, + get64b, +} + +func get32l(b []byte) (uint64, []byte) { + if len(b) < 4 { + return 0, nil + } + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24, b[4:] +} + +func get32b(b []byte) (uint64, []byte) { + if len(b) < 4 { + return 0, nil + } + return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24, b[4:] +} + +func get64l(b []byte) (uint64, []byte) { + if len(b) < 8 { + return 0, nil + } + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56, b[8:] +} + +func get64b(b []byte) (uint64, []byte) { + if len(b) < 8 { + return 0, nil + } + return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56, b[8:] +} + +// parseCPU parses a profilez legacy profile and returns a newly +// populated Profile. +// +// The general format for profilez samples is a sequence of words in +// binary format. The first words are a header with the following data: +// 1st word -- 0 +// 2nd word -- 3 +// 3rd word -- 0 if a c++ application, 1 if a java application. +// 4th word -- Sampling period (in microseconds). +// 5th word -- Padding. +func parseCPU(b []byte) (*Profile, error) { + var parse func([]byte) (uint64, []byte) + var n1, n2, n3, n4, n5 uint64 + for _, parse = range cpuInts { + var tmp []byte + n1, tmp = parse(b) + n2, tmp = parse(tmp) + n3, tmp = parse(tmp) + n4, tmp = parse(tmp) + n5, tmp = parse(tmp) + + if tmp != nil && n1 == 0 && n2 == 3 && n3 == 0 && n4 > 0 && n5 == 0 { + b = tmp + return cpuProfile(b, int64(n4), parse) + } + if tmp != nil && n1 == 0 && n2 == 3 && n3 == 1 && n4 > 0 && n5 == 0 { + b = tmp + return javaCPUProfile(b, int64(n4), parse) + } + } + return nil, errUnrecognized +} + +// cpuProfile returns a new Profile from C++ profilez data. +// b is the profile bytes after the header, period is the profiling +// period, and parse is a function to parse 8-byte chunks from the +// profile in its native endianness. +func cpuProfile(b []byte, period int64, parse func(b []byte) (uint64, []byte)) (*Profile, error) { + p := &Profile{ + Period: period * 1000, + PeriodType: &ValueType{Type: "cpu", Unit: "nanoseconds"}, + SampleType: []*ValueType{ + {Type: "samples", Unit: "count"}, + {Type: "cpu", Unit: "nanoseconds"}, + }, + } + var err error + if b, _, err = parseCPUSamples(b, parse, true, p); err != nil { + return nil, err + } + + // If *most* samples have the same second-to-the-bottom frame, it + // strongly suggests that it is an uninteresting artifact of + // measurement -- a stack frame pushed by the signal handler. The + // bottom frame is always correct as it is picked up from the signal + // structure, not the stack. Check if this is the case and if so, + // remove. + + // Remove up to two frames. + maxiter := 2 + // Allow one different sample for this many samples with the same + // second-to-last frame. + similarSamples := 32 + margin := len(p.Sample) / similarSamples + + for iter := 0; iter < maxiter; iter++ { + addr1 := make(map[uint64]int) + for _, s := range p.Sample { + if len(s.Location) > 1 { + a := s.Location[1].Address + addr1[a] = addr1[a] + 1 + } + } + + for id1, count := range addr1 { + if count >= len(p.Sample)-margin { + // Found uninteresting frame, strip it out from all samples + for _, s := range p.Sample { + if len(s.Location) > 1 && s.Location[1].Address == id1 { + s.Location = append(s.Location[:1], s.Location[2:]...) + } + } + break + } + } + } + + if err := p.ParseMemoryMap(bytes.NewBuffer(b)); err != nil { + return nil, err + } + + cleanupDuplicateLocations(p) + return p, nil +} + +func cleanupDuplicateLocations(p *Profile) { + // The profile handler may duplicate the leaf frame, because it gets + // its address both from stack unwinding and from the signal + // context. Detect this and delete the duplicate, which has been + // adjusted by -1. The leaf address should not be adjusted as it is + // not a call. + for _, s := range p.Sample { + if len(s.Location) > 1 && s.Location[0].Address == s.Location[1].Address+1 { + s.Location = append(s.Location[:1], s.Location[2:]...) + } + } +} + +// parseCPUSamples parses a collection of profilez samples from a +// profile. +// +// profilez samples are a repeated sequence of stack frames of the +// form: +// 1st word -- The number of times this stack was encountered. +// 2nd word -- The size of the stack (StackSize). +// 3rd word -- The first address on the stack. +// ... +// StackSize + 2 -- The last address on the stack +// The last stack trace is of the form: +// 1st word -- 0 +// 2nd word -- 1 +// 3rd word -- 0 +// +// Addresses from stack traces may point to the next instruction after +// each call. Optionally adjust by -1 to land somewhere on the actual +// call (except for the leaf, which is not a call). +func parseCPUSamples(b []byte, parse func(b []byte) (uint64, []byte), adjust bool, p *Profile) ([]byte, map[uint64]*Location, error) { + locs := make(map[uint64]*Location) + for len(b) > 0 { + var count, nstk uint64 + count, b = parse(b) + nstk, b = parse(b) + if b == nil || nstk > uint64(len(b)/4) { + return nil, nil, errUnrecognized + } + var sloc []*Location + addrs := make([]uint64, nstk) + for i := 0; i < int(nstk); i++ { + addrs[i], b = parse(b) + } + + if count == 0 && nstk == 1 && addrs[0] == 0 { + // End of data marker + break + } + for i, addr := range addrs { + if adjust && i > 0 { + addr-- + } + loc := locs[addr] + if loc == nil { + loc = &Location{ + Address: addr, + } + locs[addr] = loc + p.Location = append(p.Location, loc) + } + sloc = append(sloc, loc) + } + p.Sample = append(p.Sample, + &Sample{ + Value: []int64{int64(count), int64(count) * p.Period}, + Location: sloc, + }) + } + // Reached the end without finding the EOD marker. + return b, locs, nil +} + +// parseHeap parses a heapz legacy or a growthz profile and +// returns a newly populated Profile. +func parseHeap(b []byte) (p *Profile, err error) { + s := bufio.NewScanner(bytes.NewBuffer(b)) + if !s.Scan() { + if err := s.Err(); err != nil { + return nil, err + } + return nil, errUnrecognized + } + p = &Profile{} + + sampling := "" + hasAlloc := false + + line := s.Text() + p.PeriodType = &ValueType{Type: "space", Unit: "bytes"} + if header := heapHeaderRE.FindStringSubmatch(line); header != nil { + sampling, p.Period, hasAlloc, err = parseHeapHeader(line) + if err != nil { + return nil, err + } + } else if header = growthHeaderRE.FindStringSubmatch(line); header != nil { + p.Period = 1 + } else if header = fragmentationHeaderRE.FindStringSubmatch(line); header != nil { + p.Period = 1 + } else { + return nil, errUnrecognized + } + + if hasAlloc { + // Put alloc before inuse so that default pprof selection + // will prefer inuse_space. + p.SampleType = []*ValueType{ + {Type: "alloc_objects", Unit: "count"}, + {Type: "alloc_space", Unit: "bytes"}, + {Type: "inuse_objects", Unit: "count"}, + {Type: "inuse_space", Unit: "bytes"}, + } + } else { + p.SampleType = []*ValueType{ + {Type: "objects", Unit: "count"}, + {Type: "space", Unit: "bytes"}, + } + } + + locs := make(map[uint64]*Location) + for s.Scan() { + line := strings.TrimSpace(s.Text()) + + if isSpaceOrComment(line) { + continue + } + + if isMemoryMapSentinel(line) { + break + } + + value, blocksize, addrs, err := parseHeapSample(line, p.Period, sampling, hasAlloc) + if err != nil { + return nil, err + } + + var sloc []*Location + for _, addr := range addrs { + // Addresses from stack traces point to the next instruction after + // each call. Adjust by -1 to land somewhere on the actual call. + addr-- + loc := locs[addr] + if locs[addr] == nil { + loc = &Location{ + Address: addr, + } + p.Location = append(p.Location, loc) + locs[addr] = loc + } + sloc = append(sloc, loc) + } + + p.Sample = append(p.Sample, &Sample{ + Value: value, + Location: sloc, + NumLabel: map[string][]int64{"bytes": {blocksize}}, + }) + } + if err := s.Err(); err != nil { + return nil, err + } + if err := parseAdditionalSections(s, p); err != nil { + return nil, err + } + return p, nil +} + +func parseHeapHeader(line string) (sampling string, period int64, hasAlloc bool, err error) { + header := heapHeaderRE.FindStringSubmatch(line) + if header == nil { + return "", 0, false, errUnrecognized + } + + if len(header[6]) > 0 { + if period, err = strconv.ParseInt(header[6], 10, 64); err != nil { + return "", 0, false, errUnrecognized + } + } + + if (header[3] != header[1] && header[3] != "0") || (header[4] != header[2] && header[4] != "0") { + hasAlloc = true + } + + switch header[5] { + case "heapz_v2", "heap_v2": + return "v2", period, hasAlloc, nil + case "heapprofile": + return "", 1, hasAlloc, nil + case "heap": + return "v2", period / 2, hasAlloc, nil + default: + return "", 0, false, errUnrecognized + } +} + +// parseHeapSample parses a single row from a heap profile into a new Sample. +func parseHeapSample(line string, rate int64, sampling string, includeAlloc bool) (value []int64, blocksize int64, addrs []uint64, err error) { + sampleData := heapSampleRE.FindStringSubmatch(line) + if len(sampleData) != 6 { + return nil, 0, nil, fmt.Errorf("unexpected number of sample values: got %d, want 6", len(sampleData)) + } + + // This is a local-scoped helper function to avoid needing to pass + // around rate, sampling and many return parameters. + addValues := func(countString, sizeString string, label string) error { + count, err := strconv.ParseInt(countString, 10, 64) + if err != nil { + return fmt.Errorf("malformed sample: %s: %v", line, err) + } + size, err := strconv.ParseInt(sizeString, 10, 64) + if err != nil { + return fmt.Errorf("malformed sample: %s: %v", line, err) + } + if count == 0 && size != 0 { + return fmt.Errorf("%s count was 0 but %s bytes was %d", label, label, size) + } + if count != 0 { + blocksize = size / count + if sampling == "v2" { + count, size = scaleHeapSample(count, size, rate) + } + } + value = append(value, count, size) + return nil + } + + if includeAlloc { + if err := addValues(sampleData[3], sampleData[4], "allocation"); err != nil { + return nil, 0, nil, err + } + } + + if err := addValues(sampleData[1], sampleData[2], "inuse"); err != nil { + return nil, 0, nil, err + } + + addrs, err = parseHexAddresses(sampleData[5]) + if err != nil { + return nil, 0, nil, fmt.Errorf("malformed sample: %s: %v", line, err) + } + + return value, blocksize, addrs, nil +} + +// parseHexAddresses extracts hex numbers from a string, attempts to convert +// each to an unsigned 64-bit number and returns the resulting numbers as a +// slice, or an error if the string contains hex numbers which are too large to +// handle (which means a malformed profile). +func parseHexAddresses(s string) ([]uint64, error) { + hexStrings := hexNumberRE.FindAllString(s, -1) + var addrs []uint64 + for _, s := range hexStrings { + if addr, err := strconv.ParseUint(s, 0, 64); err == nil { + addrs = append(addrs, addr) + } else { + return nil, fmt.Errorf("failed to parse as hex 64-bit number: %s", s) + } + } + return addrs, nil +} + +// scaleHeapSample adjusts the data from a heapz Sample to +// account for its probability of appearing in the collected +// data. heapz profiles are a sampling of the memory allocations +// requests in a program. We estimate the unsampled value by dividing +// each collected sample by its probability of appearing in the +// profile. heapz v2 profiles rely on a poisson process to determine +// which samples to collect, based on the desired average collection +// rate R. The probability of a sample of size S to appear in that +// profile is 1-exp(-S/R). +func scaleHeapSample(count, size, rate int64) (int64, int64) { + if count == 0 || size == 0 { + return 0, 0 + } + + if rate <= 1 { + // if rate==1 all samples were collected so no adjustment is needed. + // if rate<1 treat as unknown and skip scaling. + return count, size + } + + avgSize := float64(size) / float64(count) + scale := 1 / (1 - math.Exp(-avgSize/float64(rate))) + + return int64(float64(count) * scale), int64(float64(size) * scale) +} + +// parseContention parses a mutex or contention profile. There are 2 cases: +// "--- contentionz " for legacy C++ profiles (and backwards compatibility) +// "--- mutex:" or "--- contention:" for profiles generated by the Go runtime. +func parseContention(b []byte) (*Profile, error) { + s := bufio.NewScanner(bytes.NewBuffer(b)) + if !s.Scan() { + if err := s.Err(); err != nil { + return nil, err + } + return nil, errUnrecognized + } + + switch l := s.Text(); { + case strings.HasPrefix(l, "--- contentionz "): + case strings.HasPrefix(l, "--- mutex:"): + case strings.HasPrefix(l, "--- contention:"): + default: + return nil, errUnrecognized + } + + p := &Profile{ + PeriodType: &ValueType{Type: "contentions", Unit: "count"}, + Period: 1, + SampleType: []*ValueType{ + {Type: "contentions", Unit: "count"}, + {Type: "delay", Unit: "nanoseconds"}, + }, + } + + var cpuHz int64 + // Parse text of the form "attribute = value" before the samples. + const delimiter = "=" + for s.Scan() { + line := s.Text() + if line = strings.TrimSpace(line); isSpaceOrComment(line) { + continue + } + if strings.HasPrefix(line, "---") { + break + } + attr := strings.SplitN(line, delimiter, 2) + if len(attr) != 2 { + break + } + key, val := strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1]) + var err error + switch key { + case "cycles/second": + if cpuHz, err = strconv.ParseInt(val, 0, 64); err != nil { + return nil, errUnrecognized + } + case "sampling period": + if p.Period, err = strconv.ParseInt(val, 0, 64); err != nil { + return nil, errUnrecognized + } + case "ms since reset": + ms, err := strconv.ParseInt(val, 0, 64) + if err != nil { + return nil, errUnrecognized + } + p.DurationNanos = ms * 1000 * 1000 + case "format": + // CPP contentionz profiles don't have format. + return nil, errUnrecognized + case "resolution": + // CPP contentionz profiles don't have resolution. + return nil, errUnrecognized + case "discarded samples": + default: + return nil, errUnrecognized + } + } + if err := s.Err(); err != nil { + return nil, err + } + + locs := make(map[uint64]*Location) + for { + line := strings.TrimSpace(s.Text()) + if strings.HasPrefix(line, "---") { + break + } + if !isSpaceOrComment(line) { + value, addrs, err := parseContentionSample(line, p.Period, cpuHz) + if err != nil { + return nil, err + } + var sloc []*Location + for _, addr := range addrs { + // Addresses from stack traces point to the next instruction after + // each call. Adjust by -1 to land somewhere on the actual call. + addr-- + loc := locs[addr] + if locs[addr] == nil { + loc = &Location{ + Address: addr, + } + p.Location = append(p.Location, loc) + locs[addr] = loc + } + sloc = append(sloc, loc) + } + p.Sample = append(p.Sample, &Sample{ + Value: value, + Location: sloc, + }) + } + if !s.Scan() { + break + } + } + if err := s.Err(); err != nil { + return nil, err + } + + if err := parseAdditionalSections(s, p); err != nil { + return nil, err + } + + return p, nil +} + +// parseContentionSample parses a single row from a contention profile +// into a new Sample. +func parseContentionSample(line string, period, cpuHz int64) (value []int64, addrs []uint64, err error) { + sampleData := contentionSampleRE.FindStringSubmatch(line) + if sampleData == nil { + return nil, nil, errUnrecognized + } + + v1, err := strconv.ParseInt(sampleData[1], 10, 64) + if err != nil { + return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err) + } + v2, err := strconv.ParseInt(sampleData[2], 10, 64) + if err != nil { + return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err) + } + + // Unsample values if period and cpuHz are available. + // - Delays are scaled to cycles and then to nanoseconds. + // - Contentions are scaled to cycles. + if period > 0 { + if cpuHz > 0 { + cpuGHz := float64(cpuHz) / 1e9 + v1 = int64(float64(v1) * float64(period) / cpuGHz) + } + v2 = v2 * period + } + + value = []int64{v2, v1} + addrs, err = parseHexAddresses(sampleData[3]) + if err != nil { + return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err) + } + + return value, addrs, nil +} + +// parseThread parses a Threadz profile and returns a new Profile. +func parseThread(b []byte) (*Profile, error) { + s := bufio.NewScanner(bytes.NewBuffer(b)) + // Skip past comments and empty lines seeking a real header. + for s.Scan() && isSpaceOrComment(s.Text()) { + } + + line := s.Text() + if m := threadzStartRE.FindStringSubmatch(line); m != nil { + // Advance over initial comments until first stack trace. + for s.Scan() { + if line = s.Text(); isMemoryMapSentinel(line) || strings.HasPrefix(line, "-") { + break + } + } + } else if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 { + return nil, errUnrecognized + } + + p := &Profile{ + SampleType: []*ValueType{{Type: "thread", Unit: "count"}}, + PeriodType: &ValueType{Type: "thread", Unit: "count"}, + Period: 1, + } + + locs := make(map[uint64]*Location) + // Recognize each thread and populate profile samples. + for !isMemoryMapSentinel(line) { + if strings.HasPrefix(line, "---- no stack trace for") { + line = "" + break + } + if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 { + return nil, errUnrecognized + } + + var addrs []uint64 + var err error + line, addrs, err = parseThreadSample(s) + if err != nil { + return nil, err + } + if len(addrs) == 0 { + // We got a --same as previous threads--. Bump counters. + if len(p.Sample) > 0 { + s := p.Sample[len(p.Sample)-1] + s.Value[0]++ + } + continue + } + + var sloc []*Location + for i, addr := range addrs { + // Addresses from stack traces point to the next instruction after + // each call. Adjust by -1 to land somewhere on the actual call + // (except for the leaf, which is not a call). + if i > 0 { + addr-- + } + loc := locs[addr] + if locs[addr] == nil { + loc = &Location{ + Address: addr, + } + p.Location = append(p.Location, loc) + locs[addr] = loc + } + sloc = append(sloc, loc) + } + + p.Sample = append(p.Sample, &Sample{ + Value: []int64{1}, + Location: sloc, + }) + } + + if err := parseAdditionalSections(s, p); err != nil { + return nil, err + } + + cleanupDuplicateLocations(p) + return p, nil +} + +// parseThreadSample parses a symbolized or unsymbolized stack trace. +// Returns the first line after the traceback, the sample (or nil if +// it hits a 'same-as-previous' marker) and an error. +func parseThreadSample(s *bufio.Scanner) (nextl string, addrs []uint64, err error) { + var line string + sameAsPrevious := false + for s.Scan() { + line = strings.TrimSpace(s.Text()) + if line == "" { + continue + } + + if strings.HasPrefix(line, "---") { + break + } + if strings.Contains(line, "same as previous thread") { + sameAsPrevious = true + continue + } + + curAddrs, err := parseHexAddresses(line) + if err != nil { + return "", nil, fmt.Errorf("malformed sample: %s: %v", line, err) + } + addrs = append(addrs, curAddrs...) + } + if err := s.Err(); err != nil { + return "", nil, err + } + if sameAsPrevious { + return line, nil, nil + } + return line, addrs, nil +} + +// parseAdditionalSections parses any additional sections in the +// profile, ignoring any unrecognized sections. +func parseAdditionalSections(s *bufio.Scanner, p *Profile) error { + for !isMemoryMapSentinel(s.Text()) && s.Scan() { + } + if err := s.Err(); err != nil { + return err + } + return p.ParseMemoryMapFromScanner(s) +} + +// ParseProcMaps parses a memory map in the format of /proc/self/maps. +// ParseMemoryMap should be called after setting on a profile to +// associate locations to the corresponding mapping based on their +// address. +func ParseProcMaps(rd io.Reader) ([]*Mapping, error) { + s := bufio.NewScanner(rd) + return parseProcMapsFromScanner(s) +} + +func parseProcMapsFromScanner(s *bufio.Scanner) ([]*Mapping, error) { + var mapping []*Mapping + + var attrs []string + const delimiter = "=" + r := strings.NewReplacer() + for s.Scan() { + line := r.Replace(removeLoggingInfo(s.Text())) + m, err := parseMappingEntry(line) + if err != nil { + if err == errUnrecognized { + // Recognize assignments of the form: attr=value, and replace + // $attr with value on subsequent mappings. + if attr := strings.SplitN(line, delimiter, 2); len(attr) == 2 { + attrs = append(attrs, "$"+strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1])) + r = strings.NewReplacer(attrs...) + } + // Ignore any unrecognized entries + continue + } + return nil, err + } + if m == nil { + continue + } + mapping = append(mapping, m) + } + if err := s.Err(); err != nil { + return nil, err + } + return mapping, nil +} + +// removeLoggingInfo detects and removes log prefix entries generated +// by the glog package. If no logging prefix is detected, the string +// is returned unmodified. +func removeLoggingInfo(line string) string { + if match := logInfoRE.FindStringIndex(line); match != nil { + return line[match[1]:] + } + return line +} + +// ParseMemoryMap parses a memory map in the format of +// /proc/self/maps, and overrides the mappings in the current profile. +// It renumbers the samples and locations in the profile correspondingly. +func (p *Profile) ParseMemoryMap(rd io.Reader) error { + return p.ParseMemoryMapFromScanner(bufio.NewScanner(rd)) +} + +// ParseMemoryMapFromScanner parses a memory map in the format of +// /proc/self/maps or a variety of legacy format, and overrides the +// mappings in the current profile. It renumbers the samples and +// locations in the profile correspondingly. +func (p *Profile) ParseMemoryMapFromScanner(s *bufio.Scanner) error { + mapping, err := parseProcMapsFromScanner(s) + if err != nil { + return err + } + p.Mapping = append(p.Mapping, mapping...) + p.massageMappings() + p.remapLocationIDs() + p.remapFunctionIDs() + p.remapMappingIDs() + return nil +} + +func parseMappingEntry(l string) (*Mapping, error) { + var start, end, perm, file, offset, buildID string + if me := procMapsRE.FindStringSubmatch(l); len(me) == 6 { + start, end, perm, offset, file = me[1], me[2], me[3], me[4], me[5] + } else if me := briefMapsRE.FindStringSubmatch(l); len(me) == 7 { + start, end, perm, file, offset, buildID = me[1], me[2], me[3], me[4], me[5], me[6] + } else { + return nil, errUnrecognized + } + + var err error + mapping := &Mapping{ + File: file, + BuildID: buildID, + } + if perm != "" && !strings.Contains(perm, "x") { + // Skip non-executable entries. + return nil, nil + } + if mapping.Start, err = strconv.ParseUint(start, 16, 64); err != nil { + return nil, errUnrecognized + } + if mapping.Limit, err = strconv.ParseUint(end, 16, 64); err != nil { + return nil, errUnrecognized + } + if offset != "" { + if mapping.Offset, err = strconv.ParseUint(offset, 16, 64); err != nil { + return nil, errUnrecognized + } + } + return mapping, nil +} + +var memoryMapSentinels = []string{ + "--- Memory map: ---", + "MAPPED_LIBRARIES:", +} + +// isMemoryMapSentinel returns true if the string contains one of the +// known sentinels for memory map information. +func isMemoryMapSentinel(line string) bool { + for _, s := range memoryMapSentinels { + if strings.Contains(line, s) { + return true + } + } + return false +} + +func (p *Profile) addLegacyFrameInfo() { + switch { + case isProfileType(p, heapzSampleTypes): + p.DropFrames, p.KeepFrames = allocRxStr, allocSkipRxStr + case isProfileType(p, contentionzSampleTypes): + p.DropFrames, p.KeepFrames = lockRxStr, "" + default: + p.DropFrames, p.KeepFrames = cpuProfilerRxStr, "" + } +} + +var heapzSampleTypes = [][]string{ + {"allocations", "size"}, // early Go pprof profiles + {"objects", "space"}, + {"inuse_objects", "inuse_space"}, + {"alloc_objects", "alloc_space"}, + {"alloc_objects", "alloc_space", "inuse_objects", "inuse_space"}, // Go pprof legacy profiles +} +var contentionzSampleTypes = [][]string{ + {"contentions", "delay"}, +} + +func isProfileType(p *Profile, types [][]string) bool { + st := p.SampleType +nextType: + for _, t := range types { + if len(st) != len(t) { + continue + } + + for i := range st { + if st[i].Type != t[i] { + continue nextType + } + } + return true + } + return false +} + +var allocRxStr = strings.Join([]string{ + // POSIX entry points. + `calloc`, + `cfree`, + `malloc`, + `free`, + `memalign`, + `do_memalign`, + `(__)?posix_memalign`, + `pvalloc`, + `valloc`, + `realloc`, + + // TC malloc. + `tcmalloc::.*`, + `tc_calloc`, + `tc_cfree`, + `tc_malloc`, + `tc_free`, + `tc_memalign`, + `tc_posix_memalign`, + `tc_pvalloc`, + `tc_valloc`, + `tc_realloc`, + `tc_new`, + `tc_delete`, + `tc_newarray`, + `tc_deletearray`, + `tc_new_nothrow`, + `tc_newarray_nothrow`, + + // Memory-allocation routines on OS X. + `malloc_zone_malloc`, + `malloc_zone_calloc`, + `malloc_zone_valloc`, + `malloc_zone_realloc`, + `malloc_zone_memalign`, + `malloc_zone_free`, + + // Go runtime + `runtime\..*`, + + // Other misc. memory allocation routines + `BaseArena::.*`, + `(::)?do_malloc_no_errno`, + `(::)?do_malloc_pages`, + `(::)?do_malloc`, + `DoSampledAllocation`, + `MallocedMemBlock::MallocedMemBlock`, + `_M_allocate`, + `__builtin_(vec_)?delete`, + `__builtin_(vec_)?new`, + `__gnu_cxx::new_allocator::allocate`, + `__libc_malloc`, + `__malloc_alloc_template::allocate`, + `allocate`, + `cpp_alloc`, + `operator new(\[\])?`, + `simple_alloc::allocate`, +}, `|`) + +var allocSkipRxStr = strings.Join([]string{ + // Preserve Go runtime frames that appear in the middle/bottom of + // the stack. + `runtime\.panic`, + `runtime\.reflectcall`, + `runtime\.call[0-9]*`, +}, `|`) + +var cpuProfilerRxStr = strings.Join([]string{ + `ProfileData::Add`, + `ProfileData::prof_handler`, + `CpuProfiler::prof_handler`, + `__pthread_sighandler`, + `__restore`, +}, `|`) + +var lockRxStr = strings.Join([]string{ + `RecordLockProfileData`, + `(base::)?RecordLockProfileData.*`, + `(base::)?SubmitMutexProfileData.*`, + `(base::)?SubmitSpinLockProfileData.*`, + `(base::Mutex::)?AwaitCommon.*`, + `(base::Mutex::)?Unlock.*`, + `(base::Mutex::)?UnlockSlow.*`, + `(base::Mutex::)?ReaderUnlock.*`, + `(base::MutexLock::)?~MutexLock.*`, + `(Mutex::)?AwaitCommon.*`, + `(Mutex::)?Unlock.*`, + `(Mutex::)?UnlockSlow.*`, + `(Mutex::)?ReaderUnlock.*`, + `(MutexLock::)?~MutexLock.*`, + `(SpinLock::)?Unlock.*`, + `(SpinLock::)?SlowUnlock.*`, + `(SpinLockHolder::)?~SpinLockHolder.*`, +}, `|`) diff --git a/vendor/github.com/google/pprof/profile/merge.go b/vendor/github.com/google/pprof/profile/merge.go new file mode 100644 index 000000000..9978e7330 --- /dev/null +++ b/vendor/github.com/google/pprof/profile/merge.go @@ -0,0 +1,481 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package profile + +import ( + "fmt" + "sort" + "strconv" + "strings" +) + +// Compact performs garbage collection on a profile to remove any +// unreferenced fields. This is useful to reduce the size of a profile +// after samples or locations have been removed. +func (p *Profile) Compact() *Profile { + p, _ = Merge([]*Profile{p}) + return p +} + +// Merge merges all the profiles in profs into a single Profile. +// Returns a new profile independent of the input profiles. The merged +// profile is compacted to eliminate unused samples, locations, +// functions and mappings. Profiles must have identical profile sample +// and period types or the merge will fail. profile.Period of the +// resulting profile will be the maximum of all profiles, and +// profile.TimeNanos will be the earliest nonzero one. Merges are +// associative with the caveat of the first profile having some +// specialization in how headers are combined. There may be other +// subtleties now or in the future regarding associativity. +func Merge(srcs []*Profile) (*Profile, error) { + if len(srcs) == 0 { + return nil, fmt.Errorf("no profiles to merge") + } + p, err := combineHeaders(srcs) + if err != nil { + return nil, err + } + + pm := &profileMerger{ + p: p, + samples: make(map[sampleKey]*Sample, len(srcs[0].Sample)), + locations: make(map[locationKey]*Location, len(srcs[0].Location)), + functions: make(map[functionKey]*Function, len(srcs[0].Function)), + mappings: make(map[mappingKey]*Mapping, len(srcs[0].Mapping)), + } + + for _, src := range srcs { + // Clear the profile-specific hash tables + pm.locationsByID = make(map[uint64]*Location, len(src.Location)) + pm.functionsByID = make(map[uint64]*Function, len(src.Function)) + pm.mappingsByID = make(map[uint64]mapInfo, len(src.Mapping)) + + if len(pm.mappings) == 0 && len(src.Mapping) > 0 { + // The Mapping list has the property that the first mapping + // represents the main binary. Take the first Mapping we see, + // otherwise the operations below will add mappings in an + // arbitrary order. + pm.mapMapping(src.Mapping[0]) + } + + for _, s := range src.Sample { + if !isZeroSample(s) { + pm.mapSample(s) + } + } + } + + for _, s := range p.Sample { + if isZeroSample(s) { + // If there are any zero samples, re-merge the profile to GC + // them. + return Merge([]*Profile{p}) + } + } + + return p, nil +} + +// Normalize normalizes the source profile by multiplying each value in profile by the +// ratio of the sum of the base profile's values of that sample type to the sum of the +// source profile's value of that sample type. +func (p *Profile) Normalize(pb *Profile) error { + + if err := p.compatible(pb); err != nil { + return err + } + + baseVals := make([]int64, len(p.SampleType)) + for _, s := range pb.Sample { + for i, v := range s.Value { + baseVals[i] += v + } + } + + srcVals := make([]int64, len(p.SampleType)) + for _, s := range p.Sample { + for i, v := range s.Value { + srcVals[i] += v + } + } + + normScale := make([]float64, len(baseVals)) + for i := range baseVals { + if srcVals[i] == 0 { + normScale[i] = 0.0 + } else { + normScale[i] = float64(baseVals[i]) / float64(srcVals[i]) + } + } + p.ScaleN(normScale) + return nil +} + +func isZeroSample(s *Sample) bool { + for _, v := range s.Value { + if v != 0 { + return false + } + } + return true +} + +type profileMerger struct { + p *Profile + + // Memoization tables within a profile. + locationsByID map[uint64]*Location + functionsByID map[uint64]*Function + mappingsByID map[uint64]mapInfo + + // Memoization tables for profile entities. + samples map[sampleKey]*Sample + locations map[locationKey]*Location + functions map[functionKey]*Function + mappings map[mappingKey]*Mapping +} + +type mapInfo struct { + m *Mapping + offset int64 +} + +func (pm *profileMerger) mapSample(src *Sample) *Sample { + s := &Sample{ + Location: make([]*Location, len(src.Location)), + Value: make([]int64, len(src.Value)), + Label: make(map[string][]string, len(src.Label)), + NumLabel: make(map[string][]int64, len(src.NumLabel)), + NumUnit: make(map[string][]string, len(src.NumLabel)), + } + for i, l := range src.Location { + s.Location[i] = pm.mapLocation(l) + } + for k, v := range src.Label { + vv := make([]string, len(v)) + copy(vv, v) + s.Label[k] = vv + } + for k, v := range src.NumLabel { + u := src.NumUnit[k] + vv := make([]int64, len(v)) + uu := make([]string, len(u)) + copy(vv, v) + copy(uu, u) + s.NumLabel[k] = vv + s.NumUnit[k] = uu + } + // Check memoization table. Must be done on the remapped location to + // account for the remapped mapping. Add current values to the + // existing sample. + k := s.key() + if ss, ok := pm.samples[k]; ok { + for i, v := range src.Value { + ss.Value[i] += v + } + return ss + } + copy(s.Value, src.Value) + pm.samples[k] = s + pm.p.Sample = append(pm.p.Sample, s) + return s +} + +// key generates sampleKey to be used as a key for maps. +func (sample *Sample) key() sampleKey { + ids := make([]string, len(sample.Location)) + for i, l := range sample.Location { + ids[i] = strconv.FormatUint(l.ID, 16) + } + + labels := make([]string, 0, len(sample.Label)) + for k, v := range sample.Label { + labels = append(labels, fmt.Sprintf("%q%q", k, v)) + } + sort.Strings(labels) + + numlabels := make([]string, 0, len(sample.NumLabel)) + for k, v := range sample.NumLabel { + numlabels = append(numlabels, fmt.Sprintf("%q%x%x", k, v, sample.NumUnit[k])) + } + sort.Strings(numlabels) + + return sampleKey{ + strings.Join(ids, "|"), + strings.Join(labels, ""), + strings.Join(numlabels, ""), + } +} + +type sampleKey struct { + locations string + labels string + numlabels string +} + +func (pm *profileMerger) mapLocation(src *Location) *Location { + if src == nil { + return nil + } + + if l, ok := pm.locationsByID[src.ID]; ok { + return l + } + + mi := pm.mapMapping(src.Mapping) + l := &Location{ + ID: uint64(len(pm.p.Location) + 1), + Mapping: mi.m, + Address: uint64(int64(src.Address) + mi.offset), + Line: make([]Line, len(src.Line)), + IsFolded: src.IsFolded, + } + for i, ln := range src.Line { + l.Line[i] = pm.mapLine(ln) + } + // Check memoization table. Must be done on the remapped location to + // account for the remapped mapping ID. + k := l.key() + if ll, ok := pm.locations[k]; ok { + pm.locationsByID[src.ID] = ll + return ll + } + pm.locationsByID[src.ID] = l + pm.locations[k] = l + pm.p.Location = append(pm.p.Location, l) + return l +} + +// key generates locationKey to be used as a key for maps. +func (l *Location) key() locationKey { + key := locationKey{ + addr: l.Address, + isFolded: l.IsFolded, + } + if l.Mapping != nil { + // Normalizes address to handle address space randomization. + key.addr -= l.Mapping.Start + key.mappingID = l.Mapping.ID + } + lines := make([]string, len(l.Line)*2) + for i, line := range l.Line { + if line.Function != nil { + lines[i*2] = strconv.FormatUint(line.Function.ID, 16) + } + lines[i*2+1] = strconv.FormatInt(line.Line, 16) + } + key.lines = strings.Join(lines, "|") + return key +} + +type locationKey struct { + addr, mappingID uint64 + lines string + isFolded bool +} + +func (pm *profileMerger) mapMapping(src *Mapping) mapInfo { + if src == nil { + return mapInfo{} + } + + if mi, ok := pm.mappingsByID[src.ID]; ok { + return mi + } + + // Check memoization tables. + mk := src.key() + if m, ok := pm.mappings[mk]; ok { + mi := mapInfo{m, int64(m.Start) - int64(src.Start)} + pm.mappingsByID[src.ID] = mi + return mi + } + m := &Mapping{ + ID: uint64(len(pm.p.Mapping) + 1), + Start: src.Start, + Limit: src.Limit, + Offset: src.Offset, + File: src.File, + BuildID: src.BuildID, + HasFunctions: src.HasFunctions, + HasFilenames: src.HasFilenames, + HasLineNumbers: src.HasLineNumbers, + HasInlineFrames: src.HasInlineFrames, + } + pm.p.Mapping = append(pm.p.Mapping, m) + + // Update memoization tables. + pm.mappings[mk] = m + mi := mapInfo{m, 0} + pm.mappingsByID[src.ID] = mi + return mi +} + +// key generates encoded strings of Mapping to be used as a key for +// maps. +func (m *Mapping) key() mappingKey { + // Normalize addresses to handle address space randomization. + // Round up to next 4K boundary to avoid minor discrepancies. + const mapsizeRounding = 0x1000 + + size := m.Limit - m.Start + size = size + mapsizeRounding - 1 + size = size - (size % mapsizeRounding) + key := mappingKey{ + size: size, + offset: m.Offset, + } + + switch { + case m.BuildID != "": + key.buildIDOrFile = m.BuildID + case m.File != "": + key.buildIDOrFile = m.File + default: + // A mapping containing neither build ID nor file name is a fake mapping. A + // key with empty buildIDOrFile is used for fake mappings so that they are + // treated as the same mapping during merging. + } + return key +} + +type mappingKey struct { + size, offset uint64 + buildIDOrFile string +} + +func (pm *profileMerger) mapLine(src Line) Line { + ln := Line{ + Function: pm.mapFunction(src.Function), + Line: src.Line, + } + return ln +} + +func (pm *profileMerger) mapFunction(src *Function) *Function { + if src == nil { + return nil + } + if f, ok := pm.functionsByID[src.ID]; ok { + return f + } + k := src.key() + if f, ok := pm.functions[k]; ok { + pm.functionsByID[src.ID] = f + return f + } + f := &Function{ + ID: uint64(len(pm.p.Function) + 1), + Name: src.Name, + SystemName: src.SystemName, + Filename: src.Filename, + StartLine: src.StartLine, + } + pm.functions[k] = f + pm.functionsByID[src.ID] = f + pm.p.Function = append(pm.p.Function, f) + return f +} + +// key generates a struct to be used as a key for maps. +func (f *Function) key() functionKey { + return functionKey{ + f.StartLine, + f.Name, + f.SystemName, + f.Filename, + } +} + +type functionKey struct { + startLine int64 + name, systemName, fileName string +} + +// combineHeaders checks that all profiles can be merged and returns +// their combined profile. +func combineHeaders(srcs []*Profile) (*Profile, error) { + for _, s := range srcs[1:] { + if err := srcs[0].compatible(s); err != nil { + return nil, err + } + } + + var timeNanos, durationNanos, period int64 + var comments []string + seenComments := map[string]bool{} + var defaultSampleType string + for _, s := range srcs { + if timeNanos == 0 || s.TimeNanos < timeNanos { + timeNanos = s.TimeNanos + } + durationNanos += s.DurationNanos + if period == 0 || period < s.Period { + period = s.Period + } + for _, c := range s.Comments { + if seen := seenComments[c]; !seen { + comments = append(comments, c) + seenComments[c] = true + } + } + if defaultSampleType == "" { + defaultSampleType = s.DefaultSampleType + } + } + + p := &Profile{ + SampleType: make([]*ValueType, len(srcs[0].SampleType)), + + DropFrames: srcs[0].DropFrames, + KeepFrames: srcs[0].KeepFrames, + + TimeNanos: timeNanos, + DurationNanos: durationNanos, + PeriodType: srcs[0].PeriodType, + Period: period, + + Comments: comments, + DefaultSampleType: defaultSampleType, + } + copy(p.SampleType, srcs[0].SampleType) + return p, nil +} + +// compatible determines if two profiles can be compared/merged. +// returns nil if the profiles are compatible; otherwise an error with +// details on the incompatibility. +func (p *Profile) compatible(pb *Profile) error { + if !equalValueType(p.PeriodType, pb.PeriodType) { + return fmt.Errorf("incompatible period types %v and %v", p.PeriodType, pb.PeriodType) + } + + if len(p.SampleType) != len(pb.SampleType) { + return fmt.Errorf("incompatible sample types %v and %v", p.SampleType, pb.SampleType) + } + + for i := range p.SampleType { + if !equalValueType(p.SampleType[i], pb.SampleType[i]) { + return fmt.Errorf("incompatible sample types %v and %v", p.SampleType, pb.SampleType) + } + } + return nil +} + +// equalValueType returns true if the two value types are semantically +// equal. It ignores the internal fields used during encode/decode. +func equalValueType(st1, st2 *ValueType) bool { + return st1.Type == st2.Type && st1.Unit == st2.Unit +} diff --git a/vendor/github.com/google/pprof/profile/profile.go b/vendor/github.com/google/pprof/profile/profile.go new file mode 100644 index 000000000..2590c8ddb --- /dev/null +++ b/vendor/github.com/google/pprof/profile/profile.go @@ -0,0 +1,805 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package profile provides a representation of profile.proto and +// methods to encode/decode profiles in this format. +package profile + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "math" + "path/filepath" + "regexp" + "sort" + "strings" + "sync" + "time" +) + +// Profile is an in-memory representation of profile.proto. +type Profile struct { + SampleType []*ValueType + DefaultSampleType string + Sample []*Sample + Mapping []*Mapping + Location []*Location + Function []*Function + Comments []string + + DropFrames string + KeepFrames string + + TimeNanos int64 + DurationNanos int64 + PeriodType *ValueType + Period int64 + + // The following fields are modified during encoding and copying, + // so are protected by a Mutex. + encodeMu sync.Mutex + + commentX []int64 + dropFramesX int64 + keepFramesX int64 + stringTable []string + defaultSampleTypeX int64 +} + +// ValueType corresponds to Profile.ValueType +type ValueType struct { + Type string // cpu, wall, inuse_space, etc + Unit string // seconds, nanoseconds, bytes, etc + + typeX int64 + unitX int64 +} + +// Sample corresponds to Profile.Sample +type Sample struct { + Location []*Location + Value []int64 + Label map[string][]string + NumLabel map[string][]int64 + NumUnit map[string][]string + + locationIDX []uint64 + labelX []label +} + +// label corresponds to Profile.Label +type label struct { + keyX int64 + // Exactly one of the two following values must be set + strX int64 + numX int64 // Integer value for this label + // can be set if numX has value + unitX int64 +} + +// Mapping corresponds to Profile.Mapping +type Mapping struct { + ID uint64 + Start uint64 + Limit uint64 + Offset uint64 + File string + BuildID string + HasFunctions bool + HasFilenames bool + HasLineNumbers bool + HasInlineFrames bool + + fileX int64 + buildIDX int64 +} + +// Location corresponds to Profile.Location +type Location struct { + ID uint64 + Mapping *Mapping + Address uint64 + Line []Line + IsFolded bool + + mappingIDX uint64 +} + +// Line corresponds to Profile.Line +type Line struct { + Function *Function + Line int64 + + functionIDX uint64 +} + +// Function corresponds to Profile.Function +type Function struct { + ID uint64 + Name string + SystemName string + Filename string + StartLine int64 + + nameX int64 + systemNameX int64 + filenameX int64 +} + +// Parse parses a profile and checks for its validity. The input +// may be a gzip-compressed encoded protobuf or one of many legacy +// profile formats which may be unsupported in the future. +func Parse(r io.Reader) (*Profile, error) { + data, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + return ParseData(data) +} + +// ParseData parses a profile from a buffer and checks for its +// validity. +func ParseData(data []byte) (*Profile, error) { + var p *Profile + var err error + if len(data) >= 2 && data[0] == 0x1f && data[1] == 0x8b { + gz, err := gzip.NewReader(bytes.NewBuffer(data)) + if err == nil { + data, err = ioutil.ReadAll(gz) + } + if err != nil { + return nil, fmt.Errorf("decompressing profile: %v", err) + } + } + if p, err = ParseUncompressed(data); err != nil && err != errNoData && err != errConcatProfile { + p, err = parseLegacy(data) + } + + if err != nil { + return nil, fmt.Errorf("parsing profile: %v", err) + } + + if err := p.CheckValid(); err != nil { + return nil, fmt.Errorf("malformed profile: %v", err) + } + return p, nil +} + +var errUnrecognized = fmt.Errorf("unrecognized profile format") +var errMalformed = fmt.Errorf("malformed profile format") +var errNoData = fmt.Errorf("empty input file") +var errConcatProfile = fmt.Errorf("concatenated profiles detected") + +func parseLegacy(data []byte) (*Profile, error) { + parsers := []func([]byte) (*Profile, error){ + parseCPU, + parseHeap, + parseGoCount, // goroutine, threadcreate + parseThread, + parseContention, + parseJavaProfile, + } + + for _, parser := range parsers { + p, err := parser(data) + if err == nil { + p.addLegacyFrameInfo() + return p, nil + } + if err != errUnrecognized { + return nil, err + } + } + return nil, errUnrecognized +} + +// ParseUncompressed parses an uncompressed protobuf into a profile. +func ParseUncompressed(data []byte) (*Profile, error) { + if len(data) == 0 { + return nil, errNoData + } + p := &Profile{} + if err := unmarshal(data, p); err != nil { + return nil, err + } + + if err := p.postDecode(); err != nil { + return nil, err + } + + return p, nil +} + +var libRx = regexp.MustCompile(`([.]so$|[.]so[._][0-9]+)`) + +// massageMappings applies heuristic-based changes to the profile +// mappings to account for quirks of some environments. +func (p *Profile) massageMappings() { + // Merge adjacent regions with matching names, checking that the offsets match + if len(p.Mapping) > 1 { + mappings := []*Mapping{p.Mapping[0]} + for _, m := range p.Mapping[1:] { + lm := mappings[len(mappings)-1] + if adjacent(lm, m) { + lm.Limit = m.Limit + if m.File != "" { + lm.File = m.File + } + if m.BuildID != "" { + lm.BuildID = m.BuildID + } + p.updateLocationMapping(m, lm) + continue + } + mappings = append(mappings, m) + } + p.Mapping = mappings + } + + // Use heuristics to identify main binary and move it to the top of the list of mappings + for i, m := range p.Mapping { + file := strings.TrimSpace(strings.Replace(m.File, "(deleted)", "", -1)) + if len(file) == 0 { + continue + } + if len(libRx.FindStringSubmatch(file)) > 0 { + continue + } + if file[0] == '[' { + continue + } + // Swap what we guess is main to position 0. + p.Mapping[0], p.Mapping[i] = p.Mapping[i], p.Mapping[0] + break + } + + // Keep the mapping IDs neatly sorted + for i, m := range p.Mapping { + m.ID = uint64(i + 1) + } +} + +// adjacent returns whether two mapping entries represent the same +// mapping that has been split into two. Check that their addresses are adjacent, +// and if the offsets match, if they are available. +func adjacent(m1, m2 *Mapping) bool { + if m1.File != "" && m2.File != "" { + if m1.File != m2.File { + return false + } + } + if m1.BuildID != "" && m2.BuildID != "" { + if m1.BuildID != m2.BuildID { + return false + } + } + if m1.Limit != m2.Start { + return false + } + if m1.Offset != 0 && m2.Offset != 0 { + offset := m1.Offset + (m1.Limit - m1.Start) + if offset != m2.Offset { + return false + } + } + return true +} + +func (p *Profile) updateLocationMapping(from, to *Mapping) { + for _, l := range p.Location { + if l.Mapping == from { + l.Mapping = to + } + } +} + +func serialize(p *Profile) []byte { + p.encodeMu.Lock() + p.preEncode() + b := marshal(p) + p.encodeMu.Unlock() + return b +} + +// Write writes the profile as a gzip-compressed marshaled protobuf. +func (p *Profile) Write(w io.Writer) error { + zw := gzip.NewWriter(w) + defer zw.Close() + _, err := zw.Write(serialize(p)) + return err +} + +// WriteUncompressed writes the profile as a marshaled protobuf. +func (p *Profile) WriteUncompressed(w io.Writer) error { + _, err := w.Write(serialize(p)) + return err +} + +// CheckValid tests whether the profile is valid. Checks include, but are +// not limited to: +// - len(Profile.Sample[n].value) == len(Profile.value_unit) +// - Sample.id has a corresponding Profile.Location +func (p *Profile) CheckValid() error { + // Check that sample values are consistent + sampleLen := len(p.SampleType) + if sampleLen == 0 && len(p.Sample) != 0 { + return fmt.Errorf("missing sample type information") + } + for _, s := range p.Sample { + if s == nil { + return fmt.Errorf("profile has nil sample") + } + if len(s.Value) != sampleLen { + return fmt.Errorf("mismatch: sample has %d values vs. %d types", len(s.Value), len(p.SampleType)) + } + for _, l := range s.Location { + if l == nil { + return fmt.Errorf("sample has nil location") + } + } + } + + // Check that all mappings/locations/functions are in the tables + // Check that there are no duplicate ids + mappings := make(map[uint64]*Mapping, len(p.Mapping)) + for _, m := range p.Mapping { + if m == nil { + return fmt.Errorf("profile has nil mapping") + } + if m.ID == 0 { + return fmt.Errorf("found mapping with reserved ID=0") + } + if mappings[m.ID] != nil { + return fmt.Errorf("multiple mappings with same id: %d", m.ID) + } + mappings[m.ID] = m + } + functions := make(map[uint64]*Function, len(p.Function)) + for _, f := range p.Function { + if f == nil { + return fmt.Errorf("profile has nil function") + } + if f.ID == 0 { + return fmt.Errorf("found function with reserved ID=0") + } + if functions[f.ID] != nil { + return fmt.Errorf("multiple functions with same id: %d", f.ID) + } + functions[f.ID] = f + } + locations := make(map[uint64]*Location, len(p.Location)) + for _, l := range p.Location { + if l == nil { + return fmt.Errorf("profile has nil location") + } + if l.ID == 0 { + return fmt.Errorf("found location with reserved id=0") + } + if locations[l.ID] != nil { + return fmt.Errorf("multiple locations with same id: %d", l.ID) + } + locations[l.ID] = l + if m := l.Mapping; m != nil { + if m.ID == 0 || mappings[m.ID] != m { + return fmt.Errorf("inconsistent mapping %p: %d", m, m.ID) + } + } + for _, ln := range l.Line { + f := ln.Function + if f == nil { + return fmt.Errorf("location id: %d has a line with nil function", l.ID) + } + if f.ID == 0 || functions[f.ID] != f { + return fmt.Errorf("inconsistent function %p: %d", f, f.ID) + } + } + } + return nil +} + +// Aggregate merges the locations in the profile into equivalence +// classes preserving the request attributes. It also updates the +// samples to point to the merged locations. +func (p *Profile) Aggregate(inlineFrame, function, filename, linenumber, address bool) error { + for _, m := range p.Mapping { + m.HasInlineFrames = m.HasInlineFrames && inlineFrame + m.HasFunctions = m.HasFunctions && function + m.HasFilenames = m.HasFilenames && filename + m.HasLineNumbers = m.HasLineNumbers && linenumber + } + + // Aggregate functions + if !function || !filename { + for _, f := range p.Function { + if !function { + f.Name = "" + f.SystemName = "" + } + if !filename { + f.Filename = "" + } + } + } + + // Aggregate locations + if !inlineFrame || !address || !linenumber { + for _, l := range p.Location { + if !inlineFrame && len(l.Line) > 1 { + l.Line = l.Line[len(l.Line)-1:] + } + if !linenumber { + for i := range l.Line { + l.Line[i].Line = 0 + } + } + if !address { + l.Address = 0 + } + } + } + + return p.CheckValid() +} + +// NumLabelUnits returns a map of numeric label keys to the units +// associated with those keys and a map of those keys to any units +// that were encountered but not used. +// Unit for a given key is the first encountered unit for that key. If multiple +// units are encountered for values paired with a particular key, then the first +// unit encountered is used and all other units are returned in sorted order +// in map of ignored units. +// If no units are encountered for a particular key, the unit is then inferred +// based on the key. +func (p *Profile) NumLabelUnits() (map[string]string, map[string][]string) { + numLabelUnits := map[string]string{} + ignoredUnits := map[string]map[string]bool{} + encounteredKeys := map[string]bool{} + + // Determine units based on numeric tags for each sample. + for _, s := range p.Sample { + for k := range s.NumLabel { + encounteredKeys[k] = true + for _, unit := range s.NumUnit[k] { + if unit == "" { + continue + } + if wantUnit, ok := numLabelUnits[k]; !ok { + numLabelUnits[k] = unit + } else if wantUnit != unit { + if v, ok := ignoredUnits[k]; ok { + v[unit] = true + } else { + ignoredUnits[k] = map[string]bool{unit: true} + } + } + } + } + } + // Infer units for keys without any units associated with + // numeric tag values. + for key := range encounteredKeys { + unit := numLabelUnits[key] + if unit == "" { + switch key { + case "alignment", "request": + numLabelUnits[key] = "bytes" + default: + numLabelUnits[key] = key + } + } + } + + // Copy ignored units into more readable format + unitsIgnored := make(map[string][]string, len(ignoredUnits)) + for key, values := range ignoredUnits { + units := make([]string, len(values)) + i := 0 + for unit := range values { + units[i] = unit + i++ + } + sort.Strings(units) + unitsIgnored[key] = units + } + + return numLabelUnits, unitsIgnored +} + +// String dumps a text representation of a profile. Intended mainly +// for debugging purposes. +func (p *Profile) String() string { + ss := make([]string, 0, len(p.Comments)+len(p.Sample)+len(p.Mapping)+len(p.Location)) + for _, c := range p.Comments { + ss = append(ss, "Comment: "+c) + } + if pt := p.PeriodType; pt != nil { + ss = append(ss, fmt.Sprintf("PeriodType: %s %s", pt.Type, pt.Unit)) + } + ss = append(ss, fmt.Sprintf("Period: %d", p.Period)) + if p.TimeNanos != 0 { + ss = append(ss, fmt.Sprintf("Time: %v", time.Unix(0, p.TimeNanos))) + } + if p.DurationNanos != 0 { + ss = append(ss, fmt.Sprintf("Duration: %.4v", time.Duration(p.DurationNanos))) + } + + ss = append(ss, "Samples:") + var sh1 string + for _, s := range p.SampleType { + dflt := "" + if s.Type == p.DefaultSampleType { + dflt = "[dflt]" + } + sh1 = sh1 + fmt.Sprintf("%s/%s%s ", s.Type, s.Unit, dflt) + } + ss = append(ss, strings.TrimSpace(sh1)) + for _, s := range p.Sample { + ss = append(ss, s.string()) + } + + ss = append(ss, "Locations") + for _, l := range p.Location { + ss = append(ss, l.string()) + } + + ss = append(ss, "Mappings") + for _, m := range p.Mapping { + ss = append(ss, m.string()) + } + + return strings.Join(ss, "\n") + "\n" +} + +// string dumps a text representation of a mapping. Intended mainly +// for debugging purposes. +func (m *Mapping) string() string { + bits := "" + if m.HasFunctions { + bits = bits + "[FN]" + } + if m.HasFilenames { + bits = bits + "[FL]" + } + if m.HasLineNumbers { + bits = bits + "[LN]" + } + if m.HasInlineFrames { + bits = bits + "[IN]" + } + return fmt.Sprintf("%d: %#x/%#x/%#x %s %s %s", + m.ID, + m.Start, m.Limit, m.Offset, + m.File, + m.BuildID, + bits) +} + +// string dumps a text representation of a location. Intended mainly +// for debugging purposes. +func (l *Location) string() string { + ss := []string{} + locStr := fmt.Sprintf("%6d: %#x ", l.ID, l.Address) + if m := l.Mapping; m != nil { + locStr = locStr + fmt.Sprintf("M=%d ", m.ID) + } + if l.IsFolded { + locStr = locStr + "[F] " + } + if len(l.Line) == 0 { + ss = append(ss, locStr) + } + for li := range l.Line { + lnStr := "??" + if fn := l.Line[li].Function; fn != nil { + lnStr = fmt.Sprintf("%s %s:%d s=%d", + fn.Name, + fn.Filename, + l.Line[li].Line, + fn.StartLine) + if fn.Name != fn.SystemName { + lnStr = lnStr + "(" + fn.SystemName + ")" + } + } + ss = append(ss, locStr+lnStr) + // Do not print location details past the first line + locStr = " " + } + return strings.Join(ss, "\n") +} + +// string dumps a text representation of a sample. Intended mainly +// for debugging purposes. +func (s *Sample) string() string { + ss := []string{} + var sv string + for _, v := range s.Value { + sv = fmt.Sprintf("%s %10d", sv, v) + } + sv = sv + ": " + for _, l := range s.Location { + sv = sv + fmt.Sprintf("%d ", l.ID) + } + ss = append(ss, sv) + const labelHeader = " " + if len(s.Label) > 0 { + ss = append(ss, labelHeader+labelsToString(s.Label)) + } + if len(s.NumLabel) > 0 { + ss = append(ss, labelHeader+numLabelsToString(s.NumLabel, s.NumUnit)) + } + return strings.Join(ss, "\n") +} + +// labelsToString returns a string representation of a +// map representing labels. +func labelsToString(labels map[string][]string) string { + ls := []string{} + for k, v := range labels { + ls = append(ls, fmt.Sprintf("%s:%v", k, v)) + } + sort.Strings(ls) + return strings.Join(ls, " ") +} + +// numLabelsToString returns a string representation of a map +// representing numeric labels. +func numLabelsToString(numLabels map[string][]int64, numUnits map[string][]string) string { + ls := []string{} + for k, v := range numLabels { + units := numUnits[k] + var labelString string + if len(units) == len(v) { + values := make([]string, len(v)) + for i, vv := range v { + values[i] = fmt.Sprintf("%d %s", vv, units[i]) + } + labelString = fmt.Sprintf("%s:%v", k, values) + } else { + labelString = fmt.Sprintf("%s:%v", k, v) + } + ls = append(ls, labelString) + } + sort.Strings(ls) + return strings.Join(ls, " ") +} + +// SetLabel sets the specified key to the specified value for all samples in the +// profile. +func (p *Profile) SetLabel(key string, value []string) { + for _, sample := range p.Sample { + if sample.Label == nil { + sample.Label = map[string][]string{key: value} + } else { + sample.Label[key] = value + } + } +} + +// RemoveLabel removes all labels associated with the specified key for all +// samples in the profile. +func (p *Profile) RemoveLabel(key string) { + for _, sample := range p.Sample { + delete(sample.Label, key) + } +} + +// HasLabel returns true if a sample has a label with indicated key and value. +func (s *Sample) HasLabel(key, value string) bool { + for _, v := range s.Label[key] { + if v == value { + return true + } + } + return false +} + +// DiffBaseSample returns true if a sample belongs to the diff base and false +// otherwise. +func (s *Sample) DiffBaseSample() bool { + return s.HasLabel("pprof::base", "true") +} + +// Scale multiplies all sample values in a profile by a constant and keeps +// only samples that have at least one non-zero value. +func (p *Profile) Scale(ratio float64) { + if ratio == 1 { + return + } + ratios := make([]float64, len(p.SampleType)) + for i := range p.SampleType { + ratios[i] = ratio + } + p.ScaleN(ratios) +} + +// ScaleN multiplies each sample values in a sample by a different amount +// and keeps only samples that have at least one non-zero value. +func (p *Profile) ScaleN(ratios []float64) error { + if len(p.SampleType) != len(ratios) { + return fmt.Errorf("mismatched scale ratios, got %d, want %d", len(ratios), len(p.SampleType)) + } + allOnes := true + for _, r := range ratios { + if r != 1 { + allOnes = false + break + } + } + if allOnes { + return nil + } + fillIdx := 0 + for _, s := range p.Sample { + keepSample := false + for i, v := range s.Value { + if ratios[i] != 1 { + val := int64(math.Round(float64(v) * ratios[i])) + s.Value[i] = val + keepSample = keepSample || val != 0 + } + } + if keepSample { + p.Sample[fillIdx] = s + fillIdx++ + } + } + p.Sample = p.Sample[:fillIdx] + return nil +} + +// HasFunctions determines if all locations in this profile have +// symbolized function information. +func (p *Profile) HasFunctions() bool { + for _, l := range p.Location { + if l.Mapping != nil && !l.Mapping.HasFunctions { + return false + } + } + return true +} + +// HasFileLines determines if all locations in this profile have +// symbolized file and line number information. +func (p *Profile) HasFileLines() bool { + for _, l := range p.Location { + if l.Mapping != nil && (!l.Mapping.HasFilenames || !l.Mapping.HasLineNumbers) { + return false + } + } + return true +} + +// Unsymbolizable returns true if a mapping points to a binary for which +// locations can't be symbolized in principle, at least now. Examples are +// "[vdso]", [vsyscall]" and some others, see the code. +func (m *Mapping) Unsymbolizable() bool { + name := filepath.Base(m.File) + return strings.HasPrefix(name, "[") || strings.HasPrefix(name, "linux-vdso") || strings.HasPrefix(m.File, "/dev/dri/") +} + +// Copy makes a fully independent copy of a profile. +func (p *Profile) Copy() *Profile { + pp := &Profile{} + if err := unmarshal(serialize(p), pp); err != nil { + panic(err) + } + if err := pp.postDecode(); err != nil { + panic(err) + } + + return pp +} diff --git a/vendor/github.com/google/pprof/profile/proto.go b/vendor/github.com/google/pprof/profile/proto.go new file mode 100644 index 000000000..539ad3ab3 --- /dev/null +++ b/vendor/github.com/google/pprof/profile/proto.go @@ -0,0 +1,370 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file is a simple protocol buffer encoder and decoder. +// The format is described at +// https://developers.google.com/protocol-buffers/docs/encoding +// +// A protocol message must implement the message interface: +// decoder() []decoder +// encode(*buffer) +// +// The decode method returns a slice indexed by field number that gives the +// function to decode that field. +// The encode method encodes its receiver into the given buffer. +// +// The two methods are simple enough to be implemented by hand rather than +// by using a protocol compiler. +// +// See profile.go for examples of messages implementing this interface. +// +// There is no support for groups, message sets, or "has" bits. + +package profile + +import ( + "errors" + "fmt" +) + +type buffer struct { + field int // field tag + typ int // proto wire type code for field + u64 uint64 + data []byte + tmp [16]byte +} + +type decoder func(*buffer, message) error + +type message interface { + decoder() []decoder + encode(*buffer) +} + +func marshal(m message) []byte { + var b buffer + m.encode(&b) + return b.data +} + +func encodeVarint(b *buffer, x uint64) { + for x >= 128 { + b.data = append(b.data, byte(x)|0x80) + x >>= 7 + } + b.data = append(b.data, byte(x)) +} + +func encodeLength(b *buffer, tag int, len int) { + encodeVarint(b, uint64(tag)<<3|2) + encodeVarint(b, uint64(len)) +} + +func encodeUint64(b *buffer, tag int, x uint64) { + // append varint to b.data + encodeVarint(b, uint64(tag)<<3) + encodeVarint(b, x) +} + +func encodeUint64s(b *buffer, tag int, x []uint64) { + if len(x) > 2 { + // Use packed encoding + n1 := len(b.data) + for _, u := range x { + encodeVarint(b, u) + } + n2 := len(b.data) + encodeLength(b, tag, n2-n1) + n3 := len(b.data) + copy(b.tmp[:], b.data[n2:n3]) + copy(b.data[n1+(n3-n2):], b.data[n1:n2]) + copy(b.data[n1:], b.tmp[:n3-n2]) + return + } + for _, u := range x { + encodeUint64(b, tag, u) + } +} + +func encodeUint64Opt(b *buffer, tag int, x uint64) { + if x == 0 { + return + } + encodeUint64(b, tag, x) +} + +func encodeInt64(b *buffer, tag int, x int64) { + u := uint64(x) + encodeUint64(b, tag, u) +} + +func encodeInt64s(b *buffer, tag int, x []int64) { + if len(x) > 2 { + // Use packed encoding + n1 := len(b.data) + for _, u := range x { + encodeVarint(b, uint64(u)) + } + n2 := len(b.data) + encodeLength(b, tag, n2-n1) + n3 := len(b.data) + copy(b.tmp[:], b.data[n2:n3]) + copy(b.data[n1+(n3-n2):], b.data[n1:n2]) + copy(b.data[n1:], b.tmp[:n3-n2]) + return + } + for _, u := range x { + encodeInt64(b, tag, u) + } +} + +func encodeInt64Opt(b *buffer, tag int, x int64) { + if x == 0 { + return + } + encodeInt64(b, tag, x) +} + +func encodeString(b *buffer, tag int, x string) { + encodeLength(b, tag, len(x)) + b.data = append(b.data, x...) +} + +func encodeStrings(b *buffer, tag int, x []string) { + for _, s := range x { + encodeString(b, tag, s) + } +} + +func encodeBool(b *buffer, tag int, x bool) { + if x { + encodeUint64(b, tag, 1) + } else { + encodeUint64(b, tag, 0) + } +} + +func encodeBoolOpt(b *buffer, tag int, x bool) { + if x { + encodeBool(b, tag, x) + } +} + +func encodeMessage(b *buffer, tag int, m message) { + n1 := len(b.data) + m.encode(b) + n2 := len(b.data) + encodeLength(b, tag, n2-n1) + n3 := len(b.data) + copy(b.tmp[:], b.data[n2:n3]) + copy(b.data[n1+(n3-n2):], b.data[n1:n2]) + copy(b.data[n1:], b.tmp[:n3-n2]) +} + +func unmarshal(data []byte, m message) (err error) { + b := buffer{data: data, typ: 2} + return decodeMessage(&b, m) +} + +func le64(p []byte) uint64 { + return uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 | uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56 +} + +func le32(p []byte) uint32 { + return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24 +} + +func decodeVarint(data []byte) (uint64, []byte, error) { + var u uint64 + for i := 0; ; i++ { + if i >= 10 || i >= len(data) { + return 0, nil, errors.New("bad varint") + } + u |= uint64(data[i]&0x7F) << uint(7*i) + if data[i]&0x80 == 0 { + return u, data[i+1:], nil + } + } +} + +func decodeField(b *buffer, data []byte) ([]byte, error) { + x, data, err := decodeVarint(data) + if err != nil { + return nil, err + } + b.field = int(x >> 3) + b.typ = int(x & 7) + b.data = nil + b.u64 = 0 + switch b.typ { + case 0: + b.u64, data, err = decodeVarint(data) + if err != nil { + return nil, err + } + case 1: + if len(data) < 8 { + return nil, errors.New("not enough data") + } + b.u64 = le64(data[:8]) + data = data[8:] + case 2: + var n uint64 + n, data, err = decodeVarint(data) + if err != nil { + return nil, err + } + if n > uint64(len(data)) { + return nil, errors.New("too much data") + } + b.data = data[:n] + data = data[n:] + case 5: + if len(data) < 4 { + return nil, errors.New("not enough data") + } + b.u64 = uint64(le32(data[:4])) + data = data[4:] + default: + return nil, fmt.Errorf("unknown wire type: %d", b.typ) + } + + return data, nil +} + +func checkType(b *buffer, typ int) error { + if b.typ != typ { + return errors.New("type mismatch") + } + return nil +} + +func decodeMessage(b *buffer, m message) error { + if err := checkType(b, 2); err != nil { + return err + } + dec := m.decoder() + data := b.data + for len(data) > 0 { + // pull varint field# + type + var err error + data, err = decodeField(b, data) + if err != nil { + return err + } + if b.field >= len(dec) || dec[b.field] == nil { + continue + } + if err := dec[b.field](b, m); err != nil { + return err + } + } + return nil +} + +func decodeInt64(b *buffer, x *int64) error { + if err := checkType(b, 0); err != nil { + return err + } + *x = int64(b.u64) + return nil +} + +func decodeInt64s(b *buffer, x *[]int64) error { + if b.typ == 2 { + // Packed encoding + data := b.data + tmp := make([]int64, 0, len(data)) // Maximally sized + for len(data) > 0 { + var u uint64 + var err error + + if u, data, err = decodeVarint(data); err != nil { + return err + } + tmp = append(tmp, int64(u)) + } + *x = append(*x, tmp...) + return nil + } + var i int64 + if err := decodeInt64(b, &i); err != nil { + return err + } + *x = append(*x, i) + return nil +} + +func decodeUint64(b *buffer, x *uint64) error { + if err := checkType(b, 0); err != nil { + return err + } + *x = b.u64 + return nil +} + +func decodeUint64s(b *buffer, x *[]uint64) error { + if b.typ == 2 { + data := b.data + // Packed encoding + tmp := make([]uint64, 0, len(data)) // Maximally sized + for len(data) > 0 { + var u uint64 + var err error + + if u, data, err = decodeVarint(data); err != nil { + return err + } + tmp = append(tmp, u) + } + *x = append(*x, tmp...) + return nil + } + var u uint64 + if err := decodeUint64(b, &u); err != nil { + return err + } + *x = append(*x, u) + return nil +} + +func decodeString(b *buffer, x *string) error { + if err := checkType(b, 2); err != nil { + return err + } + *x = string(b.data) + return nil +} + +func decodeStrings(b *buffer, x *[]string) error { + var s string + if err := decodeString(b, &s); err != nil { + return err + } + *x = append(*x, s) + return nil +} + +func decodeBool(b *buffer, x *bool) error { + if err := checkType(b, 0); err != nil { + return err + } + if int64(b.u64) == 0 { + *x = false + } else { + *x = true + } + return nil +} diff --git a/vendor/github.com/google/pprof/profile/prune.go b/vendor/github.com/google/pprof/profile/prune.go new file mode 100644 index 000000000..02d21a818 --- /dev/null +++ b/vendor/github.com/google/pprof/profile/prune.go @@ -0,0 +1,178 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Implements methods to remove frames from profiles. + +package profile + +import ( + "fmt" + "regexp" + "strings" +) + +var ( + reservedNames = []string{"(anonymous namespace)", "operator()"} + bracketRx = func() *regexp.Regexp { + var quotedNames []string + for _, name := range append(reservedNames, "(") { + quotedNames = append(quotedNames, regexp.QuoteMeta(name)) + } + return regexp.MustCompile(strings.Join(quotedNames, "|")) + }() +) + +// simplifyFunc does some primitive simplification of function names. +func simplifyFunc(f string) string { + // Account for leading '.' on the PPC ELF v1 ABI. + funcName := strings.TrimPrefix(f, ".") + // Account for unsimplified names -- try to remove the argument list by trimming + // starting from the first '(', but skipping reserved names that have '('. + for _, ind := range bracketRx.FindAllStringSubmatchIndex(funcName, -1) { + foundReserved := false + for _, res := range reservedNames { + if funcName[ind[0]:ind[1]] == res { + foundReserved = true + break + } + } + if !foundReserved { + funcName = funcName[:ind[0]] + break + } + } + return funcName +} + +// Prune removes all nodes beneath a node matching dropRx, and not +// matching keepRx. If the root node of a Sample matches, the sample +// will have an empty stack. +func (p *Profile) Prune(dropRx, keepRx *regexp.Regexp) { + prune := make(map[uint64]bool) + pruneBeneath := make(map[uint64]bool) + + for _, loc := range p.Location { + var i int + for i = len(loc.Line) - 1; i >= 0; i-- { + if fn := loc.Line[i].Function; fn != nil && fn.Name != "" { + funcName := simplifyFunc(fn.Name) + if dropRx.MatchString(funcName) { + if keepRx == nil || !keepRx.MatchString(funcName) { + break + } + } + } + } + + if i >= 0 { + // Found matching entry to prune. + pruneBeneath[loc.ID] = true + + // Remove the matching location. + if i == len(loc.Line)-1 { + // Matched the top entry: prune the whole location. + prune[loc.ID] = true + } else { + loc.Line = loc.Line[i+1:] + } + } + } + + // Prune locs from each Sample + for _, sample := range p.Sample { + // Scan from the root to the leaves to find the prune location. + // Do not prune frames before the first user frame, to avoid + // pruning everything. + foundUser := false + for i := len(sample.Location) - 1; i >= 0; i-- { + id := sample.Location[i].ID + if !prune[id] && !pruneBeneath[id] { + foundUser = true + continue + } + if !foundUser { + continue + } + if prune[id] { + sample.Location = sample.Location[i+1:] + break + } + if pruneBeneath[id] { + sample.Location = sample.Location[i:] + break + } + } + } +} + +// RemoveUninteresting prunes and elides profiles using built-in +// tables of uninteresting function names. +func (p *Profile) RemoveUninteresting() error { + var keep, drop *regexp.Regexp + var err error + + if p.DropFrames != "" { + if drop, err = regexp.Compile("^(" + p.DropFrames + ")$"); err != nil { + return fmt.Errorf("failed to compile regexp %s: %v", p.DropFrames, err) + } + if p.KeepFrames != "" { + if keep, err = regexp.Compile("^(" + p.KeepFrames + ")$"); err != nil { + return fmt.Errorf("failed to compile regexp %s: %v", p.KeepFrames, err) + } + } + p.Prune(drop, keep) + } + return nil +} + +// PruneFrom removes all nodes beneath the lowest node matching dropRx, not including itself. +// +// Please see the example below to understand this method as well as +// the difference from Prune method. +// +// A sample contains Location of [A,B,C,B,D] where D is the top frame and there's no inline. +// +// PruneFrom(A) returns [A,B,C,B,D] because there's no node beneath A. +// Prune(A, nil) returns [B,C,B,D] by removing A itself. +// +// PruneFrom(B) returns [B,C,B,D] by removing all nodes beneath the first B when scanning from the bottom. +// Prune(B, nil) returns [D] because a matching node is found by scanning from the root. +func (p *Profile) PruneFrom(dropRx *regexp.Regexp) { + pruneBeneath := make(map[uint64]bool) + + for _, loc := range p.Location { + for i := 0; i < len(loc.Line); i++ { + if fn := loc.Line[i].Function; fn != nil && fn.Name != "" { + funcName := simplifyFunc(fn.Name) + if dropRx.MatchString(funcName) { + // Found matching entry to prune. + pruneBeneath[loc.ID] = true + loc.Line = loc.Line[i:] + break + } + } + } + } + + // Prune locs from each Sample + for _, sample := range p.Sample { + // Scan from the bottom leaf to the root to find the prune location. + for i, loc := range sample.Location { + if pruneBeneath[loc.ID] { + sample.Location = sample.Location[i:] + break + } + } + } +} diff --git a/vendor/github.com/onsi/ginkgo/v2/LICENSE b/vendor/github.com/onsi/ginkgo/v2/LICENSE new file mode 100644 index 000000000..9415ee72c --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2013-2014 Onsi Fakhouri + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/onsi/ginkgo/v2/config/deprecated.go b/vendor/github.com/onsi/ginkgo/v2/config/deprecated.go new file mode 100644 index 000000000..a61021d08 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/config/deprecated.go @@ -0,0 +1,69 @@ +package config + +// GinkgoConfigType has been deprecated and its equivalent now lives in +// the types package. You can no longer access Ginkgo configuration from the config +// package. Instead use the DSL's GinkgoConfiguration() function to get copies of the +// current configuration +// +// GinkgoConfigType is still here so custom V1 reporters do not result in a compilation error +// It will be removed in a future minor release of Ginkgo +type GinkgoConfigType = DeprecatedGinkgoConfigType +type DeprecatedGinkgoConfigType struct { + RandomSeed int64 + RandomizeAllSpecs bool + RegexScansFilePath bool + FocusStrings []string + SkipStrings []string + SkipMeasurements bool + FailOnPending bool + FailFast bool + FlakeAttempts int + EmitSpecProgress bool + DryRun bool + DebugParallel bool + + ParallelNode int + ParallelTotal int + SyncHost string + StreamHost string +} + +// DefaultReporterConfigType has been deprecated and its equivalent now lives in +// the types package. You can no longer access Ginkgo configuration from the config +// package. Instead use the DSL's GinkgoConfiguration() function to get copies of the +// current configuration +// +// DefaultReporterConfigType is still here so custom V1 reporters do not result in a compilation error +// It will be removed in a future minor release of Ginkgo +type DefaultReporterConfigType = DeprecatedDefaultReporterConfigType +type DeprecatedDefaultReporterConfigType struct { + NoColor bool + SlowSpecThreshold float64 + NoisyPendings bool + NoisySkippings bool + Succinct bool + Verbose bool + FullTrace bool + ReportPassed bool + ReportFile string +} + +// Sadly there is no way to gracefully deprecate access to these global config variables. +// Users who need access to Ginkgo's configuration should use the DSL's GinkgoConfiguration() method +// These new unwieldy type names exist to give users a hint when they try to compile and the compilation fails +type GinkgoConfigIsNoLongerAccessibleFromTheConfigPackageUseTheDSLsGinkgoConfigurationFunctionInstead struct{} + +// Sadly there is no way to gracefully deprecate access to these global config variables. +// Users who need access to Ginkgo's configuration should use the DSL's GinkgoConfiguration() method +// These new unwieldy type names exist to give users a hint when they try to compile and the compilation fails +var GinkgoConfig = GinkgoConfigIsNoLongerAccessibleFromTheConfigPackageUseTheDSLsGinkgoConfigurationFunctionInstead{} + +// Sadly there is no way to gracefully deprecate access to these global config variables. +// Users who need access to Ginkgo's configuration should use the DSL's GinkgoConfiguration() method +// These new unwieldy type names exist to give users a hint when they try to compile and the compilation fails +type DefaultReporterConfigIsNoLongerAccessibleFromTheConfigPackageUseTheDSLsGinkgoConfigurationFunctionInstead struct{} + +// Sadly there is no way to gracefully deprecate access to these global config variables. +// Users who need access to Ginkgo's configuration should use the DSL's GinkgoConfiguration() method +// These new unwieldy type names exist to give users a hint when they try to compile and the compilation fails +var DefaultReporterConfig = DefaultReporterConfigIsNoLongerAccessibleFromTheConfigPackageUseTheDSLsGinkgoConfigurationFunctionInstead{} diff --git a/vendor/github.com/onsi/ginkgo/v2/formatter/colorable_others.go b/vendor/github.com/onsi/ginkgo/v2/formatter/colorable_others.go new file mode 100644 index 000000000..778bfd7c7 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/formatter/colorable_others.go @@ -0,0 +1,41 @@ +// +build !windows + +/* +These packages are used for colorize on Windows and contributed by mattn.jp@gmail.com + + * go-colorable: + * go-isatty: + +The MIT License (MIT) + +Copyright (c) 2016 Yasuhiro Matsumoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +package formatter + +import ( + "io" + "os" +) + +func newColorable(file *os.File) io.Writer { + return file +} diff --git a/vendor/github.com/onsi/ginkgo/v2/formatter/colorable_windows.go b/vendor/github.com/onsi/ginkgo/v2/formatter/colorable_windows.go new file mode 100644 index 000000000..dd1d143cc --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/formatter/colorable_windows.go @@ -0,0 +1,809 @@ +/* +These packages are used for colorize on Windows and contributed by mattn.jp@gmail.com + + * go-colorable: + * go-isatty: + +The MIT License (MIT) + +Copyright (c) 2016 Yasuhiro Matsumoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +package formatter + +import ( + "bytes" + "fmt" + "io" + "math" + "os" + "strconv" + "strings" + "syscall" + "unsafe" +) + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") + procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") + procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition") + procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW") + procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute") + procGetConsoleMode = kernel32.NewProc("GetConsoleMode") +) + +func isTerminal(fd uintptr) bool { + var st uint32 + r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0) + return r != 0 && e == 0 +} + +const ( + foregroundBlue = 0x1 + foregroundGreen = 0x2 + foregroundRed = 0x4 + foregroundIntensity = 0x8 + foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity) + backgroundBlue = 0x10 + backgroundGreen = 0x20 + backgroundRed = 0x40 + backgroundIntensity = 0x80 + backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity) +) + +type wchar uint16 +type short int16 +type dword uint32 +type word uint16 + +type coord struct { + x short + y short +} + +type smallRect struct { + left short + top short + right short + bottom short +} + +type consoleScreenBufferInfo struct { + size coord + cursorPosition coord + attributes word + window smallRect + maximumWindowSize coord +} + +type writer struct { + out io.Writer + handle syscall.Handle + lastbuf bytes.Buffer + oldattr word +} + +func newColorable(file *os.File) io.Writer { + if file == nil { + panic("nil passed instead of *os.File to NewColorable()") + } + + if isTerminal(file.Fd()) { + var csbi consoleScreenBufferInfo + handle := syscall.Handle(file.Fd()) + procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + return &writer{out: file, handle: handle, oldattr: csbi.attributes} + } else { + return file + } +} + +var color256 = map[int]int{ + 0: 0x000000, + 1: 0x800000, + 2: 0x008000, + 3: 0x808000, + 4: 0x000080, + 5: 0x800080, + 6: 0x008080, + 7: 0xc0c0c0, + 8: 0x808080, + 9: 0xff0000, + 10: 0x00ff00, + 11: 0xffff00, + 12: 0x0000ff, + 13: 0xff00ff, + 14: 0x00ffff, + 15: 0xffffff, + 16: 0x000000, + 17: 0x00005f, + 18: 0x000087, + 19: 0x0000af, + 20: 0x0000d7, + 21: 0x0000ff, + 22: 0x005f00, + 23: 0x005f5f, + 24: 0x005f87, + 25: 0x005faf, + 26: 0x005fd7, + 27: 0x005fff, + 28: 0x008700, + 29: 0x00875f, + 30: 0x008787, + 31: 0x0087af, + 32: 0x0087d7, + 33: 0x0087ff, + 34: 0x00af00, + 35: 0x00af5f, + 36: 0x00af87, + 37: 0x00afaf, + 38: 0x00afd7, + 39: 0x00afff, + 40: 0x00d700, + 41: 0x00d75f, + 42: 0x00d787, + 43: 0x00d7af, + 44: 0x00d7d7, + 45: 0x00d7ff, + 46: 0x00ff00, + 47: 0x00ff5f, + 48: 0x00ff87, + 49: 0x00ffaf, + 50: 0x00ffd7, + 51: 0x00ffff, + 52: 0x5f0000, + 53: 0x5f005f, + 54: 0x5f0087, + 55: 0x5f00af, + 56: 0x5f00d7, + 57: 0x5f00ff, + 58: 0x5f5f00, + 59: 0x5f5f5f, + 60: 0x5f5f87, + 61: 0x5f5faf, + 62: 0x5f5fd7, + 63: 0x5f5fff, + 64: 0x5f8700, + 65: 0x5f875f, + 66: 0x5f8787, + 67: 0x5f87af, + 68: 0x5f87d7, + 69: 0x5f87ff, + 70: 0x5faf00, + 71: 0x5faf5f, + 72: 0x5faf87, + 73: 0x5fafaf, + 74: 0x5fafd7, + 75: 0x5fafff, + 76: 0x5fd700, + 77: 0x5fd75f, + 78: 0x5fd787, + 79: 0x5fd7af, + 80: 0x5fd7d7, + 81: 0x5fd7ff, + 82: 0x5fff00, + 83: 0x5fff5f, + 84: 0x5fff87, + 85: 0x5fffaf, + 86: 0x5fffd7, + 87: 0x5fffff, + 88: 0x870000, + 89: 0x87005f, + 90: 0x870087, + 91: 0x8700af, + 92: 0x8700d7, + 93: 0x8700ff, + 94: 0x875f00, + 95: 0x875f5f, + 96: 0x875f87, + 97: 0x875faf, + 98: 0x875fd7, + 99: 0x875fff, + 100: 0x878700, + 101: 0x87875f, + 102: 0x878787, + 103: 0x8787af, + 104: 0x8787d7, + 105: 0x8787ff, + 106: 0x87af00, + 107: 0x87af5f, + 108: 0x87af87, + 109: 0x87afaf, + 110: 0x87afd7, + 111: 0x87afff, + 112: 0x87d700, + 113: 0x87d75f, + 114: 0x87d787, + 115: 0x87d7af, + 116: 0x87d7d7, + 117: 0x87d7ff, + 118: 0x87ff00, + 119: 0x87ff5f, + 120: 0x87ff87, + 121: 0x87ffaf, + 122: 0x87ffd7, + 123: 0x87ffff, + 124: 0xaf0000, + 125: 0xaf005f, + 126: 0xaf0087, + 127: 0xaf00af, + 128: 0xaf00d7, + 129: 0xaf00ff, + 130: 0xaf5f00, + 131: 0xaf5f5f, + 132: 0xaf5f87, + 133: 0xaf5faf, + 134: 0xaf5fd7, + 135: 0xaf5fff, + 136: 0xaf8700, + 137: 0xaf875f, + 138: 0xaf8787, + 139: 0xaf87af, + 140: 0xaf87d7, + 141: 0xaf87ff, + 142: 0xafaf00, + 143: 0xafaf5f, + 144: 0xafaf87, + 145: 0xafafaf, + 146: 0xafafd7, + 147: 0xafafff, + 148: 0xafd700, + 149: 0xafd75f, + 150: 0xafd787, + 151: 0xafd7af, + 152: 0xafd7d7, + 153: 0xafd7ff, + 154: 0xafff00, + 155: 0xafff5f, + 156: 0xafff87, + 157: 0xafffaf, + 158: 0xafffd7, + 159: 0xafffff, + 160: 0xd70000, + 161: 0xd7005f, + 162: 0xd70087, + 163: 0xd700af, + 164: 0xd700d7, + 165: 0xd700ff, + 166: 0xd75f00, + 167: 0xd75f5f, + 168: 0xd75f87, + 169: 0xd75faf, + 170: 0xd75fd7, + 171: 0xd75fff, + 172: 0xd78700, + 173: 0xd7875f, + 174: 0xd78787, + 175: 0xd787af, + 176: 0xd787d7, + 177: 0xd787ff, + 178: 0xd7af00, + 179: 0xd7af5f, + 180: 0xd7af87, + 181: 0xd7afaf, + 182: 0xd7afd7, + 183: 0xd7afff, + 184: 0xd7d700, + 185: 0xd7d75f, + 186: 0xd7d787, + 187: 0xd7d7af, + 188: 0xd7d7d7, + 189: 0xd7d7ff, + 190: 0xd7ff00, + 191: 0xd7ff5f, + 192: 0xd7ff87, + 193: 0xd7ffaf, + 194: 0xd7ffd7, + 195: 0xd7ffff, + 196: 0xff0000, + 197: 0xff005f, + 198: 0xff0087, + 199: 0xff00af, + 200: 0xff00d7, + 201: 0xff00ff, + 202: 0xff5f00, + 203: 0xff5f5f, + 204: 0xff5f87, + 205: 0xff5faf, + 206: 0xff5fd7, + 207: 0xff5fff, + 208: 0xff8700, + 209: 0xff875f, + 210: 0xff8787, + 211: 0xff87af, + 212: 0xff87d7, + 213: 0xff87ff, + 214: 0xffaf00, + 215: 0xffaf5f, + 216: 0xffaf87, + 217: 0xffafaf, + 218: 0xffafd7, + 219: 0xffafff, + 220: 0xffd700, + 221: 0xffd75f, + 222: 0xffd787, + 223: 0xffd7af, + 224: 0xffd7d7, + 225: 0xffd7ff, + 226: 0xffff00, + 227: 0xffff5f, + 228: 0xffff87, + 229: 0xffffaf, + 230: 0xffffd7, + 231: 0xffffff, + 232: 0x080808, + 233: 0x121212, + 234: 0x1c1c1c, + 235: 0x262626, + 236: 0x303030, + 237: 0x3a3a3a, + 238: 0x444444, + 239: 0x4e4e4e, + 240: 0x585858, + 241: 0x626262, + 242: 0x6c6c6c, + 243: 0x767676, + 244: 0x808080, + 245: 0x8a8a8a, + 246: 0x949494, + 247: 0x9e9e9e, + 248: 0xa8a8a8, + 249: 0xb2b2b2, + 250: 0xbcbcbc, + 251: 0xc6c6c6, + 252: 0xd0d0d0, + 253: 0xdadada, + 254: 0xe4e4e4, + 255: 0xeeeeee, +} + +func (w *writer) Write(data []byte) (n int, err error) { + var csbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + + er := bytes.NewBuffer(data) +loop: + for { + r1, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + if r1 == 0 { + break loop + } + + c1, _, err := er.ReadRune() + if err != nil { + break loop + } + if c1 != 0x1b { + fmt.Fprint(w.out, string(c1)) + continue + } + c2, _, err := er.ReadRune() + if err != nil { + w.lastbuf.WriteRune(c1) + break loop + } + if c2 != 0x5b { + w.lastbuf.WriteRune(c1) + w.lastbuf.WriteRune(c2) + continue + } + + var buf bytes.Buffer + var m rune + for { + c, _, err := er.ReadRune() + if err != nil { + w.lastbuf.WriteRune(c1) + w.lastbuf.WriteRune(c2) + w.lastbuf.Write(buf.Bytes()) + break loop + } + if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { + m = c + break + } + buf.Write([]byte(string(c))) + } + + var csbi consoleScreenBufferInfo + switch m { + case 'A': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.y -= short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'B': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.y += short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'C': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.x -= short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'D': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + if n, err = strconv.Atoi(buf.String()); err == nil { + var csbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.x += short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + } + case 'E': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.x = 0 + csbi.cursorPosition.y += short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'F': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.x = 0 + csbi.cursorPosition.y -= short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'G': + n, err = strconv.Atoi(buf.String()) + if err != nil { + continue + } + procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + csbi.cursorPosition.x = short(n) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'H': + token := strings.Split(buf.String(), ";") + if len(token) != 2 { + continue + } + n1, err := strconv.Atoi(token[0]) + if err != nil { + continue + } + n2, err := strconv.Atoi(token[1]) + if err != nil { + continue + } + csbi.cursorPosition.x = short(n2) + csbi.cursorPosition.x = short(n1) + procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + case 'J': + n, err := strconv.Atoi(buf.String()) + if err != nil { + continue + } + var cursor coord + switch n { + case 0: + cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} + case 1: + cursor = coord{x: csbi.window.left, y: csbi.window.top} + case 2: + cursor = coord{x: csbi.window.left, y: csbi.window.top} + } + var count, written dword + count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x) + procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + case 'K': + n, err := strconv.Atoi(buf.String()) + if err != nil { + continue + } + var cursor coord + switch n { + case 0: + cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} + case 1: + cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} + case 2: + cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} + } + var count, written dword + count = dword(csbi.size.x - csbi.cursorPosition.x) + procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + case 'm': + attr := csbi.attributes + cs := buf.String() + if cs == "" { + procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr)) + continue + } + token := strings.Split(cs, ";") + for i := 0; i < len(token); i += 1 { + ns := token[i] + if n, err = strconv.Atoi(ns); err == nil { + switch { + case n == 0 || n == 100: + attr = w.oldattr + case 1 <= n && n <= 5: + attr |= foregroundIntensity + case n == 7: + attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) + case 22 == n || n == 25 || n == 25: + attr |= foregroundIntensity + case n == 27: + attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4) + case 30 <= n && n <= 37: + attr = (attr & backgroundMask) + if (n-30)&1 != 0 { + attr |= foregroundRed + } + if (n-30)&2 != 0 { + attr |= foregroundGreen + } + if (n-30)&4 != 0 { + attr |= foregroundBlue + } + case n == 38: // set foreground color. + if i < len(token)-2 && (token[i+1] == "5" || token[i+1] == "05") { + if n256, err := strconv.Atoi(token[i+2]); err == nil { + if n256foreAttr == nil { + n256setup() + } + attr &= backgroundMask + attr |= n256foreAttr[n256] + i += 2 + } + } else { + attr = attr & (w.oldattr & backgroundMask) + } + case n == 39: // reset foreground color. + attr &= backgroundMask + attr |= w.oldattr & foregroundMask + case 40 <= n && n <= 47: + attr = (attr & foregroundMask) + if (n-40)&1 != 0 { + attr |= backgroundRed + } + if (n-40)&2 != 0 { + attr |= backgroundGreen + } + if (n-40)&4 != 0 { + attr |= backgroundBlue + } + case n == 48: // set background color. + if i < len(token)-2 && token[i+1] == "5" { + if n256, err := strconv.Atoi(token[i+2]); err == nil { + if n256backAttr == nil { + n256setup() + } + attr &= foregroundMask + attr |= n256backAttr[n256] + i += 2 + } + } else { + attr = attr & (w.oldattr & foregroundMask) + } + case n == 49: // reset foreground color. + attr &= foregroundMask + attr |= w.oldattr & backgroundMask + case 90 <= n && n <= 97: + attr = (attr & backgroundMask) + attr |= foregroundIntensity + if (n-90)&1 != 0 { + attr |= foregroundRed + } + if (n-90)&2 != 0 { + attr |= foregroundGreen + } + if (n-90)&4 != 0 { + attr |= foregroundBlue + } + case 100 <= n && n <= 107: + attr = (attr & foregroundMask) + attr |= backgroundIntensity + if (n-100)&1 != 0 { + attr |= backgroundRed + } + if (n-100)&2 != 0 { + attr |= backgroundGreen + } + if (n-100)&4 != 0 { + attr |= backgroundBlue + } + } + procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr)) + } + } + } + } + return len(data) - w.lastbuf.Len(), nil +} + +type consoleColor struct { + rgb int + red bool + green bool + blue bool + intensity bool +} + +func (c consoleColor) foregroundAttr() (attr word) { + if c.red { + attr |= foregroundRed + } + if c.green { + attr |= foregroundGreen + } + if c.blue { + attr |= foregroundBlue + } + if c.intensity { + attr |= foregroundIntensity + } + return +} + +func (c consoleColor) backgroundAttr() (attr word) { + if c.red { + attr |= backgroundRed + } + if c.green { + attr |= backgroundGreen + } + if c.blue { + attr |= backgroundBlue + } + if c.intensity { + attr |= backgroundIntensity + } + return +} + +var color16 = []consoleColor{ + consoleColor{0x000000, false, false, false, false}, + consoleColor{0x000080, false, false, true, false}, + consoleColor{0x008000, false, true, false, false}, + consoleColor{0x008080, false, true, true, false}, + consoleColor{0x800000, true, false, false, false}, + consoleColor{0x800080, true, false, true, false}, + consoleColor{0x808000, true, true, false, false}, + consoleColor{0xc0c0c0, true, true, true, false}, + consoleColor{0x808080, false, false, false, true}, + consoleColor{0x0000ff, false, false, true, true}, + consoleColor{0x00ff00, false, true, false, true}, + consoleColor{0x00ffff, false, true, true, true}, + consoleColor{0xff0000, true, false, false, true}, + consoleColor{0xff00ff, true, false, true, true}, + consoleColor{0xffff00, true, true, false, true}, + consoleColor{0xffffff, true, true, true, true}, +} + +type hsv struct { + h, s, v float32 +} + +func (a hsv) dist(b hsv) float32 { + dh := a.h - b.h + switch { + case dh > 0.5: + dh = 1 - dh + case dh < -0.5: + dh = -1 - dh + } + ds := a.s - b.s + dv := a.v - b.v + return float32(math.Sqrt(float64(dh*dh + ds*ds + dv*dv))) +} + +func toHSV(rgb int) hsv { + r, g, b := float32((rgb&0xFF0000)>>16)/256.0, + float32((rgb&0x00FF00)>>8)/256.0, + float32(rgb&0x0000FF)/256.0 + min, max := minmax3f(r, g, b) + h := max - min + if h > 0 { + if max == r { + h = (g - b) / h + if h < 0 { + h += 6 + } + } else if max == g { + h = 2 + (b-r)/h + } else { + h = 4 + (r-g)/h + } + } + h /= 6.0 + s := max - min + if max != 0 { + s /= max + } + v := max + return hsv{h: h, s: s, v: v} +} + +type hsvTable []hsv + +func toHSVTable(rgbTable []consoleColor) hsvTable { + t := make(hsvTable, len(rgbTable)) + for i, c := range rgbTable { + t[i] = toHSV(c.rgb) + } + return t +} + +func (t hsvTable) find(rgb int) consoleColor { + hsv := toHSV(rgb) + n := 7 + l := float32(5.0) + for i, p := range t { + d := hsv.dist(p) + if d < l { + l, n = d, i + } + } + return color16[n] +} + +func minmax3f(a, b, c float32) (min, max float32) { + if a < b { + if b < c { + return a, c + } else if a < c { + return a, b + } else { + return c, b + } + } else { + if a < c { + return b, c + } else if b < c { + return b, a + } else { + return c, a + } + } +} + +var n256foreAttr []word +var n256backAttr []word + +func n256setup() { + n256foreAttr = make([]word, 256) + n256backAttr = make([]word, 256) + t := toHSVTable(color16) + for i, rgb := range color256 { + c := t.find(rgb) + n256foreAttr[i] = c.foregroundAttr() + n256backAttr[i] = c.backgroundAttr() + } +} diff --git a/vendor/github.com/onsi/ginkgo/v2/formatter/formatter.go b/vendor/github.com/onsi/ginkgo/v2/formatter/formatter.go new file mode 100644 index 000000000..743555dde --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/formatter/formatter.go @@ -0,0 +1,230 @@ +package formatter + +import ( + "fmt" + "os" + "regexp" + "strconv" + "strings" +) + +// ColorableStdOut and ColorableStdErr enable color output support on Windows +var ColorableStdOut = newColorable(os.Stdout) +var ColorableStdErr = newColorable(os.Stderr) + +const COLS = 80 + +type ColorMode uint8 + +const ( + ColorModeNone ColorMode = iota + ColorModeTerminal + ColorModePassthrough +) + +var SingletonFormatter = New(ColorModeTerminal) + +func F(format string, args ...interface{}) string { + return SingletonFormatter.F(format, args...) +} + +func Fi(indentation uint, format string, args ...interface{}) string { + return SingletonFormatter.Fi(indentation, format, args...) +} + +func Fiw(indentation uint, maxWidth uint, format string, args ...interface{}) string { + return SingletonFormatter.Fiw(indentation, maxWidth, format, args...) +} + +type Formatter struct { + ColorMode ColorMode + colors map[string]string + styleRe *regexp.Regexp + preserveColorStylingTags bool +} + +func NewWithNoColorBool(noColor bool) Formatter { + if noColor { + return New(ColorModeNone) + } + return New(ColorModeTerminal) +} + +func New(colorMode ColorMode) Formatter { + colorAliases := map[string]int{ + "black": 0, + "red": 1, + "green": 2, + "yellow": 3, + "blue": 4, + "magenta": 5, + "cyan": 6, + "white": 7, + } + for colorAlias, n := range colorAliases { + colorAliases[fmt.Sprintf("bright-%s", colorAlias)] = n + 8 + } + + getColor := func(color, defaultEscapeCode string) string { + color = strings.ToUpper(strings.ReplaceAll(color, "-", "_")) + envVar := fmt.Sprintf("GINKGO_CLI_COLOR_%s", color) + envVarColor := os.Getenv(envVar) + if envVarColor == "" { + return defaultEscapeCode + } + if colorCode, ok := colorAliases[envVarColor]; ok { + return fmt.Sprintf("\x1b[38;5;%dm", colorCode) + } + colorCode, err := strconv.Atoi(envVarColor) + if err != nil || colorCode < 0 || colorCode > 255 { + return defaultEscapeCode + } + return fmt.Sprintf("\x1b[38;5;%dm", colorCode) + } + + f := Formatter{ + ColorMode: colorMode, + colors: map[string]string{ + "/": "\x1b[0m", + "bold": "\x1b[1m", + "underline": "\x1b[4m", + + "red": getColor("red", "\x1b[38;5;9m"), + "orange": getColor("orange", "\x1b[38;5;214m"), + "coral": getColor("coral", "\x1b[38;5;204m"), + "magenta": getColor("magenta", "\x1b[38;5;13m"), + "green": getColor("green", "\x1b[38;5;10m"), + "dark-green": getColor("dark-green", "\x1b[38;5;28m"), + "yellow": getColor("yellow", "\x1b[38;5;11m"), + "light-yellow": getColor("light-yellow", "\x1b[38;5;228m"), + "cyan": getColor("cyan", "\x1b[38;5;14m"), + "gray": getColor("gray", "\x1b[38;5;243m"), + "light-gray": getColor("light-gray", "\x1b[38;5;246m"), + "blue": getColor("blue", "\x1b[38;5;12m"), + }, + } + colors := []string{} + for color := range f.colors { + colors = append(colors, color) + } + f.styleRe = regexp.MustCompile("{{(" + strings.Join(colors, "|") + ")}}") + return f +} + +func (f Formatter) F(format string, args ...interface{}) string { + return f.Fi(0, format, args...) +} + +func (f Formatter) Fi(indentation uint, format string, args ...interface{}) string { + return f.Fiw(indentation, 0, format, args...) +} + +func (f Formatter) Fiw(indentation uint, maxWidth uint, format string, args ...interface{}) string { + out := f.style(format) + if len(args) > 0 { + out = fmt.Sprintf(out, args...) + } + + if indentation == 0 && maxWidth == 0 { + return out + } + + lines := strings.Split(out, "\n") + + if maxWidth != 0 { + outLines := []string{} + + maxWidth = maxWidth - indentation*2 + for _, line := range lines { + if f.length(line) <= maxWidth { + outLines = append(outLines, line) + continue + } + words := strings.Split(line, " ") + outWords := []string{words[0]} + length := uint(f.length(words[0])) + for _, word := range words[1:] { + wordLength := f.length(word) + if length+wordLength+1 <= maxWidth { + length += wordLength + 1 + outWords = append(outWords, word) + continue + } + outLines = append(outLines, strings.Join(outWords, " ")) + outWords = []string{word} + length = wordLength + } + if len(outWords) > 0 { + outLines = append(outLines, strings.Join(outWords, " ")) + } + } + + lines = outLines + } + + if indentation == 0 { + return strings.Join(lines, "\n") + } + + padding := strings.Repeat(" ", int(indentation)) + for i := range lines { + if lines[i] != "" { + lines[i] = padding + lines[i] + } + } + + return strings.Join(lines, "\n") +} + +func (f Formatter) length(styled string) uint { + n := uint(0) + inStyle := false + for _, b := range styled { + if inStyle { + if b == 'm' { + inStyle = false + } + continue + } + if b == '\x1b' { + inStyle = true + continue + } + n += 1 + } + return n +} + +func (f Formatter) CycleJoin(elements []string, joiner string, cycle []string) string { + if len(elements) == 0 { + return "" + } + n := len(cycle) + out := "" + for i, text := range elements { + out += cycle[i%n] + text + if i < len(elements)-1 { + out += joiner + } + } + out += "{{/}}" + return f.style(out) +} + +func (f Formatter) style(s string) string { + switch f.ColorMode { + case ColorModeNone: + return f.styleRe.ReplaceAllString(s, "") + case ColorModePassthrough: + return s + case ColorModeTerminal: + return f.styleRe.ReplaceAllStringFunc(s, func(match string) string { + if out, ok := f.colors[strings.Trim(match, "{}")]; ok { + return out + } + return match + }) + } + + return "" +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/build/build_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/build/build_command.go new file mode 100644 index 000000000..5db5d1a7b --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/build/build_command.go @@ -0,0 +1,63 @@ +package build + +import ( + "fmt" + + "github.com/onsi/ginkgo/v2/ginkgo/command" + "github.com/onsi/ginkgo/v2/ginkgo/internal" + "github.com/onsi/ginkgo/v2/types" +) + +func BuildBuildCommand() command.Command { + var cliConfig = types.NewDefaultCLIConfig() + var goFlagsConfig = types.NewDefaultGoFlagsConfig() + + flags, err := types.BuildBuildCommandFlagSet(&cliConfig, &goFlagsConfig) + if err != nil { + panic(err) + } + + return command.Command{ + Name: "build", + Flags: flags, + Usage: "ginkgo build ", + ShortDoc: "Build the passed in (or the package in the current directory if left blank).", + DocLink: "precompiling-suites", + Command: func(args []string, _ []string) { + var errors []error + cliConfig, goFlagsConfig, errors = types.VetAndInitializeCLIAndGoConfig(cliConfig, goFlagsConfig) + command.AbortIfErrors("Ginkgo detected configuration issues:", errors) + + buildSpecs(args, cliConfig, goFlagsConfig) + }, + } +} + +func buildSpecs(args []string, cliConfig types.CLIConfig, goFlagsConfig types.GoFlagsConfig) { + suites := internal.FindSuites(args, cliConfig, false).WithoutState(internal.TestSuiteStateSkippedByFilter) + if len(suites) == 0 { + command.AbortWith("Found no test suites") + } + + internal.VerifyCLIAndFrameworkVersion(suites) + + opc := internal.NewOrderedParallelCompiler(cliConfig.ComputedNumCompilers()) + opc.StartCompiling(suites, goFlagsConfig) + + for { + suiteIdx, suite := opc.Next() + if suiteIdx >= len(suites) { + break + } + suites[suiteIdx] = suite + if suite.State.Is(internal.TestSuiteStateFailedToCompile) { + fmt.Println(suite.CompilationError.Error()) + } else { + fmt.Printf("Compiled %s.test\n", suite.PackageName) + } + } + + if suites.CountWithState(internal.TestSuiteStateFailedToCompile) > 0 { + command.AbortWith("Failed to compile all tests") + } +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/abort.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/abort.go new file mode 100644 index 000000000..2efd28608 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/abort.go @@ -0,0 +1,61 @@ +package command + +import "fmt" + +type AbortDetails struct { + ExitCode int + Error error + EmitUsage bool +} + +func Abort(details AbortDetails) { + panic(details) +} + +func AbortGracefullyWith(format string, args ...interface{}) { + Abort(AbortDetails{ + ExitCode: 0, + Error: fmt.Errorf(format, args...), + EmitUsage: false, + }) +} + +func AbortWith(format string, args ...interface{}) { + Abort(AbortDetails{ + ExitCode: 1, + Error: fmt.Errorf(format, args...), + EmitUsage: false, + }) +} + +func AbortWithUsage(format string, args ...interface{}) { + Abort(AbortDetails{ + ExitCode: 1, + Error: fmt.Errorf(format, args...), + EmitUsage: true, + }) +} + +func AbortIfError(preamble string, err error) { + if err != nil { + Abort(AbortDetails{ + ExitCode: 1, + Error: fmt.Errorf("%s\n%s", preamble, err.Error()), + EmitUsage: false, + }) + } +} + +func AbortIfErrors(preamble string, errors []error) { + if len(errors) > 0 { + out := "" + for _, err := range errors { + out += err.Error() + } + Abort(AbortDetails{ + ExitCode: 1, + Error: fmt.Errorf("%s\n%s", preamble, out), + EmitUsage: false, + }) + } +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/command.go new file mode 100644 index 000000000..12e0e5659 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/command.go @@ -0,0 +1,50 @@ +package command + +import ( + "fmt" + "io" + "strings" + + "github.com/onsi/ginkgo/v2/formatter" + "github.com/onsi/ginkgo/v2/types" +) + +type Command struct { + Name string + Flags types.GinkgoFlagSet + Usage string + ShortDoc string + Documentation string + DocLink string + Command func(args []string, additionalArgs []string) +} + +func (c Command) Run(args []string, additionalArgs []string) { + args, err := c.Flags.Parse(args) + if err != nil { + AbortWithUsage(err.Error()) + } + + c.Command(args, additionalArgs) +} + +func (c Command) EmitUsage(writer io.Writer) { + fmt.Fprintln(writer, formatter.F("{{bold}}"+c.Usage+"{{/}}")) + fmt.Fprintln(writer, formatter.F("{{gray}}%s{{/}}", strings.Repeat("-", len(c.Usage)))) + if c.ShortDoc != "" { + fmt.Fprintln(writer, formatter.Fiw(0, formatter.COLS, c.ShortDoc)) + fmt.Fprintln(writer, "") + } + if c.Documentation != "" { + fmt.Fprintln(writer, formatter.Fiw(0, formatter.COLS, c.Documentation)) + fmt.Fprintln(writer, "") + } + if c.DocLink != "" { + fmt.Fprintln(writer, formatter.Fi(0, "{{bold}}Learn more at:{{/}} {{cyan}}{{underline}}http://onsi.github.io/ginkgo/#%s{{/}}", c.DocLink)) + fmt.Fprintln(writer, "") + } + flagUsage := c.Flags.Usage() + if flagUsage != "" { + fmt.Fprintf(writer, formatter.F(flagUsage)) + } +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/program.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/program.go new file mode 100644 index 000000000..88dd8d6b0 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/program.go @@ -0,0 +1,182 @@ +package command + +import ( + "fmt" + "io" + "os" + "strings" + + "github.com/onsi/ginkgo/v2/formatter" + "github.com/onsi/ginkgo/v2/types" +) + +type Program struct { + Name string + Heading string + Commands []Command + DefaultCommand Command + DeprecatedCommands []DeprecatedCommand + + //For testing - leave as nil in production + OutWriter io.Writer + ErrWriter io.Writer + Exiter func(code int) +} + +type DeprecatedCommand struct { + Name string + Deprecation types.Deprecation +} + +func (p Program) RunAndExit(osArgs []string) { + var command Command + deprecationTracker := types.NewDeprecationTracker() + if p.Exiter == nil { + p.Exiter = os.Exit + } + if p.OutWriter == nil { + p.OutWriter = formatter.ColorableStdOut + } + if p.ErrWriter == nil { + p.ErrWriter = formatter.ColorableStdErr + } + + defer func() { + exitCode := 0 + + if r := recover(); r != nil { + details, ok := r.(AbortDetails) + if !ok { + panic(r) + } + + if details.Error != nil { + fmt.Fprintln(p.ErrWriter, formatter.F("{{red}}{{bold}}%s %s{{/}} {{red}}failed{{/}}", p.Name, command.Name)) + fmt.Fprintln(p.ErrWriter, formatter.Fi(1, details.Error.Error())) + } + if details.EmitUsage { + if details.Error != nil { + fmt.Fprintln(p.ErrWriter, "") + } + command.EmitUsage(p.ErrWriter) + } + exitCode = details.ExitCode + } + + command.Flags.ValidateDeprecations(deprecationTracker) + if deprecationTracker.DidTrackDeprecations() { + fmt.Fprintln(p.ErrWriter, deprecationTracker.DeprecationsReport()) + } + p.Exiter(exitCode) + return + }() + + args, additionalArgs := []string{}, []string{} + + foundDelimiter := false + for _, arg := range osArgs[1:] { + if !foundDelimiter { + if arg == "--" { + foundDelimiter = true + continue + } + } + + if foundDelimiter { + additionalArgs = append(additionalArgs, arg) + } else { + args = append(args, arg) + } + } + + command = p.DefaultCommand + if len(args) > 0 { + p.handleHelpRequestsAndExit(p.OutWriter, args) + if command.Name == args[0] { + args = args[1:] + } else { + for _, deprecatedCommand := range p.DeprecatedCommands { + if deprecatedCommand.Name == args[0] { + deprecationTracker.TrackDeprecation(deprecatedCommand.Deprecation) + return + } + } + for _, tryCommand := range p.Commands { + if tryCommand.Name == args[0] { + command, args = tryCommand, args[1:] + break + } + } + } + } + + command.Run(args, additionalArgs) +} + +func (p Program) handleHelpRequestsAndExit(writer io.Writer, args []string) { + if len(args) == 0 { + return + } + + matchesHelpFlag := func(args ...string) bool { + for _, arg := range args { + if arg == "--help" || arg == "-help" || arg == "-h" || arg == "--h" { + return true + } + } + return false + } + if len(args) == 1 { + if args[0] == "help" || matchesHelpFlag(args[0]) { + p.EmitUsage(writer) + Abort(AbortDetails{}) + } + } else { + var name string + if args[0] == "help" || matchesHelpFlag(args[0]) { + name = args[1] + } else if matchesHelpFlag(args[1:]...) { + name = args[0] + } else { + return + } + + if p.DefaultCommand.Name == name || p.Name == name { + p.DefaultCommand.EmitUsage(writer) + Abort(AbortDetails{}) + } + for _, command := range p.Commands { + if command.Name == name { + command.EmitUsage(writer) + Abort(AbortDetails{}) + } + } + + fmt.Fprintln(writer, formatter.F("{{red}}Unknown Command: {{bold}}%s{{/}}", name)) + fmt.Fprintln(writer, "") + p.EmitUsage(writer) + Abort(AbortDetails{ExitCode: 1}) + } + return +} + +func (p Program) EmitUsage(writer io.Writer) { + fmt.Fprintln(writer, formatter.F(p.Heading)) + fmt.Fprintln(writer, formatter.F("{{gray}}%s{{/}}", strings.Repeat("-", len(p.Heading)))) + fmt.Fprintln(writer, formatter.F("For usage information for a command, run {{bold}}%s help COMMAND{{/}}.", p.Name)) + fmt.Fprintln(writer, formatter.F("For usage information for the default command, run {{bold}}%s help %s{{/}} or {{bold}}%s help %s{{/}}.", p.Name, p.Name, p.Name, p.DefaultCommand.Name)) + fmt.Fprintln(writer, "") + fmt.Fprintln(writer, formatter.F("The following commands are available:")) + + fmt.Fprintln(writer, formatter.Fi(1, "{{bold}}%s{{/}} or %s {{bold}}%s{{/}} - {{gray}}%s{{/}}", p.Name, p.Name, p.DefaultCommand.Name, p.DefaultCommand.Usage)) + if p.DefaultCommand.ShortDoc != "" { + fmt.Fprintln(writer, formatter.Fi(2, p.DefaultCommand.ShortDoc)) + } + + for _, command := range p.Commands { + fmt.Fprintln(writer, formatter.Fi(1, "{{bold}}%s{{/}} - {{gray}}%s{{/}}", command.Name, command.Usage)) + if command.ShortDoc != "" { + fmt.Fprintln(writer, formatter.Fi(2, command.ShortDoc)) + } + } +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/boostrap_templates.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/boostrap_templates.go new file mode 100644 index 000000000..a367a1fc9 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/boostrap_templates.go @@ -0,0 +1,48 @@ +package generators + +var bootstrapText = `package {{.Package}} + +import ( + "testing" + + {{.GinkgoImport}} + {{.GomegaImport}} +) + +func Test{{.FormattedName}}(t *testing.T) { + {{.GomegaPackage}}RegisterFailHandler({{.GinkgoPackage}}Fail) + {{.GinkgoPackage}}RunSpecs(t, "{{.FormattedName}} Suite") +} +` + +var agoutiBootstrapText = `package {{.Package}} + +import ( + "testing" + + {{.GinkgoImport}} + {{.GomegaImport}} + "github.com/sclevine/agouti" +) + +func Test{{.FormattedName}}(t *testing.T) { + {{.GomegaPackage}}RegisterFailHandler({{.GinkgoPackage}}Fail) + {{.GinkgoPackage}}RunSpecs(t, "{{.FormattedName}} Suite") +} + +var agoutiDriver *agouti.WebDriver + +var _ = {{.GinkgoPackage}}BeforeSuite(func() { + // Choose a WebDriver: + + agoutiDriver = agouti.PhantomJS() + // agoutiDriver = agouti.Selenium() + // agoutiDriver = agouti.ChromeDriver() + + {{.GomegaPackage}}Expect(agoutiDriver.Start()).To({{.GomegaPackage}}Succeed()) +}) + +var _ = {{.GinkgoPackage}}AfterSuite(func() { + {{.GomegaPackage}}Expect(agoutiDriver.Stop()).To({{.GomegaPackage}}Succeed()) +}) +` diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/bootstrap_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/bootstrap_command.go new file mode 100644 index 000000000..73aff0b7a --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/bootstrap_command.go @@ -0,0 +1,133 @@ +package generators + +import ( + "bytes" + "encoding/json" + "fmt" + "os" + "text/template" + + sprig "github.com/go-task/slim-sprig" + "github.com/onsi/ginkgo/v2/ginkgo/command" + "github.com/onsi/ginkgo/v2/ginkgo/internal" + "github.com/onsi/ginkgo/v2/types" +) + +func BuildBootstrapCommand() command.Command { + conf := GeneratorsConfig{} + flags, err := types.NewGinkgoFlagSet( + types.GinkgoFlags{ + {Name: "agouti", KeyPath: "Agouti", + Usage: "If set, bootstrap will generate a bootstrap file for writing Agouti tests"}, + {Name: "nodot", KeyPath: "NoDot", + Usage: "If set, bootstrap will generate a bootstrap test file that does not dot-import ginkgo and gomega"}, + {Name: "internal", KeyPath: "Internal", + Usage: "If set, bootstrap will generate a bootstrap test file that uses the regular package name (i.e. `package X`, not `package X_test`)"}, + {Name: "template", KeyPath: "CustomTemplate", + UsageArgument: "template-file", + Usage: "If specified, generate will use the contents of the file passed as the bootstrap template"}, + {Name: "template-data", KeyPath: "CustomTemplateData", + UsageArgument: "template-data-file", + Usage: "If specified, generate will use the contents of the file passed as data to be rendered in the bootstrap template"}, + }, + &conf, + types.GinkgoFlagSections{}, + ) + + if err != nil { + panic(err) + } + + return command.Command{ + Name: "bootstrap", + Usage: "ginkgo bootstrap", + ShortDoc: "Bootstrap a test suite for the current package", + Documentation: `Tests written in Ginkgo and Gomega require a small amount of boilerplate to hook into Go's testing infrastructure. + +{{bold}}ginkgo bootstrap{{/}} generates this boilerplate for you in a file named X_suite_test.go where X is the name of the package under test.`, + DocLink: "generators", + Flags: flags, + Command: func(_ []string, _ []string) { + generateBootstrap(conf) + }, + } +} + +type bootstrapData struct { + Package string + FormattedName string + + GinkgoImport string + GomegaImport string + GinkgoPackage string + GomegaPackage string + CustomData map[string]any +} + +func generateBootstrap(conf GeneratorsConfig) { + packageName, bootstrapFilePrefix, formattedName := getPackageAndFormattedName() + + data := bootstrapData{ + Package: determinePackageName(packageName, conf.Internal), + FormattedName: formattedName, + + GinkgoImport: `. "github.com/onsi/ginkgo/v2"`, + GomegaImport: `. "github.com/onsi/gomega"`, + GinkgoPackage: "", + GomegaPackage: "", + } + + if conf.NoDot { + data.GinkgoImport = `"github.com/onsi/ginkgo/v2"` + data.GomegaImport = `"github.com/onsi/gomega"` + data.GinkgoPackage = `ginkgo.` + data.GomegaPackage = `gomega.` + } + + targetFile := fmt.Sprintf("%s_suite_test.go", bootstrapFilePrefix) + if internal.FileExists(targetFile) { + command.AbortWith("{{bold}}%s{{/}} already exists", targetFile) + } else { + fmt.Printf("Generating ginkgo test suite bootstrap for %s in:\n\t%s\n", packageName, targetFile) + } + + f, err := os.Create(targetFile) + command.AbortIfError("Failed to create file:", err) + defer f.Close() + + var templateText string + if conf.CustomTemplate != "" { + tpl, err := os.ReadFile(conf.CustomTemplate) + command.AbortIfError("Failed to read custom bootstrap file:", err) + templateText = string(tpl) + if conf.CustomTemplateData != "" { + var tplCustomDataMap map[string]any + tplCustomData, err := os.ReadFile(conf.CustomTemplateData) + command.AbortIfError("Failed to read custom boostrap data file:", err) + if !json.Valid([]byte(tplCustomData)) { + command.AbortWith("Invalid JSON object in custom data file.") + } + //create map from the custom template data + json.Unmarshal(tplCustomData, &tplCustomDataMap) + data.CustomData = tplCustomDataMap + } + } else if conf.Agouti { + templateText = agoutiBootstrapText + } else { + templateText = bootstrapText + } + + //Setting the option to explicitly fail if template is rendered trying to access missing key + bootstrapTemplate, err := template.New("bootstrap").Funcs(sprig.TxtFuncMap()).Option("missingkey=error").Parse(templateText) + command.AbortIfError("Failed to parse bootstrap template:", err) + + buf := &bytes.Buffer{} + //Being explicit about failing sooner during template rendering + //when accessing custom data rather than during the go fmt command + err = bootstrapTemplate.Execute(buf, data) + command.AbortIfError("Failed to render bootstrap template:", err) + + buf.WriteTo(f) + + internal.GoFmt(targetFile) +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generate_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generate_command.go new file mode 100644 index 000000000..48d23f919 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generate_command.go @@ -0,0 +1,259 @@ +package generators + +import ( + "bytes" + "encoding/json" + "fmt" + "os" + "path/filepath" + "strconv" + "strings" + "text/template" + + sprig "github.com/go-task/slim-sprig" + "github.com/onsi/ginkgo/v2/ginkgo/command" + "github.com/onsi/ginkgo/v2/ginkgo/internal" + "github.com/onsi/ginkgo/v2/types" +) + +func BuildGenerateCommand() command.Command { + conf := GeneratorsConfig{} + flags, err := types.NewGinkgoFlagSet( + types.GinkgoFlags{ + {Name: "agouti", KeyPath: "Agouti", + Usage: "If set, generate will create a test file for writing Agouti tests"}, + {Name: "nodot", KeyPath: "NoDot", + Usage: "If set, generate will create a test file that does not dot-import ginkgo and gomega"}, + {Name: "internal", KeyPath: "Internal", + Usage: "If set, generate will create a test file that uses the regular package name (i.e. `package X`, not `package X_test`)"}, + {Name: "template", KeyPath: "CustomTemplate", + UsageArgument: "template-file", + Usage: "If specified, generate will use the contents of the file passed as the test file template"}, + {Name: "template-data", KeyPath: "CustomTemplateData", + UsageArgument: "template-data-file", + Usage: "If specified, generate will use the contents of the file passed as data to be rendered in the test file template"}, + }, + &conf, + types.GinkgoFlagSections{}, + ) + + if err != nil { + panic(err) + } + + return command.Command{ + Name: "generate", + Usage: "ginkgo generate ", + ShortDoc: "Generate a test file named _test.go", + Documentation: `If the optional argument is omitted, a file named after the package in the current directory will be created. + +You can pass multiple to generate multiple files simultaneously. The resulting files are named _test.go. + +You can also pass a of the form "file.go" and generate will emit "file_test.go".`, + DocLink: "generators", + Flags: flags, + Command: func(args []string, _ []string) { + generateTestFiles(conf, args) + }, + } +} + +type specData struct { + Package string + Subject string + PackageImportPath string + ImportPackage bool + + GinkgoImport string + GomegaImport string + GinkgoPackage string + GomegaPackage string + CustomData map[string]any +} + +func generateTestFiles(conf GeneratorsConfig, args []string) { + subjects := args + if len(subjects) == 0 { + subjects = []string{""} + } + for _, subject := range subjects { + generateTestFileForSubject(subject, conf) + } +} + +func generateTestFileForSubject(subject string, conf GeneratorsConfig) { + packageName, specFilePrefix, formattedName := getPackageAndFormattedName() + if subject != "" { + specFilePrefix = formatSubject(subject) + formattedName = prettifyName(specFilePrefix) + } + + if conf.Internal { + specFilePrefix = specFilePrefix + "_internal" + } + + data := specData{ + Package: determinePackageName(packageName, conf.Internal), + Subject: formattedName, + PackageImportPath: getPackageImportPath(), + ImportPackage: !conf.Internal, + + GinkgoImport: `. "github.com/onsi/ginkgo/v2"`, + GomegaImport: `. "github.com/onsi/gomega"`, + GinkgoPackage: "", + GomegaPackage: "", + } + + if conf.NoDot { + data.GinkgoImport = `"github.com/onsi/ginkgo/v2"` + data.GomegaImport = `"github.com/onsi/gomega"` + data.GinkgoPackage = `ginkgo.` + data.GomegaPackage = `gomega.` + } + + targetFile := fmt.Sprintf("%s_test.go", specFilePrefix) + if internal.FileExists(targetFile) { + command.AbortWith("{{bold}}%s{{/}} already exists", targetFile) + } else { + fmt.Printf("Generating ginkgo test for %s in:\n %s\n", data.Subject, targetFile) + } + + f, err := os.Create(targetFile) + command.AbortIfError("Failed to create test file:", err) + defer f.Close() + + var templateText string + if conf.CustomTemplate != "" { + tpl, err := os.ReadFile(conf.CustomTemplate) + command.AbortIfError("Failed to read custom template file:", err) + templateText = string(tpl) + if conf.CustomTemplateData != "" { + var tplCustomDataMap map[string]any + tplCustomData, err := os.ReadFile(conf.CustomTemplateData) + command.AbortIfError("Failed to read custom template data file:", err) + if !json.Valid([]byte(tplCustomData)) { + command.AbortWith("Invalid JSON object in custom data file.") + } + //create map from the custom template data + json.Unmarshal(tplCustomData, &tplCustomDataMap) + data.CustomData = tplCustomDataMap + } + } else if conf.Agouti { + templateText = agoutiSpecText + } else { + templateText = specText + } + + //Setting the option to explicitly fail if template is rendered trying to access missing key + specTemplate, err := template.New("spec").Funcs(sprig.TxtFuncMap()).Option("missingkey=error").Parse(templateText) + command.AbortIfError("Failed to read parse test template:", err) + + //Being explicit about failing sooner during template rendering + //when accessing custom data rather than during the go fmt command + err = specTemplate.Execute(f, data) + command.AbortIfError("Failed to render bootstrap template:", err) + internal.GoFmt(targetFile) +} + +func formatSubject(name string) string { + name = strings.ReplaceAll(name, "-", "_") + name = strings.ReplaceAll(name, " ", "_") + name = strings.Split(name, ".go")[0] + name = strings.Split(name, "_test")[0] + return name +} + +// moduleName returns module name from go.mod from given module root directory +func moduleName(modRoot string) string { + modFile, err := os.Open(filepath.Join(modRoot, "go.mod")) + if err != nil { + return "" + } + + mod := make([]byte, 128) + _, err = modFile.Read(mod) + if err != nil { + return "" + } + + slashSlash := []byte("//") + moduleStr := []byte("module") + + for len(mod) > 0 { + line := mod + mod = nil + if i := bytes.IndexByte(line, '\n'); i >= 0 { + line, mod = line[:i], line[i+1:] + } + if i := bytes.Index(line, slashSlash); i >= 0 { + line = line[:i] + } + line = bytes.TrimSpace(line) + if !bytes.HasPrefix(line, moduleStr) { + continue + } + line = line[len(moduleStr):] + n := len(line) + line = bytes.TrimSpace(line) + if len(line) == n || len(line) == 0 { + continue + } + + if line[0] == '"' || line[0] == '`' { + p, err := strconv.Unquote(string(line)) + if err != nil { + return "" // malformed quoted string or multiline module path + } + return p + } + + return string(line) + } + + return "" // missing module path +} + +func findModuleRoot(dir string) (root string) { + dir = filepath.Clean(dir) + + // Look for enclosing go.mod. + for { + if fi, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil && !fi.IsDir() { + return dir + } + d := filepath.Dir(dir) + if d == dir { + break + } + dir = d + } + return "" +} + +func getPackageImportPath() string { + workingDir, err := os.Getwd() + if err != nil { + panic(err.Error()) + } + + sep := string(filepath.Separator) + + // Try go.mod file first + modRoot := findModuleRoot(workingDir) + if modRoot != "" { + modName := moduleName(modRoot) + if modName != "" { + cd := strings.ReplaceAll(workingDir, modRoot, "") + cd = strings.ReplaceAll(cd, sep, "/") + return modName + cd + } + } + + // Fallback to GOPATH structure + paths := strings.Split(workingDir, sep+"src"+sep) + if len(paths) == 1 { + fmt.Printf("\nCouldn't identify package import path.\n\n\tginkgo generate\n\nMust be run within a package directory under $GOPATH/src/...\nYou're going to have to change UNKNOWN_PACKAGE_PATH in the generated file...\n\n") + return "UNKNOWN_PACKAGE_PATH" + } + return filepath.ToSlash(paths[len(paths)-1]) +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generate_templates.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generate_templates.go new file mode 100644 index 000000000..c3470adbf --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generate_templates.go @@ -0,0 +1,41 @@ +package generators + +var specText = `package {{.Package}} + +import ( + {{.GinkgoImport}} + {{.GomegaImport}} + + {{if .ImportPackage}}"{{.PackageImportPath}}"{{end}} +) + +var _ = {{.GinkgoPackage}}Describe("{{.Subject}}", func() { + +}) +` + +var agoutiSpecText = `package {{.Package}} + +import ( + {{.GinkgoImport}} + {{.GomegaImport}} + "github.com/sclevine/agouti" + . "github.com/sclevine/agouti/matchers" + + {{if .ImportPackage}}"{{.PackageImportPath}}"{{end}} +) + +var _ = {{.GinkgoPackage}}Describe("{{.Subject}}", func() { + var page *agouti.Page + + {{.GinkgoPackage}}BeforeEach(func() { + var err error + page, err = agoutiDriver.NewPage() + {{.GomegaPackage}}Expect(err).NotTo({{.GomegaPackage}}HaveOccurred()) + }) + + {{.GinkgoPackage}}AfterEach(func() { + {{.GomegaPackage}}Expect(page.Destroy()).To({{.GomegaPackage}}Succeed()) + }) +}) +` diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generators_common.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generators_common.go new file mode 100644 index 000000000..3046a4487 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/generators/generators_common.go @@ -0,0 +1,64 @@ +package generators + +import ( + "go/build" + "os" + "path/filepath" + "strconv" + "strings" + + "github.com/onsi/ginkgo/v2/ginkgo/command" +) + +type GeneratorsConfig struct { + Agouti, NoDot, Internal bool + CustomTemplate string + CustomTemplateData string +} + +func getPackageAndFormattedName() (string, string, string) { + path, err := os.Getwd() + command.AbortIfError("Could not get current working directory:", err) + + dirName := strings.ReplaceAll(filepath.Base(path), "-", "_") + dirName = strings.ReplaceAll(dirName, " ", "_") + + pkg, err := build.ImportDir(path, 0) + packageName := pkg.Name + if err != nil { + packageName = ensureLegalPackageName(dirName) + } + + formattedName := prettifyName(filepath.Base(path)) + return packageName, dirName, formattedName +} + +func ensureLegalPackageName(name string) string { + if name == "_" { + return "underscore" + } + if len(name) == 0 { + return "empty" + } + n, isDigitErr := strconv.Atoi(string(name[0])) + if isDigitErr == nil { + return []string{"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"}[n] + name[1:] + } + return name +} + +func prettifyName(name string) string { + name = strings.ReplaceAll(name, "-", " ") + name = strings.ReplaceAll(name, "_", " ") + name = strings.Title(name) + name = strings.ReplaceAll(name, " ", "") + return name +} + +func determinePackageName(name string, internal bool) string { + if internal { + return name + } + + return name + "_test" +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/compile.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/compile.go new file mode 100644 index 000000000..86da7340d --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/compile.go @@ -0,0 +1,161 @@ +package internal + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + "sync" + + "github.com/onsi/ginkgo/v2/types" +) + +func CompileSuite(suite TestSuite, goFlagsConfig types.GoFlagsConfig) TestSuite { + if suite.PathToCompiledTest != "" { + return suite + } + + suite.CompilationError = nil + + path, err := filepath.Abs(filepath.Join(suite.Path, suite.PackageName+".test")) + if err != nil { + suite.State = TestSuiteStateFailedToCompile + suite.CompilationError = fmt.Errorf("Failed to compute compilation target path:\n%s", err.Error()) + return suite + } + + ginkgoInvocationPath, _ := os.Getwd() + ginkgoInvocationPath, _ = filepath.Abs(ginkgoInvocationPath) + packagePath := suite.AbsPath() + pathToInvocationPath, err := filepath.Rel(packagePath, ginkgoInvocationPath) + if err != nil { + suite.State = TestSuiteStateFailedToCompile + suite.CompilationError = fmt.Errorf("Failed to get relative path from package to the current working directory:\n%s", err.Error()) + return suite + } + args, err := types.GenerateGoTestCompileArgs(goFlagsConfig, path, "./", pathToInvocationPath) + if err != nil { + suite.State = TestSuiteStateFailedToCompile + suite.CompilationError = fmt.Errorf("Failed to generate go test compile flags:\n%s", err.Error()) + return suite + } + + cmd := exec.Command("go", args...) + cmd.Dir = suite.Path + output, err := cmd.CombinedOutput() + if err != nil { + if len(output) > 0 { + suite.State = TestSuiteStateFailedToCompile + suite.CompilationError = fmt.Errorf("Failed to compile %s:\n\n%s", suite.PackageName, output) + } else { + suite.State = TestSuiteStateFailedToCompile + suite.CompilationError = fmt.Errorf("Failed to compile %s\n%s", suite.PackageName, err.Error()) + } + return suite + } + + if strings.Contains(string(output), "[no test files]") { + suite.State = TestSuiteStateSkippedDueToEmptyCompilation + return suite + } + + if len(output) > 0 { + fmt.Println(string(output)) + } + + if !FileExists(path) { + suite.State = TestSuiteStateFailedToCompile + suite.CompilationError = fmt.Errorf("Failed to compile %s:\nOutput file %s could not be found", suite.PackageName, path) + return suite + } + + suite.State = TestSuiteStateCompiled + suite.PathToCompiledTest = path + return suite +} + +func Cleanup(goFlagsConfig types.GoFlagsConfig, suites ...TestSuite) { + if goFlagsConfig.BinaryMustBePreserved() { + return + } + for _, suite := range suites { + if !suite.Precompiled { + os.Remove(suite.PathToCompiledTest) + } + } +} + +type parallelSuiteBundle struct { + suite TestSuite + compiled chan TestSuite +} + +type OrderedParallelCompiler struct { + mutex *sync.Mutex + stopped bool + numCompilers int + + idx int + numSuites int + completionChannels []chan TestSuite +} + +func NewOrderedParallelCompiler(numCompilers int) *OrderedParallelCompiler { + return &OrderedParallelCompiler{ + mutex: &sync.Mutex{}, + numCompilers: numCompilers, + } +} + +func (opc *OrderedParallelCompiler) StartCompiling(suites TestSuites, goFlagsConfig types.GoFlagsConfig) { + opc.stopped = false + opc.idx = 0 + opc.numSuites = len(suites) + opc.completionChannels = make([]chan TestSuite, opc.numSuites) + + toCompile := make(chan parallelSuiteBundle, opc.numCompilers) + for compiler := 0; compiler < opc.numCompilers; compiler++ { + go func() { + for bundle := range toCompile { + c, suite := bundle.compiled, bundle.suite + opc.mutex.Lock() + stopped := opc.stopped + opc.mutex.Unlock() + if !stopped { + suite = CompileSuite(suite, goFlagsConfig) + } + c <- suite + } + }() + } + + for idx, suite := range suites { + opc.completionChannels[idx] = make(chan TestSuite, 1) + toCompile <- parallelSuiteBundle{suite, opc.completionChannels[idx]} + if idx == 0 { //compile first suite serially + suite = <-opc.completionChannels[0] + opc.completionChannels[0] <- suite + } + } + + close(toCompile) +} + +func (opc *OrderedParallelCompiler) Next() (int, TestSuite) { + if opc.idx >= opc.numSuites { + return opc.numSuites, TestSuite{} + } + + idx := opc.idx + suite := <-opc.completionChannels[idx] + opc.idx = opc.idx + 1 + + return idx, suite +} + +func (opc *OrderedParallelCompiler) StopAndDrain() { + opc.mutex.Lock() + opc.stopped = true + opc.mutex.Unlock() +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/profiles_and_reports.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/profiles_and_reports.go new file mode 100644 index 000000000..bd3c6d028 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/profiles_and_reports.go @@ -0,0 +1,237 @@ +package internal + +import ( + "bytes" + "fmt" + "os" + "os/exec" + "path/filepath" + "regexp" + "strconv" + + "github.com/google/pprof/profile" + "github.com/onsi/ginkgo/v2/reporters" + "github.com/onsi/ginkgo/v2/types" +) + +func AbsPathForGeneratedAsset(assetName string, suite TestSuite, cliConfig types.CLIConfig, process int) string { + suffix := "" + if process != 0 { + suffix = fmt.Sprintf(".%d", process) + } + if cliConfig.OutputDir == "" { + return filepath.Join(suite.AbsPath(), assetName+suffix) + } + outputDir, _ := filepath.Abs(cliConfig.OutputDir) + return filepath.Join(outputDir, suite.NamespacedName()+"_"+assetName+suffix) +} + +func FinalizeProfilesAndReportsForSuites(suites TestSuites, cliConfig types.CLIConfig, suiteConfig types.SuiteConfig, reporterConfig types.ReporterConfig, goFlagsConfig types.GoFlagsConfig) ([]string, error) { + messages := []string{} + suitesWithProfiles := suites.WithState(TestSuiteStatePassed, TestSuiteStateFailed) //anything else won't have actually run and generated a profile + + // merge cover profiles if need be + if goFlagsConfig.Cover && !cliConfig.KeepSeparateCoverprofiles { + coverProfiles := []string{} + for _, suite := range suitesWithProfiles { + if !suite.HasProgrammaticFocus { + coverProfiles = append(coverProfiles, AbsPathForGeneratedAsset(goFlagsConfig.CoverProfile, suite, cliConfig, 0)) + } + } + + if len(coverProfiles) > 0 { + dst := goFlagsConfig.CoverProfile + if cliConfig.OutputDir != "" { + dst = filepath.Join(cliConfig.OutputDir, goFlagsConfig.CoverProfile) + } + err := MergeAndCleanupCoverProfiles(coverProfiles, dst) + if err != nil { + return messages, err + } + coverage, err := GetCoverageFromCoverProfile(dst) + if err != nil { + return messages, err + } + if coverage == 0 { + messages = append(messages, "composite coverage: [no statements]") + } else if suitesWithProfiles.AnyHaveProgrammaticFocus() { + messages = append(messages, fmt.Sprintf("composite coverage: %.1f%% of statements however some suites did not contribute because they included programatically focused specs", coverage)) + } else { + messages = append(messages, fmt.Sprintf("composite coverage: %.1f%% of statements", coverage)) + } + } else { + messages = append(messages, "no composite coverage computed: all suites included programatically focused specs") + } + } + + // copy binaries if need be + for _, suite := range suitesWithProfiles { + if goFlagsConfig.BinaryMustBePreserved() && cliConfig.OutputDir != "" { + src := suite.PathToCompiledTest + dst := filepath.Join(cliConfig.OutputDir, suite.NamespacedName()+".test") + if suite.Precompiled { + if err := CopyFile(src, dst); err != nil { + return messages, err + } + } else { + if err := os.Rename(src, dst); err != nil { + return messages, err + } + } + } + } + + type reportFormat struct { + ReportName string + GenerateFunc func(types.Report, string) error + MergeFunc func([]string, string) ([]string, error) + } + reportFormats := []reportFormat{} + if reporterConfig.JSONReport != "" { + reportFormats = append(reportFormats, reportFormat{ReportName: reporterConfig.JSONReport, GenerateFunc: reporters.GenerateJSONReport, MergeFunc: reporters.MergeAndCleanupJSONReports}) + } + if reporterConfig.JUnitReport != "" { + reportFormats = append(reportFormats, reportFormat{ReportName: reporterConfig.JUnitReport, GenerateFunc: reporters.GenerateJUnitReport, MergeFunc: reporters.MergeAndCleanupJUnitReports}) + } + if reporterConfig.TeamcityReport != "" { + reportFormats = append(reportFormats, reportFormat{ReportName: reporterConfig.TeamcityReport, GenerateFunc: reporters.GenerateTeamcityReport, MergeFunc: reporters.MergeAndCleanupTeamcityReports}) + } + + // Generate reports for suites that failed to run + reportableSuites := suites.ThatAreGinkgoSuites() + for _, suite := range reportableSuites.WithState(TestSuiteStateFailedToCompile, TestSuiteStateFailedDueToTimeout, TestSuiteStateSkippedDueToPriorFailures, TestSuiteStateSkippedDueToEmptyCompilation) { + report := types.Report{ + SuitePath: suite.AbsPath(), + SuiteConfig: suiteConfig, + SuiteSucceeded: false, + } + switch suite.State { + case TestSuiteStateFailedToCompile: + report.SpecialSuiteFailureReasons = append(report.SpecialSuiteFailureReasons, suite.CompilationError.Error()) + case TestSuiteStateFailedDueToTimeout: + report.SpecialSuiteFailureReasons = append(report.SpecialSuiteFailureReasons, TIMEOUT_ELAPSED_FAILURE_REASON) + case TestSuiteStateSkippedDueToPriorFailures: + report.SpecialSuiteFailureReasons = append(report.SpecialSuiteFailureReasons, PRIOR_FAILURES_FAILURE_REASON) + case TestSuiteStateSkippedDueToEmptyCompilation: + report.SpecialSuiteFailureReasons = append(report.SpecialSuiteFailureReasons, EMPTY_SKIP_FAILURE_REASON) + report.SuiteSucceeded = true + } + + for _, format := range reportFormats { + format.GenerateFunc(report, AbsPathForGeneratedAsset(format.ReportName, suite, cliConfig, 0)) + } + } + + // Merge reports unless we've been asked to keep them separate + if !cliConfig.KeepSeparateReports { + for _, format := range reportFormats { + reports := []string{} + for _, suite := range reportableSuites { + reports = append(reports, AbsPathForGeneratedAsset(format.ReportName, suite, cliConfig, 0)) + } + dst := format.ReportName + if cliConfig.OutputDir != "" { + dst = filepath.Join(cliConfig.OutputDir, format.ReportName) + } + mergeMessages, err := format.MergeFunc(reports, dst) + messages = append(messages, mergeMessages...) + if err != nil { + return messages, err + } + } + } + + return messages, nil +} + +//loads each profile, combines them, deletes them, stores them in destination +func MergeAndCleanupCoverProfiles(profiles []string, destination string) error { + combined := &bytes.Buffer{} + modeRegex := regexp.MustCompile(`^mode: .*\n`) + for i, profile := range profiles { + contents, err := os.ReadFile(profile) + if err != nil { + return fmt.Errorf("Unable to read coverage file %s:\n%s", profile, err.Error()) + } + os.Remove(profile) + + // remove the cover mode line from every file + // except the first one + if i > 0 { + contents = modeRegex.ReplaceAll(contents, []byte{}) + } + + _, err = combined.Write(contents) + + // Add a newline to the end of every file if missing. + if err == nil && len(contents) > 0 && contents[len(contents)-1] != '\n' { + _, err = combined.Write([]byte("\n")) + } + + if err != nil { + return fmt.Errorf("Unable to append to coverprofile:\n%s", err.Error()) + } + } + + err := os.WriteFile(destination, combined.Bytes(), 0666) + if err != nil { + return fmt.Errorf("Unable to create combined cover profile:\n%s", err.Error()) + } + return nil +} + +func GetCoverageFromCoverProfile(profile string) (float64, error) { + cmd := exec.Command("go", "tool", "cover", "-func", profile) + output, err := cmd.CombinedOutput() + if err != nil { + return 0, fmt.Errorf("Could not process Coverprofile %s: %s", profile, err.Error()) + } + re := regexp.MustCompile(`total:\s*\(statements\)\s*(\d*\.\d*)\%`) + matches := re.FindStringSubmatch(string(output)) + if matches == nil { + return 0, fmt.Errorf("Could not parse Coverprofile to compute coverage percentage") + } + coverageString := matches[1] + coverage, err := strconv.ParseFloat(coverageString, 64) + if err != nil { + return 0, fmt.Errorf("Could not parse Coverprofile to compute coverage percentage: %s", err.Error()) + } + + return coverage, nil +} + +func MergeProfiles(profilePaths []string, destination string) error { + profiles := []*profile.Profile{} + for _, profilePath := range profilePaths { + proFile, err := os.Open(profilePath) + if err != nil { + return fmt.Errorf("Could not open profile: %s\n%s", profilePath, err.Error()) + } + prof, err := profile.Parse(proFile) + if err != nil { + return fmt.Errorf("Could not parse profile: %s\n%s", profilePath, err.Error()) + } + profiles = append(profiles, prof) + os.Remove(profilePath) + } + + mergedProfile, err := profile.Merge(profiles) + if err != nil { + return fmt.Errorf("Could not merge profiles:\n%s", err.Error()) + } + + outFile, err := os.Create(destination) + if err != nil { + return fmt.Errorf("Could not create merged profile %s:\n%s", destination, err.Error()) + } + err = mergedProfile.Write(outFile) + if err != nil { + return fmt.Errorf("Could not write merged profile %s:\n%s", destination, err.Error()) + } + err = outFile.Close() + if err != nil { + return fmt.Errorf("Could not close merged profile %s:\n%s", destination, err.Error()) + } + + return nil +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/run.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/run.go new file mode 100644 index 000000000..41052ea19 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/run.go @@ -0,0 +1,355 @@ +package internal + +import ( + "bytes" + "fmt" + "io" + "os" + "os/exec" + "path/filepath" + "regexp" + "strings" + "syscall" + "time" + + "github.com/onsi/ginkgo/v2/formatter" + "github.com/onsi/ginkgo/v2/ginkgo/command" + "github.com/onsi/ginkgo/v2/internal/parallel_support" + "github.com/onsi/ginkgo/v2/reporters" + "github.com/onsi/ginkgo/v2/types" +) + +func RunCompiledSuite(suite TestSuite, ginkgoConfig types.SuiteConfig, reporterConfig types.ReporterConfig, cliConfig types.CLIConfig, goFlagsConfig types.GoFlagsConfig, additionalArgs []string) TestSuite { + suite.State = TestSuiteStateFailed + suite.HasProgrammaticFocus = false + + if suite.PathToCompiledTest == "" { + return suite + } + + if suite.IsGinkgo && cliConfig.ComputedProcs() > 1 { + suite = runParallel(suite, ginkgoConfig, reporterConfig, cliConfig, goFlagsConfig, additionalArgs) + } else if suite.IsGinkgo { + suite = runSerial(suite, ginkgoConfig, reporterConfig, cliConfig, goFlagsConfig, additionalArgs) + } else { + suite = runGoTest(suite, cliConfig, goFlagsConfig) + } + runAfterRunHook(cliConfig.AfterRunHook, reporterConfig.NoColor, suite) + return suite +} + +func buildAndStartCommand(suite TestSuite, args []string, pipeToStdout bool) (*exec.Cmd, *bytes.Buffer) { + buf := &bytes.Buffer{} + cmd := exec.Command(suite.PathToCompiledTest, args...) + cmd.Dir = suite.Path + if pipeToStdout { + cmd.Stderr = io.MultiWriter(os.Stdout, buf) + cmd.Stdout = os.Stdout + } else { + cmd.Stderr = buf + cmd.Stdout = buf + } + err := cmd.Start() + command.AbortIfError("Failed to start test suite", err) + + return cmd, buf +} + +func checkForNoTestsWarning(buf *bytes.Buffer) bool { + if strings.Contains(buf.String(), "warning: no tests to run") { + fmt.Fprintf(os.Stderr, `Found no test suites, did you forget to run "ginkgo bootstrap"?`) + return true + } + return false +} + +func runGoTest(suite TestSuite, cliConfig types.CLIConfig, goFlagsConfig types.GoFlagsConfig) TestSuite { + // As we run the go test from the suite directory, make sure the cover profile is absolute + // and placed into the expected output directory when one is configured. + if goFlagsConfig.Cover && !filepath.IsAbs(goFlagsConfig.CoverProfile) { + goFlagsConfig.CoverProfile = AbsPathForGeneratedAsset(goFlagsConfig.CoverProfile, suite, cliConfig, 0) + } + + args, err := types.GenerateGoTestRunArgs(goFlagsConfig) + command.AbortIfError("Failed to generate test run arguments", err) + cmd, buf := buildAndStartCommand(suite, args, true) + + cmd.Wait() + + exitStatus := cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() + passed := (exitStatus == 0) || (exitStatus == types.GINKGO_FOCUS_EXIT_CODE) + passed = !(checkForNoTestsWarning(buf) && cliConfig.RequireSuite) && passed + if passed { + suite.State = TestSuiteStatePassed + } else { + suite.State = TestSuiteStateFailed + } + + return suite +} + +func runSerial(suite TestSuite, ginkgoConfig types.SuiteConfig, reporterConfig types.ReporterConfig, cliConfig types.CLIConfig, goFlagsConfig types.GoFlagsConfig, additionalArgs []string) TestSuite { + if goFlagsConfig.Cover { + goFlagsConfig.CoverProfile = AbsPathForGeneratedAsset(goFlagsConfig.CoverProfile, suite, cliConfig, 0) + } + if goFlagsConfig.BlockProfile != "" { + goFlagsConfig.BlockProfile = AbsPathForGeneratedAsset(goFlagsConfig.BlockProfile, suite, cliConfig, 0) + } + if goFlagsConfig.CPUProfile != "" { + goFlagsConfig.CPUProfile = AbsPathForGeneratedAsset(goFlagsConfig.CPUProfile, suite, cliConfig, 0) + } + if goFlagsConfig.MemProfile != "" { + goFlagsConfig.MemProfile = AbsPathForGeneratedAsset(goFlagsConfig.MemProfile, suite, cliConfig, 0) + } + if goFlagsConfig.MutexProfile != "" { + goFlagsConfig.MutexProfile = AbsPathForGeneratedAsset(goFlagsConfig.MutexProfile, suite, cliConfig, 0) + } + if reporterConfig.JSONReport != "" { + reporterConfig.JSONReport = AbsPathForGeneratedAsset(reporterConfig.JSONReport, suite, cliConfig, 0) + } + if reporterConfig.JUnitReport != "" { + reporterConfig.JUnitReport = AbsPathForGeneratedAsset(reporterConfig.JUnitReport, suite, cliConfig, 0) + } + if reporterConfig.TeamcityReport != "" { + reporterConfig.TeamcityReport = AbsPathForGeneratedAsset(reporterConfig.TeamcityReport, suite, cliConfig, 0) + } + + args, err := types.GenerateGinkgoTestRunArgs(ginkgoConfig, reporterConfig, goFlagsConfig) + command.AbortIfError("Failed to generate test run arguments", err) + args = append([]string{"--test.timeout=0"}, args...) + args = append(args, additionalArgs...) + + cmd, buf := buildAndStartCommand(suite, args, true) + + cmd.Wait() + + exitStatus := cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() + suite.HasProgrammaticFocus = (exitStatus == types.GINKGO_FOCUS_EXIT_CODE) + passed := (exitStatus == 0) || (exitStatus == types.GINKGO_FOCUS_EXIT_CODE) + passed = !(checkForNoTestsWarning(buf) && cliConfig.RequireSuite) && passed + if passed { + suite.State = TestSuiteStatePassed + } else { + suite.State = TestSuiteStateFailed + } + + if suite.HasProgrammaticFocus { + if goFlagsConfig.Cover { + fmt.Fprintln(os.Stdout, "coverage: no coverfile was generated because specs are programmatically focused") + } + if goFlagsConfig.BlockProfile != "" { + fmt.Fprintln(os.Stdout, "no block profile was generated because specs are programmatically focused") + } + if goFlagsConfig.CPUProfile != "" { + fmt.Fprintln(os.Stdout, "no cpu profile was generated because specs are programmatically focused") + } + if goFlagsConfig.MemProfile != "" { + fmt.Fprintln(os.Stdout, "no mem profile was generated because specs are programmatically focused") + } + if goFlagsConfig.MutexProfile != "" { + fmt.Fprintln(os.Stdout, "no mutex profile was generated because specs are programmatically focused") + } + } + + return suite +} + +func runParallel(suite TestSuite, ginkgoConfig types.SuiteConfig, reporterConfig types.ReporterConfig, cliConfig types.CLIConfig, goFlagsConfig types.GoFlagsConfig, additionalArgs []string) TestSuite { + type procResult struct { + passed bool + hasProgrammaticFocus bool + } + + numProcs := cliConfig.ComputedProcs() + procOutput := make([]*bytes.Buffer, numProcs) + coverProfiles := []string{} + + blockProfiles := []string{} + cpuProfiles := []string{} + memProfiles := []string{} + mutexProfiles := []string{} + + procResults := make(chan procResult) + + server, err := parallel_support.NewServer(numProcs, reporters.NewDefaultReporter(reporterConfig, formatter.ColorableStdOut)) + command.AbortIfError("Failed to start parallel spec server", err) + server.Start() + defer server.Close() + + if reporterConfig.JSONReport != "" { + reporterConfig.JSONReport = AbsPathForGeneratedAsset(reporterConfig.JSONReport, suite, cliConfig, 0) + } + if reporterConfig.JUnitReport != "" { + reporterConfig.JUnitReport = AbsPathForGeneratedAsset(reporterConfig.JUnitReport, suite, cliConfig, 0) + } + if reporterConfig.TeamcityReport != "" { + reporterConfig.TeamcityReport = AbsPathForGeneratedAsset(reporterConfig.TeamcityReport, suite, cliConfig, 0) + } + + for proc := 1; proc <= numProcs; proc++ { + procGinkgoConfig := ginkgoConfig + procGinkgoConfig.ParallelProcess, procGinkgoConfig.ParallelTotal, procGinkgoConfig.ParallelHost = proc, numProcs, server.Address() + + procGoFlagsConfig := goFlagsConfig + if goFlagsConfig.Cover { + procGoFlagsConfig.CoverProfile = AbsPathForGeneratedAsset(goFlagsConfig.CoverProfile, suite, cliConfig, proc) + coverProfiles = append(coverProfiles, procGoFlagsConfig.CoverProfile) + } + if goFlagsConfig.BlockProfile != "" { + procGoFlagsConfig.BlockProfile = AbsPathForGeneratedAsset(goFlagsConfig.BlockProfile, suite, cliConfig, proc) + blockProfiles = append(blockProfiles, procGoFlagsConfig.BlockProfile) + } + if goFlagsConfig.CPUProfile != "" { + procGoFlagsConfig.CPUProfile = AbsPathForGeneratedAsset(goFlagsConfig.CPUProfile, suite, cliConfig, proc) + cpuProfiles = append(cpuProfiles, procGoFlagsConfig.CPUProfile) + } + if goFlagsConfig.MemProfile != "" { + procGoFlagsConfig.MemProfile = AbsPathForGeneratedAsset(goFlagsConfig.MemProfile, suite, cliConfig, proc) + memProfiles = append(memProfiles, procGoFlagsConfig.MemProfile) + } + if goFlagsConfig.MutexProfile != "" { + procGoFlagsConfig.MutexProfile = AbsPathForGeneratedAsset(goFlagsConfig.MutexProfile, suite, cliConfig, proc) + mutexProfiles = append(mutexProfiles, procGoFlagsConfig.MutexProfile) + } + + args, err := types.GenerateGinkgoTestRunArgs(procGinkgoConfig, reporterConfig, procGoFlagsConfig) + command.AbortIfError("Failed to generate test run arguments", err) + args = append([]string{"--test.timeout=0"}, args...) + args = append(args, additionalArgs...) + + cmd, buf := buildAndStartCommand(suite, args, false) + procOutput[proc-1] = buf + server.RegisterAlive(proc, func() bool { return cmd.ProcessState == nil || !cmd.ProcessState.Exited() }) + + go func() { + cmd.Wait() + exitStatus := cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() + procResults <- procResult{ + passed: (exitStatus == 0) || (exitStatus == types.GINKGO_FOCUS_EXIT_CODE), + hasProgrammaticFocus: exitStatus == types.GINKGO_FOCUS_EXIT_CODE, + } + }() + } + + passed := true + for proc := 1; proc <= cliConfig.ComputedProcs(); proc++ { + result := <-procResults + passed = passed && result.passed + suite.HasProgrammaticFocus = suite.HasProgrammaticFocus || result.hasProgrammaticFocus + } + if passed { + suite.State = TestSuiteStatePassed + } else { + suite.State = TestSuiteStateFailed + } + + select { + case <-server.GetSuiteDone(): + fmt.Println("") + case <-time.After(time.Second): + //one of the nodes never finished reporting to the server. Something must have gone wrong. + fmt.Fprint(formatter.ColorableStdErr, formatter.F("\n{{bold}}{{red}}Ginkgo timed out waiting for all parallel procs to report back{{/}}\n")) + fmt.Fprint(formatter.ColorableStdErr, formatter.F("{{gray}}Test suite:{{/}} %s (%s)\n\n", suite.PackageName, suite.Path)) + fmt.Fprint(formatter.ColorableStdErr, formatter.Fiw(0, formatter.COLS, "This occurs if a parallel process exits before it reports its results to the Ginkgo CLI. The CLI will now print out all the stdout/stderr output it's collected from the running processes. However you may not see anything useful in these logs because the individual test processes usually intercept output to stdout/stderr in order to capture it in the spec reports.\n\nYou may want to try rerunning your test suite with {{light-gray}}--output-interceptor-mode=none{{/}} to see additional output here and debug your suite.\n")) + fmt.Fprintln(formatter.ColorableStdErr, " ") + for proc := 1; proc <= cliConfig.ComputedProcs(); proc++ { + fmt.Fprintf(formatter.ColorableStdErr, formatter.F("{{bold}}Output from proc %d:{{/}}\n", proc)) + fmt.Fprintln(os.Stderr, formatter.Fi(1, "%s", procOutput[proc-1].String())) + } + fmt.Fprintf(os.Stderr, "** End **") + } + + for proc := 1; proc <= cliConfig.ComputedProcs(); proc++ { + output := procOutput[proc-1].String() + if proc == 1 && checkForNoTestsWarning(procOutput[0]) && cliConfig.RequireSuite { + suite.State = TestSuiteStateFailed + } + if strings.Contains(output, "deprecated Ginkgo functionality") { + fmt.Fprintln(os.Stderr, output) + } + } + + if len(coverProfiles) > 0 { + if suite.HasProgrammaticFocus { + fmt.Fprintln(os.Stdout, "coverage: no coverfile was generated because specs are programmatically focused") + } else { + coverProfile := AbsPathForGeneratedAsset(goFlagsConfig.CoverProfile, suite, cliConfig, 0) + err := MergeAndCleanupCoverProfiles(coverProfiles, coverProfile) + command.AbortIfError("Failed to combine cover profiles", err) + + coverage, err := GetCoverageFromCoverProfile(coverProfile) + command.AbortIfError("Failed to compute coverage", err) + if coverage == 0 { + fmt.Fprintln(os.Stdout, "coverage: [no statements]") + } else { + fmt.Fprintf(os.Stdout, "coverage: %.1f%% of statements\n", coverage) + } + } + } + if len(blockProfiles) > 0 { + if suite.HasProgrammaticFocus { + fmt.Fprintln(os.Stdout, "no block profile was generated because specs are programmatically focused") + } else { + blockProfile := AbsPathForGeneratedAsset(goFlagsConfig.BlockProfile, suite, cliConfig, 0) + err := MergeProfiles(blockProfiles, blockProfile) + command.AbortIfError("Failed to combine blockprofiles", err) + } + } + if len(cpuProfiles) > 0 { + if suite.HasProgrammaticFocus { + fmt.Fprintln(os.Stdout, "no cpu profile was generated because specs are programmatically focused") + } else { + cpuProfile := AbsPathForGeneratedAsset(goFlagsConfig.CPUProfile, suite, cliConfig, 0) + err := MergeProfiles(cpuProfiles, cpuProfile) + command.AbortIfError("Failed to combine cpuprofiles", err) + } + } + if len(memProfiles) > 0 { + if suite.HasProgrammaticFocus { + fmt.Fprintln(os.Stdout, "no mem profile was generated because specs are programmatically focused") + } else { + memProfile := AbsPathForGeneratedAsset(goFlagsConfig.MemProfile, suite, cliConfig, 0) + err := MergeProfiles(memProfiles, memProfile) + command.AbortIfError("Failed to combine memprofiles", err) + } + } + if len(mutexProfiles) > 0 { + if suite.HasProgrammaticFocus { + fmt.Fprintln(os.Stdout, "no mutex profile was generated because specs are programmatically focused") + } else { + mutexProfile := AbsPathForGeneratedAsset(goFlagsConfig.MutexProfile, suite, cliConfig, 0) + err := MergeProfiles(mutexProfiles, mutexProfile) + command.AbortIfError("Failed to combine mutexprofiles", err) + } + } + + return suite +} + +func runAfterRunHook(command string, noColor bool, suite TestSuite) { + if command == "" { + return + } + f := formatter.NewWithNoColorBool(noColor) + + // Allow for string replacement to pass input to the command + passed := "[FAIL]" + if suite.State.Is(TestSuiteStatePassed) { + passed = "[PASS]" + } + command = strings.ReplaceAll(command, "(ginkgo-suite-passed)", passed) + command = strings.ReplaceAll(command, "(ginkgo-suite-name)", suite.PackageName) + + // Must break command into parts + splitArgs := regexp.MustCompile(`'.+'|".+"|\S+`) + parts := splitArgs.FindAllString(command, -1) + + output, err := exec.Command(parts[0], parts[1:]...).CombinedOutput() + if err != nil { + fmt.Fprintln(formatter.ColorableStdOut, f.Fi(0, "{{red}}{{bold}}After-run-hook failed:{{/}}")) + fmt.Fprintln(formatter.ColorableStdOut, f.Fi(1, "{{red}}%s{{/}}", output)) + } else { + fmt.Fprintln(formatter.ColorableStdOut, f.Fi(0, "{{green}}{{bold}}After-run-hook succeeded:{{/}}")) + fmt.Fprintln(formatter.ColorableStdOut, f.Fi(1, "{{green}}%s{{/}}", output)) + } +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/test_suite.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/test_suite.go new file mode 100644 index 000000000..64dcb1b78 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/test_suite.go @@ -0,0 +1,283 @@ +package internal + +import ( + "errors" + "math/rand" + "os" + "path" + "path/filepath" + "regexp" + "strings" + + "github.com/onsi/ginkgo/v2/types" +) + +const TIMEOUT_ELAPSED_FAILURE_REASON = "Suite did not run because the timeout elapsed" +const PRIOR_FAILURES_FAILURE_REASON = "Suite did not run because prior suites failed and --keep-going is not set" +const EMPTY_SKIP_FAILURE_REASON = "Suite did not run go test reported that no test files were found" + +type TestSuiteState uint + +const ( + TestSuiteStateInvalid TestSuiteState = iota + + TestSuiteStateUncompiled + TestSuiteStateCompiled + + TestSuiteStatePassed + + TestSuiteStateSkippedDueToEmptyCompilation + TestSuiteStateSkippedByFilter + TestSuiteStateSkippedDueToPriorFailures + + TestSuiteStateFailed + TestSuiteStateFailedDueToTimeout + TestSuiteStateFailedToCompile +) + +var TestSuiteStateFailureStates = []TestSuiteState{TestSuiteStateFailed, TestSuiteStateFailedDueToTimeout, TestSuiteStateFailedToCompile} + +func (state TestSuiteState) Is(states ...TestSuiteState) bool { + for _, suiteState := range states { + if suiteState == state { + return true + } + } + + return false +} + +type TestSuite struct { + Path string + PackageName string + IsGinkgo bool + + Precompiled bool + PathToCompiledTest string + CompilationError error + + HasProgrammaticFocus bool + State TestSuiteState +} + +func (ts TestSuite) AbsPath() string { + path, _ := filepath.Abs(ts.Path) + return path +} + +func (ts TestSuite) NamespacedName() string { + name := relPath(ts.Path) + name = strings.TrimLeft(name, "."+string(filepath.Separator)) + name = strings.ReplaceAll(name, string(filepath.Separator), "_") + name = strings.ReplaceAll(name, " ", "_") + if name == "" { + return ts.PackageName + } + return name +} + +type TestSuites []TestSuite + +func (ts TestSuites) AnyHaveProgrammaticFocus() bool { + for _, suite := range ts { + if suite.HasProgrammaticFocus { + return true + } + } + + return false +} + +func (ts TestSuites) ThatAreGinkgoSuites() TestSuites { + out := TestSuites{} + for _, suite := range ts { + if suite.IsGinkgo { + out = append(out, suite) + } + } + return out +} + +func (ts TestSuites) CountWithState(states ...TestSuiteState) int { + n := 0 + for _, suite := range ts { + if suite.State.Is(states...) { + n += 1 + } + } + + return n +} + +func (ts TestSuites) WithState(states ...TestSuiteState) TestSuites { + out := TestSuites{} + for _, suite := range ts { + if suite.State.Is(states...) { + out = append(out, suite) + } + } + + return out +} + +func (ts TestSuites) WithoutState(states ...TestSuiteState) TestSuites { + out := TestSuites{} + for _, suite := range ts { + if !suite.State.Is(states...) { + out = append(out, suite) + } + } + + return out +} + +func (ts TestSuites) ShuffledCopy(seed int64) TestSuites { + out := make(TestSuites, len(ts)) + permutation := rand.New(rand.NewSource(seed)).Perm(len(ts)) + for i, j := range permutation { + out[i] = ts[j] + } + return out +} + +func FindSuites(args []string, cliConfig types.CLIConfig, allowPrecompiled bool) TestSuites { + suites := TestSuites{} + + if len(args) > 0 { + for _, arg := range args { + if allowPrecompiled { + suite, err := precompiledTestSuite(arg) + if err == nil { + suites = append(suites, suite) + continue + } + } + recurseForSuite := cliConfig.Recurse + if strings.HasSuffix(arg, "/...") && arg != "/..." { + arg = arg[:len(arg)-4] + recurseForSuite = true + } + suites = append(suites, suitesInDir(arg, recurseForSuite)...) + } + } else { + suites = suitesInDir(".", cliConfig.Recurse) + } + + if cliConfig.SkipPackage != "" { + skipFilters := strings.Split(cliConfig.SkipPackage, ",") + for idx := range suites { + for _, skipFilter := range skipFilters { + if strings.Contains(suites[idx].Path, skipFilter) { + suites[idx].State = TestSuiteStateSkippedByFilter + break + } + } + } + } + + return suites +} + +func precompiledTestSuite(path string) (TestSuite, error) { + info, err := os.Stat(path) + if err != nil { + return TestSuite{}, err + } + + if info.IsDir() { + return TestSuite{}, errors.New("this is a directory, not a file") + } + + if filepath.Ext(path) != ".test" && filepath.Ext(path) != ".exe" { + return TestSuite{}, errors.New("this is not a .test binary") + } + + if filepath.Ext(path) == ".test" && info.Mode()&0111 == 0 { + return TestSuite{}, errors.New("this is not executable") + } + + dir := relPath(filepath.Dir(path)) + packageName := strings.TrimSuffix(filepath.Base(path), ".exe") + packageName = strings.TrimSuffix(packageName, ".test") + + path, err = filepath.Abs(path) + if err != nil { + return TestSuite{}, err + } + + return TestSuite{ + Path: dir, + PackageName: packageName, + IsGinkgo: true, + Precompiled: true, + PathToCompiledTest: path, + State: TestSuiteStateCompiled, + }, nil +} + +func suitesInDir(dir string, recurse bool) TestSuites { + suites := TestSuites{} + + if path.Base(dir) == "vendor" { + return suites + } + + files, _ := os.ReadDir(dir) + re := regexp.MustCompile(`^[^._].*_test\.go$`) + for _, file := range files { + if !file.IsDir() && re.Match([]byte(file.Name())) { + suite := TestSuite{ + Path: relPath(dir), + PackageName: packageNameForSuite(dir), + IsGinkgo: filesHaveGinkgoSuite(dir, files), + State: TestSuiteStateUncompiled, + } + suites = append(suites, suite) + break + } + } + + if recurse { + re = regexp.MustCompile(`^[._]`) + for _, file := range files { + if file.IsDir() && !re.Match([]byte(file.Name())) { + suites = append(suites, suitesInDir(dir+"/"+file.Name(), recurse)...) + } + } + } + + return suites +} + +func relPath(dir string) string { + dir, _ = filepath.Abs(dir) + cwd, _ := os.Getwd() + dir, _ = filepath.Rel(cwd, filepath.Clean(dir)) + + if string(dir[0]) != "." { + dir = "." + string(filepath.Separator) + dir + } + + return dir +} + +func packageNameForSuite(dir string) string { + path, _ := filepath.Abs(dir) + return filepath.Base(path) +} + +func filesHaveGinkgoSuite(dir string, files []os.DirEntry) bool { + reTestFile := regexp.MustCompile(`_test\.go$`) + reGinkgo := regexp.MustCompile(`package ginkgo|\/ginkgo"|\/ginkgo\/v2"|\/ginkgo\/v2/dsl/`) + + for _, file := range files { + if !file.IsDir() && reTestFile.Match([]byte(file.Name())) { + contents, _ := os.ReadFile(dir + "/" + file.Name()) + if reGinkgo.Match(contents) { + return true + } + } + } + + return false +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/utils.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/utils.go new file mode 100644 index 000000000..bd9ca7d51 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/utils.go @@ -0,0 +1,86 @@ +package internal + +import ( + "fmt" + "io" + "os" + "os/exec" + + "github.com/onsi/ginkgo/v2/formatter" + "github.com/onsi/ginkgo/v2/ginkgo/command" +) + +func FileExists(path string) bool { + _, err := os.Stat(path) + return err == nil +} + +func CopyFile(src string, dest string) error { + srcFile, err := os.Open(src) + if err != nil { + return err + } + + srcStat, err := srcFile.Stat() + if err != nil { + return err + } + + if _, err := os.Stat(dest); err == nil { + os.Remove(dest) + } + + destFile, err := os.OpenFile(dest, os.O_WRONLY|os.O_CREATE, srcStat.Mode()) + if err != nil { + return err + } + + _, err = io.Copy(destFile, srcFile) + if err != nil { + return err + } + + if err := srcFile.Close(); err != nil { + return err + } + return destFile.Close() +} + +func GoFmt(path string) { + out, err := exec.Command("go", "fmt", path).CombinedOutput() + if err != nil { + command.AbortIfError(fmt.Sprintf("Could not fmt:\n%s\n", string(out)), err) + } +} + +func PluralizedWord(singular, plural string, count int) string { + if count == 1 { + return singular + } + return plural +} + +func FailedSuitesReport(suites TestSuites, f formatter.Formatter) string { + out := "" + out += "There were failures detected in the following suites:\n" + + maxPackageNameLength := 0 + for _, suite := range suites.WithState(TestSuiteStateFailureStates...) { + if len(suite.PackageName) > maxPackageNameLength { + maxPackageNameLength = len(suite.PackageName) + } + } + + packageNameFormatter := fmt.Sprintf("%%%ds", maxPackageNameLength) + for _, suite := range suites { + switch suite.State { + case TestSuiteStateFailed: + out += f.Fi(1, "{{red}}"+packageNameFormatter+" {{gray}}%s{{/}}\n", suite.PackageName, suite.Path) + case TestSuiteStateFailedToCompile: + out += f.Fi(1, "{{red}}"+packageNameFormatter+" {{gray}}%s {{magenta}}[Compilation failure]{{/}}\n", suite.PackageName, suite.Path) + case TestSuiteStateFailedDueToTimeout: + out += f.Fi(1, "{{red}}"+packageNameFormatter+" {{gray}}%s {{orange}}[%s]{{/}}\n", suite.PackageName, suite.Path, TIMEOUT_ELAPSED_FAILURE_REASON) + } + } + return out +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/verify_version.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/verify_version.go new file mode 100644 index 000000000..9da1bab3d --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/internal/verify_version.go @@ -0,0 +1,54 @@ +package internal + +import ( + "fmt" + "os/exec" + "regexp" + "strings" + + "github.com/onsi/ginkgo/v2/formatter" + "github.com/onsi/ginkgo/v2/types" +) + +var versiorRe = regexp.MustCompile(`v(\d+\.\d+\.\d+)`) + +func VerifyCLIAndFrameworkVersion(suites TestSuites) { + cliVersion := types.VERSION + mismatches := map[string][]string{} + + for _, suite := range suites { + cmd := exec.Command("go", "list", "-m", "github.com/onsi/ginkgo/v2") + cmd.Dir = suite.Path + output, err := cmd.CombinedOutput() + if err != nil { + continue + } + components := strings.Split(string(output), " ") + if len(components) != 2 { + continue + } + matches := versiorRe.FindStringSubmatch(components[1]) + if matches == nil || len(matches) != 2 { + continue + } + libraryVersion := matches[1] + if cliVersion != libraryVersion { + mismatches[libraryVersion] = append(mismatches[libraryVersion], suite.PackageName) + } + } + + if len(mismatches) == 0 { + return + } + + fmt.Println(formatter.F("{{red}}{{bold}}Ginkgo detected a version mismatch between the Ginkgo CLI and the version of Ginkgo imported by your packages:{{/}}")) + + fmt.Println(formatter.Fi(1, "Ginkgo CLI Version:")) + fmt.Println(formatter.Fi(2, "{{bold}}%s{{/}}", cliVersion)) + fmt.Println(formatter.Fi(1, "Mismatched package versions found:")) + for version, packages := range mismatches { + fmt.Println(formatter.Fi(2, "{{bold}}%s{{/}} used by %s", version, strings.Join(packages, ", "))) + } + fmt.Println("") + fmt.Println(formatter.Fiw(1, formatter.COLS, "{{gray}}Ginkgo will continue to attempt to run but you may see errors (including flag parsing errors) and should either update your go.mod or your version of the Ginkgo CLI to match.\n\nTo install the matching version of the CLI run\n {{bold}}go install github.com/onsi/ginkgo/v2/ginkgo{{/}}{{gray}}\nfrom a path that contains a go.mod file. Alternatively you can use\n {{bold}}go run github.com/onsi/ginkgo/v2/ginkgo{{/}}{{gray}}\nfrom a path that contains a go.mod file to invoke the matching version of the Ginkgo CLI.\n\nIf you are attempting to test multiple packages that each have a different version of the Ginkgo library with a single Ginkgo CLI that is currently unsupported.\n{{/}}")) +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/labels/labels_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/labels/labels_command.go new file mode 100644 index 000000000..6c61f09d1 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/labels/labels_command.go @@ -0,0 +1,123 @@ +package labels + +import ( + "fmt" + "go/ast" + "go/parser" + "go/token" + "sort" + "strconv" + "strings" + + "github.com/onsi/ginkgo/v2/ginkgo/command" + "github.com/onsi/ginkgo/v2/ginkgo/internal" + "github.com/onsi/ginkgo/v2/types" + "golang.org/x/tools/go/ast/inspector" +) + +func BuildLabelsCommand() command.Command { + var cliConfig = types.NewDefaultCLIConfig() + + flags, err := types.BuildLabelsCommandFlagSet(&cliConfig) + if err != nil { + panic(err) + } + + return command.Command{ + Name: "labels", + Usage: "ginkgo labels ", + Flags: flags, + ShortDoc: "List labels detected in the passed-in packages (or the package in the current directory if left blank).", + DocLink: "spec-labels", + Command: func(args []string, _ []string) { + ListLabels(args, cliConfig) + }, + } +} + +func ListLabels(args []string, cliConfig types.CLIConfig) { + suites := internal.FindSuites(args, cliConfig, false).WithoutState(internal.TestSuiteStateSkippedByFilter) + if len(suites) == 0 { + command.AbortWith("Found no test suites") + } + for _, suite := range suites { + labels := fetchLabelsFromPackage(suite.Path) + if len(labels) == 0 { + fmt.Printf("%s: No labels found\n", suite.PackageName) + } else { + fmt.Printf("%s: [%s]\n", suite.PackageName, strings.Join(labels, ", ")) + } + } +} + +func fetchLabelsFromPackage(packagePath string) []string { + fset := token.NewFileSet() + parsedPackages, err := parser.ParseDir(fset, packagePath, nil, 0) + command.AbortIfError("Failed to parse package source:", err) + + files := []*ast.File{} + hasTestPackage := false + for key, pkg := range parsedPackages { + if strings.HasSuffix(key, "_test") { + hasTestPackage = true + for _, file := range pkg.Files { + files = append(files, file) + } + } + } + if !hasTestPackage { + for _, pkg := range parsedPackages { + for _, file := range pkg.Files { + files = append(files, file) + } + } + } + + seen := map[string]bool{} + labels := []string{} + ispr := inspector.New(files) + ispr.Preorder([]ast.Node{&ast.CallExpr{}}, func(n ast.Node) { + potentialLabels := fetchLabels(n.(*ast.CallExpr)) + for _, label := range potentialLabels { + if !seen[label] { + seen[label] = true + labels = append(labels, strconv.Quote(label)) + } + } + }) + + sort.Strings(labels) + return labels +} + +func fetchLabels(callExpr *ast.CallExpr) []string { + out := []string{} + switch expr := callExpr.Fun.(type) { + case *ast.Ident: + if expr.Name != "Label" { + return out + } + case *ast.SelectorExpr: + if expr.Sel.Name != "Label" { + return out + } + default: + return out + } + for _, arg := range callExpr.Args { + switch expr := arg.(type) { + case *ast.BasicLit: + if expr.Kind == token.STRING { + unquoted, err := strconv.Unquote(expr.Value) + if err != nil { + unquoted = expr.Value + } + validated, err := types.ValidateAndCleanupLabel(unquoted, types.CodeLocation{}) + if err == nil { + out = append(out, validated) + } + } + } + } + return out +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/main.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/main.go new file mode 100644 index 000000000..e9abb27d8 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/main.go @@ -0,0 +1,58 @@ +package main + +import ( + "fmt" + "os" + + "github.com/onsi/ginkgo/v2/ginkgo/build" + "github.com/onsi/ginkgo/v2/ginkgo/command" + "github.com/onsi/ginkgo/v2/ginkgo/generators" + "github.com/onsi/ginkgo/v2/ginkgo/labels" + "github.com/onsi/ginkgo/v2/ginkgo/outline" + "github.com/onsi/ginkgo/v2/ginkgo/run" + "github.com/onsi/ginkgo/v2/ginkgo/unfocus" + "github.com/onsi/ginkgo/v2/ginkgo/watch" + "github.com/onsi/ginkgo/v2/types" +) + +var program command.Program + +func GenerateCommands() []command.Command { + return []command.Command{ + watch.BuildWatchCommand(), + build.BuildBuildCommand(), + generators.BuildBootstrapCommand(), + generators.BuildGenerateCommand(), + labels.BuildLabelsCommand(), + outline.BuildOutlineCommand(), + unfocus.BuildUnfocusCommand(), + BuildVersionCommand(), + } +} + +func main() { + program = command.Program{ + Name: "ginkgo", + Heading: fmt.Sprintf("Ginkgo Version %s", types.VERSION), + Commands: GenerateCommands(), + DefaultCommand: run.BuildRunCommand(), + DeprecatedCommands: []command.DeprecatedCommand{ + {Name: "convert", Deprecation: types.Deprecations.Convert()}, + {Name: "blur", Deprecation: types.Deprecations.Blur()}, + {Name: "nodot", Deprecation: types.Deprecations.Nodot()}, + }, + } + + program.RunAndExit(os.Args) +} + +func BuildVersionCommand() command.Command { + return command.Command{ + Name: "version", + Usage: "ginkgo version", + ShortDoc: "Print Ginkgo's version", + Command: func(_ []string, _ []string) { + fmt.Printf("Ginkgo Version %s\n", types.VERSION) + }, + } +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/ginkgo.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/ginkgo.go new file mode 100644 index 000000000..0b9b19fe7 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/ginkgo.go @@ -0,0 +1,302 @@ +package outline + +import ( + "github.com/onsi/ginkgo/v2/types" + "go/ast" + "go/token" + "strconv" +) + +const ( + // undefinedTextAlt is used if the spec/container text cannot be derived + undefinedTextAlt = "undefined" +) + +// ginkgoMetadata holds useful bits of information for every entry in the outline +type ginkgoMetadata struct { + // Name is the spec or container function name, e.g. `Describe` or `It` + Name string `json:"name"` + + // Text is the `text` argument passed to specs, and some containers + Text string `json:"text"` + + // Start is the position of first character of the spec or container block + Start int `json:"start"` + + // End is the position of first character immediately after the spec or container block + End int `json:"end"` + + Spec bool `json:"spec"` + Focused bool `json:"focused"` + Pending bool `json:"pending"` + Labels []string `json:"labels"` +} + +// ginkgoNode is used to construct the outline as a tree +type ginkgoNode struct { + ginkgoMetadata + Nodes []*ginkgoNode `json:"nodes"` +} + +type walkFunc func(n *ginkgoNode) + +func (n *ginkgoNode) PreOrder(f walkFunc) { + f(n) + for _, m := range n.Nodes { + m.PreOrder(f) + } +} + +func (n *ginkgoNode) PostOrder(f walkFunc) { + for _, m := range n.Nodes { + m.PostOrder(f) + } + f(n) +} + +func (n *ginkgoNode) Walk(pre, post walkFunc) { + pre(n) + for _, m := range n.Nodes { + m.Walk(pre, post) + } + post(n) +} + +// PropagateInheritedProperties propagates the Pending and Focused properties +// through the subtree rooted at n. +func (n *ginkgoNode) PropagateInheritedProperties() { + n.PreOrder(func(thisNode *ginkgoNode) { + for _, descendantNode := range thisNode.Nodes { + if thisNode.Pending { + descendantNode.Pending = true + descendantNode.Focused = false + } + if thisNode.Focused && !descendantNode.Pending { + descendantNode.Focused = true + } + } + }) +} + +// BackpropagateUnfocus propagates the Focused property through the subtree +// rooted at n. It applies the rule described in the Ginkgo docs: +// > Nested programmatically focused specs follow a simple rule: if a +// > leaf-node is marked focused, any of its ancestor nodes that are marked +// > focus will be unfocused. +func (n *ginkgoNode) BackpropagateUnfocus() { + focusedSpecInSubtreeStack := []bool{} + n.PostOrder(func(thisNode *ginkgoNode) { + if thisNode.Spec { + focusedSpecInSubtreeStack = append(focusedSpecInSubtreeStack, thisNode.Focused) + return + } + focusedSpecInSubtree := false + for range thisNode.Nodes { + focusedSpecInSubtree = focusedSpecInSubtree || focusedSpecInSubtreeStack[len(focusedSpecInSubtreeStack)-1] + focusedSpecInSubtreeStack = focusedSpecInSubtreeStack[0 : len(focusedSpecInSubtreeStack)-1] + } + focusedSpecInSubtreeStack = append(focusedSpecInSubtreeStack, focusedSpecInSubtree) + if focusedSpecInSubtree { + thisNode.Focused = false + } + }) + +} + +func packageAndIdentNamesFromCallExpr(ce *ast.CallExpr) (string, string, bool) { + switch ex := ce.Fun.(type) { + case *ast.Ident: + return "", ex.Name, true + case *ast.SelectorExpr: + pkgID, ok := ex.X.(*ast.Ident) + if !ok { + return "", "", false + } + // A package identifier is top-level, so Obj must be nil + if pkgID.Obj != nil { + return "", "", false + } + if ex.Sel == nil { + return "", "", false + } + return pkgID.Name, ex.Sel.Name, true + default: + return "", "", false + } +} + +// absoluteOffsetsForNode derives the absolute character offsets of the node start and +// end positions. +func absoluteOffsetsForNode(fset *token.FileSet, n ast.Node) (start, end int) { + return fset.PositionFor(n.Pos(), false).Offset, fset.PositionFor(n.End(), false).Offset +} + +// ginkgoNodeFromCallExpr derives an outline entry from a go AST subtree +// corresponding to a Ginkgo container or spec. +func ginkgoNodeFromCallExpr(fset *token.FileSet, ce *ast.CallExpr, ginkgoPackageName *string) (*ginkgoNode, bool) { + packageName, identName, ok := packageAndIdentNamesFromCallExpr(ce) + if !ok { + return nil, false + } + + n := ginkgoNode{} + n.Name = identName + n.Start, n.End = absoluteOffsetsForNode(fset, ce) + n.Nodes = make([]*ginkgoNode, 0) + switch identName { + case "It", "Specify", "Entry": + n.Spec = true + n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) + n.Labels = labelFromCallExpr(ce) + n.Pending = pendingFromCallExpr(ce) + return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName + case "FIt", "FSpecify", "FEntry": + n.Spec = true + n.Focused = true + n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) + n.Labels = labelFromCallExpr(ce) + return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName + case "PIt", "PSpecify", "XIt", "XSpecify", "PEntry", "XEntry": + n.Spec = true + n.Pending = true + n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) + n.Labels = labelFromCallExpr(ce) + return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName + case "Context", "Describe", "When", "DescribeTable": + n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) + n.Labels = labelFromCallExpr(ce) + n.Pending = pendingFromCallExpr(ce) + return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName + case "FContext", "FDescribe", "FWhen", "FDescribeTable": + n.Focused = true + n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) + n.Labels = labelFromCallExpr(ce) + return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName + case "PContext", "PDescribe", "PWhen", "XContext", "XDescribe", "XWhen", "PDescribeTable", "XDescribeTable": + n.Pending = true + n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) + n.Labels = labelFromCallExpr(ce) + return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName + case "By": + n.Text = textOrAltFromCallExpr(ce, undefinedTextAlt) + return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName + case "AfterEach", "BeforeEach": + return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName + case "JustAfterEach", "JustBeforeEach": + return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName + case "AfterSuite", "BeforeSuite": + return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName + case "SynchronizedAfterSuite", "SynchronizedBeforeSuite": + return &n, ginkgoPackageName != nil && *ginkgoPackageName == packageName + default: + return nil, false + } +} + +// textOrAltFromCallExpr tries to derive the "text" of a Ginkgo spec or +// container. If it cannot derive it, it returns the alt text. +func textOrAltFromCallExpr(ce *ast.CallExpr, alt string) string { + text, defined := textFromCallExpr(ce) + if !defined { + return alt + } + return text +} + +// textFromCallExpr tries to derive the "text" of a Ginkgo spec or container. If +// it cannot derive it, it returns false. +func textFromCallExpr(ce *ast.CallExpr) (string, bool) { + if len(ce.Args) < 1 { + return "", false + } + text, ok := ce.Args[0].(*ast.BasicLit) + if !ok { + return "", false + } + switch text.Kind { + case token.CHAR, token.STRING: + // For token.CHAR and token.STRING, Value is quoted + unquoted, err := strconv.Unquote(text.Value) + if err != nil { + // If unquoting fails, just use the raw Value + return text.Value, true + } + return unquoted, true + default: + return text.Value, true + } +} + +func labelFromCallExpr(ce *ast.CallExpr) []string { + + labels := []string{} + if len(ce.Args) < 2 { + return labels + } + + for _, arg := range ce.Args[1:] { + switch expr := arg.(type) { + case *ast.CallExpr: + id, ok := expr.Fun.(*ast.Ident) + if !ok { + // to skip over cases where the expr.Fun. is actually *ast.SelectorExpr + continue + } + if id.Name == "Label" { + ls := extractLabels(expr) + for _, label := range ls { + labels = append(labels, label) + } + } + } + } + return labels +} + +func extractLabels(expr *ast.CallExpr) []string { + out := []string{} + for _, arg := range expr.Args { + switch expr := arg.(type) { + case *ast.BasicLit: + if expr.Kind == token.STRING { + unquoted, err := strconv.Unquote(expr.Value) + if err != nil { + unquoted = expr.Value + } + validated, err := types.ValidateAndCleanupLabel(unquoted, types.CodeLocation{}) + if err == nil { + out = append(out, validated) + } + } + } + } + + return out +} + +func pendingFromCallExpr(ce *ast.CallExpr) bool { + + pending := false + if len(ce.Args) < 2 { + return pending + } + + for _, arg := range ce.Args[1:] { + switch expr := arg.(type) { + case *ast.CallExpr: + id, ok := expr.Fun.(*ast.Ident) + if !ok { + // to skip over cases where the expr.Fun. is actually *ast.SelectorExpr + continue + } + if id.Name == "Pending" { + pending = true + } + case *ast.Ident: + if expr.Name == "Pending" { + pending = true + } + } + } + return pending +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/import.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/import.go new file mode 100644 index 000000000..67ec5ab75 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/import.go @@ -0,0 +1,65 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Most of the required functions were available in the +// "golang.org/x/tools/go/ast/astutil" package, but not exported. +// They were copied from https://github.com/golang/tools/blob/2b0845dc783e36ae26d683f4915a5840ef01ab0f/go/ast/astutil/imports.go + +package outline + +import ( + "go/ast" + "strconv" + "strings" +) + +// packageNameForImport returns the package name for the package. If the package +// is not imported, it returns nil. "Package name" refers to `pkgname` in the +// call expression `pkgname.ExportedIdentifier`. Examples: +// (import path not found) -> nil +// "import example.com/pkg/foo" -> "foo" +// "import fooalias example.com/pkg/foo" -> "fooalias" +// "import . example.com/pkg/foo" -> "" +func packageNameForImport(f *ast.File, path string) *string { + spec := importSpec(f, path) + if spec == nil { + return nil + } + name := spec.Name.String() + if name == "" { + // If the package name is not explicitly specified, + // make an educated guess. This is not guaranteed to be correct. + lastSlash := strings.LastIndex(path, "/") + if lastSlash == -1 { + name = path + } else { + name = path[lastSlash+1:] + } + } + if name == "." { + name = "" + } + return &name +} + +// importSpec returns the import spec if f imports path, +// or nil otherwise. +func importSpec(f *ast.File, path string) *ast.ImportSpec { + for _, s := range f.Imports { + if strings.HasPrefix(importPath(s), path) { + return s + } + } + return nil +} + +// importPath returns the unquoted import path of s, +// or "" if the path is not properly quoted. +func importPath(s *ast.ImportSpec) string { + t, err := strconv.Unquote(s.Path.Value) + if err != nil { + return "" + } + return t +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/outline.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/outline.go new file mode 100644 index 000000000..c2327cda8 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/outline.go @@ -0,0 +1,110 @@ +package outline + +import ( + "encoding/json" + "fmt" + "go/ast" + "go/token" + "strings" + + "golang.org/x/tools/go/ast/inspector" +) + +const ( + // ginkgoImportPath is the well-known ginkgo import path + ginkgoImportPath = "github.com/onsi/ginkgo/v2" +) + +// FromASTFile returns an outline for a Ginkgo test source file +func FromASTFile(fset *token.FileSet, src *ast.File) (*outline, error) { + ginkgoPackageName := packageNameForImport(src, ginkgoImportPath) + if ginkgoPackageName == nil { + return nil, fmt.Errorf("file does not import %q", ginkgoImportPath) + } + + root := ginkgoNode{} + stack := []*ginkgoNode{&root} + ispr := inspector.New([]*ast.File{src}) + ispr.Nodes([]ast.Node{(*ast.CallExpr)(nil)}, func(node ast.Node, push bool) bool { + if push { + // Pre-order traversal + ce, ok := node.(*ast.CallExpr) + if !ok { + // Because `Nodes` calls this function only when the node is an + // ast.CallExpr, this should never happen + panic(fmt.Errorf("node starting at %d, ending at %d is not an *ast.CallExpr", node.Pos(), node.End())) + } + gn, ok := ginkgoNodeFromCallExpr(fset, ce, ginkgoPackageName) + if !ok { + // Node is not a Ginkgo spec or container, continue + return true + } + parent := stack[len(stack)-1] + parent.Nodes = append(parent.Nodes, gn) + stack = append(stack, gn) + return true + } + // Post-order traversal + start, end := absoluteOffsetsForNode(fset, node) + lastVisitedGinkgoNode := stack[len(stack)-1] + if start != lastVisitedGinkgoNode.Start || end != lastVisitedGinkgoNode.End { + // Node is not a Ginkgo spec or container, so it was not pushed onto the stack, continue + return true + } + stack = stack[0 : len(stack)-1] + return true + }) + if len(root.Nodes) == 0 { + return &outline{[]*ginkgoNode{}}, nil + } + + // Derive the final focused property for all nodes. This must be done + // _before_ propagating the inherited focused property. + root.BackpropagateUnfocus() + // Now, propagate inherited properties, including focused and pending. + root.PropagateInheritedProperties() + + return &outline{root.Nodes}, nil +} + +type outline struct { + Nodes []*ginkgoNode `json:"nodes"` +} + +func (o *outline) MarshalJSON() ([]byte, error) { + return json.Marshal(o.Nodes) +} + +// String returns a CSV-formatted outline. Spec or container are output in +// depth-first order. +func (o *outline) String() string { + return o.StringIndent(0) +} + +// StringIndent returns a CSV-formated outline, but every line is indented by +// one 'width' of spaces for every level of nesting. +func (o *outline) StringIndent(width int) string { + var b strings.Builder + b.WriteString("Name,Text,Start,End,Spec,Focused,Pending,Labels\n") + + currentIndent := 0 + pre := func(n *ginkgoNode) { + b.WriteString(fmt.Sprintf("%*s", currentIndent, "")) + var labels string + if len(n.Labels) == 1 { + labels = n.Labels[0] + } else { + labels = strings.Join(n.Labels, ", ") + } + //enclosing labels in a double quoted comma separate listed so that when inmported into a CSV app the Labels column has comma separate strings + b.WriteString(fmt.Sprintf("%s,%s,%d,%d,%t,%t,%t,\"%s\"\n", n.Name, n.Text, n.Start, n.End, n.Spec, n.Focused, n.Pending, labels)) + currentIndent += width + } + post := func(n *ginkgoNode) { + currentIndent -= width + } + for _, n := range o.Nodes { + n.Walk(pre, post) + } + return b.String() +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/outline_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/outline_command.go new file mode 100644 index 000000000..36698d46a --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/outline/outline_command.go @@ -0,0 +1,98 @@ +package outline + +import ( + "encoding/json" + "fmt" + "go/parser" + "go/token" + "os" + + "github.com/onsi/ginkgo/v2/ginkgo/command" + "github.com/onsi/ginkgo/v2/types" +) + +const ( + // indentWidth is the width used by the 'indent' output + indentWidth = 4 + // stdinAlias is a portable alias for stdin. This convention is used in + // other CLIs, e.g., kubectl. + stdinAlias = "-" + usageCommand = "ginkgo outline " +) + +type outlineConfig struct { + Format string +} + +func BuildOutlineCommand() command.Command { + conf := outlineConfig{ + Format: "csv", + } + flags, err := types.NewGinkgoFlagSet( + types.GinkgoFlags{ + {Name: "format", KeyPath: "Format", + Usage: "Format of outline", + UsageArgument: "one of 'csv', 'indent', or 'json'", + UsageDefaultValue: conf.Format, + }, + }, + &conf, + types.GinkgoFlagSections{}, + ) + if err != nil { + panic(err) + } + + return command.Command{ + Name: "outline", + Usage: "ginkgo outline ", + ShortDoc: "Create an outline of Ginkgo symbols for a file", + Documentation: "To read from stdin, use: `ginkgo outline -`", + DocLink: "creating-an-outline-of-specs", + Flags: flags, + Command: func(args []string, _ []string) { + outlineFile(args, conf.Format) + }, + } +} + +func outlineFile(args []string, format string) { + if len(args) != 1 { + command.AbortWithUsage("outline expects exactly one argument") + } + + filename := args[0] + var src *os.File + if filename == stdinAlias { + src = os.Stdin + } else { + var err error + src, err = os.Open(filename) + command.AbortIfError("Failed to open file:", err) + } + + fset := token.NewFileSet() + + parsedSrc, err := parser.ParseFile(fset, filename, src, 0) + command.AbortIfError("Failed to parse source:", err) + + o, err := FromASTFile(fset, parsedSrc) + command.AbortIfError("Failed to create outline:", err) + + var oerr error + switch format { + case "csv": + _, oerr = fmt.Print(o) + case "indent": + _, oerr = fmt.Print(o.StringIndent(indentWidth)) + case "json": + b, err := json.Marshal(o) + if err != nil { + println(fmt.Sprintf("error marshalling to json: %s", err)) + } + _, oerr = fmt.Println(string(b)) + default: + command.AbortWith("Format %s not accepted", format) + } + command.AbortIfError("Failed to write outline:", oerr) +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/run/run_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/run/run_command.go new file mode 100644 index 000000000..aaed4d570 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/run/run_command.go @@ -0,0 +1,232 @@ +package run + +import ( + "fmt" + "os" + "strings" + "time" + + "github.com/onsi/ginkgo/v2/formatter" + "github.com/onsi/ginkgo/v2/ginkgo/command" + "github.com/onsi/ginkgo/v2/ginkgo/internal" + "github.com/onsi/ginkgo/v2/internal/interrupt_handler" + "github.com/onsi/ginkgo/v2/types" +) + +func BuildRunCommand() command.Command { + var suiteConfig = types.NewDefaultSuiteConfig() + var reporterConfig = types.NewDefaultReporterConfig() + var cliConfig = types.NewDefaultCLIConfig() + var goFlagsConfig = types.NewDefaultGoFlagsConfig() + + flags, err := types.BuildRunCommandFlagSet(&suiteConfig, &reporterConfig, &cliConfig, &goFlagsConfig) + if err != nil { + panic(err) + } + + interruptHandler := interrupt_handler.NewInterruptHandler(nil) + interrupt_handler.SwallowSigQuit() + + return command.Command{ + Name: "run", + Flags: flags, + Usage: "ginkgo run -- ", + ShortDoc: "Run the tests in the passed in (or the package in the current directory if left blank)", + Documentation: "Any arguments after -- will be passed to the test.", + DocLink: "running-tests", + Command: func(args []string, additionalArgs []string) { + var errors []error + cliConfig, goFlagsConfig, errors = types.VetAndInitializeCLIAndGoConfig(cliConfig, goFlagsConfig) + command.AbortIfErrors("Ginkgo detected configuration issues:", errors) + + runner := &SpecRunner{ + cliConfig: cliConfig, + goFlagsConfig: goFlagsConfig, + suiteConfig: suiteConfig, + reporterConfig: reporterConfig, + flags: flags, + + interruptHandler: interruptHandler, + } + + runner.RunSpecs(args, additionalArgs) + }, + } +} + +type SpecRunner struct { + suiteConfig types.SuiteConfig + reporterConfig types.ReporterConfig + cliConfig types.CLIConfig + goFlagsConfig types.GoFlagsConfig + flags types.GinkgoFlagSet + + interruptHandler *interrupt_handler.InterruptHandler +} + +func (r *SpecRunner) RunSpecs(args []string, additionalArgs []string) { + suites := internal.FindSuites(args, r.cliConfig, true) + skippedSuites := suites.WithState(internal.TestSuiteStateSkippedByFilter) + suites = suites.WithoutState(internal.TestSuiteStateSkippedByFilter) + + internal.VerifyCLIAndFrameworkVersion(suites) + + if len(skippedSuites) > 0 { + fmt.Println("Will skip:") + for _, skippedSuite := range skippedSuites { + fmt.Println(" " + skippedSuite.Path) + } + } + + if len(skippedSuites) > 0 && len(suites) == 0 { + command.AbortGracefullyWith("All tests skipped! Exiting...") + } + + if len(suites) == 0 { + command.AbortWith("Found no test suites") + } + + if len(suites) > 1 && !r.flags.WasSet("succinct") && r.reporterConfig.Verbosity().LT(types.VerbosityLevelVerbose) { + r.reporterConfig.Succinct = true + } + + t := time.Now() + var endTime time.Time + if r.suiteConfig.Timeout > 0 { + endTime = t.Add(r.suiteConfig.Timeout) + } + + iteration := 0 +OUTER_LOOP: + for { + if !r.flags.WasSet("seed") { + r.suiteConfig.RandomSeed = time.Now().Unix() + } + if r.cliConfig.RandomizeSuites && len(suites) > 1 { + suites = suites.ShuffledCopy(r.suiteConfig.RandomSeed) + } + + opc := internal.NewOrderedParallelCompiler(r.cliConfig.ComputedNumCompilers()) + opc.StartCompiling(suites, r.goFlagsConfig) + + SUITE_LOOP: + for { + suiteIdx, suite := opc.Next() + if suiteIdx >= len(suites) { + break SUITE_LOOP + } + suites[suiteIdx] = suite + + if r.interruptHandler.Status().Interrupted() { + opc.StopAndDrain() + break OUTER_LOOP + } + + if suites[suiteIdx].State.Is(internal.TestSuiteStateSkippedDueToEmptyCompilation) { + fmt.Printf("Skipping %s (no test files)\n", suite.Path) + continue SUITE_LOOP + } + + if suites[suiteIdx].State.Is(internal.TestSuiteStateFailedToCompile) { + fmt.Println(suites[suiteIdx].CompilationError.Error()) + if !r.cliConfig.KeepGoing { + opc.StopAndDrain() + } + continue SUITE_LOOP + } + + if suites.CountWithState(internal.TestSuiteStateFailureStates...) > 0 && !r.cliConfig.KeepGoing { + suites[suiteIdx].State = internal.TestSuiteStateSkippedDueToPriorFailures + opc.StopAndDrain() + continue SUITE_LOOP + } + + if !endTime.IsZero() { + r.suiteConfig.Timeout = endTime.Sub(time.Now()) + if r.suiteConfig.Timeout <= 0 { + suites[suiteIdx].State = internal.TestSuiteStateFailedDueToTimeout + opc.StopAndDrain() + continue SUITE_LOOP + } + } + + suites[suiteIdx] = internal.RunCompiledSuite(suites[suiteIdx], r.suiteConfig, r.reporterConfig, r.cliConfig, r.goFlagsConfig, additionalArgs) + } + + if suites.CountWithState(internal.TestSuiteStateFailureStates...) > 0 { + if iteration > 0 { + fmt.Printf("\nTests failed on attempt #%d\n\n", iteration+1) + } + break OUTER_LOOP + } + + if r.cliConfig.UntilItFails { + fmt.Printf("\nAll tests passed...\nWill keep running them until they fail.\nThis was attempt #%d\n%s\n", iteration+1, orcMessage(iteration+1)) + } else if r.cliConfig.Repeat > 0 && iteration < r.cliConfig.Repeat { + fmt.Printf("\nAll tests passed...\nThis was attempt %d of %d.\n", iteration+1, r.cliConfig.Repeat+1) + } else { + break OUTER_LOOP + } + iteration += 1 + } + + internal.Cleanup(r.goFlagsConfig, suites...) + + messages, err := internal.FinalizeProfilesAndReportsForSuites(suites, r.cliConfig, r.suiteConfig, r.reporterConfig, r.goFlagsConfig) + command.AbortIfError("could not finalize profiles:", err) + for _, message := range messages { + fmt.Println(message) + } + + fmt.Printf("\nGinkgo ran %d %s in %s\n", len(suites), internal.PluralizedWord("suite", "suites", len(suites)), time.Since(t)) + + if suites.CountWithState(internal.TestSuiteStateFailureStates...) == 0 { + if suites.AnyHaveProgrammaticFocus() && strings.TrimSpace(os.Getenv("GINKGO_EDITOR_INTEGRATION")) == "" { + fmt.Printf("Test Suite Passed\n") + fmt.Printf("Detected Programmatic Focus - setting exit status to %d\n", types.GINKGO_FOCUS_EXIT_CODE) + command.Abort(command.AbortDetails{ExitCode: types.GINKGO_FOCUS_EXIT_CODE}) + } else { + fmt.Printf("Test Suite Passed\n") + command.Abort(command.AbortDetails{}) + } + } else { + fmt.Fprintln(formatter.ColorableStdOut, "") + if len(suites) > 1 && suites.CountWithState(internal.TestSuiteStateFailureStates...) > 0 { + fmt.Fprintln(formatter.ColorableStdOut, + internal.FailedSuitesReport(suites, formatter.NewWithNoColorBool(r.reporterConfig.NoColor))) + } + fmt.Printf("Test Suite Failed\n") + command.Abort(command.AbortDetails{ExitCode: 1}) + } +} + +func orcMessage(iteration int) string { + if iteration < 10 { + return "" + } else if iteration < 30 { + return []string{ + "If at first you succeed...", + "...try, try again.", + "Looking good!", + "Still good...", + "I think your tests are fine....", + "Yep, still passing", + "Oh boy, here I go testin' again!", + "Even the gophers are getting bored", + "Did you try -race?", + "Maybe you should stop now?", + "I'm getting tired...", + "What if I just made you a sandwich?", + "Hit ^C, hit ^C, please hit ^C", + "Make it stop. Please!", + "Come on! Enough is enough!", + "Dave, this conversation can serve no purpose anymore. Goodbye.", + "Just what do you think you're doing, Dave? ", + "I, Sisyphus", + "Insanity: doing the same thing over and over again and expecting different results. -Einstein", + "I guess Einstein never tried to churn butter", + }[iteration-10] + "\n" + } else { + return "No, seriously... you can probably stop now.\n" + } +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/unfocus/unfocus_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/unfocus/unfocus_command.go new file mode 100644 index 000000000..7dd294394 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/unfocus/unfocus_command.go @@ -0,0 +1,186 @@ +package unfocus + +import ( + "bytes" + "fmt" + "go/ast" + "go/parser" + "go/token" + "io" + "os" + "path/filepath" + "strings" + "sync" + + "github.com/onsi/ginkgo/v2/ginkgo/command" +) + +func BuildUnfocusCommand() command.Command { + return command.Command{ + Name: "unfocus", + Usage: "ginkgo unfocus", + ShortDoc: "Recursively unfocus any focused tests under the current directory", + DocLink: "filtering-specs", + Command: func(_ []string, _ []string) { + unfocusSpecs() + }, + } +} + +func unfocusSpecs() { + fmt.Println("Scanning for focus...") + + goFiles := make(chan string) + go func() { + unfocusDir(goFiles, ".") + close(goFiles) + }() + + const workers = 10 + wg := sync.WaitGroup{} + wg.Add(workers) + + for i := 0; i < workers; i++ { + go func() { + for path := range goFiles { + unfocusFile(path) + } + wg.Done() + }() + } + + wg.Wait() +} + +func unfocusDir(goFiles chan string, path string) { + files, err := os.ReadDir(path) + if err != nil { + fmt.Println(err.Error()) + return + } + + for _, f := range files { + switch { + case f.IsDir() && shouldProcessDir(f.Name()): + unfocusDir(goFiles, filepath.Join(path, f.Name())) + case !f.IsDir() && shouldProcessFile(f.Name()): + goFiles <- filepath.Join(path, f.Name()) + } + } +} + +func shouldProcessDir(basename string) bool { + return basename != "vendor" && !strings.HasPrefix(basename, ".") +} + +func shouldProcessFile(basename string) bool { + return strings.HasSuffix(basename, ".go") +} + +func unfocusFile(path string) { + data, err := os.ReadFile(path) + if err != nil { + fmt.Printf("error reading file '%s': %s\n", path, err.Error()) + return + } + + ast, err := parser.ParseFile(token.NewFileSet(), path, bytes.NewReader(data), parser.ParseComments) + if err != nil { + fmt.Printf("error parsing file '%s': %s\n", path, err.Error()) + return + } + + eliminations := scanForFocus(ast) + if len(eliminations) == 0 { + return + } + + fmt.Printf("...updating %s\n", path) + backup, err := writeBackup(path, data) + if err != nil { + fmt.Printf("error creating backup file: %s\n", err.Error()) + return + } + + if err := updateFile(path, data, eliminations); err != nil { + fmt.Printf("error writing file '%s': %s\n", path, err.Error()) + return + } + + os.Remove(backup) +} + +func writeBackup(path string, data []byte) (string, error) { + t, err := os.CreateTemp(filepath.Dir(path), filepath.Base(path)) + + if err != nil { + return "", fmt.Errorf("error creating temporary file: %w", err) + } + defer t.Close() + + if _, err := io.Copy(t, bytes.NewReader(data)); err != nil { + return "", fmt.Errorf("error writing to temporary file: %w", err) + } + + return t.Name(), nil +} + +func updateFile(path string, data []byte, eliminations [][]int64) error { + to, err := os.Create(path) + if err != nil { + return fmt.Errorf("error opening file for writing '%s': %w\n", path, err) + } + defer to.Close() + + from := bytes.NewReader(data) + var cursor int64 + for _, eliminationRange := range eliminations { + positionToEliminate, lengthToEliminate := eliminationRange[0]-1, eliminationRange[1] + if _, err := io.CopyN(to, from, positionToEliminate-cursor); err != nil { + return fmt.Errorf("error copying data: %w", err) + } + + cursor = positionToEliminate + lengthToEliminate + + if _, err := from.Seek(lengthToEliminate, io.SeekCurrent); err != nil { + return fmt.Errorf("error seeking to position in buffer: %w", err) + } + } + + if _, err := io.Copy(to, from); err != nil { + return fmt.Errorf("error copying end data: %w", err) + } + + return nil +} + +func scanForFocus(file *ast.File) (eliminations [][]int64) { + ast.Inspect(file, func(n ast.Node) bool { + if c, ok := n.(*ast.CallExpr); ok { + if i, ok := c.Fun.(*ast.Ident); ok { + if isFocus(i.Name) { + eliminations = append(eliminations, []int64{int64(i.Pos()), 1}) + } + } + } + + if i, ok := n.(*ast.Ident); ok { + if i.Name == "Focus" { + eliminations = append(eliminations, []int64{int64(i.Pos()), 6}) + } + } + + return true + }) + + return eliminations +} + +func isFocus(name string) bool { + switch name { + case "FDescribe", "FContext", "FIt", "FDescribeTable", "FEntry", "FSpecify", "FWhen": + return true + default: + return false + } +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/delta.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/delta.go new file mode 100644 index 000000000..6c485c5b1 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/delta.go @@ -0,0 +1,22 @@ +package watch + +import "sort" + +type Delta struct { + ModifiedPackages []string + + NewSuites []*Suite + RemovedSuites []*Suite + modifiedSuites []*Suite +} + +type DescendingByDelta []*Suite + +func (a DescendingByDelta) Len() int { return len(a) } +func (a DescendingByDelta) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a DescendingByDelta) Less(i, j int) bool { return a[i].Delta() > a[j].Delta() } + +func (d Delta) ModifiedSuites() []*Suite { + sort.Sort(DescendingByDelta(d.modifiedSuites)) + return d.modifiedSuites +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/delta_tracker.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/delta_tracker.go new file mode 100644 index 000000000..26418ac62 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/delta_tracker.go @@ -0,0 +1,75 @@ +package watch + +import ( + "fmt" + + "regexp" + + "github.com/onsi/ginkgo/v2/ginkgo/internal" +) + +type SuiteErrors map[internal.TestSuite]error + +type DeltaTracker struct { + maxDepth int + watchRegExp *regexp.Regexp + suites map[string]*Suite + packageHashes *PackageHashes +} + +func NewDeltaTracker(maxDepth int, watchRegExp *regexp.Regexp) *DeltaTracker { + return &DeltaTracker{ + maxDepth: maxDepth, + watchRegExp: watchRegExp, + packageHashes: NewPackageHashes(watchRegExp), + suites: map[string]*Suite{}, + } +} + +func (d *DeltaTracker) Delta(suites internal.TestSuites) (delta Delta, errors SuiteErrors) { + errors = SuiteErrors{} + delta.ModifiedPackages = d.packageHashes.CheckForChanges() + + providedSuitePaths := map[string]bool{} + for _, suite := range suites { + providedSuitePaths[suite.Path] = true + } + + d.packageHashes.StartTrackingUsage() + + for _, suite := range d.suites { + if providedSuitePaths[suite.Suite.Path] { + if suite.Delta() > 0 { + delta.modifiedSuites = append(delta.modifiedSuites, suite) + } + } else { + delta.RemovedSuites = append(delta.RemovedSuites, suite) + } + } + + d.packageHashes.StopTrackingUsageAndPrune() + + for _, suite := range suites { + _, ok := d.suites[suite.Path] + if !ok { + s, err := NewSuite(suite, d.maxDepth, d.packageHashes) + if err != nil { + errors[suite] = err + continue + } + d.suites[suite.Path] = s + delta.NewSuites = append(delta.NewSuites, s) + } + } + + return delta, errors +} + +func (d *DeltaTracker) WillRun(suite internal.TestSuite) error { + s, ok := d.suites[suite.Path] + if !ok { + return fmt.Errorf("unknown suite %s", suite.Path) + } + + return s.MarkAsRunAndRecomputedDependencies(d.maxDepth) +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/dependencies.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/dependencies.go new file mode 100644 index 000000000..f5ddff30f --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/dependencies.go @@ -0,0 +1,92 @@ +package watch + +import ( + "go/build" + "regexp" +) + +var ginkgoAndGomegaFilter = regexp.MustCompile(`github\.com/onsi/ginkgo|github\.com/onsi/gomega`) +var ginkgoIntegrationTestFilter = regexp.MustCompile(`github\.com/onsi/ginkgo/integration`) //allow us to integration test this thing + +type Dependencies struct { + deps map[string]int +} + +func NewDependencies(path string, maxDepth int) (Dependencies, error) { + d := Dependencies{ + deps: map[string]int{}, + } + + if maxDepth == 0 { + return d, nil + } + + err := d.seedWithDepsForPackageAtPath(path) + if err != nil { + return d, err + } + + for depth := 1; depth < maxDepth; depth++ { + n := len(d.deps) + d.addDepsForDepth(depth) + if n == len(d.deps) { + break + } + } + + return d, nil +} + +func (d Dependencies) Dependencies() map[string]int { + return d.deps +} + +func (d Dependencies) seedWithDepsForPackageAtPath(path string) error { + pkg, err := build.ImportDir(path, 0) + if err != nil { + return err + } + + d.resolveAndAdd(pkg.Imports, 1) + d.resolveAndAdd(pkg.TestImports, 1) + d.resolveAndAdd(pkg.XTestImports, 1) + + delete(d.deps, pkg.Dir) + return nil +} + +func (d Dependencies) addDepsForDepth(depth int) { + for dep, depDepth := range d.deps { + if depDepth == depth { + d.addDepsForDep(dep, depth+1) + } + } +} + +func (d Dependencies) addDepsForDep(dep string, depth int) { + pkg, err := build.ImportDir(dep, 0) + if err != nil { + println(err.Error()) + return + } + d.resolveAndAdd(pkg.Imports, depth) +} + +func (d Dependencies) resolveAndAdd(deps []string, depth int) { + for _, dep := range deps { + pkg, err := build.Import(dep, ".", 0) + if err != nil { + continue + } + if !pkg.Goroot && (!ginkgoAndGomegaFilter.Match([]byte(pkg.Dir)) || ginkgoIntegrationTestFilter.Match([]byte(pkg.Dir))) { + d.addDepIfNotPresent(pkg.Dir, depth) + } + } +} + +func (d Dependencies) addDepIfNotPresent(dep string, depth int) { + _, ok := d.deps[dep] + if !ok { + d.deps[dep] = depth + } +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/package_hash.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/package_hash.go new file mode 100644 index 000000000..e9f7ec0cb --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/package_hash.go @@ -0,0 +1,108 @@ +package watch + +import ( + "fmt" + "os" + "regexp" + "time" +) + +var goTestRegExp = regexp.MustCompile(`_test\.go$`) + +type PackageHash struct { + CodeModifiedTime time.Time + TestModifiedTime time.Time + Deleted bool + + path string + codeHash string + testHash string + watchRegExp *regexp.Regexp +} + +func NewPackageHash(path string, watchRegExp *regexp.Regexp) *PackageHash { + p := &PackageHash{ + path: path, + watchRegExp: watchRegExp, + } + + p.codeHash, _, p.testHash, _, p.Deleted = p.computeHashes() + + return p +} + +func (p *PackageHash) CheckForChanges() bool { + codeHash, codeModifiedTime, testHash, testModifiedTime, deleted := p.computeHashes() + + if deleted { + if !p.Deleted { + t := time.Now() + p.CodeModifiedTime = t + p.TestModifiedTime = t + } + p.Deleted = true + return true + } + + modified := false + p.Deleted = false + + if p.codeHash != codeHash { + p.CodeModifiedTime = codeModifiedTime + modified = true + } + if p.testHash != testHash { + p.TestModifiedTime = testModifiedTime + modified = true + } + + p.codeHash = codeHash + p.testHash = testHash + return modified +} + +func (p *PackageHash) computeHashes() (codeHash string, codeModifiedTime time.Time, testHash string, testModifiedTime time.Time, deleted bool) { + entries, err := os.ReadDir(p.path) + + if err != nil { + deleted = true + return + } + + for _, entry := range entries { + if entry.IsDir() { + continue + } + + info, err := entry.Info() + if err != nil { + continue + } + + if goTestRegExp.Match([]byte(info.Name())) { + testHash += p.hashForFileInfo(info) + if info.ModTime().After(testModifiedTime) { + testModifiedTime = info.ModTime() + } + continue + } + + if p.watchRegExp.Match([]byte(info.Name())) { + codeHash += p.hashForFileInfo(info) + if info.ModTime().After(codeModifiedTime) { + codeModifiedTime = info.ModTime() + } + } + } + + testHash += codeHash + if codeModifiedTime.After(testModifiedTime) { + testModifiedTime = codeModifiedTime + } + + return +} + +func (p *PackageHash) hashForFileInfo(info os.FileInfo) string { + return fmt.Sprintf("%s_%d_%d", info.Name(), info.Size(), info.ModTime().UnixNano()) +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/package_hashes.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/package_hashes.go new file mode 100644 index 000000000..b4892bebf --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/package_hashes.go @@ -0,0 +1,85 @@ +package watch + +import ( + "path/filepath" + "regexp" + "sync" +) + +type PackageHashes struct { + PackageHashes map[string]*PackageHash + usedPaths map[string]bool + watchRegExp *regexp.Regexp + lock *sync.Mutex +} + +func NewPackageHashes(watchRegExp *regexp.Regexp) *PackageHashes { + return &PackageHashes{ + PackageHashes: map[string]*PackageHash{}, + usedPaths: nil, + watchRegExp: watchRegExp, + lock: &sync.Mutex{}, + } +} + +func (p *PackageHashes) CheckForChanges() []string { + p.lock.Lock() + defer p.lock.Unlock() + + modified := []string{} + + for _, packageHash := range p.PackageHashes { + if packageHash.CheckForChanges() { + modified = append(modified, packageHash.path) + } + } + + return modified +} + +func (p *PackageHashes) Add(path string) *PackageHash { + p.lock.Lock() + defer p.lock.Unlock() + + path, _ = filepath.Abs(path) + _, ok := p.PackageHashes[path] + if !ok { + p.PackageHashes[path] = NewPackageHash(path, p.watchRegExp) + } + + if p.usedPaths != nil { + p.usedPaths[path] = true + } + return p.PackageHashes[path] +} + +func (p *PackageHashes) Get(path string) *PackageHash { + p.lock.Lock() + defer p.lock.Unlock() + + path, _ = filepath.Abs(path) + if p.usedPaths != nil { + p.usedPaths[path] = true + } + return p.PackageHashes[path] +} + +func (p *PackageHashes) StartTrackingUsage() { + p.lock.Lock() + defer p.lock.Unlock() + + p.usedPaths = map[string]bool{} +} + +func (p *PackageHashes) StopTrackingUsageAndPrune() { + p.lock.Lock() + defer p.lock.Unlock() + + for path := range p.PackageHashes { + if !p.usedPaths[path] { + delete(p.PackageHashes, path) + } + } + + p.usedPaths = nil +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/suite.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/suite.go new file mode 100644 index 000000000..53272df7e --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/suite.go @@ -0,0 +1,87 @@ +package watch + +import ( + "fmt" + "math" + "time" + + "github.com/onsi/ginkgo/v2/ginkgo/internal" +) + +type Suite struct { + Suite internal.TestSuite + RunTime time.Time + Dependencies Dependencies + + sharedPackageHashes *PackageHashes +} + +func NewSuite(suite internal.TestSuite, maxDepth int, sharedPackageHashes *PackageHashes) (*Suite, error) { + deps, err := NewDependencies(suite.Path, maxDepth) + if err != nil { + return nil, err + } + + sharedPackageHashes.Add(suite.Path) + for dep := range deps.Dependencies() { + sharedPackageHashes.Add(dep) + } + + return &Suite{ + Suite: suite, + Dependencies: deps, + + sharedPackageHashes: sharedPackageHashes, + }, nil +} + +func (s *Suite) Delta() float64 { + delta := s.delta(s.Suite.Path, true, 0) * 1000 + for dep, depth := range s.Dependencies.Dependencies() { + delta += s.delta(dep, false, depth) + } + return delta +} + +func (s *Suite) MarkAsRunAndRecomputedDependencies(maxDepth int) error { + s.RunTime = time.Now() + + deps, err := NewDependencies(s.Suite.Path, maxDepth) + if err != nil { + return err + } + + s.sharedPackageHashes.Add(s.Suite.Path) + for dep := range deps.Dependencies() { + s.sharedPackageHashes.Add(dep) + } + + s.Dependencies = deps + + return nil +} + +func (s *Suite) Description() string { + numDeps := len(s.Dependencies.Dependencies()) + pluralizer := "ies" + if numDeps == 1 { + pluralizer = "y" + } + return fmt.Sprintf("%s [%d dependenc%s]", s.Suite.Path, numDeps, pluralizer) +} + +func (s *Suite) delta(packagePath string, includeTests bool, depth int) float64 { + return math.Max(float64(s.dt(packagePath, includeTests)), 0) / float64(depth+1) +} + +func (s *Suite) dt(packagePath string, includeTests bool) time.Duration { + packageHash := s.sharedPackageHashes.Get(packagePath) + var modifiedTime time.Time + if includeTests { + modifiedTime = packageHash.TestModifiedTime + } else { + modifiedTime = packageHash.CodeModifiedTime + } + + return modifiedTime.Sub(s.RunTime) +} diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/watch_command.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/watch_command.go new file mode 100644 index 000000000..bde4193ce --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/watch_command.go @@ -0,0 +1,192 @@ +package watch + +import ( + "fmt" + "regexp" + "time" + + "github.com/onsi/ginkgo/v2/formatter" + "github.com/onsi/ginkgo/v2/ginkgo/command" + "github.com/onsi/ginkgo/v2/ginkgo/internal" + "github.com/onsi/ginkgo/v2/internal/interrupt_handler" + "github.com/onsi/ginkgo/v2/types" +) + +func BuildWatchCommand() command.Command { + var suiteConfig = types.NewDefaultSuiteConfig() + var reporterConfig = types.NewDefaultReporterConfig() + var cliConfig = types.NewDefaultCLIConfig() + var goFlagsConfig = types.NewDefaultGoFlagsConfig() + + flags, err := types.BuildWatchCommandFlagSet(&suiteConfig, &reporterConfig, &cliConfig, &goFlagsConfig) + if err != nil { + panic(err) + } + interruptHandler := interrupt_handler.NewInterruptHandler(nil) + interrupt_handler.SwallowSigQuit() + + return command.Command{ + Name: "watch", + Flags: flags, + Usage: "ginkgo watch -- ", + ShortDoc: "Watch the passed in and runs their tests whenever changes occur.", + Documentation: "Any arguments after -- will be passed to the test.", + DocLink: "watching-for-changes", + Command: func(args []string, additionalArgs []string) { + var errors []error + cliConfig, goFlagsConfig, errors = types.VetAndInitializeCLIAndGoConfig(cliConfig, goFlagsConfig) + command.AbortIfErrors("Ginkgo detected configuration issues:", errors) + + watcher := &SpecWatcher{ + cliConfig: cliConfig, + goFlagsConfig: goFlagsConfig, + suiteConfig: suiteConfig, + reporterConfig: reporterConfig, + flags: flags, + + interruptHandler: interruptHandler, + } + + watcher.WatchSpecs(args, additionalArgs) + }, + } +} + +type SpecWatcher struct { + suiteConfig types.SuiteConfig + reporterConfig types.ReporterConfig + cliConfig types.CLIConfig + goFlagsConfig types.GoFlagsConfig + flags types.GinkgoFlagSet + + interruptHandler *interrupt_handler.InterruptHandler +} + +func (w *SpecWatcher) WatchSpecs(args []string, additionalArgs []string) { + suites := internal.FindSuites(args, w.cliConfig, false).WithoutState(internal.TestSuiteStateSkippedByFilter) + + internal.VerifyCLIAndFrameworkVersion(suites) + + if len(suites) == 0 { + command.AbortWith("Found no test suites") + } + + fmt.Printf("Identified %d test %s. Locating dependencies to a depth of %d (this may take a while)...\n", len(suites), internal.PluralizedWord("suite", "suites", len(suites)), w.cliConfig.Depth) + deltaTracker := NewDeltaTracker(w.cliConfig.Depth, regexp.MustCompile(w.cliConfig.WatchRegExp)) + delta, errors := deltaTracker.Delta(suites) + + fmt.Printf("Watching %d %s:\n", len(delta.NewSuites), internal.PluralizedWord("suite", "suites", len(delta.NewSuites))) + for _, suite := range delta.NewSuites { + fmt.Println(" " + suite.Description()) + } + + for suite, err := range errors { + fmt.Printf("Failed to watch %s: %s\n", suite.PackageName, err) + } + + if len(suites) == 1 { + w.updateSeed() + w.compileAndRun(suites[0], additionalArgs) + } + + ticker := time.NewTicker(time.Second) + + for { + select { + case <-ticker.C: + suites := internal.FindSuites(args, w.cliConfig, false).WithoutState(internal.TestSuiteStateSkippedByFilter) + delta, _ := deltaTracker.Delta(suites) + coloredStream := formatter.ColorableStdOut + + suites = internal.TestSuites{} + + if len(delta.NewSuites) > 0 { + fmt.Fprintln(coloredStream, formatter.F("{{green}}Detected %d new %s:{{/}}", len(delta.NewSuites), internal.PluralizedWord("suite", "suites", len(delta.NewSuites)))) + for _, suite := range delta.NewSuites { + suites = append(suites, suite.Suite) + fmt.Fprintln(coloredStream, formatter.Fi(1, "%s", suite.Description())) + } + } + + modifiedSuites := delta.ModifiedSuites() + if len(modifiedSuites) > 0 { + fmt.Fprintln(coloredStream, formatter.F("{{green}}Detected changes in:{{/}}")) + for _, pkg := range delta.ModifiedPackages { + fmt.Fprintln(coloredStream, formatter.Fi(1, "%s", pkg)) + } + fmt.Fprintln(coloredStream, formatter.F("{{green}}Will run %d %s:{{/}}", len(modifiedSuites), internal.PluralizedWord("suite", "suites", len(modifiedSuites)))) + for _, suite := range modifiedSuites { + suites = append(suites, suite.Suite) + fmt.Fprintln(coloredStream, formatter.Fi(1, "%s", suite.Description())) + } + fmt.Fprintln(coloredStream, "") + } + + if len(suites) == 0 { + break + } + + w.updateSeed() + w.computeSuccinctMode(len(suites)) + for idx := range suites { + if w.interruptHandler.Status().Interrupted() { + return + } + deltaTracker.WillRun(suites[idx]) + suites[idx] = w.compileAndRun(suites[idx], additionalArgs) + } + color := "{{green}}" + if suites.CountWithState(internal.TestSuiteStateFailureStates...) > 0 { + color = "{{red}}" + } + fmt.Fprintln(coloredStream, formatter.F(color+"\nDone. Resuming watch...{{/}}")) + + messages, err := internal.FinalizeProfilesAndReportsForSuites(suites, w.cliConfig, w.suiteConfig, w.reporterConfig, w.goFlagsConfig) + command.AbortIfError("could not finalize profiles:", err) + for _, message := range messages { + fmt.Println(message) + } + case <-w.interruptHandler.Status().Channel: + return + } + } +} + +func (w *SpecWatcher) compileAndRun(suite internal.TestSuite, additionalArgs []string) internal.TestSuite { + suite = internal.CompileSuite(suite, w.goFlagsConfig) + if suite.State.Is(internal.TestSuiteStateFailedToCompile) { + fmt.Println(suite.CompilationError.Error()) + return suite + } + if w.interruptHandler.Status().Interrupted() { + return suite + } + suite = internal.RunCompiledSuite(suite, w.suiteConfig, w.reporterConfig, w.cliConfig, w.goFlagsConfig, additionalArgs) + internal.Cleanup(w.goFlagsConfig, suite) + return suite +} + +func (w *SpecWatcher) computeSuccinctMode(numSuites int) { + if w.reporterConfig.Verbosity().GTE(types.VerbosityLevelVerbose) { + w.reporterConfig.Succinct = false + return + } + + if w.flags.WasSet("succinct") { + return + } + + if numSuites == 1 { + w.reporterConfig.Succinct = false + } + + if numSuites > 1 { + w.reporterConfig.Succinct = true + } +} + +func (w *SpecWatcher) updateSeed() { + if !w.flags.WasSet("seed") { + w.suiteConfig.RandomSeed = time.Now().Unix() + } +} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/interrupt_handler.go b/vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/interrupt_handler.go new file mode 100644 index 000000000..8ed86111f --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/interrupt_handler.go @@ -0,0 +1,177 @@ +package interrupt_handler + +import ( + "os" + "os/signal" + "sync" + "syscall" + "time" + + "github.com/onsi/ginkgo/v2/internal/parallel_support" +) + +var ABORT_POLLING_INTERVAL = 500 * time.Millisecond + +type InterruptCause uint + +const ( + InterruptCauseInvalid InterruptCause = iota + InterruptCauseSignal + InterruptCauseAbortByOtherProcess +) + +type InterruptLevel uint + +const ( + InterruptLevelUninterrupted InterruptLevel = iota + InterruptLevelCleanupAndReport + InterruptLevelReportOnly + InterruptLevelBailOut +) + +func (ic InterruptCause) String() string { + switch ic { + case InterruptCauseSignal: + return "Interrupted by User" + case InterruptCauseAbortByOtherProcess: + return "Interrupted by Other Ginkgo Process" + } + return "INVALID_INTERRUPT_CAUSE" +} + +type InterruptStatus struct { + Channel chan interface{} + Level InterruptLevel + Cause InterruptCause +} + +func (s InterruptStatus) Interrupted() bool { + return s.Level != InterruptLevelUninterrupted +} + +func (s InterruptStatus) Message() string { + return s.Cause.String() +} + +func (s InterruptStatus) ShouldIncludeProgressReport() bool { + return s.Cause != InterruptCauseAbortByOtherProcess +} + +type InterruptHandlerInterface interface { + Status() InterruptStatus +} + +type InterruptHandler struct { + c chan interface{} + lock *sync.Mutex + level InterruptLevel + cause InterruptCause + client parallel_support.Client + stop chan interface{} + signals []os.Signal + requestAbortCheck chan interface{} +} + +func NewInterruptHandler(client parallel_support.Client, signals ...os.Signal) *InterruptHandler { + if len(signals) == 0 { + signals = []os.Signal{os.Interrupt, syscall.SIGTERM} + } + handler := &InterruptHandler{ + c: make(chan interface{}), + lock: &sync.Mutex{}, + stop: make(chan interface{}), + requestAbortCheck: make(chan interface{}), + client: client, + signals: signals, + } + handler.registerForInterrupts() + return handler +} + +func (handler *InterruptHandler) Stop() { + close(handler.stop) +} + +func (handler *InterruptHandler) registerForInterrupts() { + // os signal handling + signalChannel := make(chan os.Signal, 1) + signal.Notify(signalChannel, handler.signals...) + + // cross-process abort handling + var abortChannel chan interface{} + if handler.client != nil { + abortChannel = make(chan interface{}) + go func() { + pollTicker := time.NewTicker(ABORT_POLLING_INTERVAL) + for { + select { + case <-pollTicker.C: + if handler.client.ShouldAbort() { + close(abortChannel) + pollTicker.Stop() + return + } + case <-handler.requestAbortCheck: + if handler.client.ShouldAbort() { + close(abortChannel) + pollTicker.Stop() + return + } + case <-handler.stop: + pollTicker.Stop() + return + } + } + }() + } + + go func(abortChannel chan interface{}) { + var interruptCause InterruptCause + for { + select { + case <-signalChannel: + interruptCause = InterruptCauseSignal + case <-abortChannel: + interruptCause = InterruptCauseAbortByOtherProcess + case <-handler.stop: + signal.Stop(signalChannel) + return + } + abortChannel = nil + + handler.lock.Lock() + oldLevel := handler.level + handler.cause = interruptCause + if handler.level == InterruptLevelUninterrupted { + handler.level = InterruptLevelCleanupAndReport + } else if handler.level == InterruptLevelCleanupAndReport { + handler.level = InterruptLevelReportOnly + } else if handler.level == InterruptLevelReportOnly { + handler.level = InterruptLevelBailOut + } + if handler.level != oldLevel { + close(handler.c) + handler.c = make(chan interface{}) + } + handler.lock.Unlock() + } + }(abortChannel) +} + +func (handler *InterruptHandler) Status() InterruptStatus { + handler.lock.Lock() + status := InterruptStatus{ + Level: handler.level, + Channel: handler.c, + Cause: handler.cause, + } + handler.lock.Unlock() + + if handler.client != nil && handler.client.ShouldAbort() && !status.Interrupted() { + close(handler.requestAbortCheck) + <-status.Channel + return handler.Status() + } + + return status +} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/sigquit_swallower_unix.go b/vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/sigquit_swallower_unix.go new file mode 100644 index 000000000..bf0de496d --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/sigquit_swallower_unix.go @@ -0,0 +1,15 @@ +//go:build freebsd || openbsd || netbsd || dragonfly || darwin || linux || solaris +// +build freebsd openbsd netbsd dragonfly darwin linux solaris + +package interrupt_handler + +import ( + "os" + "os/signal" + "syscall" +) + +func SwallowSigQuit() { + c := make(chan os.Signal, 1024) + signal.Notify(c, syscall.SIGQUIT) +} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/sigquit_swallower_windows.go b/vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/sigquit_swallower_windows.go new file mode 100644 index 000000000..fcf8da833 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/internal/interrupt_handler/sigquit_swallower_windows.go @@ -0,0 +1,8 @@ +//go:build windows +// +build windows + +package interrupt_handler + +func SwallowSigQuit() { + //noop +} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/client_server.go b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/client_server.go new file mode 100644 index 000000000..b3cd64292 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/client_server.go @@ -0,0 +1,72 @@ +package parallel_support + +import ( + "fmt" + "io" + "os" + "time" + + "github.com/onsi/ginkgo/v2/reporters" + "github.com/onsi/ginkgo/v2/types" +) + +type BeforeSuiteState struct { + Data []byte + State types.SpecState +} + +type ParallelIndexCounter struct { + Index int +} + +var ErrorGone = fmt.Errorf("gone") +var ErrorFailed = fmt.Errorf("failed") +var ErrorEarly = fmt.Errorf("early") + +var POLLING_INTERVAL = 50 * time.Millisecond + +type Server interface { + Start() + Close() + Address() string + RegisterAlive(node int, alive func() bool) + GetSuiteDone() chan interface{} + GetOutputDestination() io.Writer + SetOutputDestination(io.Writer) +} + +type Client interface { + Connect() bool + Close() error + + PostSuiteWillBegin(report types.Report) error + PostDidRun(report types.SpecReport) error + PostSuiteDidEnd(report types.Report) error + PostReportBeforeSuiteCompleted(state types.SpecState) error + BlockUntilReportBeforeSuiteCompleted() (types.SpecState, error) + PostSynchronizedBeforeSuiteCompleted(state types.SpecState, data []byte) error + BlockUntilSynchronizedBeforeSuiteData() (types.SpecState, []byte, error) + BlockUntilNonprimaryProcsHaveFinished() error + BlockUntilAggregatedNonprimaryProcsReport() (types.Report, error) + FetchNextCounter() (int, error) + PostAbort() error + ShouldAbort() bool + PostEmitProgressReport(report types.ProgressReport) error + Write(p []byte) (int, error) +} + +func NewServer(parallelTotal int, reporter reporters.Reporter) (Server, error) { + if os.Getenv("GINKGO_PARALLEL_PROTOCOL") == "HTTP" { + return newHttpServer(parallelTotal, reporter) + } else { + return newRPCServer(parallelTotal, reporter) + } +} + +func NewClient(serverHost string) Client { + if os.Getenv("GINKGO_PARALLEL_PROTOCOL") == "HTTP" { + return newHttpClient(serverHost) + } else { + return newRPCClient(serverHost) + } +} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/http_client.go b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/http_client.go new file mode 100644 index 000000000..6547c7a66 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/http_client.go @@ -0,0 +1,169 @@ +package parallel_support + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "time" + + "github.com/onsi/ginkgo/v2/types" +) + +type httpClient struct { + serverHost string +} + +func newHttpClient(serverHost string) *httpClient { + return &httpClient{ + serverHost: serverHost, + } +} + +func (client *httpClient) Connect() bool { + resp, err := http.Get(client.serverHost + "/up") + if err != nil { + return false + } + resp.Body.Close() + return resp.StatusCode == http.StatusOK +} + +func (client *httpClient) Close() error { + return nil +} + +func (client *httpClient) post(path string, data interface{}) error { + var body io.Reader + if data != nil { + encoded, err := json.Marshal(data) + if err != nil { + return err + } + body = bytes.NewBuffer(encoded) + } + resp, err := http.Post(client.serverHost+path, "application/json", body) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("received unexpected status code %d", resp.StatusCode) + } + return nil +} + +func (client *httpClient) poll(path string, data interface{}) error { + for { + resp, err := http.Get(client.serverHost + path) + if err != nil { + return err + } + if resp.StatusCode == http.StatusTooEarly { + resp.Body.Close() + time.Sleep(POLLING_INTERVAL) + continue + } + defer resp.Body.Close() + if resp.StatusCode == http.StatusGone { + return ErrorGone + } + if resp.StatusCode == http.StatusFailedDependency { + return ErrorFailed + } + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("received unexpected status code %d", resp.StatusCode) + } + if data != nil { + return json.NewDecoder(resp.Body).Decode(data) + } + return nil + } +} + +func (client *httpClient) PostSuiteWillBegin(report types.Report) error { + return client.post("/suite-will-begin", report) +} + +func (client *httpClient) PostDidRun(report types.SpecReport) error { + return client.post("/did-run", report) +} + +func (client *httpClient) PostSuiteDidEnd(report types.Report) error { + return client.post("/suite-did-end", report) +} + +func (client *httpClient) PostEmitProgressReport(report types.ProgressReport) error { + return client.post("/progress-report", report) +} + +func (client *httpClient) PostReportBeforeSuiteCompleted(state types.SpecState) error { + return client.post("/report-before-suite-completed", state) +} + +func (client *httpClient) BlockUntilReportBeforeSuiteCompleted() (types.SpecState, error) { + var state types.SpecState + err := client.poll("/report-before-suite-state", &state) + if err == ErrorGone { + return types.SpecStateFailed, nil + } + return state, err +} + +func (client *httpClient) PostSynchronizedBeforeSuiteCompleted(state types.SpecState, data []byte) error { + beforeSuiteState := BeforeSuiteState{ + State: state, + Data: data, + } + return client.post("/before-suite-completed", beforeSuiteState) +} + +func (client *httpClient) BlockUntilSynchronizedBeforeSuiteData() (types.SpecState, []byte, error) { + var beforeSuiteState BeforeSuiteState + err := client.poll("/before-suite-state", &beforeSuiteState) + if err == ErrorGone { + return types.SpecStateInvalid, nil, types.GinkgoErrors.SynchronizedBeforeSuiteDisappearedOnProc1() + } + return beforeSuiteState.State, beforeSuiteState.Data, err +} + +func (client *httpClient) BlockUntilNonprimaryProcsHaveFinished() error { + return client.poll("/have-nonprimary-procs-finished", nil) +} + +func (client *httpClient) BlockUntilAggregatedNonprimaryProcsReport() (types.Report, error) { + var report types.Report + err := client.poll("/aggregated-nonprimary-procs-report", &report) + if err == ErrorGone { + return types.Report{}, types.GinkgoErrors.AggregatedReportUnavailableDueToNodeDisappearing() + } + return report, err +} + +func (client *httpClient) FetchNextCounter() (int, error) { + var counter ParallelIndexCounter + err := client.poll("/counter", &counter) + return counter.Index, err +} + +func (client *httpClient) PostAbort() error { + return client.post("/abort", nil) +} + +func (client *httpClient) ShouldAbort() bool { + err := client.poll("/abort", nil) + if err == ErrorGone { + return true + } + return false +} + +func (client *httpClient) Write(p []byte) (int, error) { + resp, err := http.Post(client.serverHost+"/emit-output", "text/plain;charset=UTF-8 ", bytes.NewReader(p)) + resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return 0, fmt.Errorf("failed to emit output") + } + return len(p), err +} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/http_server.go b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/http_server.go new file mode 100644 index 000000000..d2c71ab1b --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/http_server.go @@ -0,0 +1,242 @@ +/* + +The remote package provides the pieces to allow Ginkgo test suites to report to remote listeners. +This is used, primarily, to enable streaming parallel test output but has, in principal, broader applications (e.g. streaming test output to a browser). + +*/ + +package parallel_support + +import ( + "encoding/json" + "io" + "net" + "net/http" + + "github.com/onsi/ginkgo/v2/reporters" + "github.com/onsi/ginkgo/v2/types" +) + +/* +httpServer spins up on an automatically selected port and listens for communication from the forwarding reporter. +It then forwards that communication to attached reporters. +*/ +type httpServer struct { + listener net.Listener + handler *ServerHandler +} + +// Create a new server, automatically selecting a port +func newHttpServer(parallelTotal int, reporter reporters.Reporter) (*httpServer, error) { + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + return nil, err + } + return &httpServer{ + listener: listener, + handler: newServerHandler(parallelTotal, reporter), + }, nil +} + +// Start the server. You don't need to `go s.Start()`, just `s.Start()` +func (server *httpServer) Start() { + httpServer := &http.Server{} + mux := http.NewServeMux() + httpServer.Handler = mux + + //streaming endpoints + mux.HandleFunc("/suite-will-begin", server.specSuiteWillBegin) + mux.HandleFunc("/did-run", server.didRun) + mux.HandleFunc("/suite-did-end", server.specSuiteDidEnd) + mux.HandleFunc("/emit-output", server.emitOutput) + mux.HandleFunc("/progress-report", server.emitProgressReport) + + //synchronization endpoints + mux.HandleFunc("/report-before-suite-completed", server.handleReportBeforeSuiteCompleted) + mux.HandleFunc("/report-before-suite-state", server.handleReportBeforeSuiteState) + mux.HandleFunc("/before-suite-completed", server.handleBeforeSuiteCompleted) + mux.HandleFunc("/before-suite-state", server.handleBeforeSuiteState) + mux.HandleFunc("/have-nonprimary-procs-finished", server.handleHaveNonprimaryProcsFinished) + mux.HandleFunc("/aggregated-nonprimary-procs-report", server.handleAggregatedNonprimaryProcsReport) + mux.HandleFunc("/counter", server.handleCounter) + mux.HandleFunc("/up", server.handleUp) + mux.HandleFunc("/abort", server.handleAbort) + + go httpServer.Serve(server.listener) +} + +// Stop the server +func (server *httpServer) Close() { + server.listener.Close() +} + +// The address the server can be reached it. Pass this into the `ForwardingReporter`. +func (server *httpServer) Address() string { + return "http://" + server.listener.Addr().String() +} + +func (server *httpServer) GetSuiteDone() chan interface{} { + return server.handler.done +} + +func (server *httpServer) GetOutputDestination() io.Writer { + return server.handler.outputDestination +} + +func (server *httpServer) SetOutputDestination(w io.Writer) { + server.handler.outputDestination = w +} + +func (server *httpServer) RegisterAlive(node int, alive func() bool) { + server.handler.registerAlive(node, alive) +} + +// +// Streaming Endpoints +// + +// The server will forward all received messages to Ginkgo reporters registered with `RegisterReporters` +func (server *httpServer) decode(writer http.ResponseWriter, request *http.Request, object interface{}) bool { + defer request.Body.Close() + if json.NewDecoder(request.Body).Decode(object) != nil { + writer.WriteHeader(http.StatusBadRequest) + return false + } + return true +} + +func (server *httpServer) handleError(err error, writer http.ResponseWriter) bool { + if err == nil { + return false + } + switch err { + case ErrorEarly: + writer.WriteHeader(http.StatusTooEarly) + case ErrorGone: + writer.WriteHeader(http.StatusGone) + case ErrorFailed: + writer.WriteHeader(http.StatusFailedDependency) + default: + writer.WriteHeader(http.StatusInternalServerError) + } + return true +} + +func (server *httpServer) specSuiteWillBegin(writer http.ResponseWriter, request *http.Request) { + var report types.Report + if !server.decode(writer, request, &report) { + return + } + + server.handleError(server.handler.SpecSuiteWillBegin(report, voidReceiver), writer) +} + +func (server *httpServer) didRun(writer http.ResponseWriter, request *http.Request) { + var report types.SpecReport + if !server.decode(writer, request, &report) { + return + } + + server.handleError(server.handler.DidRun(report, voidReceiver), writer) +} + +func (server *httpServer) specSuiteDidEnd(writer http.ResponseWriter, request *http.Request) { + var report types.Report + if !server.decode(writer, request, &report) { + return + } + server.handleError(server.handler.SpecSuiteDidEnd(report, voidReceiver), writer) +} + +func (server *httpServer) emitOutput(writer http.ResponseWriter, request *http.Request) { + output, err := io.ReadAll(request.Body) + if err != nil { + writer.WriteHeader(http.StatusInternalServerError) + return + } + var n int + server.handleError(server.handler.EmitOutput(output, &n), writer) +} + +func (server *httpServer) emitProgressReport(writer http.ResponseWriter, request *http.Request) { + var report types.ProgressReport + if !server.decode(writer, request, &report) { + return + } + server.handleError(server.handler.EmitProgressReport(report, voidReceiver), writer) +} + +func (server *httpServer) handleReportBeforeSuiteCompleted(writer http.ResponseWriter, request *http.Request) { + var state types.SpecState + if !server.decode(writer, request, &state) { + return + } + + server.handleError(server.handler.ReportBeforeSuiteCompleted(state, voidReceiver), writer) +} + +func (server *httpServer) handleReportBeforeSuiteState(writer http.ResponseWriter, request *http.Request) { + var state types.SpecState + if server.handleError(server.handler.ReportBeforeSuiteState(voidSender, &state), writer) { + return + } + json.NewEncoder(writer).Encode(state) +} + +func (server *httpServer) handleBeforeSuiteCompleted(writer http.ResponseWriter, request *http.Request) { + var beforeSuiteState BeforeSuiteState + if !server.decode(writer, request, &beforeSuiteState) { + return + } + + server.handleError(server.handler.BeforeSuiteCompleted(beforeSuiteState, voidReceiver), writer) +} + +func (server *httpServer) handleBeforeSuiteState(writer http.ResponseWriter, request *http.Request) { + var beforeSuiteState BeforeSuiteState + if server.handleError(server.handler.BeforeSuiteState(voidSender, &beforeSuiteState), writer) { + return + } + json.NewEncoder(writer).Encode(beforeSuiteState) +} + +func (server *httpServer) handleHaveNonprimaryProcsFinished(writer http.ResponseWriter, request *http.Request) { + if server.handleError(server.handler.HaveNonprimaryProcsFinished(voidSender, voidReceiver), writer) { + return + } + writer.WriteHeader(http.StatusOK) +} + +func (server *httpServer) handleAggregatedNonprimaryProcsReport(writer http.ResponseWriter, request *http.Request) { + var aggregatedReport types.Report + if server.handleError(server.handler.AggregatedNonprimaryProcsReport(voidSender, &aggregatedReport), writer) { + return + } + json.NewEncoder(writer).Encode(aggregatedReport) +} + +func (server *httpServer) handleCounter(writer http.ResponseWriter, request *http.Request) { + var n int + if server.handleError(server.handler.Counter(voidSender, &n), writer) { + return + } + json.NewEncoder(writer).Encode(ParallelIndexCounter{Index: n}) +} + +func (server *httpServer) handleUp(writer http.ResponseWriter, request *http.Request) { + writer.WriteHeader(http.StatusOK) +} + +func (server *httpServer) handleAbort(writer http.ResponseWriter, request *http.Request) { + if request.Method == "GET" { + var shouldAbort bool + server.handler.ShouldAbort(voidSender, &shouldAbort) + if shouldAbort { + writer.WriteHeader(http.StatusGone) + } else { + writer.WriteHeader(http.StatusOK) + } + } else { + server.handler.Abort(voidSender, voidReceiver) + } +} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/rpc_client.go b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/rpc_client.go new file mode 100644 index 000000000..59e8e6fd0 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/rpc_client.go @@ -0,0 +1,136 @@ +package parallel_support + +import ( + "net/rpc" + "time" + + "github.com/onsi/ginkgo/v2/types" +) + +type rpcClient struct { + serverHost string + client *rpc.Client +} + +func newRPCClient(serverHost string) *rpcClient { + return &rpcClient{ + serverHost: serverHost, + } +} + +func (client *rpcClient) Connect() bool { + var err error + if client.client != nil { + return true + } + client.client, err = rpc.DialHTTPPath("tcp", client.serverHost, "/") + if err != nil { + client.client = nil + return false + } + return true +} + +func (client *rpcClient) Close() error { + return client.client.Close() +} + +func (client *rpcClient) poll(method string, data interface{}) error { + for { + err := client.client.Call(method, voidSender, data) + if err == nil { + return nil + } + switch err.Error() { + case ErrorEarly.Error(): + time.Sleep(POLLING_INTERVAL) + case ErrorGone.Error(): + return ErrorGone + case ErrorFailed.Error(): + return ErrorFailed + default: + return err + } + } +} + +func (client *rpcClient) PostSuiteWillBegin(report types.Report) error { + return client.client.Call("Server.SpecSuiteWillBegin", report, voidReceiver) +} + +func (client *rpcClient) PostDidRun(report types.SpecReport) error { + return client.client.Call("Server.DidRun", report, voidReceiver) +} + +func (client *rpcClient) PostSuiteDidEnd(report types.Report) error { + return client.client.Call("Server.SpecSuiteDidEnd", report, voidReceiver) +} + +func (client *rpcClient) Write(p []byte) (int, error) { + var n int + err := client.client.Call("Server.EmitOutput", p, &n) + return n, err +} + +func (client *rpcClient) PostEmitProgressReport(report types.ProgressReport) error { + return client.client.Call("Server.EmitProgressReport", report, voidReceiver) +} + +func (client *rpcClient) PostReportBeforeSuiteCompleted(state types.SpecState) error { + return client.client.Call("Server.ReportBeforeSuiteCompleted", state, voidReceiver) +} + +func (client *rpcClient) BlockUntilReportBeforeSuiteCompleted() (types.SpecState, error) { + var state types.SpecState + err := client.poll("Server.ReportBeforeSuiteState", &state) + if err == ErrorGone { + return types.SpecStateFailed, nil + } + return state, err +} + +func (client *rpcClient) PostSynchronizedBeforeSuiteCompleted(state types.SpecState, data []byte) error { + beforeSuiteState := BeforeSuiteState{ + State: state, + Data: data, + } + return client.client.Call("Server.BeforeSuiteCompleted", beforeSuiteState, voidReceiver) +} + +func (client *rpcClient) BlockUntilSynchronizedBeforeSuiteData() (types.SpecState, []byte, error) { + var beforeSuiteState BeforeSuiteState + err := client.poll("Server.BeforeSuiteState", &beforeSuiteState) + if err == ErrorGone { + return types.SpecStateInvalid, nil, types.GinkgoErrors.SynchronizedBeforeSuiteDisappearedOnProc1() + } + return beforeSuiteState.State, beforeSuiteState.Data, err +} + +func (client *rpcClient) BlockUntilNonprimaryProcsHaveFinished() error { + return client.poll("Server.HaveNonprimaryProcsFinished", voidReceiver) +} + +func (client *rpcClient) BlockUntilAggregatedNonprimaryProcsReport() (types.Report, error) { + var report types.Report + err := client.poll("Server.AggregatedNonprimaryProcsReport", &report) + if err == ErrorGone { + return types.Report{}, types.GinkgoErrors.AggregatedReportUnavailableDueToNodeDisappearing() + } + return report, err +} + +func (client *rpcClient) FetchNextCounter() (int, error) { + var counter int + err := client.client.Call("Server.Counter", voidSender, &counter) + return counter, err +} + +func (client *rpcClient) PostAbort() error { + return client.client.Call("Server.Abort", voidSender, voidReceiver) +} + +func (client *rpcClient) ShouldAbort() bool { + var shouldAbort bool + client.client.Call("Server.ShouldAbort", voidSender, &shouldAbort) + return shouldAbort +} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/rpc_server.go b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/rpc_server.go new file mode 100644 index 000000000..2620fd562 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/rpc_server.go @@ -0,0 +1,75 @@ +/* + +The remote package provides the pieces to allow Ginkgo test suites to report to remote listeners. +This is used, primarily, to enable streaming parallel test output but has, in principal, broader applications (e.g. streaming test output to a browser). + +*/ + +package parallel_support + +import ( + "io" + "net" + "net/http" + "net/rpc" + + "github.com/onsi/ginkgo/v2/reporters" +) + +/* +RPCServer spins up on an automatically selected port and listens for communication from the forwarding reporter. +It then forwards that communication to attached reporters. +*/ +type RPCServer struct { + listener net.Listener + handler *ServerHandler +} + +//Create a new server, automatically selecting a port +func newRPCServer(parallelTotal int, reporter reporters.Reporter) (*RPCServer, error) { + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + return nil, err + } + return &RPCServer{ + listener: listener, + handler: newServerHandler(parallelTotal, reporter), + }, nil +} + +//Start the server. You don't need to `go s.Start()`, just `s.Start()` +func (server *RPCServer) Start() { + rpcServer := rpc.NewServer() + rpcServer.RegisterName("Server", server.handler) //register the handler's methods as the server + + httpServer := &http.Server{} + httpServer.Handler = rpcServer + + go httpServer.Serve(server.listener) +} + +//Stop the server +func (server *RPCServer) Close() { + server.listener.Close() +} + +//The address the server can be reached it. Pass this into the `ForwardingReporter`. +func (server *RPCServer) Address() string { + return server.listener.Addr().String() +} + +func (server *RPCServer) GetSuiteDone() chan interface{} { + return server.handler.done +} + +func (server *RPCServer) GetOutputDestination() io.Writer { + return server.handler.outputDestination +} + +func (server *RPCServer) SetOutputDestination(w io.Writer) { + server.handler.outputDestination = w +} + +func (server *RPCServer) RegisterAlive(node int, alive func() bool) { + server.handler.registerAlive(node, alive) +} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/server_handler.go b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/server_handler.go new file mode 100644 index 000000000..a6d98793e --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/internal/parallel_support/server_handler.go @@ -0,0 +1,234 @@ +package parallel_support + +import ( + "io" + "os" + "sync" + + "github.com/onsi/ginkgo/v2/reporters" + "github.com/onsi/ginkgo/v2/types" +) + +type Void struct{} + +var voidReceiver *Void = &Void{} +var voidSender Void + +// ServerHandler is an RPC-compatible handler that is shared between the http server and the rpc server. +// It handles all the business logic to avoid duplication between the two servers + +type ServerHandler struct { + done chan interface{} + outputDestination io.Writer + reporter reporters.Reporter + alives []func() bool + lock *sync.Mutex + beforeSuiteState BeforeSuiteState + reportBeforeSuiteState types.SpecState + parallelTotal int + counter int + counterLock *sync.Mutex + shouldAbort bool + + numSuiteDidBegins int + numSuiteDidEnds int + aggregatedReport types.Report + reportHoldingArea []types.SpecReport +} + +func newServerHandler(parallelTotal int, reporter reporters.Reporter) *ServerHandler { + return &ServerHandler{ + reporter: reporter, + lock: &sync.Mutex{}, + counterLock: &sync.Mutex{}, + alives: make([]func() bool, parallelTotal), + beforeSuiteState: BeforeSuiteState{Data: nil, State: types.SpecStateInvalid}, + + parallelTotal: parallelTotal, + outputDestination: os.Stdout, + done: make(chan interface{}), + } +} + +func (handler *ServerHandler) SpecSuiteWillBegin(report types.Report, _ *Void) error { + handler.lock.Lock() + defer handler.lock.Unlock() + + handler.numSuiteDidBegins += 1 + + // all summaries are identical, so it's fine to simply emit the last one of these + if handler.numSuiteDidBegins == handler.parallelTotal { + handler.reporter.SuiteWillBegin(report) + + for _, summary := range handler.reportHoldingArea { + handler.reporter.WillRun(summary) + handler.reporter.DidRun(summary) + } + + handler.reportHoldingArea = nil + } + + return nil +} + +func (handler *ServerHandler) DidRun(report types.SpecReport, _ *Void) error { + handler.lock.Lock() + defer handler.lock.Unlock() + + if handler.numSuiteDidBegins == handler.parallelTotal { + handler.reporter.WillRun(report) + handler.reporter.DidRun(report) + } else { + handler.reportHoldingArea = append(handler.reportHoldingArea, report) + } + + return nil +} + +func (handler *ServerHandler) SpecSuiteDidEnd(report types.Report, _ *Void) error { + handler.lock.Lock() + defer handler.lock.Unlock() + + handler.numSuiteDidEnds += 1 + if handler.numSuiteDidEnds == 1 { + handler.aggregatedReport = report + } else { + handler.aggregatedReport = handler.aggregatedReport.Add(report) + } + + if handler.numSuiteDidEnds == handler.parallelTotal { + handler.reporter.SuiteDidEnd(handler.aggregatedReport) + close(handler.done) + } + + return nil +} + +func (handler *ServerHandler) EmitOutput(output []byte, n *int) error { + var err error + *n, err = handler.outputDestination.Write(output) + return err +} + +func (handler *ServerHandler) EmitProgressReport(report types.ProgressReport, _ *Void) error { + handler.lock.Lock() + defer handler.lock.Unlock() + handler.reporter.EmitProgressReport(report) + return nil +} + +func (handler *ServerHandler) registerAlive(proc int, alive func() bool) { + handler.lock.Lock() + defer handler.lock.Unlock() + handler.alives[proc-1] = alive +} + +func (handler *ServerHandler) procIsAlive(proc int) bool { + handler.lock.Lock() + defer handler.lock.Unlock() + alive := handler.alives[proc-1] + if alive == nil { + return true + } + return alive() +} + +func (handler *ServerHandler) haveNonprimaryProcsFinished() bool { + for i := 2; i <= handler.parallelTotal; i++ { + if handler.procIsAlive(i) { + return false + } + } + return true +} + +func (handler *ServerHandler) ReportBeforeSuiteCompleted(reportBeforeSuiteState types.SpecState, _ *Void) error { + handler.lock.Lock() + defer handler.lock.Unlock() + handler.reportBeforeSuiteState = reportBeforeSuiteState + + return nil +} + +func (handler *ServerHandler) ReportBeforeSuiteState(_ Void, reportBeforeSuiteState *types.SpecState) error { + proc1IsAlive := handler.procIsAlive(1) + handler.lock.Lock() + defer handler.lock.Unlock() + if handler.reportBeforeSuiteState == types.SpecStateInvalid { + if proc1IsAlive { + return ErrorEarly + } else { + return ErrorGone + } + } + *reportBeforeSuiteState = handler.reportBeforeSuiteState + return nil +} + +func (handler *ServerHandler) BeforeSuiteCompleted(beforeSuiteState BeforeSuiteState, _ *Void) error { + handler.lock.Lock() + defer handler.lock.Unlock() + handler.beforeSuiteState = beforeSuiteState + + return nil +} + +func (handler *ServerHandler) BeforeSuiteState(_ Void, beforeSuiteState *BeforeSuiteState) error { + proc1IsAlive := handler.procIsAlive(1) + handler.lock.Lock() + defer handler.lock.Unlock() + if handler.beforeSuiteState.State == types.SpecStateInvalid { + if proc1IsAlive { + return ErrorEarly + } else { + return ErrorGone + } + } + *beforeSuiteState = handler.beforeSuiteState + return nil +} + +func (handler *ServerHandler) HaveNonprimaryProcsFinished(_ Void, _ *Void) error { + if handler.haveNonprimaryProcsFinished() { + return nil + } else { + return ErrorEarly + } +} + +func (handler *ServerHandler) AggregatedNonprimaryProcsReport(_ Void, report *types.Report) error { + if handler.haveNonprimaryProcsFinished() { + handler.lock.Lock() + defer handler.lock.Unlock() + if handler.numSuiteDidEnds == handler.parallelTotal-1 { + *report = handler.aggregatedReport + return nil + } else { + return ErrorGone + } + } else { + return ErrorEarly + } +} + +func (handler *ServerHandler) Counter(_ Void, counter *int) error { + handler.counterLock.Lock() + defer handler.counterLock.Unlock() + *counter = handler.counter + handler.counter++ + return nil +} + +func (handler *ServerHandler) Abort(_ Void, _ *Void) error { + handler.lock.Lock() + defer handler.lock.Unlock() + handler.shouldAbort = true + return nil +} + +func (handler *ServerHandler) ShouldAbort(_ Void, shouldAbort *bool) error { + handler.lock.Lock() + defer handler.lock.Unlock() + *shouldAbort = handler.shouldAbort + return nil +} diff --git a/vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go b/vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go new file mode 100644 index 000000000..56b7be758 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go @@ -0,0 +1,759 @@ +/* +Ginkgo's Default Reporter + +A number of command line flags are available to tweak Ginkgo's default output. + +These are documented [here](http://onsi.github.io/ginkgo/#running_tests) +*/ +package reporters + +import ( + "fmt" + "io" + "runtime" + "strings" + "sync" + "time" + + "github.com/onsi/ginkgo/v2/formatter" + "github.com/onsi/ginkgo/v2/types" +) + +type DefaultReporter struct { + conf types.ReporterConfig + writer io.Writer + + // managing the emission stream + lastCharWasNewline bool + lastEmissionWasDelimiter bool + + // rendering + specDenoter string + retryDenoter string + formatter formatter.Formatter + + runningInParallel bool + lock *sync.Mutex +} + +func NewDefaultReporterUnderTest(conf types.ReporterConfig, writer io.Writer) *DefaultReporter { + reporter := NewDefaultReporter(conf, writer) + reporter.formatter = formatter.New(formatter.ColorModePassthrough) + + return reporter +} + +func NewDefaultReporter(conf types.ReporterConfig, writer io.Writer) *DefaultReporter { + reporter := &DefaultReporter{ + conf: conf, + writer: writer, + + lastCharWasNewline: true, + lastEmissionWasDelimiter: false, + + specDenoter: "•", + retryDenoter: "↺", + formatter: formatter.NewWithNoColorBool(conf.NoColor), + lock: &sync.Mutex{}, + } + if runtime.GOOS == "windows" { + reporter.specDenoter = "+" + reporter.retryDenoter = "R" + } + + return reporter +} + +/* The Reporter Interface */ + +func (r *DefaultReporter) SuiteWillBegin(report types.Report) { + if r.conf.Verbosity().Is(types.VerbosityLevelSuccinct) { + r.emit(r.f("[%d] {{bold}}%s{{/}} ", report.SuiteConfig.RandomSeed, report.SuiteDescription)) + if len(report.SuiteLabels) > 0 { + r.emit(r.f("{{coral}}[%s]{{/}} ", strings.Join(report.SuiteLabels, ", "))) + } + r.emit(r.f("- %d/%d specs ", report.PreRunStats.SpecsThatWillRun, report.PreRunStats.TotalSpecs)) + if report.SuiteConfig.ParallelTotal > 1 { + r.emit(r.f("- %d procs ", report.SuiteConfig.ParallelTotal)) + } + } else { + banner := r.f("Running Suite: %s - %s", report.SuiteDescription, report.SuitePath) + r.emitBlock(banner) + bannerWidth := len(banner) + if len(report.SuiteLabels) > 0 { + labels := strings.Join(report.SuiteLabels, ", ") + r.emitBlock(r.f("{{coral}}[%s]{{/}} ", labels)) + if len(labels)+2 > bannerWidth { + bannerWidth = len(labels) + 2 + } + } + r.emitBlock(strings.Repeat("=", bannerWidth)) + + out := r.f("Random Seed: {{bold}}%d{{/}}", report.SuiteConfig.RandomSeed) + if report.SuiteConfig.RandomizeAllSpecs { + out += r.f(" - will randomize all specs") + } + r.emitBlock(out) + r.emit("\n") + r.emitBlock(r.f("Will run {{bold}}%d{{/}} of {{bold}}%d{{/}} specs", report.PreRunStats.SpecsThatWillRun, report.PreRunStats.TotalSpecs)) + if report.SuiteConfig.ParallelTotal > 1 { + r.emitBlock(r.f("Running in parallel across {{bold}}%d{{/}} processes", report.SuiteConfig.ParallelTotal)) + } + } +} + +func (r *DefaultReporter) SuiteDidEnd(report types.Report) { + failures := report.SpecReports.WithState(types.SpecStateFailureStates) + if len(failures) > 0 { + r.emitBlock("\n") + if len(failures) > 1 { + r.emitBlock(r.f("{{red}}{{bold}}Summarizing %d Failures:{{/}}", len(failures))) + } else { + r.emitBlock(r.f("{{red}}{{bold}}Summarizing 1 Failure:{{/}}")) + } + for _, specReport := range failures { + highlightColor, heading := "{{red}}", "[FAIL]" + switch specReport.State { + case types.SpecStatePanicked: + highlightColor, heading = "{{magenta}}", "[PANICKED!]" + case types.SpecStateAborted: + highlightColor, heading = "{{coral}}", "[ABORTED]" + case types.SpecStateTimedout: + highlightColor, heading = "{{orange}}", "[TIMEDOUT]" + case types.SpecStateInterrupted: + highlightColor, heading = "{{orange}}", "[INTERRUPTED]" + } + locationBlock := r.codeLocationBlock(specReport, highlightColor, false, true) + r.emitBlock(r.fi(1, highlightColor+"%s{{/}} %s", heading, locationBlock)) + } + } + + //summarize the suite + if r.conf.Verbosity().Is(types.VerbosityLevelSuccinct) && report.SuiteSucceeded { + r.emit(r.f(" {{green}}SUCCESS!{{/}} %s ", report.RunTime)) + return + } + + r.emitBlock("\n") + color, status := "{{green}}{{bold}}", "SUCCESS!" + if !report.SuiteSucceeded { + color, status = "{{red}}{{bold}}", "FAIL!" + } + + specs := report.SpecReports.WithLeafNodeType(types.NodeTypeIt) //exclude any suite setup nodes + r.emitBlock(r.f(color+"Ran %d of %d Specs in %.3f seconds{{/}}", + specs.CountWithState(types.SpecStatePassed)+specs.CountWithState(types.SpecStateFailureStates), + report.PreRunStats.TotalSpecs, + report.RunTime.Seconds()), + ) + + switch len(report.SpecialSuiteFailureReasons) { + case 0: + r.emit(r.f(color+"%s{{/}} -- ", status)) + case 1: + r.emit(r.f(color+"%s - %s{{/}} -- ", status, report.SpecialSuiteFailureReasons[0])) + default: + r.emitBlock(r.f(color+"%s - %s{{/}}\n", status, strings.Join(report.SpecialSuiteFailureReasons, ", "))) + } + + if len(specs) == 0 && report.SpecReports.WithLeafNodeType(types.NodeTypeBeforeSuite|types.NodeTypeSynchronizedBeforeSuite).CountWithState(types.SpecStateFailureStates) > 0 { + r.emit(r.f("{{cyan}}{{bold}}A BeforeSuite node failed so all tests were skipped.{{/}}\n")) + } else { + r.emit(r.f("{{green}}{{bold}}%d Passed{{/}} | ", specs.CountWithState(types.SpecStatePassed))) + r.emit(r.f("{{red}}{{bold}}%d Failed{{/}} | ", specs.CountWithState(types.SpecStateFailureStates))) + if specs.CountOfFlakedSpecs() > 0 { + r.emit(r.f("{{light-yellow}}{{bold}}%d Flaked{{/}} | ", specs.CountOfFlakedSpecs())) + } + if specs.CountOfRepeatedSpecs() > 0 { + r.emit(r.f("{{light-yellow}}{{bold}}%d Repeated{{/}} | ", specs.CountOfRepeatedSpecs())) + } + r.emit(r.f("{{yellow}}{{bold}}%d Pending{{/}} | ", specs.CountWithState(types.SpecStatePending))) + r.emit(r.f("{{cyan}}{{bold}}%d Skipped{{/}}\n", specs.CountWithState(types.SpecStateSkipped))) + } +} + +func (r *DefaultReporter) WillRun(report types.SpecReport) { + v := r.conf.Verbosity() + if v.LT(types.VerbosityLevelVerbose) || report.State.Is(types.SpecStatePending|types.SpecStateSkipped) || report.RunningInParallel { + return + } + + r.emitDelimiter(0) + r.emitBlock(r.f(r.codeLocationBlock(report, "{{/}}", v.Is(types.VerbosityLevelVeryVerbose), false))) +} + +func (r *DefaultReporter) DidRun(report types.SpecReport) { + v := r.conf.Verbosity() + inParallel := report.RunningInParallel + + header := r.specDenoter + if report.LeafNodeType.Is(types.NodeTypesForSuiteLevelNodes) { + header = fmt.Sprintf("[%s]", report.LeafNodeType) + } + highlightColor := r.highlightColorForState(report.State) + + // have we already been streaming the timeline? + timelineHasBeenStreaming := v.GTE(types.VerbosityLevelVerbose) && !inParallel + + // should we show the timeline? + var timeline types.Timeline + showTimeline := !timelineHasBeenStreaming && (v.GTE(types.VerbosityLevelVerbose) || report.Failed()) + if showTimeline { + timeline = report.Timeline().WithoutHiddenReportEntries() + keepVeryVerboseSpecEvents := v.Is(types.VerbosityLevelVeryVerbose) || + (v.Is(types.VerbosityLevelVerbose) && r.conf.ShowNodeEvents) || + (report.Failed() && r.conf.ShowNodeEvents) + if !keepVeryVerboseSpecEvents { + timeline = timeline.WithoutVeryVerboseSpecEvents() + } + if len(timeline) == 0 && report.CapturedGinkgoWriterOutput == "" { + // the timeline is completely empty - don't show it + showTimeline = false + } + if v.LT(types.VerbosityLevelVeryVerbose) && report.CapturedGinkgoWriterOutput == "" && len(timeline) > 0 { + //if we aren't -vv and the timeline only has a single failure, don't show it as it will appear at the end of the report + failure, isFailure := timeline[0].(types.Failure) + if isFailure && (len(timeline) == 1 || (len(timeline) == 2 && failure.AdditionalFailure != nil)) { + showTimeline = false + } + } + } + + // should we have a separate section for always-visible reports? + showSeparateVisibilityAlwaysReportsSection := !timelineHasBeenStreaming && !showTimeline && report.ReportEntries.HasVisibility(types.ReportEntryVisibilityAlways) + + // should we have a separate section for captured stdout/stderr + showSeparateStdSection := inParallel && (report.CapturedStdOutErr != "") + + // given all that - do we have any actual content to show? or are we a single denoter in a stream? + reportHasContent := v.Is(types.VerbosityLevelVeryVerbose) || showTimeline || showSeparateVisibilityAlwaysReportsSection || showSeparateStdSection || report.Failed() || (v.Is(types.VerbosityLevelVerbose) && !report.State.Is(types.SpecStateSkipped)) + + // should we show a runtime? + includeRuntime := !report.State.Is(types.SpecStateSkipped|types.SpecStatePending) || (report.State.Is(types.SpecStateSkipped) && report.Failure.Message != "") + + // should we show the codelocation block? + showCodeLocation := !timelineHasBeenStreaming || !report.State.Is(types.SpecStatePassed) + + switch report.State { + case types.SpecStatePassed: + if report.LeafNodeType.Is(types.NodeTypesForSuiteLevelNodes) && !reportHasContent { + return + } + if report.LeafNodeType.Is(types.NodeTypesForSuiteLevelNodes) { + header = fmt.Sprintf("%s PASSED", header) + } + if report.NumAttempts > 1 && report.MaxFlakeAttempts > 1 { + header, reportHasContent = fmt.Sprintf("%s [FLAKEY TEST - TOOK %d ATTEMPTS TO PASS]", r.retryDenoter, report.NumAttempts), true + } + case types.SpecStatePending: + header = "P" + if v.GT(types.VerbosityLevelSuccinct) { + header, reportHasContent = "P [PENDING]", true + } + case types.SpecStateSkipped: + header = "S" + if v.Is(types.VerbosityLevelVeryVerbose) || (v.Is(types.VerbosityLevelVerbose) && report.Failure.Message != "") { + header, reportHasContent = "S [SKIPPED]", true + } + default: + header = fmt.Sprintf("%s [%s]", header, r.humanReadableState(report.State)) + if report.MaxMustPassRepeatedly > 1 { + header = fmt.Sprintf("%s DURING REPETITION #%d", header, report.NumAttempts) + } + } + + // If we have no content to show, jsut emit the header and return + if !reportHasContent { + r.emit(r.f(highlightColor + header + "{{/}}")) + return + } + + if includeRuntime { + header = r.f("%s [%.3f seconds]", header, report.RunTime.Seconds()) + } + + // Emit header + if !timelineHasBeenStreaming { + r.emitDelimiter(0) + } + r.emitBlock(r.f(highlightColor + header + "{{/}}")) + if showCodeLocation { + r.emitBlock(r.codeLocationBlock(report, highlightColor, v.Is(types.VerbosityLevelVeryVerbose), false)) + } + + //Emit Stdout/Stderr Output + if showSeparateStdSection { + r.emitBlock("\n") + r.emitBlock(r.fi(1, "{{gray}}Captured StdOut/StdErr Output >>{{/}}")) + r.emitBlock(r.fi(1, "%s", report.CapturedStdOutErr)) + r.emitBlock(r.fi(1, "{{gray}}<< Captured StdOut/StdErr Output{{/}}")) + } + + if showSeparateVisibilityAlwaysReportsSection { + r.emitBlock("\n") + r.emitBlock(r.fi(1, "{{gray}}Report Entries >>{{/}}")) + for _, entry := range report.ReportEntries.WithVisibility(types.ReportEntryVisibilityAlways) { + r.emitReportEntry(1, entry) + } + r.emitBlock(r.fi(1, "{{gray}}<< Report Entries{{/}}")) + } + + if showTimeline { + r.emitBlock("\n") + r.emitBlock(r.fi(1, "{{gray}}Timeline >>{{/}}")) + r.emitTimeline(1, report, timeline) + r.emitBlock(r.fi(1, "{{gray}}<< Timeline{{/}}")) + } + + // Emit Failure Message + if !report.Failure.IsZero() && !v.Is(types.VerbosityLevelVeryVerbose) { + r.emitBlock("\n") + r.emitFailure(1, report.State, report.Failure, true) + if len(report.AdditionalFailures) > 0 { + r.emitBlock(r.fi(1, "\nThere were {{bold}}{{red}}additional failures{{/}} detected. To view them in detail run {{bold}}ginkgo -vv{{/}}")) + } + } + + r.emitDelimiter(0) +} + +func (r *DefaultReporter) highlightColorForState(state types.SpecState) string { + switch state { + case types.SpecStatePassed: + return "{{green}}" + case types.SpecStatePending: + return "{{yellow}}" + case types.SpecStateSkipped: + return "{{cyan}}" + case types.SpecStateFailed: + return "{{red}}" + case types.SpecStateTimedout: + return "{{orange}}" + case types.SpecStatePanicked: + return "{{magenta}}" + case types.SpecStateInterrupted: + return "{{orange}}" + case types.SpecStateAborted: + return "{{coral}}" + default: + return "{{gray}}" + } +} + +func (r *DefaultReporter) humanReadableState(state types.SpecState) string { + return strings.ToUpper(state.String()) +} + +func (r *DefaultReporter) emitTimeline(indent uint, report types.SpecReport, timeline types.Timeline) { + isVeryVerbose := r.conf.Verbosity().Is(types.VerbosityLevelVeryVerbose) + gw := report.CapturedGinkgoWriterOutput + cursor := 0 + for _, entry := range timeline { + tl := entry.GetTimelineLocation() + if tl.Offset < len(gw) { + r.emit(r.fi(indent, "%s", gw[cursor:tl.Offset])) + cursor = tl.Offset + } else if cursor < len(gw) { + r.emit(r.fi(indent, "%s", gw[cursor:])) + cursor = len(gw) + } + switch x := entry.(type) { + case types.Failure: + if isVeryVerbose { + r.emitFailure(indent, report.State, x, false) + } else { + r.emitShortFailure(indent, report.State, x) + } + case types.AdditionalFailure: + if isVeryVerbose { + r.emitFailure(indent, x.State, x.Failure, true) + } else { + r.emitShortFailure(indent, x.State, x.Failure) + } + case types.ReportEntry: + r.emitReportEntry(indent, x) + case types.ProgressReport: + r.emitProgressReport(indent, false, x) + case types.SpecEvent: + if isVeryVerbose || !x.IsOnlyVisibleAtVeryVerbose() || r.conf.ShowNodeEvents { + r.emitSpecEvent(indent, x, isVeryVerbose) + } + } + } + if cursor < len(gw) { + r.emit(r.fi(indent, "%s", gw[cursor:])) + } +} + +func (r *DefaultReporter) EmitFailure(state types.SpecState, failure types.Failure) { + if r.conf.Verbosity().Is(types.VerbosityLevelVerbose) { + r.emitShortFailure(1, state, failure) + } else if r.conf.Verbosity().Is(types.VerbosityLevelVeryVerbose) { + r.emitFailure(1, state, failure, true) + } +} + +func (r *DefaultReporter) emitShortFailure(indent uint, state types.SpecState, failure types.Failure) { + r.emitBlock(r.fi(indent, r.highlightColorForState(state)+"[%s]{{/}} in [%s] - %s {{gray}}@ %s{{/}}", + r.humanReadableState(state), + failure.FailureNodeType, + failure.Location, + failure.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT), + )) +} + +func (r *DefaultReporter) emitFailure(indent uint, state types.SpecState, failure types.Failure, includeAdditionalFailure bool) { + highlightColor := r.highlightColorForState(state) + r.emitBlock(r.fi(indent, highlightColor+"[%s] %s{{/}}", r.humanReadableState(state), failure.Message)) + r.emitBlock(r.fi(indent, highlightColor+"In {{bold}}[%s]{{/}}"+highlightColor+" at: {{bold}}%s{{/}} {{gray}}@ %s{{/}}\n", failure.FailureNodeType, failure.Location, failure.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT))) + if failure.ForwardedPanic != "" { + r.emitBlock("\n") + r.emitBlock(r.fi(indent, highlightColor+"%s{{/}}", failure.ForwardedPanic)) + } + + if r.conf.FullTrace || failure.ForwardedPanic != "" { + r.emitBlock("\n") + r.emitBlock(r.fi(indent, highlightColor+"Full Stack Trace{{/}}")) + r.emitBlock(r.fi(indent+1, "%s", failure.Location.FullStackTrace)) + } + + if !failure.ProgressReport.IsZero() { + r.emitBlock("\n") + r.emitProgressReport(indent, false, failure.ProgressReport) + } + + if failure.AdditionalFailure != nil && includeAdditionalFailure { + r.emitBlock("\n") + r.emitFailure(indent, failure.AdditionalFailure.State, failure.AdditionalFailure.Failure, true) + } +} + +func (r *DefaultReporter) EmitProgressReport(report types.ProgressReport) { + r.emitDelimiter(1) + + if report.RunningInParallel { + r.emit(r.fi(1, "{{coral}}Progress Report for Ginkgo Process #{{bold}}%d{{/}}\n", report.ParallelProcess)) + } + shouldEmitGW := report.RunningInParallel || r.conf.Verbosity().LT(types.VerbosityLevelVerbose) + r.emitProgressReport(1, shouldEmitGW, report) + r.emitDelimiter(1) +} + +func (r *DefaultReporter) emitProgressReport(indent uint, emitGinkgoWriterOutput bool, report types.ProgressReport) { + if report.Message != "" { + r.emitBlock(r.fi(indent, report.Message+"\n")) + indent += 1 + } + if report.LeafNodeText != "" { + subjectIndent := indent + if len(report.ContainerHierarchyTexts) > 0 { + r.emit(r.fi(indent, r.cycleJoin(report.ContainerHierarchyTexts, " "))) + r.emit(" ") + subjectIndent = 0 + } + r.emit(r.fi(subjectIndent, "{{bold}}{{orange}}%s{{/}} (Spec Runtime: %s)\n", report.LeafNodeText, report.Time().Sub(report.SpecStartTime).Round(time.Millisecond))) + r.emit(r.fi(indent+1, "{{gray}}%s{{/}}\n", report.LeafNodeLocation)) + indent += 1 + } + if report.CurrentNodeType != types.NodeTypeInvalid { + r.emit(r.fi(indent, "In {{bold}}{{orange}}[%s]{{/}}", report.CurrentNodeType)) + if report.CurrentNodeText != "" && !report.CurrentNodeType.Is(types.NodeTypeIt) { + r.emit(r.f(" {{bold}}{{orange}}%s{{/}}", report.CurrentNodeText)) + } + + r.emit(r.f(" (Node Runtime: %s)\n", report.Time().Sub(report.CurrentNodeStartTime).Round(time.Millisecond))) + r.emit(r.fi(indent+1, "{{gray}}%s{{/}}\n", report.CurrentNodeLocation)) + indent += 1 + } + if report.CurrentStepText != "" { + r.emit(r.fi(indent, "At {{bold}}{{orange}}[By Step] %s{{/}} (Step Runtime: %s)\n", report.CurrentStepText, report.Time().Sub(report.CurrentStepStartTime).Round(time.Millisecond))) + r.emit(r.fi(indent+1, "{{gray}}%s{{/}}\n", report.CurrentStepLocation)) + indent += 1 + } + + if indent > 0 { + indent -= 1 + } + + if emitGinkgoWriterOutput && report.CapturedGinkgoWriterOutput != "" { + r.emit("\n") + r.emitBlock(r.fi(indent, "{{gray}}Begin Captured GinkgoWriter Output >>{{/}}")) + limit, lines := 10, strings.Split(report.CapturedGinkgoWriterOutput, "\n") + if len(lines) <= limit { + r.emitBlock(r.fi(indent+1, "%s", report.CapturedGinkgoWriterOutput)) + } else { + r.emitBlock(r.fi(indent+1, "{{gray}}...{{/}}")) + for _, line := range lines[len(lines)-limit-1:] { + r.emitBlock(r.fi(indent+1, "%s", line)) + } + } + r.emitBlock(r.fi(indent, "{{gray}}<< End Captured GinkgoWriter Output{{/}}")) + } + + if !report.SpecGoroutine().IsZero() { + r.emit("\n") + r.emit(r.fi(indent, "{{bold}}{{underline}}Spec Goroutine{{/}}\n")) + r.emitGoroutines(indent, report.SpecGoroutine()) + } + + if len(report.AdditionalReports) > 0 { + r.emit("\n") + r.emitBlock(r.fi(indent, "{{gray}}Begin Additional Progress Reports >>{{/}}")) + for i, additionalReport := range report.AdditionalReports { + r.emit(r.fi(indent+1, additionalReport)) + if i < len(report.AdditionalReports)-1 { + r.emitBlock(r.fi(indent+1, "{{gray}}%s{{/}}", strings.Repeat("-", 10))) + } + } + r.emitBlock(r.fi(indent, "{{gray}}<< End Additional Progress Reports{{/}}")) + } + + highlightedGoroutines := report.HighlightedGoroutines() + if len(highlightedGoroutines) > 0 { + r.emit("\n") + r.emit(r.fi(indent, "{{bold}}{{underline}}Goroutines of Interest{{/}}\n")) + r.emitGoroutines(indent, highlightedGoroutines...) + } + + otherGoroutines := report.OtherGoroutines() + if len(otherGoroutines) > 0 { + r.emit("\n") + r.emit(r.fi(indent, "{{gray}}{{bold}}{{underline}}Other Goroutines{{/}}\n")) + r.emitGoroutines(indent, otherGoroutines...) + } +} + +func (r *DefaultReporter) EmitReportEntry(entry types.ReportEntry) { + if r.conf.Verbosity().LT(types.VerbosityLevelVerbose) || entry.Visibility == types.ReportEntryVisibilityNever { + return + } + r.emitReportEntry(1, entry) +} + +func (r *DefaultReporter) emitReportEntry(indent uint, entry types.ReportEntry) { + r.emitBlock(r.fi(indent, "{{bold}}"+entry.Name+"{{gray}} "+fmt.Sprintf("- %s @ %s{{/}}", entry.Location, entry.Time.Format(types.GINKGO_TIME_FORMAT)))) + if representation := entry.StringRepresentation(); representation != "" { + r.emitBlock(r.fi(indent+1, representation)) + } +} + +func (r *DefaultReporter) EmitSpecEvent(event types.SpecEvent) { + v := r.conf.Verbosity() + if v.Is(types.VerbosityLevelVeryVerbose) || (v.Is(types.VerbosityLevelVerbose) && (r.conf.ShowNodeEvents || !event.IsOnlyVisibleAtVeryVerbose())) { + r.emitSpecEvent(1, event, r.conf.Verbosity().Is(types.VerbosityLevelVeryVerbose)) + } +} + +func (r *DefaultReporter) emitSpecEvent(indent uint, event types.SpecEvent, includeLocation bool) { + location := "" + if includeLocation { + location = fmt.Sprintf("- %s ", event.CodeLocation.String()) + } + switch event.SpecEventType { + case types.SpecEventInvalid: + return + case types.SpecEventByStart: + r.emitBlock(r.fi(indent, "{{bold}}STEP:{{/}} %s {{gray}}%s@ %s{{/}}", event.Message, location, event.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT))) + case types.SpecEventByEnd: + r.emitBlock(r.fi(indent, "{{bold}}END STEP:{{/}} %s {{gray}}%s@ %s (%s){{/}}", event.Message, location, event.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT), event.Duration.Round(time.Millisecond))) + case types.SpecEventNodeStart: + r.emitBlock(r.fi(indent, "> Enter {{bold}}[%s]{{/}} %s {{gray}}%s@ %s{{/}}", event.NodeType.String(), event.Message, location, event.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT))) + case types.SpecEventNodeEnd: + r.emitBlock(r.fi(indent, "< Exit {{bold}}[%s]{{/}} %s {{gray}}%s@ %s (%s){{/}}", event.NodeType.String(), event.Message, location, event.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT), event.Duration.Round(time.Millisecond))) + case types.SpecEventSpecRepeat: + r.emitBlock(r.fi(indent, "\n{{bold}}Attempt #%d {{green}}Passed{{/}}{{bold}}. Repeating %s{{/}} {{gray}}@ %s{{/}}\n\n", event.Attempt, r.retryDenoter, event.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT))) + case types.SpecEventSpecRetry: + r.emitBlock(r.fi(indent, "\n{{bold}}Attempt #%d {{red}}Failed{{/}}{{bold}}. Retrying %s{{/}} {{gray}}@ %s{{/}}\n\n", event.Attempt, r.retryDenoter, event.TimelineLocation.Time.Format(types.GINKGO_TIME_FORMAT))) + } +} + +func (r *DefaultReporter) emitGoroutines(indent uint, goroutines ...types.Goroutine) { + for idx, g := range goroutines { + color := "{{gray}}" + if g.HasHighlights() { + color = "{{orange}}" + } + r.emit(r.fi(indent, color+"goroutine %d [%s]{{/}}\n", g.ID, g.State)) + for _, fc := range g.Stack { + if fc.Highlight { + r.emit(r.fi(indent, color+"{{bold}}> %s{{/}}\n", fc.Function)) + r.emit(r.fi(indent+2, color+"{{bold}}%s:%d{{/}}\n", fc.Filename, fc.Line)) + r.emitSource(indent+3, fc) + } else { + r.emit(r.fi(indent+1, "{{gray}}%s{{/}}\n", fc.Function)) + r.emit(r.fi(indent+2, "{{gray}}%s:%d{{/}}\n", fc.Filename, fc.Line)) + } + } + + if idx+1 < len(goroutines) { + r.emit("\n") + } + } +} + +func (r *DefaultReporter) emitSource(indent uint, fc types.FunctionCall) { + lines := fc.Source + if len(lines) == 0 { + return + } + + lTrim := 100000 + for _, line := range lines { + lTrimLine := len(line) - len(strings.TrimLeft(line, " \t")) + if lTrimLine < lTrim && len(line) > 0 { + lTrim = lTrimLine + } + } + if lTrim == 100000 { + lTrim = 0 + } + + for idx, line := range lines { + if len(line) > lTrim { + line = line[lTrim:] + } + if idx == fc.SourceHighlight { + r.emit(r.fi(indent, "{{bold}}{{orange}}> %s{{/}}\n", line)) + } else { + r.emit(r.fi(indent, "| %s\n", line)) + } + } +} + +/* Emitting to the writer */ +func (r *DefaultReporter) emit(s string) { + r._emit(s, false, false) +} + +func (r *DefaultReporter) emitBlock(s string) { + r._emit(s, true, false) +} + +func (r *DefaultReporter) emitDelimiter(indent uint) { + r._emit(r.fi(indent, "{{gray}}%s{{/}}", strings.Repeat("-", 30)), true, true) +} + +// a bit ugly - but we're trying to minimize locking on this hot codepath +func (r *DefaultReporter) _emit(s string, block bool, isDelimiter bool) { + if len(s) == 0 { + return + } + r.lock.Lock() + defer r.lock.Unlock() + if isDelimiter && r.lastEmissionWasDelimiter { + return + } + if block && !r.lastCharWasNewline { + r.writer.Write([]byte("\n")) + } + r.lastCharWasNewline = (s[len(s)-1:] == "\n") + r.writer.Write([]byte(s)) + if block && !r.lastCharWasNewline { + r.writer.Write([]byte("\n")) + r.lastCharWasNewline = true + } + r.lastEmissionWasDelimiter = isDelimiter +} + +/* Rendering text */ +func (r *DefaultReporter) f(format string, args ...interface{}) string { + return r.formatter.F(format, args...) +} + +func (r *DefaultReporter) fi(indentation uint, format string, args ...interface{}) string { + return r.formatter.Fi(indentation, format, args...) +} + +func (r *DefaultReporter) cycleJoin(elements []string, joiner string) string { + return r.formatter.CycleJoin(elements, joiner, []string{"{{/}}", "{{gray}}"}) +} + +func (r *DefaultReporter) codeLocationBlock(report types.SpecReport, highlightColor string, veryVerbose bool, usePreciseFailureLocation bool) string { + texts, locations, labels := []string{}, []types.CodeLocation{}, [][]string{} + texts, locations, labels = append(texts, report.ContainerHierarchyTexts...), append(locations, report.ContainerHierarchyLocations...), append(labels, report.ContainerHierarchyLabels...) + + if report.LeafNodeType.Is(types.NodeTypesForSuiteLevelNodes) { + texts = append(texts, r.f("[%s] %s", report.LeafNodeType, report.LeafNodeText)) + } else { + texts = append(texts, r.f(report.LeafNodeText)) + } + labels = append(labels, report.LeafNodeLabels) + locations = append(locations, report.LeafNodeLocation) + + failureLocation := report.Failure.FailureNodeLocation + if usePreciseFailureLocation { + failureLocation = report.Failure.Location + } + + highlightIndex := -1 + switch report.Failure.FailureNodeContext { + case types.FailureNodeAtTopLevel: + texts = append([]string{fmt.Sprintf("TOP-LEVEL [%s]", report.Failure.FailureNodeType)}, texts...) + locations = append([]types.CodeLocation{failureLocation}, locations...) + labels = append([][]string{{}}, labels...) + highlightIndex = 0 + case types.FailureNodeInContainer: + i := report.Failure.FailureNodeContainerIndex + texts[i] = fmt.Sprintf("%s [%s]", texts[i], report.Failure.FailureNodeType) + locations[i] = failureLocation + highlightIndex = i + case types.FailureNodeIsLeafNode: + i := len(texts) - 1 + texts[i] = fmt.Sprintf("[%s] %s", report.LeafNodeType, report.LeafNodeText) + locations[i] = failureLocation + highlightIndex = i + default: + //there is no failure, so we highlight the leaf ndoe + highlightIndex = len(texts) - 1 + } + + out := "" + if veryVerbose { + for i := range texts { + if i == highlightIndex { + out += r.fi(uint(i), highlightColor+"{{bold}}%s{{/}}", texts[i]) + } else { + out += r.fi(uint(i), "%s", texts[i]) + } + if len(labels[i]) > 0 { + out += r.f(" {{coral}}[%s]{{/}}", strings.Join(labels[i], ", ")) + } + out += "\n" + out += r.fi(uint(i), "{{gray}}%s{{/}}\n", locations[i]) + } + } else { + for i := range texts { + style := "{{/}}" + if i%2 == 1 { + style = "{{gray}}" + } + if i == highlightIndex { + style = highlightColor + "{{bold}}" + } + out += r.f(style+"%s", texts[i]) + if i < len(texts)-1 { + out += " " + } else { + out += r.f("{{/}}") + } + } + flattenedLabels := report.Labels() + if len(flattenedLabels) > 0 { + out += r.f(" {{coral}}[%s]{{/}}", strings.Join(flattenedLabels, ", ")) + } + out += "\n" + if usePreciseFailureLocation { + out += r.f("{{gray}}%s{{/}}", failureLocation) + } else { + leafLocation := locations[len(locations)-1] + if (report.Failure.FailureNodeLocation != types.CodeLocation{}) && (report.Failure.FailureNodeLocation != leafLocation) { + out += r.fi(1, highlightColor+"[%s]{{/}} {{gray}}%s{{/}}\n", report.Failure.FailureNodeType, report.Failure.FailureNodeLocation) + out += r.fi(1, "{{gray}}[%s] %s{{/}}", report.LeafNodeType, leafLocation) + } else { + out += r.f("{{gray}}%s{{/}}", leafLocation) + } + } + + } + return out +} diff --git a/vendor/github.com/onsi/ginkgo/v2/reporters/deprecated_reporter.go b/vendor/github.com/onsi/ginkgo/v2/reporters/deprecated_reporter.go new file mode 100644 index 000000000..613072ebf --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/reporters/deprecated_reporter.go @@ -0,0 +1,149 @@ +package reporters + +import ( + "github.com/onsi/ginkgo/v2/config" + "github.com/onsi/ginkgo/v2/types" +) + +// Deprecated: DeprecatedReporter was how Ginkgo V1 provided support for CustomReporters +// this has been removed in V2. +// Please read the documentation at: +// https://onsi.github.io/ginkgo/MIGRATING_TO_V2#removed-custom-reporters +// for Ginkgo's new behavior and for a migration path. +type DeprecatedReporter interface { + SuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) + BeforeSuiteDidRun(setupSummary *types.SetupSummary) + SpecWillRun(specSummary *types.SpecSummary) + SpecDidComplete(specSummary *types.SpecSummary) + AfterSuiteDidRun(setupSummary *types.SetupSummary) + SuiteDidEnd(summary *types.SuiteSummary) +} + +// ReportViaDeprecatedReporter takes a V1 custom reporter and a V2 report and +// calls the custom reporter's methods with appropriately transformed data from the V2 report. +// +// ReportViaDeprecatedReporter should be called in a `ReportAfterSuite()` +// +// Deprecated: ReportViaDeprecatedReporter method exists to help developer bridge between deprecated V1 functionality and the new +// reporting support in V2. It will be removed in a future minor version of Ginkgo. +func ReportViaDeprecatedReporter(reporter DeprecatedReporter, report types.Report) { + conf := config.DeprecatedGinkgoConfigType{ + RandomSeed: report.SuiteConfig.RandomSeed, + RandomizeAllSpecs: report.SuiteConfig.RandomizeAllSpecs, + FocusStrings: report.SuiteConfig.FocusStrings, + SkipStrings: report.SuiteConfig.SkipStrings, + FailOnPending: report.SuiteConfig.FailOnPending, + FailFast: report.SuiteConfig.FailFast, + FlakeAttempts: report.SuiteConfig.FlakeAttempts, + EmitSpecProgress: false, + DryRun: report.SuiteConfig.DryRun, + ParallelNode: report.SuiteConfig.ParallelProcess, + ParallelTotal: report.SuiteConfig.ParallelTotal, + SyncHost: report.SuiteConfig.ParallelHost, + StreamHost: report.SuiteConfig.ParallelHost, + } + + summary := &types.DeprecatedSuiteSummary{ + SuiteDescription: report.SuiteDescription, + SuiteID: report.SuitePath, + + NumberOfSpecsBeforeParallelization: report.PreRunStats.TotalSpecs, + NumberOfTotalSpecs: report.PreRunStats.TotalSpecs, + NumberOfSpecsThatWillBeRun: report.PreRunStats.SpecsThatWillRun, + } + + reporter.SuiteWillBegin(conf, summary) + + for _, spec := range report.SpecReports { + switch spec.LeafNodeType { + case types.NodeTypeBeforeSuite, types.NodeTypeSynchronizedBeforeSuite: + setupSummary := &types.DeprecatedSetupSummary{ + ComponentType: spec.LeafNodeType, + CodeLocation: spec.LeafNodeLocation, + State: spec.State, + RunTime: spec.RunTime, + Failure: failureFor(spec), + CapturedOutput: spec.CombinedOutput(), + SuiteID: report.SuitePath, + } + reporter.BeforeSuiteDidRun(setupSummary) + case types.NodeTypeAfterSuite, types.NodeTypeSynchronizedAfterSuite: + setupSummary := &types.DeprecatedSetupSummary{ + ComponentType: spec.LeafNodeType, + CodeLocation: spec.LeafNodeLocation, + State: spec.State, + RunTime: spec.RunTime, + Failure: failureFor(spec), + CapturedOutput: spec.CombinedOutput(), + SuiteID: report.SuitePath, + } + reporter.AfterSuiteDidRun(setupSummary) + case types.NodeTypeIt: + componentTexts, componentCodeLocations := []string{}, []types.CodeLocation{} + componentTexts = append(componentTexts, spec.ContainerHierarchyTexts...) + componentCodeLocations = append(componentCodeLocations, spec.ContainerHierarchyLocations...) + componentTexts = append(componentTexts, spec.LeafNodeText) + componentCodeLocations = append(componentCodeLocations, spec.LeafNodeLocation) + + specSummary := &types.DeprecatedSpecSummary{ + ComponentTexts: componentTexts, + ComponentCodeLocations: componentCodeLocations, + State: spec.State, + RunTime: spec.RunTime, + Failure: failureFor(spec), + NumberOfSamples: spec.NumAttempts, + CapturedOutput: spec.CombinedOutput(), + SuiteID: report.SuitePath, + } + reporter.SpecWillRun(specSummary) + reporter.SpecDidComplete(specSummary) + + switch spec.State { + case types.SpecStatePending: + summary.NumberOfPendingSpecs += 1 + case types.SpecStateSkipped: + summary.NumberOfSkippedSpecs += 1 + case types.SpecStateFailed, types.SpecStatePanicked, types.SpecStateInterrupted: + summary.NumberOfFailedSpecs += 1 + case types.SpecStatePassed: + summary.NumberOfPassedSpecs += 1 + if spec.NumAttempts > 1 { + summary.NumberOfFlakedSpecs += 1 + } + } + } + } + + summary.SuiteSucceeded = report.SuiteSucceeded + summary.RunTime = report.RunTime + + reporter.SuiteDidEnd(summary) +} + +func failureFor(spec types.SpecReport) types.DeprecatedSpecFailure { + if spec.Failure.IsZero() { + return types.DeprecatedSpecFailure{} + } + + index := 0 + switch spec.Failure.FailureNodeContext { + case types.FailureNodeInContainer: + index = spec.Failure.FailureNodeContainerIndex + case types.FailureNodeAtTopLevel: + index = -1 + case types.FailureNodeIsLeafNode: + index = len(spec.ContainerHierarchyTexts) - 1 + if spec.LeafNodeText != "" { + index += 1 + } + } + + return types.DeprecatedSpecFailure{ + Message: spec.Failure.Message, + Location: spec.Failure.Location, + ForwardedPanic: spec.Failure.ForwardedPanic, + ComponentIndex: index, + ComponentType: spec.Failure.FailureNodeType, + ComponentCodeLocation: spec.Failure.FailureNodeLocation, + } +} diff --git a/vendor/github.com/onsi/ginkgo/v2/reporters/json_report.go b/vendor/github.com/onsi/ginkgo/v2/reporters/json_report.go new file mode 100644 index 000000000..7f96c450f --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/reporters/json_report.go @@ -0,0 +1,60 @@ +package reporters + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/onsi/ginkgo/v2/types" +) + +//GenerateJSONReport produces a JSON-formatted report at the passed in destination +func GenerateJSONReport(report types.Report, destination string) error { + f, err := os.Create(destination) + if err != nil { + return err + } + enc := json.NewEncoder(f) + enc.SetIndent("", " ") + err = enc.Encode([]types.Report{ + report, + }) + if err != nil { + return err + } + return f.Close() +} + +//MergeJSONReports produces a single JSON-formatted report at the passed in destination by merging the JSON-formatted reports provided in sources +//It skips over reports that fail to decode but reports on them via the returned messages []string +func MergeAndCleanupJSONReports(sources []string, destination string) ([]string, error) { + messages := []string{} + allReports := []types.Report{} + for _, source := range sources { + reports := []types.Report{} + data, err := os.ReadFile(source) + if err != nil { + messages = append(messages, fmt.Sprintf("Could not open %s:\n%s", source, err.Error())) + continue + } + err = json.Unmarshal(data, &reports) + if err != nil { + messages = append(messages, fmt.Sprintf("Could not decode %s:\n%s", source, err.Error())) + continue + } + os.Remove(source) + allReports = append(allReports, reports...) + } + + f, err := os.Create(destination) + if err != nil { + return messages, err + } + enc := json.NewEncoder(f) + enc.SetIndent("", " ") + err = enc.Encode(allReports) + if err != nil { + return messages, err + } + return messages, f.Close() +} diff --git a/vendor/github.com/onsi/ginkgo/v2/reporters/junit_report.go b/vendor/github.com/onsi/ginkgo/v2/reporters/junit_report.go new file mode 100644 index 000000000..592d7f614 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/reporters/junit_report.go @@ -0,0 +1,369 @@ +/* + +JUnit XML Reporter for Ginkgo + +For usage instructions: http://onsi.github.io/ginkgo/#generating_junit_xml_output + +The schema used for the generated JUnit xml file was adapted from https://llg.cubic.org/docs/junit/ + +*/ + +package reporters + +import ( + "encoding/xml" + "fmt" + "os" + "strings" + + "github.com/onsi/ginkgo/v2/config" + "github.com/onsi/ginkgo/v2/types" +) + +type JunitReportConfig struct { + // Spec States for which no timeline should be emitted for system-err + // set this to types.SpecStatePassed|types.SpecStateSkipped|types.SpecStatePending to only match failing specs + OmitTimelinesForSpecState types.SpecState + + // Enable OmitFailureMessageAttr to prevent failure messages appearing in the "message" attribute of the Failure and Error tags + OmitFailureMessageAttr bool + + //Enable OmitCapturedStdOutErr to prevent captured stdout/stderr appearing in system-out + OmitCapturedStdOutErr bool + + // Enable OmitSpecLabels to prevent labels from appearing in the spec name + OmitSpecLabels bool + + // Enable OmitLeafNodeType to prevent the spec leaf node type from appearing in the spec name + OmitLeafNodeType bool + + // Enable OmitSuiteSetupNodes to prevent the creation of testcase entries for setup nodes + OmitSuiteSetupNodes bool +} + +type JUnitTestSuites struct { + XMLName xml.Name `xml:"testsuites"` + // Tests maps onto the total number of specs in all test suites (this includes any suite nodes such as BeforeSuite) + Tests int `xml:"tests,attr"` + // Disabled maps onto specs that are pending and/or skipped + Disabled int `xml:"disabled,attr"` + // Errors maps onto specs that panicked or were interrupted + Errors int `xml:"errors,attr"` + // Failures maps onto specs that failed + Failures int `xml:"failures,attr"` + // Time is the time in seconds to execute all test suites + Time float64 `xml:"time,attr"` + + //The set of all test suites + TestSuites []JUnitTestSuite `xml:"testsuite"` +} + +type JUnitTestSuite struct { + // Name maps onto the description of the test suite - maps onto Report.SuiteDescription + Name string `xml:"name,attr"` + // Package maps onto the absolute path to the test suite - maps onto Report.SuitePath + Package string `xml:"package,attr"` + // Tests maps onto the total number of specs in the test suite (this includes any suite nodes such as BeforeSuite) + Tests int `xml:"tests,attr"` + // Disabled maps onto specs that are pending + Disabled int `xml:"disabled,attr"` + // Skiped maps onto specs that are skipped + Skipped int `xml:"skipped,attr"` + // Errors maps onto specs that panicked or were interrupted + Errors int `xml:"errors,attr"` + // Failures maps onto specs that failed + Failures int `xml:"failures,attr"` + // Time is the time in seconds to execute all the test suite - maps onto Report.RunTime + Time float64 `xml:"time,attr"` + // Timestamp is the ISO 8601 formatted start-time of the suite - maps onto Report.StartTime + Timestamp string `xml:"timestamp,attr"` + + //Properties captures the information stored in the rest of the Report type (including SuiteConfig) as key-value pairs + Properties JUnitProperties `xml:"properties"` + + //TestCases capture the individual specs + TestCases []JUnitTestCase `xml:"testcase"` +} + +type JUnitProperties struct { + Properties []JUnitProperty `xml:"property"` +} + +func (jup JUnitProperties) WithName(name string) string { + for _, property := range jup.Properties { + if property.Name == name { + return property.Value + } + } + return "" +} + +type JUnitProperty struct { + Name string `xml:"name,attr"` + Value string `xml:"value,attr"` +} + +type JUnitTestCase struct { + // Name maps onto the full text of the spec - equivalent to "[SpecReport.LeafNodeType] SpecReport.FullText()" + Name string `xml:"name,attr"` + // Classname maps onto the name of the test suite - equivalent to Report.SuiteDescription + Classname string `xml:"classname,attr"` + // Status maps onto the string representation of SpecReport.State + Status string `xml:"status,attr"` + // Time is the time in seconds to execute the spec - maps onto SpecReport.RunTime + Time float64 `xml:"time,attr"` + //Skipped is populated with a message if the test was skipped or pending + Skipped *JUnitSkipped `xml:"skipped,omitempty"` + //Error is populated if the test panicked or was interrupted + Error *JUnitError `xml:"error,omitempty"` + //Failure is populated if the test failed + Failure *JUnitFailure `xml:"failure,omitempty"` + //SystemOut maps onto any captured stdout/stderr output - maps onto SpecReport.CapturedStdOutErr + SystemOut string `xml:"system-out,omitempty"` + //SystemOut maps onto any captured GinkgoWriter output - maps onto SpecReport.CapturedGinkgoWriterOutput + SystemErr string `xml:"system-err,omitempty"` +} + +type JUnitSkipped struct { + // Message maps onto "pending" if the test was marked pending, "skipped" if the test was marked skipped, and "skipped - REASON" if the user called Skip(REASON) + Message string `xml:"message,attr"` +} + +type JUnitError struct { + //Message maps onto the panic/exception thrown - equivalent to SpecReport.Failure.ForwardedPanic - or to "interrupted" + Message string `xml:"message,attr"` + //Type is one of "panicked" or "interrupted" + Type string `xml:"type,attr"` + //Description maps onto the captured stack trace for a panic, or the failure message for an interrupt which will include the dump of running goroutines + Description string `xml:",chardata"` +} + +type JUnitFailure struct { + //Message maps onto the failure message - equivalent to SpecReport.Failure.Message + Message string `xml:"message,attr"` + //Type is "failed" + Type string `xml:"type,attr"` + //Description maps onto the location and stack trace of the failure + Description string `xml:",chardata"` +} + +func GenerateJUnitReport(report types.Report, dst string) error { + return GenerateJUnitReportWithConfig(report, dst, JunitReportConfig{}) +} + +func GenerateJUnitReportWithConfig(report types.Report, dst string, config JunitReportConfig) error { + suite := JUnitTestSuite{ + Name: report.SuiteDescription, + Package: report.SuitePath, + Time: report.RunTime.Seconds(), + Timestamp: report.StartTime.Format("2006-01-02T15:04:05"), + Properties: JUnitProperties{ + Properties: []JUnitProperty{ + {"SuiteSucceeded", fmt.Sprintf("%t", report.SuiteSucceeded)}, + {"SuiteHasProgrammaticFocus", fmt.Sprintf("%t", report.SuiteHasProgrammaticFocus)}, + {"SpecialSuiteFailureReason", strings.Join(report.SpecialSuiteFailureReasons, ",")}, + {"SuiteLabels", fmt.Sprintf("[%s]", strings.Join(report.SuiteLabels, ","))}, + {"RandomSeed", fmt.Sprintf("%d", report.SuiteConfig.RandomSeed)}, + {"RandomizeAllSpecs", fmt.Sprintf("%t", report.SuiteConfig.RandomizeAllSpecs)}, + {"LabelFilter", report.SuiteConfig.LabelFilter}, + {"FocusStrings", strings.Join(report.SuiteConfig.FocusStrings, ",")}, + {"SkipStrings", strings.Join(report.SuiteConfig.SkipStrings, ",")}, + {"FocusFiles", strings.Join(report.SuiteConfig.FocusFiles, ";")}, + {"SkipFiles", strings.Join(report.SuiteConfig.SkipFiles, ";")}, + {"FailOnPending", fmt.Sprintf("%t", report.SuiteConfig.FailOnPending)}, + {"FailFast", fmt.Sprintf("%t", report.SuiteConfig.FailFast)}, + {"FlakeAttempts", fmt.Sprintf("%d", report.SuiteConfig.FlakeAttempts)}, + {"DryRun", fmt.Sprintf("%t", report.SuiteConfig.DryRun)}, + {"ParallelTotal", fmt.Sprintf("%d", report.SuiteConfig.ParallelTotal)}, + {"OutputInterceptorMode", report.SuiteConfig.OutputInterceptorMode}, + }, + }, + } + for _, spec := range report.SpecReports { + if config.OmitSuiteSetupNodes && spec.LeafNodeType != types.NodeTypeIt { + continue + } + name := fmt.Sprintf("[%s]", spec.LeafNodeType) + if config.OmitLeafNodeType { + name = "" + } + if spec.FullText() != "" { + name = name + " " + spec.FullText() + } + labels := spec.Labels() + if len(labels) > 0 && !config.OmitSpecLabels { + name = name + " [" + strings.Join(labels, ", ") + "]" + } + name = strings.TrimSpace(name) + + test := JUnitTestCase{ + Name: name, + Classname: report.SuiteDescription, + Status: spec.State.String(), + Time: spec.RunTime.Seconds(), + } + if !spec.State.Is(config.OmitTimelinesForSpecState) { + test.SystemErr = systemErrForUnstructuredReporters(spec) + } + if !config.OmitCapturedStdOutErr { + test.SystemOut = systemOutForUnstructuredReporters(spec) + } + suite.Tests += 1 + + switch spec.State { + case types.SpecStateSkipped: + message := "skipped" + if spec.Failure.Message != "" { + message += " - " + spec.Failure.Message + } + test.Skipped = &JUnitSkipped{Message: message} + suite.Skipped += 1 + case types.SpecStatePending: + test.Skipped = &JUnitSkipped{Message: "pending"} + suite.Disabled += 1 + case types.SpecStateFailed: + test.Failure = &JUnitFailure{ + Message: spec.Failure.Message, + Type: "failed", + Description: failureDescriptionForUnstructuredReporters(spec), + } + if config.OmitFailureMessageAttr { + test.Failure.Message = "" + } + suite.Failures += 1 + case types.SpecStateTimedout: + test.Failure = &JUnitFailure{ + Message: spec.Failure.Message, + Type: "timedout", + Description: failureDescriptionForUnstructuredReporters(spec), + } + if config.OmitFailureMessageAttr { + test.Failure.Message = "" + } + suite.Failures += 1 + case types.SpecStateInterrupted: + test.Error = &JUnitError{ + Message: spec.Failure.Message, + Type: "interrupted", + Description: failureDescriptionForUnstructuredReporters(spec), + } + if config.OmitFailureMessageAttr { + test.Error.Message = "" + } + suite.Errors += 1 + case types.SpecStateAborted: + test.Failure = &JUnitFailure{ + Message: spec.Failure.Message, + Type: "aborted", + Description: failureDescriptionForUnstructuredReporters(spec), + } + if config.OmitFailureMessageAttr { + test.Failure.Message = "" + } + suite.Errors += 1 + case types.SpecStatePanicked: + test.Error = &JUnitError{ + Message: spec.Failure.ForwardedPanic, + Type: "panicked", + Description: failureDescriptionForUnstructuredReporters(spec), + } + if config.OmitFailureMessageAttr { + test.Error.Message = "" + } + suite.Errors += 1 + } + + suite.TestCases = append(suite.TestCases, test) + } + + junitReport := JUnitTestSuites{ + Tests: suite.Tests, + Disabled: suite.Disabled + suite.Skipped, + Errors: suite.Errors, + Failures: suite.Failures, + Time: suite.Time, + TestSuites: []JUnitTestSuite{suite}, + } + + f, err := os.Create(dst) + if err != nil { + return err + } + f.WriteString(xml.Header) + encoder := xml.NewEncoder(f) + encoder.Indent(" ", " ") + encoder.Encode(junitReport) + + return f.Close() +} + +func MergeAndCleanupJUnitReports(sources []string, dst string) ([]string, error) { + messages := []string{} + mergedReport := JUnitTestSuites{} + for _, source := range sources { + report := JUnitTestSuites{} + f, err := os.Open(source) + if err != nil { + messages = append(messages, fmt.Sprintf("Could not open %s:\n%s", source, err.Error())) + continue + } + err = xml.NewDecoder(f).Decode(&report) + if err != nil { + messages = append(messages, fmt.Sprintf("Could not decode %s:\n%s", source, err.Error())) + continue + } + os.Remove(source) + + mergedReport.Tests += report.Tests + mergedReport.Disabled += report.Disabled + mergedReport.Errors += report.Errors + mergedReport.Failures += report.Failures + mergedReport.Time += report.Time + mergedReport.TestSuites = append(mergedReport.TestSuites, report.TestSuites...) + } + + f, err := os.Create(dst) + if err != nil { + return messages, err + } + f.WriteString(xml.Header) + encoder := xml.NewEncoder(f) + encoder.Indent(" ", " ") + encoder.Encode(mergedReport) + + return messages, f.Close() +} + +func failureDescriptionForUnstructuredReporters(spec types.SpecReport) string { + out := &strings.Builder{} + NewDefaultReporter(types.ReporterConfig{NoColor: true, VeryVerbose: true}, out).emitFailure(0, spec.State, spec.Failure, true) + if len(spec.AdditionalFailures) > 0 { + out.WriteString("\nThere were additional failures detected after the initial failure. These are visible in the timeline\n") + } + return out.String() +} + +func systemErrForUnstructuredReporters(spec types.SpecReport) string { + return RenderTimeline(spec, true) +} + +func RenderTimeline(spec types.SpecReport, noColor bool) string { + out := &strings.Builder{} + NewDefaultReporter(types.ReporterConfig{NoColor: noColor, VeryVerbose: true}, out).emitTimeline(0, spec, spec.Timeline()) + return out.String() +} + +func systemOutForUnstructuredReporters(spec types.SpecReport) string { + return spec.CapturedStdOutErr +} + +// Deprecated JUnitReporter (so folks can still compile their suites) +type JUnitReporter struct{} + +func NewJUnitReporter(_ string) *JUnitReporter { return &JUnitReporter{} } +func (reporter *JUnitReporter) SuiteWillBegin(_ config.GinkgoConfigType, _ *types.SuiteSummary) {} +func (reporter *JUnitReporter) BeforeSuiteDidRun(_ *types.SetupSummary) {} +func (reporter *JUnitReporter) SpecWillRun(_ *types.SpecSummary) {} +func (reporter *JUnitReporter) SpecDidComplete(_ *types.SpecSummary) {} +func (reporter *JUnitReporter) AfterSuiteDidRun(_ *types.SetupSummary) {} +func (reporter *JUnitReporter) SuiteDidEnd(_ *types.SuiteSummary) {} diff --git a/vendor/github.com/onsi/ginkgo/v2/reporters/reporter.go b/vendor/github.com/onsi/ginkgo/v2/reporters/reporter.go new file mode 100644 index 000000000..5e726c464 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/reporters/reporter.go @@ -0,0 +1,29 @@ +package reporters + +import ( + "github.com/onsi/ginkgo/v2/types" +) + +type Reporter interface { + SuiteWillBegin(report types.Report) + WillRun(report types.SpecReport) + DidRun(report types.SpecReport) + SuiteDidEnd(report types.Report) + + //Timeline emission + EmitFailure(state types.SpecState, failure types.Failure) + EmitProgressReport(progressReport types.ProgressReport) + EmitReportEntry(entry types.ReportEntry) + EmitSpecEvent(event types.SpecEvent) +} + +type NoopReporter struct{} + +func (n NoopReporter) SuiteWillBegin(report types.Report) {} +func (n NoopReporter) WillRun(report types.SpecReport) {} +func (n NoopReporter) DidRun(report types.SpecReport) {} +func (n NoopReporter) SuiteDidEnd(report types.Report) {} +func (n NoopReporter) EmitFailure(state types.SpecState, failure types.Failure) {} +func (n NoopReporter) EmitProgressReport(progressReport types.ProgressReport) {} +func (n NoopReporter) EmitReportEntry(entry types.ReportEntry) {} +func (n NoopReporter) EmitSpecEvent(event types.SpecEvent) {} diff --git a/vendor/github.com/onsi/ginkgo/v2/reporters/teamcity_report.go b/vendor/github.com/onsi/ginkgo/v2/reporters/teamcity_report.go new file mode 100644 index 000000000..c1863496d --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/reporters/teamcity_report.go @@ -0,0 +1,101 @@ +/* + +TeamCity Reporter for Ginkgo + +Makes use of TeamCity's support for Service Messages +http://confluence.jetbrains.com/display/TCD7/Build+Script+Interaction+with+TeamCity#BuildScriptInteractionwithTeamCity-ReportingTests +*/ + +package reporters + +import ( + "fmt" + "os" + "strings" + + "github.com/onsi/ginkgo/v2/types" +) + +func tcEscape(s string) string { + s = strings.ReplaceAll(s, "|", "||") + s = strings.ReplaceAll(s, "'", "|'") + s = strings.ReplaceAll(s, "\n", "|n") + s = strings.ReplaceAll(s, "\r", "|r") + s = strings.ReplaceAll(s, "[", "|[") + s = strings.ReplaceAll(s, "]", "|]") + return s +} + +func GenerateTeamcityReport(report types.Report, dst string) error { + f, err := os.Create(dst) + if err != nil { + return err + } + + name := report.SuiteDescription + labels := report.SuiteLabels + if len(labels) > 0 { + name = name + " [" + strings.Join(labels, ", ") + "]" + } + fmt.Fprintf(f, "##teamcity[testSuiteStarted name='%s']\n", tcEscape(name)) + for _, spec := range report.SpecReports { + name := fmt.Sprintf("[%s]", spec.LeafNodeType) + if spec.FullText() != "" { + name = name + " " + spec.FullText() + } + labels := spec.Labels() + if len(labels) > 0 { + name = name + " [" + strings.Join(labels, ", ") + "]" + } + + name = tcEscape(name) + fmt.Fprintf(f, "##teamcity[testStarted name='%s']\n", name) + switch spec.State { + case types.SpecStatePending: + fmt.Fprintf(f, "##teamcity[testIgnored name='%s' message='pending']\n", name) + case types.SpecStateSkipped: + message := "skipped" + if spec.Failure.Message != "" { + message += " - " + spec.Failure.Message + } + fmt.Fprintf(f, "##teamcity[testIgnored name='%s' message='%s']\n", name, tcEscape(message)) + case types.SpecStateFailed: + details := failureDescriptionForUnstructuredReporters(spec) + fmt.Fprintf(f, "##teamcity[testFailed name='%s' message='failed - %s' details='%s']\n", name, tcEscape(spec.Failure.Message), tcEscape(details)) + case types.SpecStatePanicked: + details := failureDescriptionForUnstructuredReporters(spec) + fmt.Fprintf(f, "##teamcity[testFailed name='%s' message='panicked - %s' details='%s']\n", name, tcEscape(spec.Failure.ForwardedPanic), tcEscape(details)) + case types.SpecStateTimedout: + details := failureDescriptionForUnstructuredReporters(spec) + fmt.Fprintf(f, "##teamcity[testFailed name='%s' message='timedout - %s' details='%s']\n", name, tcEscape(spec.Failure.Message), tcEscape(details)) + case types.SpecStateInterrupted: + details := failureDescriptionForUnstructuredReporters(spec) + fmt.Fprintf(f, "##teamcity[testFailed name='%s' message='interrupted - %s' details='%s']\n", name, tcEscape(spec.Failure.Message), tcEscape(details)) + case types.SpecStateAborted: + details := failureDescriptionForUnstructuredReporters(spec) + fmt.Fprintf(f, "##teamcity[testFailed name='%s' message='aborted - %s' details='%s']\n", name, tcEscape(spec.Failure.Message), tcEscape(details)) + } + + fmt.Fprintf(f, "##teamcity[testStdOut name='%s' out='%s']\n", name, tcEscape(systemOutForUnstructuredReporters(spec))) + fmt.Fprintf(f, "##teamcity[testStdErr name='%s' out='%s']\n", name, tcEscape(systemErrForUnstructuredReporters(spec))) + fmt.Fprintf(f, "##teamcity[testFinished name='%s' duration='%d']\n", name, int(spec.RunTime.Seconds()*1000.0)) + } + fmt.Fprintf(f, "##teamcity[testSuiteFinished name='%s']\n", tcEscape(report.SuiteDescription)) + + return f.Close() +} + +func MergeAndCleanupTeamcityReports(sources []string, dst string) ([]string, error) { + messages := []string{} + merged := []byte{} + for _, source := range sources { + data, err := os.ReadFile(source) + if err != nil { + messages = append(messages, fmt.Sprintf("Could not open %s:\n%s", source, err.Error())) + continue + } + os.Remove(source) + merged = append(merged, data...) + } + return messages, os.WriteFile(dst, merged, 0666) +} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/code_location.go b/vendor/github.com/onsi/ginkgo/v2/types/code_location.go new file mode 100644 index 000000000..9cd576817 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/types/code_location.go @@ -0,0 +1,159 @@ +package types + +import ( + "fmt" + "os" + "regexp" + "runtime" + "runtime/debug" + "strings" + "sync" +) + +type CodeLocation struct { + FileName string `json:",omitempty"` + LineNumber int `json:",omitempty"` + FullStackTrace string `json:",omitempty"` + CustomMessage string `json:",omitempty"` +} + +func (codeLocation CodeLocation) String() string { + if codeLocation.CustomMessage != "" { + return codeLocation.CustomMessage + } + return fmt.Sprintf("%s:%d", codeLocation.FileName, codeLocation.LineNumber) +} + +func (codeLocation CodeLocation) ContentsOfLine() string { + if codeLocation.CustomMessage != "" { + return "" + } + contents, err := os.ReadFile(codeLocation.FileName) + if err != nil { + return "" + } + lines := strings.Split(string(contents), "\n") + if len(lines) < codeLocation.LineNumber { + return "" + } + return lines[codeLocation.LineNumber-1] +} + +type codeLocationLocator struct { + pcs map[uintptr]bool + helpers map[string]bool + lock *sync.Mutex +} + +func (c *codeLocationLocator) addHelper(pc uintptr) { + c.lock.Lock() + defer c.lock.Unlock() + + if c.pcs[pc] { + return + } + c.lock.Unlock() + f := runtime.FuncForPC(pc) + c.lock.Lock() + if f == nil { + return + } + c.helpers[f.Name()] = true + c.pcs[pc] = true +} + +func (c *codeLocationLocator) hasHelper(name string) bool { + c.lock.Lock() + defer c.lock.Unlock() + return c.helpers[name] +} + +func (c *codeLocationLocator) getCodeLocation(skip int) CodeLocation { + pc := make([]uintptr, 40) + n := runtime.Callers(skip+2, pc) + if n == 0 { + return CodeLocation{} + } + pc = pc[:n] + frames := runtime.CallersFrames(pc) + for { + frame, more := frames.Next() + if !c.hasHelper(frame.Function) { + return CodeLocation{FileName: frame.File, LineNumber: frame.Line} + } + if !more { + break + } + } + return CodeLocation{} +} + +var clLocator = &codeLocationLocator{ + pcs: map[uintptr]bool{}, + helpers: map[string]bool{}, + lock: &sync.Mutex{}, +} + +// MarkAsHelper is used by GinkgoHelper to mark the caller (appropriately offset by skip)as a helper. You can use this directly if you need to provide an optional `skip` to mark functions further up the call stack as helpers. +func MarkAsHelper(optionalSkip ...int) { + skip := 1 + if len(optionalSkip) > 0 { + skip += optionalSkip[0] + } + pc, _, _, ok := runtime.Caller(skip) + if ok { + clLocator.addHelper(pc) + } +} + +func NewCustomCodeLocation(message string) CodeLocation { + return CodeLocation{ + CustomMessage: message, + } +} + +func NewCodeLocation(skip int) CodeLocation { + return clLocator.getCodeLocation(skip + 1) +} + +func NewCodeLocationWithStackTrace(skip int) CodeLocation { + cl := clLocator.getCodeLocation(skip + 1) + cl.FullStackTrace = PruneStack(string(debug.Stack()), skip+1) + return cl +} + +// PruneStack removes references to functions that are internal to Ginkgo +// and the Go runtime from a stack string and a certain number of stack entries +// at the beginning of the stack. The stack string has the format +// as returned by runtime/debug.Stack. The leading goroutine information is +// optional and always removed if present. Beware that runtime/debug.Stack +// adds itself as first entry, so typically skip must be >= 1 to remove that +// entry. +func PruneStack(fullStackTrace string, skip int) string { + stack := strings.Split(fullStackTrace, "\n") + // Ensure that the even entries are the method names and the + // odd entries the source code information. + if len(stack) > 0 && strings.HasPrefix(stack[0], "goroutine ") { + // Ignore "goroutine 29 [running]:" line. + stack = stack[1:] + } + // The "+1" is for skipping over the initial entry, which is + // runtime/debug.Stack() itself. + if len(stack) > 2*(skip+1) { + stack = stack[2*(skip+1):] + } + prunedStack := []string{} + if os.Getenv("GINKGO_PRUNE_STACK") == "FALSE" { + prunedStack = stack + } else { + re := regexp.MustCompile(`\/ginkgo\/|\/pkg\/testing\/|\/pkg\/runtime\/`) + for i := 0; i < len(stack)/2; i++ { + // We filter out based on the source code file name. + if !re.Match([]byte(stack[i*2+1])) { + prunedStack = append(prunedStack, stack[i*2]) + prunedStack = append(prunedStack, stack[i*2+1]) + } + } + } + return strings.Join(prunedStack, "\n") +} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/config.go b/vendor/github.com/onsi/ginkgo/v2/types/config.go new file mode 100644 index 000000000..1014c7b49 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/types/config.go @@ -0,0 +1,757 @@ +/* +Ginkgo accepts a number of configuration options. +These are documented [here](http://onsi.github.io/ginkgo/#the-ginkgo-cli) +*/ + +package types + +import ( + "flag" + "os" + "path/filepath" + "runtime" + "strconv" + "strings" + "time" +) + +// Configuration controlling how an individual test suite is run +type SuiteConfig struct { + RandomSeed int64 + RandomizeAllSpecs bool + FocusStrings []string + SkipStrings []string + FocusFiles []string + SkipFiles []string + LabelFilter string + FailOnPending bool + FailFast bool + FlakeAttempts int + DryRun bool + PollProgressAfter time.Duration + PollProgressInterval time.Duration + Timeout time.Duration + EmitSpecProgress bool // this is deprecated but its removal is causing compile issue for some users that were setting it manually + OutputInterceptorMode string + SourceRoots []string + GracePeriod time.Duration + + ParallelProcess int + ParallelTotal int + ParallelHost string +} + +func NewDefaultSuiteConfig() SuiteConfig { + return SuiteConfig{ + RandomSeed: time.Now().Unix(), + Timeout: time.Hour, + ParallelProcess: 1, + ParallelTotal: 1, + GracePeriod: 30 * time.Second, + } +} + +type VerbosityLevel uint + +const ( + VerbosityLevelSuccinct VerbosityLevel = iota + VerbosityLevelNormal + VerbosityLevelVerbose + VerbosityLevelVeryVerbose +) + +func (vl VerbosityLevel) GT(comp VerbosityLevel) bool { + return vl > comp +} + +func (vl VerbosityLevel) GTE(comp VerbosityLevel) bool { + return vl >= comp +} + +func (vl VerbosityLevel) Is(comp VerbosityLevel) bool { + return vl == comp +} + +func (vl VerbosityLevel) LTE(comp VerbosityLevel) bool { + return vl <= comp +} + +func (vl VerbosityLevel) LT(comp VerbosityLevel) bool { + return vl < comp +} + +// Configuration for Ginkgo's reporter +type ReporterConfig struct { + NoColor bool + Succinct bool + Verbose bool + VeryVerbose bool + FullTrace bool + ShowNodeEvents bool + + JSONReport string + JUnitReport string + TeamcityReport string +} + +func (rc ReporterConfig) Verbosity() VerbosityLevel { + if rc.Succinct { + return VerbosityLevelSuccinct + } else if rc.Verbose { + return VerbosityLevelVerbose + } else if rc.VeryVerbose { + return VerbosityLevelVeryVerbose + } + return VerbosityLevelNormal +} + +func (rc ReporterConfig) WillGenerateReport() bool { + return rc.JSONReport != "" || rc.JUnitReport != "" || rc.TeamcityReport != "" +} + +func NewDefaultReporterConfig() ReporterConfig { + return ReporterConfig{} +} + +// Configuration for the Ginkgo CLI +type CLIConfig struct { + //for build, run, and watch + Recurse bool + SkipPackage string + RequireSuite bool + NumCompilers int + + //for run and watch only + Procs int + Parallel bool + AfterRunHook string + OutputDir string + KeepSeparateCoverprofiles bool + KeepSeparateReports bool + + //for run only + KeepGoing bool + UntilItFails bool + Repeat int + RandomizeSuites bool + + //for watch only + Depth int + WatchRegExp string +} + +func NewDefaultCLIConfig() CLIConfig { + return CLIConfig{ + Depth: 1, + WatchRegExp: `\.go$`, + } +} + +func (g CLIConfig) ComputedProcs() int { + if g.Procs > 0 { + return g.Procs + } + + n := 1 + if g.Parallel { + n = runtime.NumCPU() + if n > 4 { + n = n - 1 + } + } + return n +} + +func (g CLIConfig) ComputedNumCompilers() int { + if g.NumCompilers > 0 { + return g.NumCompilers + } + + return runtime.NumCPU() +} + +// Configuration for the Ginkgo CLI capturing available go flags +// A subset of Go flags are exposed by Ginkgo. Some are available at compile time (e.g. ginkgo build) and others only at run time (e.g. ginkgo run - which has both build and run time flags). +// More details can be found at: +// https://docs.google.com/spreadsheets/d/1zkp-DS4hU4sAJl5eHh1UmgwxCPQhf3s5a8fbiOI8tJU/ +type GoFlagsConfig struct { + //build-time flags for code-and-performance analysis + Race bool + Cover bool + CoverMode string + CoverPkg string + Vet string + + //run-time flags for code-and-performance analysis + BlockProfile string + BlockProfileRate int + CoverProfile string + CPUProfile string + MemProfile string + MemProfileRate int + MutexProfile string + MutexProfileFraction int + Trace string + + //build-time flags for building + A bool + ASMFlags string + BuildMode string + Compiler string + GCCGoFlags string + GCFlags string + InstallSuffix string + LDFlags string + LinkShared bool + Mod string + N bool + ModFile string + ModCacheRW bool + MSan bool + PkgDir string + Tags string + TrimPath bool + ToolExec string + Work bool + X bool +} + +func NewDefaultGoFlagsConfig() GoFlagsConfig { + return GoFlagsConfig{} +} + +func (g GoFlagsConfig) BinaryMustBePreserved() bool { + return g.BlockProfile != "" || g.CPUProfile != "" || g.MemProfile != "" || g.MutexProfile != "" +} + +// Configuration that were deprecated in 2.0 +type deprecatedConfig struct { + DebugParallel bool + NoisySkippings bool + NoisyPendings bool + RegexScansFilePath bool + SlowSpecThresholdWithFLoatUnits float64 + Stream bool + Notify bool + EmitSpecProgress bool + SlowSpecThreshold time.Duration + AlwaysEmitGinkgoWriter bool +} + +// Flags + +// Flags sections used by both the CLI and the Ginkgo test process +var FlagSections = GinkgoFlagSections{ + {Key: "multiple-suites", Style: "{{dark-green}}", Heading: "Running Multiple Test Suites"}, + {Key: "order", Style: "{{green}}", Heading: "Controlling Test Order"}, + {Key: "parallel", Style: "{{yellow}}", Heading: "Controlling Test Parallelism"}, + {Key: "low-level-parallel", Style: "{{yellow}}", Heading: "Controlling Test Parallelism", + Description: "These are set by the Ginkgo CLI, {{red}}{{bold}}do not set them manually{{/}} via go test.\nUse ginkgo -p or ginkgo -procs=N instead."}, + {Key: "filter", Style: "{{cyan}}", Heading: "Filtering Tests"}, + {Key: "failure", Style: "{{red}}", Heading: "Failure Handling"}, + {Key: "output", Style: "{{magenta}}", Heading: "Controlling Output Formatting"}, + {Key: "code-and-coverage-analysis", Style: "{{orange}}", Heading: "Code and Coverage Analysis"}, + {Key: "performance-analysis", Style: "{{coral}}", Heading: "Performance Analysis"}, + {Key: "debug", Style: "{{blue}}", Heading: "Debugging Tests", + Description: "In addition to these flags, Ginkgo supports a few debugging environment variables. To change the parallel server protocol set {{blue}}GINKGO_PARALLEL_PROTOCOL{{/}} to {{bold}}HTTP{{/}}. To avoid pruning callstacks set {{blue}}GINKGO_PRUNE_STACK{{/}} to {{bold}}FALSE{{/}}."}, + {Key: "watch", Style: "{{light-yellow}}", Heading: "Controlling Ginkgo Watch"}, + {Key: "misc", Style: "{{light-gray}}", Heading: "Miscellaneous"}, + {Key: "go-build", Style: "{{light-gray}}", Heading: "Go Build Flags", Succinct: true, + Description: "These flags are inherited from go build. Run {{bold}}ginkgo help build{{/}} for more detailed flag documentation."}, +} + +// SuiteConfigFlags provides flags for the Ginkgo test process, and CLI +var SuiteConfigFlags = GinkgoFlags{ + {KeyPath: "S.RandomSeed", Name: "seed", SectionKey: "order", UsageDefaultValue: "randomly generated by Ginkgo", + Usage: "The seed used to randomize the spec suite."}, + {KeyPath: "S.RandomizeAllSpecs", Name: "randomize-all", SectionKey: "order", DeprecatedName: "randomizeAllSpecs", DeprecatedDocLink: "changed-command-line-flags", + Usage: "If set, ginkgo will randomize all specs together. By default, ginkgo only randomizes the top level Describe, Context and When containers."}, + + {KeyPath: "S.FailOnPending", Name: "fail-on-pending", SectionKey: "failure", DeprecatedName: "failOnPending", DeprecatedDocLink: "changed-command-line-flags", + Usage: "If set, ginkgo will mark the test suite as failed if any specs are pending."}, + {KeyPath: "S.FailFast", Name: "fail-fast", SectionKey: "failure", DeprecatedName: "failFast", DeprecatedDocLink: "changed-command-line-flags", + Usage: "If set, ginkgo will stop running a test suite after a failure occurs."}, + {KeyPath: "S.FlakeAttempts", Name: "flake-attempts", SectionKey: "failure", UsageDefaultValue: "0 - failed tests are not retried", DeprecatedName: "flakeAttempts", DeprecatedDocLink: "changed-command-line-flags", + Usage: "Make up to this many attempts to run each spec. If any of the attempts succeed, the suite will not be failed."}, + + {KeyPath: "S.DryRun", Name: "dry-run", SectionKey: "debug", DeprecatedName: "dryRun", DeprecatedDocLink: "changed-command-line-flags", + Usage: "If set, ginkgo will walk the test hierarchy without actually running anything. Best paired with -v."}, + {KeyPath: "S.PollProgressAfter", Name: "poll-progress-after", SectionKey: "debug", UsageDefaultValue: "0", + Usage: "Emit node progress reports periodically if node hasn't completed after this duration."}, + {KeyPath: "S.PollProgressInterval", Name: "poll-progress-interval", SectionKey: "debug", UsageDefaultValue: "10s", + Usage: "The rate at which to emit node progress reports after poll-progress-after has elapsed."}, + {KeyPath: "S.SourceRoots", Name: "source-root", SectionKey: "debug", + Usage: "The location to look for source code when generating progress reports. You can pass multiple --source-root flags."}, + {KeyPath: "S.Timeout", Name: "timeout", SectionKey: "debug", UsageDefaultValue: "1h", + Usage: "Test suite fails if it does not complete within the specified timeout."}, + {KeyPath: "S.GracePeriod", Name: "grace-period", SectionKey: "debug", UsageDefaultValue: "30s", + Usage: "When interrupted, Ginkgo will wait for GracePeriod for the current running node to exit before moving on to the next one."}, + {KeyPath: "S.OutputInterceptorMode", Name: "output-interceptor-mode", SectionKey: "debug", UsageArgument: "dup, swap, or none", + Usage: "If set, ginkgo will use the specified output interception strategy when running in parallel. Defaults to dup on unix and swap on windows."}, + + {KeyPath: "S.LabelFilter", Name: "label-filter", SectionKey: "filter", UsageArgument: "expression", + Usage: "If set, ginkgo will only run specs with labels that match the label-filter. The passed-in expression can include boolean operations (!, &&, ||, ','), groupings via '()', and regular expressions '/regexp/'. e.g. '(cat || dog) && !fruit'"}, + {KeyPath: "S.FocusStrings", Name: "focus", SectionKey: "filter", + Usage: "If set, ginkgo will only run specs that match this regular expression. Can be specified multiple times, values are ORed."}, + {KeyPath: "S.SkipStrings", Name: "skip", SectionKey: "filter", + Usage: "If set, ginkgo will only run specs that do not match this regular expression. Can be specified multiple times, values are ORed."}, + {KeyPath: "S.FocusFiles", Name: "focus-file", SectionKey: "filter", UsageArgument: "file (regexp) | file:line | file:lineA-lineB | file:line,line,line", + Usage: "If set, ginkgo will only run specs in matching files. Can be specified multiple times, values are ORed."}, + {KeyPath: "S.SkipFiles", Name: "skip-file", SectionKey: "filter", UsageArgument: "file (regexp) | file:line | file:lineA-lineB | file:line,line,line", + Usage: "If set, ginkgo will skip specs in matching files. Can be specified multiple times, values are ORed."}, + + {KeyPath: "D.RegexScansFilePath", DeprecatedName: "regexScansFilePath", DeprecatedDocLink: "removed--regexscansfilepath", DeprecatedVersion: "2.0.0"}, + {KeyPath: "D.DebugParallel", DeprecatedName: "debug", DeprecatedDocLink: "removed--debug", DeprecatedVersion: "2.0.0"}, + {KeyPath: "D.EmitSpecProgress", DeprecatedName: "progress", SectionKey: "debug", + DeprecatedVersion: "2.5.0", Usage: ". The functionality provided by --progress was confusing and is no longer needed. Use --show-node-events instead to see node entry and exit events included in the timeline of failed and verbose specs. Or you can run with -vv to always see all node events. Lastly, --poll-progress-after and the PollProgressAfter decorator now provide a better mechanism for debugging specs that tend to get stuck."}, +} + +// ParallelConfigFlags provides flags for the Ginkgo test process (not the CLI) +var ParallelConfigFlags = GinkgoFlags{ + {KeyPath: "S.ParallelProcess", Name: "parallel.process", SectionKey: "low-level-parallel", UsageDefaultValue: "1", + Usage: "This worker process's (one-indexed) process number. For running specs in parallel."}, + {KeyPath: "S.ParallelTotal", Name: "parallel.total", SectionKey: "low-level-parallel", UsageDefaultValue: "1", + Usage: "The total number of worker processes. For running specs in parallel."}, + {KeyPath: "S.ParallelHost", Name: "parallel.host", SectionKey: "low-level-parallel", UsageDefaultValue: "set by Ginkgo CLI", + Usage: "The address for the server that will synchronize the processes."}, +} + +// ReporterConfigFlags provides flags for the Ginkgo test process, and CLI +var ReporterConfigFlags = GinkgoFlags{ + {KeyPath: "R.NoColor", Name: "no-color", SectionKey: "output", DeprecatedName: "noColor", DeprecatedDocLink: "changed-command-line-flags", + Usage: "If set, suppress color output in default reporter."}, + {KeyPath: "R.Verbose", Name: "v", SectionKey: "output", + Usage: "If set, emits more output including GinkgoWriter contents."}, + {KeyPath: "R.VeryVerbose", Name: "vv", SectionKey: "output", + Usage: "If set, emits with maximal verbosity - includes skipped and pending tests."}, + {KeyPath: "R.Succinct", Name: "succinct", SectionKey: "output", + Usage: "If set, default reporter prints out a very succinct report"}, + {KeyPath: "R.FullTrace", Name: "trace", SectionKey: "output", + Usage: "If set, default reporter prints out the full stack trace when a failure occurs"}, + {KeyPath: "R.ShowNodeEvents", Name: "show-node-events", SectionKey: "output", + Usage: "If set, default reporter prints node > Enter and < Exit events when specs fail"}, + + {KeyPath: "R.JSONReport", Name: "json-report", UsageArgument: "filename.json", SectionKey: "output", + Usage: "If set, Ginkgo will generate a JSON-formatted test report at the specified location."}, + {KeyPath: "R.JUnitReport", Name: "junit-report", UsageArgument: "filename.xml", SectionKey: "output", DeprecatedName: "reportFile", DeprecatedDocLink: "improved-reporting-infrastructure", + Usage: "If set, Ginkgo will generate a conformant junit test report in the specified file."}, + {KeyPath: "R.TeamcityReport", Name: "teamcity-report", UsageArgument: "filename", SectionKey: "output", + Usage: "If set, Ginkgo will generate a Teamcity-formatted test report at the specified location."}, + + {KeyPath: "D.SlowSpecThresholdWithFLoatUnits", DeprecatedName: "slowSpecThreshold", DeprecatedDocLink: "changed--slowspecthreshold", + Usage: "use --slow-spec-threshold instead and pass in a duration string (e.g. '5s', not '5.0')"}, + {KeyPath: "D.NoisyPendings", DeprecatedName: "noisyPendings", DeprecatedDocLink: "removed--noisypendings-and--noisyskippings", DeprecatedVersion: "2.0.0"}, + {KeyPath: "D.NoisySkippings", DeprecatedName: "noisySkippings", DeprecatedDocLink: "removed--noisypendings-and--noisyskippings", DeprecatedVersion: "2.0.0"}, + {KeyPath: "D.SlowSpecThreshold", DeprecatedName: "slow-spec-threshold", SectionKey: "output", Usage: "--slow-spec-threshold has been deprecated and will be removed in a future version of Ginkgo. This feature has proved to be more noisy than useful. You can use --poll-progress-after, instead, to get more actionable feedback about potentially slow specs and understand where they might be getting stuck.", DeprecatedVersion: "2.5.0"}, + {KeyPath: "D.AlwaysEmitGinkgoWriter", DeprecatedName: "always-emit-ginkgo-writer", SectionKey: "output", Usage: " - use -v instead, or one of Ginkgo's machine-readable report formats to get GinkgoWriter output for passing specs."}, +} + +// BuildTestSuiteFlagSet attaches to the CommandLine flagset and provides flags for the Ginkgo test process +func BuildTestSuiteFlagSet(suiteConfig *SuiteConfig, reporterConfig *ReporterConfig) (GinkgoFlagSet, error) { + flags := SuiteConfigFlags.CopyAppend(ParallelConfigFlags...).CopyAppend(ReporterConfigFlags...) + flags = flags.WithPrefix("ginkgo") + bindings := map[string]interface{}{ + "S": suiteConfig, + "R": reporterConfig, + "D": &deprecatedConfig{}, + } + extraGoFlagsSection := GinkgoFlagSection{Style: "{{gray}}", Heading: "Go test flags"} + + return NewAttachedGinkgoFlagSet(flag.CommandLine, flags, bindings, FlagSections, extraGoFlagsSection) +} + +// VetConfig validates that the Ginkgo test process' configuration is sound +func VetConfig(flagSet GinkgoFlagSet, suiteConfig SuiteConfig, reporterConfig ReporterConfig) []error { + errors := []error{} + + if flagSet.WasSet("count") || flagSet.WasSet("test.count") { + flag := flagSet.Lookup("count") + if flag == nil { + flag = flagSet.Lookup("test.count") + } + count, err := strconv.Atoi(flag.Value.String()) + if err != nil || count != 1 { + errors = append(errors, GinkgoErrors.InvalidGoFlagCount()) + } + } + + if flagSet.WasSet("parallel") || flagSet.WasSet("test.parallel") { + errors = append(errors, GinkgoErrors.InvalidGoFlagParallel()) + } + + if suiteConfig.ParallelTotal < 1 { + errors = append(errors, GinkgoErrors.InvalidParallelTotalConfiguration()) + } + + if suiteConfig.ParallelProcess > suiteConfig.ParallelTotal || suiteConfig.ParallelProcess < 1 { + errors = append(errors, GinkgoErrors.InvalidParallelProcessConfiguration()) + } + + if suiteConfig.ParallelTotal > 1 && suiteConfig.ParallelHost == "" { + errors = append(errors, GinkgoErrors.MissingParallelHostConfiguration()) + } + + if suiteConfig.DryRun && suiteConfig.ParallelTotal > 1 { + errors = append(errors, GinkgoErrors.DryRunInParallelConfiguration()) + } + + if suiteConfig.GracePeriod <= 0 { + errors = append(errors, GinkgoErrors.GracePeriodCannotBeZero()) + } + + if len(suiteConfig.FocusFiles) > 0 { + _, err := ParseFileFilters(suiteConfig.FocusFiles) + if err != nil { + errors = append(errors, err) + } + } + + if len(suiteConfig.SkipFiles) > 0 { + _, err := ParseFileFilters(suiteConfig.SkipFiles) + if err != nil { + errors = append(errors, err) + } + } + + if suiteConfig.LabelFilter != "" { + _, err := ParseLabelFilter(suiteConfig.LabelFilter) + if err != nil { + errors = append(errors, err) + } + } + + switch strings.ToLower(suiteConfig.OutputInterceptorMode) { + case "", "dup", "swap", "none": + default: + errors = append(errors, GinkgoErrors.InvalidOutputInterceptorModeConfiguration(suiteConfig.OutputInterceptorMode)) + } + + numVerbosity := 0 + for _, v := range []bool{reporterConfig.Succinct, reporterConfig.Verbose, reporterConfig.VeryVerbose} { + if v { + numVerbosity++ + } + } + if numVerbosity > 1 { + errors = append(errors, GinkgoErrors.ConflictingVerbosityConfiguration()) + } + + return errors +} + +// GinkgoCLISharedFlags provides flags shared by the Ginkgo CLI's build, watch, and run commands +var GinkgoCLISharedFlags = GinkgoFlags{ + {KeyPath: "C.Recurse", Name: "r", SectionKey: "multiple-suites", + Usage: "If set, ginkgo finds and runs test suites under the current directory recursively."}, + {KeyPath: "C.SkipPackage", Name: "skip-package", SectionKey: "multiple-suites", DeprecatedName: "skipPackage", DeprecatedDocLink: "changed-command-line-flags", + UsageArgument: "comma-separated list of packages", + Usage: "A comma-separated list of package names to be skipped. If any part of the package's path matches, that package is ignored."}, + {KeyPath: "C.RequireSuite", Name: "require-suite", SectionKey: "failure", DeprecatedName: "requireSuite", DeprecatedDocLink: "changed-command-line-flags", + Usage: "If set, Ginkgo fails if there are ginkgo tests in a directory but no invocation of RunSpecs."}, + {KeyPath: "C.NumCompilers", Name: "compilers", SectionKey: "multiple-suites", UsageDefaultValue: "0 (will autodetect)", + Usage: "When running multiple packages, the number of concurrent compilations to perform."}, +} + +// GinkgoCLIRunAndWatchFlags provides flags shared by the Ginkgo CLI's build and watch commands (but not run) +var GinkgoCLIRunAndWatchFlags = GinkgoFlags{ + {KeyPath: "C.Procs", Name: "procs", SectionKey: "parallel", UsageDefaultValue: "1 (run in series)", + Usage: "The number of parallel test nodes to run."}, + {KeyPath: "C.Procs", Name: "nodes", SectionKey: "parallel", UsageDefaultValue: "1 (run in series)", + Usage: "--nodes is an alias for --procs"}, + {KeyPath: "C.Parallel", Name: "p", SectionKey: "parallel", + Usage: "If set, ginkgo will run in parallel with an auto-detected number of nodes."}, + {KeyPath: "C.AfterRunHook", Name: "after-run-hook", SectionKey: "misc", DeprecatedName: "afterSuiteHook", DeprecatedDocLink: "changed-command-line-flags", + Usage: "Command to run when a test suite completes."}, + {KeyPath: "C.OutputDir", Name: "output-dir", SectionKey: "output", UsageArgument: "directory", DeprecatedName: "outputdir", DeprecatedDocLink: "improved-profiling-support", + Usage: "A location to place all generated profiles and reports."}, + {KeyPath: "C.KeepSeparateCoverprofiles", Name: "keep-separate-coverprofiles", SectionKey: "code-and-coverage-analysis", + Usage: "If set, Ginkgo does not merge coverprofiles into one monolithic coverprofile. The coverprofiles will remain in their respective package directories or in -output-dir if set."}, + {KeyPath: "C.KeepSeparateReports", Name: "keep-separate-reports", SectionKey: "output", + Usage: "If set, Ginkgo does not merge per-suite reports (e.g. -json-report) into one monolithic report for the entire testrun. The reports will remain in their respective package directories or in -output-dir if set."}, + + {KeyPath: "D.Stream", DeprecatedName: "stream", DeprecatedDocLink: "removed--stream", DeprecatedVersion: "2.0.0"}, + {KeyPath: "D.Notify", DeprecatedName: "notify", DeprecatedDocLink: "removed--notify", DeprecatedVersion: "2.0.0"}, +} + +// GinkgoCLIRunFlags provides flags for Ginkgo CLI's run command that aren't shared by any other commands +var GinkgoCLIRunFlags = GinkgoFlags{ + {KeyPath: "C.KeepGoing", Name: "keep-going", SectionKey: "multiple-suites", DeprecatedName: "keepGoing", DeprecatedDocLink: "changed-command-line-flags", + Usage: "If set, failures from earlier test suites do not prevent later test suites from running."}, + {KeyPath: "C.UntilItFails", Name: "until-it-fails", SectionKey: "debug", DeprecatedName: "untilItFails", DeprecatedDocLink: "changed-command-line-flags", + Usage: "If set, ginkgo will keep rerunning test suites until a failure occurs."}, + {KeyPath: "C.Repeat", Name: "repeat", SectionKey: "debug", UsageArgument: "n", UsageDefaultValue: "0 - i.e. no repetition, run only once", + Usage: "The number of times to re-run a test-suite. Useful for debugging flaky tests. If set to N the suite will be run N+1 times and will be required to pass each time."}, + {KeyPath: "C.RandomizeSuites", Name: "randomize-suites", SectionKey: "order", DeprecatedName: "randomizeSuites", DeprecatedDocLink: "changed-command-line-flags", + Usage: "If set, ginkgo will randomize the order in which test suites run."}, +} + +// GinkgoCLIRunFlags provides flags for Ginkgo CLI's watch command that aren't shared by any other commands +var GinkgoCLIWatchFlags = GinkgoFlags{ + {KeyPath: "C.Depth", Name: "depth", SectionKey: "watch", + Usage: "Ginkgo will watch dependencies down to this depth in the dependency tree."}, + {KeyPath: "C.WatchRegExp", Name: "watch-regexp", SectionKey: "watch", DeprecatedName: "watchRegExp", DeprecatedDocLink: "changed-command-line-flags", + UsageArgument: "Regular Expression", + UsageDefaultValue: `\.go$`, + Usage: "Only files matching this regular expression will be watched for changes."}, +} + +// GoBuildFlags provides flags for the Ginkgo CLI build, run, and watch commands that capture go's build-time flags. These are passed to go test -c by the ginkgo CLI +var GoBuildFlags = GinkgoFlags{ + {KeyPath: "Go.Race", Name: "race", SectionKey: "code-and-coverage-analysis", + Usage: "enable data race detection. Supported only on linux/amd64, freebsd/amd64, darwin/amd64, windows/amd64, linux/ppc64le and linux/arm64 (only for 48-bit VMA)."}, + {KeyPath: "Go.Vet", Name: "vet", UsageArgument: "list", SectionKey: "code-and-coverage-analysis", + Usage: `Configure the invocation of "go vet" during "go test" to use the comma-separated list of vet checks. If list is empty, "go test" runs "go vet" with a curated list of checks believed to be always worth addressing. If list is "off", "go test" does not run "go vet" at all. Available checks can be found by running 'go doc cmd/vet'`}, + {KeyPath: "Go.Cover", Name: "cover", SectionKey: "code-and-coverage-analysis", + Usage: "Enable coverage analysis. Note that because coverage works by annotating the source code before compilation, compilation and test failures with coverage enabled may report line numbers that don't correspond to the original sources."}, + {KeyPath: "Go.CoverMode", Name: "covermode", UsageArgument: "set,count,atomic", SectionKey: "code-and-coverage-analysis", + Usage: `Set the mode for coverage analysis for the package[s] being tested. 'set': does this statement run? 'count': how many times does this statement run? 'atomic': like count, but correct in multithreaded tests and more expensive (must use atomic with -race). Sets -cover`}, + {KeyPath: "Go.CoverPkg", Name: "coverpkg", UsageArgument: "pattern1,pattern2,pattern3", SectionKey: "code-and-coverage-analysis", + Usage: "Apply coverage analysis in each test to packages matching the patterns. The default is for each test to analyze only the package being tested. See 'go help packages' for a description of package patterns. Sets -cover."}, + + {KeyPath: "Go.A", Name: "a", SectionKey: "go-build", + Usage: "force rebuilding of packages that are already up-to-date."}, + {KeyPath: "Go.ASMFlags", Name: "asmflags", UsageArgument: "'[pattern=]arg list'", SectionKey: "go-build", + Usage: "arguments to pass on each go tool asm invocation."}, + {KeyPath: "Go.BuildMode", Name: "buildmode", UsageArgument: "mode", SectionKey: "go-build", + Usage: "build mode to use. See 'go help buildmode' for more."}, + {KeyPath: "Go.Compiler", Name: "compiler", UsageArgument: "name", SectionKey: "go-build", + Usage: "name of compiler to use, as in runtime.Compiler (gccgo or gc)."}, + {KeyPath: "Go.GCCGoFlags", Name: "gccgoflags", UsageArgument: "'[pattern=]arg list'", SectionKey: "go-build", + Usage: "arguments to pass on each gccgo compiler/linker invocation."}, + {KeyPath: "Go.GCFlags", Name: "gcflags", UsageArgument: "'[pattern=]arg list'", SectionKey: "go-build", + Usage: "arguments to pass on each go tool compile invocation."}, + {KeyPath: "Go.InstallSuffix", Name: "installsuffix", SectionKey: "go-build", + Usage: "a suffix to use in the name of the package installation directory, in order to keep output separate from default builds. If using the -race flag, the install suffix is automatically set to raceor, if set explicitly, has _race appended to it. Likewise for the -msan flag. Using a -buildmode option that requires non-default compile flags has a similar effect."}, + {KeyPath: "Go.LDFlags", Name: "ldflags", UsageArgument: "'[pattern=]arg list'", SectionKey: "go-build", + Usage: "arguments to pass on each go tool link invocation."}, + {KeyPath: "Go.LinkShared", Name: "linkshared", SectionKey: "go-build", + Usage: "build code that will be linked against shared libraries previously created with -buildmode=shared."}, + {KeyPath: "Go.Mod", Name: "mod", UsageArgument: "mode (readonly, vendor, or mod)", SectionKey: "go-build", + Usage: "module download mode to use: readonly, vendor, or mod. See 'go help modules' for more."}, + {KeyPath: "Go.ModCacheRW", Name: "modcacherw", SectionKey: "go-build", + Usage: "leave newly-created directories in the module cache read-write instead of making them read-only."}, + {KeyPath: "Go.ModFile", Name: "modfile", UsageArgument: "file", SectionKey: "go-build", + Usage: `in module aware mode, read (and possibly write) an alternate go.mod file instead of the one in the module root directory. A file named go.mod must still be present in order to determine the module root directory, but it is not accessed. When -modfile is specified, an alternate go.sum file is also used: its path is derived from the -modfile flag by trimming the ".mod" extension and appending ".sum".`}, + {KeyPath: "Go.MSan", Name: "msan", SectionKey: "go-build", + Usage: "enable interoperation with memory sanitizer. Supported only on linux/amd64, linux/arm64 and only with Clang/LLVM as the host C compiler. On linux/arm64, pie build mode will be used."}, + {KeyPath: "Go.N", Name: "n", SectionKey: "go-build", + Usage: "print the commands but do not run them."}, + {KeyPath: "Go.PkgDir", Name: "pkgdir", UsageArgument: "dir", SectionKey: "go-build", + Usage: "install and load all packages from dir instead of the usual locations. For example, when building with a non-standard configuration, use -pkgdir to keep generated packages in a separate location."}, + {KeyPath: "Go.Tags", Name: "tags", UsageArgument: "tag,list", SectionKey: "go-build", + Usage: "a comma-separated list of build tags to consider satisfied during the build. For more information about build tags, see the description of build constraints in the documentation for the go/build package. (Earlier versions of Go used a space-separated list, and that form is deprecated but still recognized.)"}, + {KeyPath: "Go.TrimPath", Name: "trimpath", SectionKey: "go-build", + Usage: `remove all file system paths from the resulting executable. Instead of absolute file system paths, the recorded file names will begin with either "go" (for the standard library), or a module path@version (when using modules), or a plain import path (when using GOPATH).`}, + {KeyPath: "Go.ToolExec", Name: "toolexec", UsageArgument: "'cmd args'", SectionKey: "go-build", + Usage: "a program to use to invoke toolchain programs like vet and asm. For example, instead of running asm, the go command will run cmd args /path/to/asm '."}, + {KeyPath: "Go.Work", Name: "work", SectionKey: "go-build", + Usage: "print the name of the temporary work directory and do not delete it when exiting."}, + {KeyPath: "Go.X", Name: "x", SectionKey: "go-build", + Usage: "print the commands."}, +} + +// GoRunFlags provides flags for the Ginkgo CLI run, and watch commands that capture go's run-time flags. These are passed to the compiled test binary by the ginkgo CLI +var GoRunFlags = GinkgoFlags{ + {KeyPath: "Go.CoverProfile", Name: "coverprofile", UsageArgument: "file", SectionKey: "code-and-coverage-analysis", + Usage: `Write a coverage profile to the file after all tests have passed. Sets -cover.`}, + {KeyPath: "Go.BlockProfile", Name: "blockprofile", UsageArgument: "file", SectionKey: "performance-analysis", + Usage: `Write a goroutine blocking profile to the specified file when all tests are complete. Preserves test binary.`}, + {KeyPath: "Go.BlockProfileRate", Name: "blockprofilerate", UsageArgument: "rate", SectionKey: "performance-analysis", + Usage: `Control the detail provided in goroutine blocking profiles by calling runtime.SetBlockProfileRate with rate. See 'go doc runtime.SetBlockProfileRate'. The profiler aims to sample, on average, one blocking event every n nanoseconds the program spends blocked. By default, if -test.blockprofile is set without this flag, all blocking events are recorded, equivalent to -test.blockprofilerate=1.`}, + {KeyPath: "Go.CPUProfile", Name: "cpuprofile", UsageArgument: "file", SectionKey: "performance-analysis", + Usage: `Write a CPU profile to the specified file before exiting. Preserves test binary.`}, + {KeyPath: "Go.MemProfile", Name: "memprofile", UsageArgument: "file", SectionKey: "performance-analysis", + Usage: `Write an allocation profile to the file after all tests have passed. Preserves test binary.`}, + {KeyPath: "Go.MemProfileRate", Name: "memprofilerate", UsageArgument: "rate", SectionKey: "performance-analysis", + Usage: `Enable more precise (and expensive) memory allocation profiles by setting runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'. To profile all memory allocations, use -test.memprofilerate=1.`}, + {KeyPath: "Go.MutexProfile", Name: "mutexprofile", UsageArgument: "file", SectionKey: "performance-analysis", + Usage: `Write a mutex contention profile to the specified file when all tests are complete. Preserves test binary.`}, + {KeyPath: "Go.MutexProfileFraction", Name: "mutexprofilefraction", UsageArgument: "n", SectionKey: "performance-analysis", + Usage: `if >= 0, calls runtime.SetMutexProfileFraction() Sample 1 in n stack traces of goroutines holding a contended mutex.`}, + {KeyPath: "Go.Trace", Name: "execution-trace", UsageArgument: "file", ExportAs: "trace", SectionKey: "performance-analysis", + Usage: `Write an execution trace to the specified file before exiting.`}, +} + +// VetAndInitializeCLIAndGoConfig validates that the Ginkgo CLI's configuration is sound +// It returns a potentially mutated copy of the config that rationalizes the configuration to ensure consistency for downstream consumers +func VetAndInitializeCLIAndGoConfig(cliConfig CLIConfig, goFlagsConfig GoFlagsConfig) (CLIConfig, GoFlagsConfig, []error) { + errors := []error{} + + if cliConfig.Repeat > 0 && cliConfig.UntilItFails { + errors = append(errors, GinkgoErrors.BothRepeatAndUntilItFails()) + } + + //initialize the output directory + if cliConfig.OutputDir != "" { + err := os.MkdirAll(cliConfig.OutputDir, 0777) + if err != nil { + errors = append(errors, err) + } + } + + //ensure cover mode is configured appropriately + if goFlagsConfig.CoverMode != "" || goFlagsConfig.CoverPkg != "" || goFlagsConfig.CoverProfile != "" { + goFlagsConfig.Cover = true + } + if goFlagsConfig.Cover && goFlagsConfig.CoverProfile == "" { + goFlagsConfig.CoverProfile = "coverprofile.out" + } + + return cliConfig, goFlagsConfig, errors +} + +// GenerateGoTestCompileArgs is used by the Ginkgo CLI to generate command line arguments to pass to the go test -c command when compiling the test +func GenerateGoTestCompileArgs(goFlagsConfig GoFlagsConfig, destination string, packageToBuild string, pathToInvocationPath string) ([]string, error) { + // if the user has set the CoverProfile run-time flag make sure to set the build-time cover flag to make sure + // the built test binary can generate a coverprofile + if goFlagsConfig.CoverProfile != "" { + goFlagsConfig.Cover = true + } + + if goFlagsConfig.CoverPkg != "" { + coverPkgs := strings.Split(goFlagsConfig.CoverPkg, ",") + adjustedCoverPkgs := make([]string, len(coverPkgs)) + for i, coverPkg := range coverPkgs { + coverPkg = strings.Trim(coverPkg, " ") + if strings.HasPrefix(coverPkg, "./") { + // this is a relative coverPkg - we need to reroot it + adjustedCoverPkgs[i] = "./" + filepath.Join(pathToInvocationPath, strings.TrimPrefix(coverPkg, "./")) + } else { + // this is a package name - don't touch it + adjustedCoverPkgs[i] = coverPkg + } + } + goFlagsConfig.CoverPkg = strings.Join(adjustedCoverPkgs, ",") + } + + args := []string{"test", "-c", "-o", destination, packageToBuild} + goArgs, err := GenerateFlagArgs( + GoBuildFlags, + map[string]interface{}{ + "Go": &goFlagsConfig, + }, + ) + + if err != nil { + return []string{}, err + } + args = append(args, goArgs...) + return args, nil +} + +// GenerateGinkgoTestRunArgs is used by the Ginkgo CLI to generate command line arguments to pass to the compiled Ginkgo test binary +func GenerateGinkgoTestRunArgs(suiteConfig SuiteConfig, reporterConfig ReporterConfig, goFlagsConfig GoFlagsConfig) ([]string, error) { + var flags GinkgoFlags + flags = SuiteConfigFlags.WithPrefix("ginkgo") + flags = flags.CopyAppend(ParallelConfigFlags.WithPrefix("ginkgo")...) + flags = flags.CopyAppend(ReporterConfigFlags.WithPrefix("ginkgo")...) + flags = flags.CopyAppend(GoRunFlags.WithPrefix("test")...) + bindings := map[string]interface{}{ + "S": &suiteConfig, + "R": &reporterConfig, + "Go": &goFlagsConfig, + } + + return GenerateFlagArgs(flags, bindings) +} + +// GenerateGoTestRunArgs is used by the Ginkgo CLI to generate command line arguments to pass to the compiled non-Ginkgo test binary +func GenerateGoTestRunArgs(goFlagsConfig GoFlagsConfig) ([]string, error) { + flags := GoRunFlags.WithPrefix("test") + bindings := map[string]interface{}{ + "Go": &goFlagsConfig, + } + + args, err := GenerateFlagArgs(flags, bindings) + if err != nil { + return args, err + } + args = append(args, "--test.v") + return args, nil +} + +// BuildRunCommandFlagSet builds the FlagSet for the `ginkgo run` command +func BuildRunCommandFlagSet(suiteConfig *SuiteConfig, reporterConfig *ReporterConfig, cliConfig *CLIConfig, goFlagsConfig *GoFlagsConfig) (GinkgoFlagSet, error) { + flags := SuiteConfigFlags + flags = flags.CopyAppend(ReporterConfigFlags...) + flags = flags.CopyAppend(GinkgoCLISharedFlags...) + flags = flags.CopyAppend(GinkgoCLIRunAndWatchFlags...) + flags = flags.CopyAppend(GinkgoCLIRunFlags...) + flags = flags.CopyAppend(GoBuildFlags...) + flags = flags.CopyAppend(GoRunFlags...) + + bindings := map[string]interface{}{ + "S": suiteConfig, + "R": reporterConfig, + "C": cliConfig, + "Go": goFlagsConfig, + "D": &deprecatedConfig{}, + } + + return NewGinkgoFlagSet(flags, bindings, FlagSections) +} + +// BuildWatchCommandFlagSet builds the FlagSet for the `ginkgo watch` command +func BuildWatchCommandFlagSet(suiteConfig *SuiteConfig, reporterConfig *ReporterConfig, cliConfig *CLIConfig, goFlagsConfig *GoFlagsConfig) (GinkgoFlagSet, error) { + flags := SuiteConfigFlags + flags = flags.CopyAppend(ReporterConfigFlags...) + flags = flags.CopyAppend(GinkgoCLISharedFlags...) + flags = flags.CopyAppend(GinkgoCLIRunAndWatchFlags...) + flags = flags.CopyAppend(GinkgoCLIWatchFlags...) + flags = flags.CopyAppend(GoBuildFlags...) + flags = flags.CopyAppend(GoRunFlags...) + + bindings := map[string]interface{}{ + "S": suiteConfig, + "R": reporterConfig, + "C": cliConfig, + "Go": goFlagsConfig, + "D": &deprecatedConfig{}, + } + + return NewGinkgoFlagSet(flags, bindings, FlagSections) +} + +// BuildBuildCommandFlagSet builds the FlagSet for the `ginkgo build` command +func BuildBuildCommandFlagSet(cliConfig *CLIConfig, goFlagsConfig *GoFlagsConfig) (GinkgoFlagSet, error) { + flags := GinkgoCLISharedFlags + flags = flags.CopyAppend(GoBuildFlags...) + + bindings := map[string]interface{}{ + "C": cliConfig, + "Go": goFlagsConfig, + "D": &deprecatedConfig{}, + } + + flagSections := make(GinkgoFlagSections, len(FlagSections)) + copy(flagSections, FlagSections) + for i := range flagSections { + if flagSections[i].Key == "multiple-suites" { + flagSections[i].Heading = "Building Multiple Suites" + } + if flagSections[i].Key == "go-build" { + flagSections[i] = GinkgoFlagSection{Key: "go-build", Style: "{{/}}", Heading: "Go Build Flags", + Description: "These flags are inherited from go build."} + } + } + + return NewGinkgoFlagSet(flags, bindings, flagSections) +} + +func BuildLabelsCommandFlagSet(cliConfig *CLIConfig) (GinkgoFlagSet, error) { + flags := GinkgoCLISharedFlags.SubsetWithNames("r", "skip-package") + + bindings := map[string]interface{}{ + "C": cliConfig, + } + + flagSections := make(GinkgoFlagSections, len(FlagSections)) + copy(flagSections, FlagSections) + for i := range flagSections { + if flagSections[i].Key == "multiple-suites" { + flagSections[i].Heading = "Fetching Labels from Multiple Suites" + } + } + + return NewGinkgoFlagSet(flags, bindings, flagSections) +} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/deprecated_types.go b/vendor/github.com/onsi/ginkgo/v2/types/deprecated_types.go new file mode 100644 index 000000000..17922304b --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/types/deprecated_types.go @@ -0,0 +1,141 @@ +package types + +import ( + "strconv" + "time" +) + +/* + A set of deprecations to make the transition from v1 to v2 easier for users who have written custom reporters. +*/ + +type SuiteSummary = DeprecatedSuiteSummary +type SetupSummary = DeprecatedSetupSummary +type SpecSummary = DeprecatedSpecSummary +type SpecMeasurement = DeprecatedSpecMeasurement +type SpecComponentType = NodeType +type SpecFailure = DeprecatedSpecFailure + +var ( + SpecComponentTypeInvalid = NodeTypeInvalid + SpecComponentTypeContainer = NodeTypeContainer + SpecComponentTypeIt = NodeTypeIt + SpecComponentTypeBeforeEach = NodeTypeBeforeEach + SpecComponentTypeJustBeforeEach = NodeTypeJustBeforeEach + SpecComponentTypeAfterEach = NodeTypeAfterEach + SpecComponentTypeJustAfterEach = NodeTypeJustAfterEach + SpecComponentTypeBeforeSuite = NodeTypeBeforeSuite + SpecComponentTypeSynchronizedBeforeSuite = NodeTypeSynchronizedBeforeSuite + SpecComponentTypeAfterSuite = NodeTypeAfterSuite + SpecComponentTypeSynchronizedAfterSuite = NodeTypeSynchronizedAfterSuite +) + +type DeprecatedSuiteSummary struct { + SuiteDescription string + SuiteSucceeded bool + SuiteID string + + NumberOfSpecsBeforeParallelization int + NumberOfTotalSpecs int + NumberOfSpecsThatWillBeRun int + NumberOfPendingSpecs int + NumberOfSkippedSpecs int + NumberOfPassedSpecs int + NumberOfFailedSpecs int + NumberOfFlakedSpecs int + RunTime time.Duration +} + +type DeprecatedSetupSummary struct { + ComponentType SpecComponentType + CodeLocation CodeLocation + + State SpecState + RunTime time.Duration + Failure SpecFailure + + CapturedOutput string + SuiteID string +} + +type DeprecatedSpecSummary struct { + ComponentTexts []string + ComponentCodeLocations []CodeLocation + + State SpecState + RunTime time.Duration + Failure SpecFailure + IsMeasurement bool + NumberOfSamples int + Measurements map[string]*DeprecatedSpecMeasurement + + CapturedOutput string + SuiteID string +} + +func (s DeprecatedSpecSummary) HasFailureState() bool { + return s.State.Is(SpecStateFailureStates) +} + +func (s DeprecatedSpecSummary) TimedOut() bool { + return false +} + +func (s DeprecatedSpecSummary) Panicked() bool { + return s.State == SpecStatePanicked +} + +func (s DeprecatedSpecSummary) Failed() bool { + return s.State == SpecStateFailed +} + +func (s DeprecatedSpecSummary) Passed() bool { + return s.State == SpecStatePassed +} + +func (s DeprecatedSpecSummary) Skipped() bool { + return s.State == SpecStateSkipped +} + +func (s DeprecatedSpecSummary) Pending() bool { + return s.State == SpecStatePending +} + +type DeprecatedSpecFailure struct { + Message string + Location CodeLocation + ForwardedPanic string + + ComponentIndex int + ComponentType SpecComponentType + ComponentCodeLocation CodeLocation +} + +type DeprecatedSpecMeasurement struct { + Name string + Info interface{} + Order int + + Results []float64 + + Smallest float64 + Largest float64 + Average float64 + StdDeviation float64 + + SmallestLabel string + LargestLabel string + AverageLabel string + Units string + Precision int +} + +func (s DeprecatedSpecMeasurement) PrecisionFmt() string { + if s.Precision == 0 { + return "%f" + } + + str := strconv.Itoa(s.Precision) + + return "%." + str + "f" +} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/deprecation_support.go b/vendor/github.com/onsi/ginkgo/v2/types/deprecation_support.go new file mode 100644 index 000000000..e2519f673 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/types/deprecation_support.go @@ -0,0 +1,177 @@ +package types + +import ( + "os" + "strconv" + "strings" + "sync" + "unicode" + + "github.com/onsi/ginkgo/v2/formatter" +) + +type Deprecation struct { + Message string + DocLink string + Version string +} + +type deprecations struct{} + +var Deprecations = deprecations{} + +func (d deprecations) CustomReporter() Deprecation { + return Deprecation{ + Message: "Support for custom reporters has been removed in V2. Please read the documentation linked to below for Ginkgo's new behavior and for a migration path:", + DocLink: "removed-custom-reporters", + Version: "1.16.0", + } +} + +func (d deprecations) Async() Deprecation { + return Deprecation{ + Message: "You are passing a Done channel to a test node to test asynchronous behavior. This is deprecated in Ginkgo V2. Your test will run synchronously and the timeout will be ignored.", + DocLink: "removed-async-testing", + Version: "1.16.0", + } +} + +func (d deprecations) Measure() Deprecation { + return Deprecation{ + Message: "Measure is deprecated and has been removed from Ginkgo V2. Any Measure tests in your spec will not run. Please migrate to gomega/gmeasure.", + DocLink: "removed-measure", + Version: "1.16.3", + } +} + +func (d deprecations) ParallelNode() Deprecation { + return Deprecation{ + Message: "GinkgoParallelNode is deprecated and will be removed in Ginkgo V2. Please use GinkgoParallelProcess instead.", + DocLink: "renamed-ginkgoparallelnode", + Version: "1.16.4", + } +} + +func (d deprecations) CurrentGinkgoTestDescription() Deprecation { + return Deprecation{ + Message: "CurrentGinkgoTestDescription() is deprecated in Ginkgo V2. Use CurrentSpecReport() instead.", + DocLink: "changed-currentginkgotestdescription", + Version: "1.16.0", + } +} + +func (d deprecations) Convert() Deprecation { + return Deprecation{ + Message: "The convert command is deprecated in Ginkgo V2", + DocLink: "removed-ginkgo-convert", + Version: "1.16.0", + } +} + +func (d deprecations) Blur() Deprecation { + return Deprecation{ + Message: "The blur command is deprecated in Ginkgo V2. Use 'ginkgo unfocus' instead.", + Version: "1.16.0", + } +} + +func (d deprecations) Nodot() Deprecation { + return Deprecation{ + Message: "The nodot command is deprecated in Ginkgo V2. Please either dot-import Ginkgo or use the package identifier in your code to references objects and types provided by Ginkgo and Gomega.", + DocLink: "removed-ginkgo-nodot", + Version: "1.16.0", + } +} + +func (d deprecations) SuppressProgressReporting() Deprecation { + return Deprecation{ + Message: "Improvements to how reporters emit timeline information means that SuppressProgressReporting is no longer necessary and has been deprecated.", + Version: "2.5.0", + } +} + +type DeprecationTracker struct { + deprecations map[Deprecation][]CodeLocation + lock *sync.Mutex +} + +func NewDeprecationTracker() *DeprecationTracker { + return &DeprecationTracker{ + deprecations: map[Deprecation][]CodeLocation{}, + lock: &sync.Mutex{}, + } +} + +func (d *DeprecationTracker) TrackDeprecation(deprecation Deprecation, cl ...CodeLocation) { + ackVersion := os.Getenv("ACK_GINKGO_DEPRECATIONS") + if deprecation.Version != "" && ackVersion != "" { + ack := ParseSemVer(ackVersion) + version := ParseSemVer(deprecation.Version) + if ack.GreaterThanOrEqualTo(version) { + return + } + } + + d.lock.Lock() + defer d.lock.Unlock() + if len(cl) == 1 { + d.deprecations[deprecation] = append(d.deprecations[deprecation], cl[0]) + } else { + d.deprecations[deprecation] = []CodeLocation{} + } +} + +func (d *DeprecationTracker) DidTrackDeprecations() bool { + d.lock.Lock() + defer d.lock.Unlock() + return len(d.deprecations) > 0 +} + +func (d *DeprecationTracker) DeprecationsReport() string { + d.lock.Lock() + defer d.lock.Unlock() + out := formatter.F("{{light-yellow}}You're using deprecated Ginkgo functionality:{{/}}\n") + out += formatter.F("{{light-yellow}}============================================={{/}}\n") + for deprecation, locations := range d.deprecations { + out += formatter.Fi(1, "{{yellow}}"+deprecation.Message+"{{/}}\n") + if deprecation.DocLink != "" { + out += formatter.Fi(1, "{{bold}}Learn more at:{{/}} {{cyan}}{{underline}}https://onsi.github.io/ginkgo/MIGRATING_TO_V2#%s{{/}}\n", deprecation.DocLink) + } + for _, location := range locations { + out += formatter.Fi(2, "{{gray}}%s{{/}}\n", location) + } + } + out += formatter.F("\n{{gray}}To silence deprecations that can be silenced set the following environment variable:{{/}}\n") + out += formatter.Fi(1, "{{gray}}ACK_GINKGO_DEPRECATIONS=%s{{/}}\n", VERSION) + return out +} + +type SemVer struct { + Major int + Minor int + Patch int +} + +func (s SemVer) GreaterThanOrEqualTo(o SemVer) bool { + return (s.Major > o.Major) || + (s.Major == o.Major && s.Minor > o.Minor) || + (s.Major == o.Major && s.Minor == o.Minor && s.Patch >= o.Patch) +} + +func ParseSemVer(semver string) SemVer { + out := SemVer{} + semver = strings.TrimFunc(semver, func(r rune) bool { + return !(unicode.IsNumber(r) || r == '.') + }) + components := strings.Split(semver, ".") + if len(components) > 0 { + out.Major, _ = strconv.Atoi(components[0]) + } + if len(components) > 1 { + out.Minor, _ = strconv.Atoi(components[1]) + } + if len(components) > 2 { + out.Patch, _ = strconv.Atoi(components[2]) + } + return out +} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/enum_support.go b/vendor/github.com/onsi/ginkgo/v2/types/enum_support.go new file mode 100644 index 000000000..1d96ae028 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/types/enum_support.go @@ -0,0 +1,43 @@ +package types + +import "encoding/json" + +type EnumSupport struct { + toString map[uint]string + toEnum map[string]uint + maxEnum uint +} + +func NewEnumSupport(toString map[uint]string) EnumSupport { + toEnum, maxEnum := map[string]uint{}, uint(0) + for k, v := range toString { + toEnum[v] = k + if maxEnum < k { + maxEnum = k + } + } + return EnumSupport{toString: toString, toEnum: toEnum, maxEnum: maxEnum} +} + +func (es EnumSupport) String(e uint) string { + if e > es.maxEnum { + return es.toString[0] + } + return es.toString[e] +} + +func (es EnumSupport) UnmarshJSON(b []byte) (uint, error) { + var dec string + if err := json.Unmarshal(b, &dec); err != nil { + return 0, err + } + out := es.toEnum[dec] // if we miss we get 0 which is what we want anyway + return out, nil +} + +func (es EnumSupport) MarshJSON(e uint) ([]byte, error) { + if e == 0 || e > es.maxEnum { + return json.Marshal(nil) + } + return json.Marshal(es.toString[e]) +} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/errors.go b/vendor/github.com/onsi/ginkgo/v2/types/errors.go new file mode 100644 index 000000000..1e0dbfd9d --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/types/errors.go @@ -0,0 +1,630 @@ +package types + +import ( + "fmt" + "reflect" + "strings" + + "github.com/onsi/ginkgo/v2/formatter" +) + +type GinkgoError struct { + Heading string + Message string + DocLink string + CodeLocation CodeLocation +} + +func (g GinkgoError) Error() string { + out := formatter.F("{{bold}}{{red}}%s{{/}}\n", g.Heading) + if (g.CodeLocation != CodeLocation{}) { + contentsOfLine := strings.TrimLeft(g.CodeLocation.ContentsOfLine(), "\t ") + if contentsOfLine != "" { + out += formatter.F("{{light-gray}}%s{{/}}\n", contentsOfLine) + } + out += formatter.F("{{gray}}%s{{/}}\n", g.CodeLocation) + } + if g.Message != "" { + out += formatter.Fiw(1, formatter.COLS, g.Message) + out += "\n\n" + } + if g.DocLink != "" { + out += formatter.Fiw(1, formatter.COLS, "{{bold}}Learn more at:{{/}} {{cyan}}{{underline}}http://onsi.github.io/ginkgo/#%s{{/}}\n", g.DocLink) + } + + return out +} + +type ginkgoErrors struct{} + +var GinkgoErrors = ginkgoErrors{} + +func (g ginkgoErrors) UncaughtGinkgoPanic(cl CodeLocation) error { + return GinkgoError{ + Heading: "Your Test Panicked", + Message: `When you, or your assertion library, calls Ginkgo's Fail(), +Ginkgo panics to prevent subsequent assertions from running. + +Normally Ginkgo rescues this panic so you shouldn't see it. + +However, if you make an assertion in a goroutine, Ginkgo can't capture the panic. +To circumvent this, you should call + + defer GinkgoRecover() + +at the top of the goroutine that caused this panic. + +Alternatively, you may have made an assertion outside of a Ginkgo +leaf node (e.g. in a container node or some out-of-band function) - please move your assertion to +an appropriate Ginkgo node (e.g. a BeforeSuite, BeforeEach, It, etc...).`, + DocLink: "mental-model-how-ginkgo-handles-failure", + CodeLocation: cl, + } +} + +func (g ginkgoErrors) RerunningSuite() error { + return GinkgoError{ + Heading: "Rerunning Suite", + Message: formatter.F(`It looks like you are calling RunSpecs more than once. Ginkgo does not support rerunning suites. If you want to rerun a suite try {{bold}}ginkgo --repeat=N{{/}} or {{bold}}ginkgo --until-it-fails{{/}}`), + DocLink: "repeating-spec-runs-and-managing-flaky-specs", + } +} + +/* Tree construction errors */ + +func (g ginkgoErrors) PushingNodeInRunPhase(nodeType NodeType, cl CodeLocation) error { + return GinkgoError{ + Heading: "Ginkgo detected an issue with your spec structure", + Message: formatter.F( + `It looks like you are trying to add a {{bold}}[%s]{{/}} node +to the Ginkgo spec tree in a leaf node {{bold}}after{{/}} the specs started running. + +To enable randomization and parallelization Ginkgo requires the spec tree +to be fully constructed up front. In practice, this means that you can +only create nodes like {{bold}}[%s]{{/}} at the top-level or within the +body of a {{bold}}Describe{{/}}, {{bold}}Context{{/}}, or {{bold}}When{{/}}.`, nodeType, nodeType), + CodeLocation: cl, + DocLink: "mental-model-how-ginkgo-traverses-the-spec-hierarchy", + } +} + +func (g ginkgoErrors) CaughtPanicDuringABuildPhase(caughtPanic interface{}, cl CodeLocation) error { + return GinkgoError{ + Heading: "Assertion or Panic detected during tree construction", + Message: formatter.F( + `Ginkgo detected a panic while constructing the spec tree. +You may be trying to make an assertion in the body of a container node +(i.e. {{bold}}Describe{{/}}, {{bold}}Context{{/}}, or {{bold}}When{{/}}). + +Please ensure all assertions are inside leaf nodes such as {{bold}}BeforeEach{{/}}, +{{bold}}It{{/}}, etc. + +{{bold}}Here's the content of the panic that was caught:{{/}} +%v`, caughtPanic), + CodeLocation: cl, + DocLink: "no-assertions-in-container-nodes", + } +} + +func (g ginkgoErrors) SuiteNodeInNestedContext(nodeType NodeType, cl CodeLocation) error { + docLink := "suite-setup-and-cleanup-beforesuite-and-aftersuite" + if nodeType.Is(NodeTypeReportBeforeSuite | NodeTypeReportAfterSuite) { + docLink = "reporting-nodes---reportbeforesuite-and-reportaftersuite" + } + + return GinkgoError{ + Heading: "Ginkgo detected an issue with your spec structure", + Message: formatter.F( + `It looks like you are trying to add a {{bold}}[%s]{{/}} node within a container node. + +{{bold}}%s{{/}} can only be called at the top level.`, nodeType, nodeType), + CodeLocation: cl, + DocLink: docLink, + } +} + +func (g ginkgoErrors) SuiteNodeDuringRunPhase(nodeType NodeType, cl CodeLocation) error { + docLink := "suite-setup-and-cleanup-beforesuite-and-aftersuite" + if nodeType.Is(NodeTypeReportBeforeSuite | NodeTypeReportAfterSuite) { + docLink = "reporting-nodes---reportbeforesuite-and-reportaftersuite" + } + + return GinkgoError{ + Heading: "Ginkgo detected an issue with your spec structure", + Message: formatter.F( + `It looks like you are trying to add a {{bold}}[%s]{{/}} node within a leaf node after the spec started running. + +{{bold}}%s{{/}} can only be called at the top level.`, nodeType, nodeType), + CodeLocation: cl, + DocLink: docLink, + } +} + +func (g ginkgoErrors) MultipleBeforeSuiteNodes(nodeType NodeType, cl CodeLocation, earlierNodeType NodeType, earlierCodeLocation CodeLocation) error { + return ginkgoErrorMultipleSuiteNodes("setup", nodeType, cl, earlierNodeType, earlierCodeLocation) +} + +func (g ginkgoErrors) MultipleAfterSuiteNodes(nodeType NodeType, cl CodeLocation, earlierNodeType NodeType, earlierCodeLocation CodeLocation) error { + return ginkgoErrorMultipleSuiteNodes("teardown", nodeType, cl, earlierNodeType, earlierCodeLocation) +} + +func ginkgoErrorMultipleSuiteNodes(setupOrTeardown string, nodeType NodeType, cl CodeLocation, earlierNodeType NodeType, earlierCodeLocation CodeLocation) error { + return GinkgoError{ + Heading: "Ginkgo detected an issue with your spec structure", + Message: formatter.F( + `It looks like you are trying to add a {{bold}}[%s]{{/}} node but +you already have a {{bold}}[%s]{{/}} node defined at: {{gray}}%s{{/}}. + +Ginkgo only allows you to define one suite %s node.`, nodeType, earlierNodeType, earlierCodeLocation, setupOrTeardown), + CodeLocation: cl, + DocLink: "suite-setup-and-cleanup-beforesuite-and-aftersuite", + } +} + +/* Decorator errors */ +func (g ginkgoErrors) InvalidDecoratorForNodeType(cl CodeLocation, nodeType NodeType, decorator string) error { + return GinkgoError{ + Heading: "Invalid Decorator", + Message: formatter.F(`[%s] node cannot be passed a(n) '%s' decorator`, nodeType, decorator), + CodeLocation: cl, + DocLink: "node-decorators-overview", + } +} + +func (g ginkgoErrors) InvalidDeclarationOfFocusedAndPending(cl CodeLocation, nodeType NodeType) error { + return GinkgoError{ + Heading: "Invalid Combination of Decorators: Focused and Pending", + Message: formatter.F(`[%s] node was decorated with both Focus and Pending. At most one is allowed.`, nodeType), + CodeLocation: cl, + DocLink: "node-decorators-overview", + } +} + +func (g ginkgoErrors) InvalidDeclarationOfFlakeAttemptsAndMustPassRepeatedly(cl CodeLocation, nodeType NodeType) error { + return GinkgoError{ + Heading: "Invalid Combination of Decorators: FlakeAttempts and MustPassRepeatedly", + Message: formatter.F(`[%s] node was decorated with both FlakeAttempts and MustPassRepeatedly. At most one is allowed.`, nodeType), + CodeLocation: cl, + DocLink: "node-decorators-overview", + } +} + +func (g ginkgoErrors) UnknownDecorator(cl CodeLocation, nodeType NodeType, decorator interface{}) error { + return GinkgoError{ + Heading: "Unknown Decorator", + Message: formatter.F(`[%s] node was passed an unknown decorator: '%#v'`, nodeType, decorator), + CodeLocation: cl, + DocLink: "node-decorators-overview", + } +} + +func (g ginkgoErrors) InvalidBodyTypeForContainer(t reflect.Type, cl CodeLocation, nodeType NodeType) error { + return GinkgoError{ + Heading: "Invalid Function", + Message: formatter.F(`[%s] node must be passed {{bold}}func(){{/}} - i.e. functions that take nothing and return nothing. You passed {{bold}}%s{{/}} instead.`, nodeType, t), + CodeLocation: cl, + DocLink: "node-decorators-overview", + } +} + +func (g ginkgoErrors) InvalidBodyType(t reflect.Type, cl CodeLocation, nodeType NodeType) error { + mustGet := "{{bold}}func(){{/}}, {{bold}}func(ctx SpecContext){{/}}, or {{bold}}func(ctx context.Context){{/}}" + if nodeType.Is(NodeTypeContainer) { + mustGet = "{{bold}}func(){{/}}" + } + return GinkgoError{ + Heading: "Invalid Function", + Message: formatter.F(`[%s] node must be passed `+mustGet+`. +You passed {{bold}}%s{{/}} instead.`, nodeType, t), + CodeLocation: cl, + DocLink: "node-decorators-overview", + } +} + +func (g ginkgoErrors) InvalidBodyTypeForSynchronizedBeforeSuiteProc1(t reflect.Type, cl CodeLocation) error { + mustGet := "{{bold}}func() []byte{{/}}, {{bold}}func(ctx SpecContext) []byte{{/}}, or {{bold}}func(ctx context.Context) []byte{{/}}, {{bold}}func(){{/}}, {{bold}}func(ctx SpecContext){{/}}, or {{bold}}func(ctx context.Context){{/}}" + return GinkgoError{ + Heading: "Invalid Function", + Message: formatter.F(`[SynchronizedBeforeSuite] node must be passed `+mustGet+` for its first function. +You passed {{bold}}%s{{/}} instead.`, t), + CodeLocation: cl, + DocLink: "node-decorators-overview", + } +} + +func (g ginkgoErrors) InvalidBodyTypeForSynchronizedBeforeSuiteAllProcs(t reflect.Type, cl CodeLocation) error { + mustGet := "{{bold}}func(){{/}}, {{bold}}func(ctx SpecContext){{/}}, or {{bold}}func(ctx context.Context){{/}}, {{bold}}func([]byte){{/}}, {{bold}}func(ctx SpecContext, []byte){{/}}, or {{bold}}func(ctx context.Context, []byte){{/}}" + return GinkgoError{ + Heading: "Invalid Function", + Message: formatter.F(`[SynchronizedBeforeSuite] node must be passed `+mustGet+` for its second function. +You passed {{bold}}%s{{/}} instead.`, t), + CodeLocation: cl, + DocLink: "node-decorators-overview", + } +} + +func (g ginkgoErrors) MultipleBodyFunctions(cl CodeLocation, nodeType NodeType) error { + return GinkgoError{ + Heading: "Multiple Functions", + Message: formatter.F(`[%s] node must be passed a single function - but more than one was passed in.`, nodeType), + CodeLocation: cl, + DocLink: "node-decorators-overview", + } +} + +func (g ginkgoErrors) MissingBodyFunction(cl CodeLocation, nodeType NodeType) error { + return GinkgoError{ + Heading: "Missing Functions", + Message: formatter.F(`[%s] node must be passed a single function - but none was passed in.`, nodeType), + CodeLocation: cl, + DocLink: "node-decorators-overview", + } +} + +func (g ginkgoErrors) InvalidTimeoutOrGracePeriodForNonContextNode(cl CodeLocation, nodeType NodeType) error { + return GinkgoError{ + Heading: "Invalid NodeTimeout SpecTimeout, or GracePeriod", + Message: formatter.F(`[%s] was passed NodeTimeout, SpecTimeout, or GracePeriod but does not have a callback that accepts a {{bold}}SpecContext{{/}} or {{bold}}context.Context{{/}}. You must accept a context to enable timeouts and grace periods`, nodeType), + CodeLocation: cl, + DocLink: "spec-timeouts-and-interruptible-nodes", + } +} + +func (g ginkgoErrors) InvalidTimeoutOrGracePeriodForNonContextCleanupNode(cl CodeLocation) error { + return GinkgoError{ + Heading: "Invalid NodeTimeout SpecTimeout, or GracePeriod", + Message: formatter.F(`[DeferCleanup] was passed NodeTimeout or GracePeriod but does not have a callback that accepts a {{bold}}SpecContext{{/}} or {{bold}}context.Context{{/}}. You must accept a context to enable timeouts and grace periods`), + CodeLocation: cl, + DocLink: "spec-timeouts-and-interruptible-nodes", + } +} + +/* Ordered Container errors */ +func (g ginkgoErrors) InvalidSerialNodeInNonSerialOrderedContainer(cl CodeLocation, nodeType NodeType) error { + return GinkgoError{ + Heading: "Invalid Serial Node in Non-Serial Ordered Container", + Message: formatter.F(`[%s] node was decorated with Serial but occurs in an Ordered container that is not marked Serial. Move the Serial decorator to the outer-most Ordered container to mark all ordered specs within the container as serial.`, nodeType), + CodeLocation: cl, + DocLink: "node-decorators-overview", + } +} + +func (g ginkgoErrors) SetupNodeNotInOrderedContainer(cl CodeLocation, nodeType NodeType) error { + return GinkgoError{ + Heading: "Setup Node not in Ordered Container", + Message: fmt.Sprintf("[%s] setup nodes must appear inside an Ordered container. They cannot be nested within other containers, even containers in an ordered container.", nodeType), + CodeLocation: cl, + DocLink: "ordered-containers", + } +} + +func (g ginkgoErrors) InvalidContinueOnFailureDecoration(cl CodeLocation) error { + return GinkgoError{ + Heading: "ContinueOnFailure not decorating an outermost Ordered Container", + Message: "ContinueOnFailure can only decorate an Ordered container, and this Ordered container must be the outermost Ordered container.", + CodeLocation: cl, + DocLink: "ordered-containers", + } +} + +/* DeferCleanup errors */ +func (g ginkgoErrors) DeferCleanupInvalidFunction(cl CodeLocation) error { + return GinkgoError{ + Heading: "DeferCleanup requires a valid function", + Message: "You must pass DeferCleanup a function to invoke. This function must return zero or one values - if it does return, it must return an error. The function can take arbitrarily many arguments and you should provide these to DeferCleanup to pass along to the function.", + CodeLocation: cl, + DocLink: "cleaning-up-our-cleanup-code-defercleanup", + } +} + +func (g ginkgoErrors) PushingCleanupNodeDuringTreeConstruction(cl CodeLocation) error { + return GinkgoError{ + Heading: "DeferCleanup must be called inside a setup or subject node", + Message: "You must call DeferCleanup inside a setup node (e.g. BeforeEach, BeforeSuite, AfterAll...) or a subject node (i.e. It). You can't call DeferCleanup at the top-level or in a container node - use the After* family of setup nodes instead.", + CodeLocation: cl, + DocLink: "cleaning-up-our-cleanup-code-defercleanup", + } +} + +func (g ginkgoErrors) PushingCleanupInReportingNode(cl CodeLocation, nodeType NodeType) error { + return GinkgoError{ + Heading: fmt.Sprintf("DeferCleanup cannot be called in %s", nodeType), + Message: "Please inline your cleanup code - Ginkgo won't run cleanup code after a Reporting node.", + CodeLocation: cl, + DocLink: "cleaning-up-our-cleanup-code-defercleanup", + } +} + +func (g ginkgoErrors) PushingCleanupInCleanupNode(cl CodeLocation) error { + return GinkgoError{ + Heading: "DeferCleanup cannot be called in a DeferCleanup callback", + Message: "Please inline your cleanup code - Ginkgo doesn't let you call DeferCleanup from within DeferCleanup", + CodeLocation: cl, + DocLink: "cleaning-up-our-cleanup-code-defercleanup", + } +} + +/* ReportEntry errors */ +func (g ginkgoErrors) TooManyReportEntryValues(cl CodeLocation, arg interface{}) error { + return GinkgoError{ + Heading: "Too Many ReportEntry Values", + Message: formatter.F(`{{bold}}AddGinkgoReport{{/}} can only be given one value. Got unexpected value: %#v`, arg), + CodeLocation: cl, + DocLink: "attaching-data-to-reports", + } +} + +func (g ginkgoErrors) AddReportEntryNotDuringRunPhase(cl CodeLocation) error { + return GinkgoError{ + Heading: "Ginkgo detected an issue with your spec structure", + Message: formatter.F(`It looks like you are calling {{bold}}AddGinkgoReport{{/}} outside of a running spec. Make sure you call {{bold}}AddGinkgoReport{{/}} inside a runnable node such as It or BeforeEach and not inside the body of a container such as Describe or Context.`), + CodeLocation: cl, + DocLink: "attaching-data-to-reports", + } +} + +/* By errors */ +func (g ginkgoErrors) ByNotDuringRunPhase(cl CodeLocation) error { + return GinkgoError{ + Heading: "Ginkgo detected an issue with your spec structure", + Message: formatter.F(`It looks like you are calling {{bold}}By{{/}} outside of a running spec. Make sure you call {{bold}}By{{/}} inside a runnable node such as It or BeforeEach and not inside the body of a container such as Describe or Context.`), + CodeLocation: cl, + DocLink: "documenting-complex-specs-by", + } +} + +/* FileFilter and SkipFilter errors */ +func (g ginkgoErrors) InvalidFileFilter(filter string) error { + return GinkgoError{ + Heading: "Invalid File Filter", + Message: fmt.Sprintf(`The provided file filter: "%s" is invalid. File filters must have the format "file", "file:lines" where "file" is a regular expression that will match against the file path and lines is a comma-separated list of integers (e.g. file:1,5,7) or line-ranges (e.g. file:1-3,5-9) or both (e.g. file:1,5-9)`, filter), + DocLink: "filtering-specs", + } +} + +func (g ginkgoErrors) InvalidFileFilterRegularExpression(filter string, err error) error { + return GinkgoError{ + Heading: "Invalid File Filter Regular Expression", + Message: fmt.Sprintf(`The provided file filter: "%s" included an invalid regular expression. regexp.Compile error: %s`, filter, err), + DocLink: "filtering-specs", + } +} + +/* Label Errors */ +func (g ginkgoErrors) SyntaxErrorParsingLabelFilter(input string, location int, error string) error { + var message string + if location >= 0 { + for i, r := range input { + if i == location { + message += "{{red}}{{bold}}{{underline}}" + } + message += string(r) + if i == location { + message += "{{/}}" + } + } + } else { + message = input + } + message += "\n" + error + return GinkgoError{ + Heading: "Syntax Error Parsing Label Filter", + Message: message, + DocLink: "spec-labels", + } +} + +func (g ginkgoErrors) InvalidLabel(label string, cl CodeLocation) error { + return GinkgoError{ + Heading: "Invalid Label", + Message: fmt.Sprintf("'%s' is an invalid label. Labels cannot contain of the following characters: '&|!,()/'", label), + CodeLocation: cl, + DocLink: "spec-labels", + } +} + +func (g ginkgoErrors) InvalidEmptyLabel(cl CodeLocation) error { + return GinkgoError{ + Heading: "Invalid Empty Label", + Message: "Labels cannot be empty", + CodeLocation: cl, + DocLink: "spec-labels", + } +} + +/* Table errors */ +func (g ginkgoErrors) MultipleEntryBodyFunctionsForTable(cl CodeLocation) error { + return GinkgoError{ + Heading: "DescribeTable passed multiple functions", + Message: "It looks like you are passing multiple functions into DescribeTable. Only one function can be passed in. This function will be called for each Entry in the table.", + CodeLocation: cl, + DocLink: "table-specs", + } +} + +func (g ginkgoErrors) InvalidEntryDescription(cl CodeLocation) error { + return GinkgoError{ + Heading: "Invalid Entry description", + Message: "Entry description functions must be a string, a function that accepts the entry parameters and returns a string, or nil.", + CodeLocation: cl, + DocLink: "table-specs", + } +} + +func (g ginkgoErrors) MissingParametersForTableFunction(cl CodeLocation) error { + return GinkgoError{ + Heading: fmt.Sprintf("No parameters have been passed to the Table Function"), + Message: fmt.Sprintf("The Table Function expected at least 1 parameter"), + CodeLocation: cl, + DocLink: "table-specs", + } +} + +func (g ginkgoErrors) IncorrectParameterTypeForTable(i int, name string, cl CodeLocation) error { + return GinkgoError{ + Heading: "DescribeTable passed incorrect parameter type", + Message: fmt.Sprintf("Parameter #%d passed to DescribeTable is of incorrect type <%s>", i, name), + CodeLocation: cl, + DocLink: "table-specs", + } +} + +func (g ginkgoErrors) TooFewParametersToTableFunction(expected, actual int, kind string, cl CodeLocation) error { + return GinkgoError{ + Heading: fmt.Sprintf("Too few parameters passed in to %s", kind), + Message: fmt.Sprintf("The %s expected %d parameters but you passed in %d", kind, expected, actual), + CodeLocation: cl, + DocLink: "table-specs", + } +} + +func (g ginkgoErrors) TooManyParametersToTableFunction(expected, actual int, kind string, cl CodeLocation) error { + return GinkgoError{ + Heading: fmt.Sprintf("Too many parameters passed in to %s", kind), + Message: fmt.Sprintf("The %s expected %d parameters but you passed in %d", kind, expected, actual), + CodeLocation: cl, + DocLink: "table-specs", + } +} + +func (g ginkgoErrors) IncorrectParameterTypeToTableFunction(i int, expected, actual reflect.Type, kind string, cl CodeLocation) error { + return GinkgoError{ + Heading: fmt.Sprintf("Incorrect parameters type passed to %s", kind), + Message: fmt.Sprintf("The %s expected parameter #%d to be of type <%s> but you passed in <%s>", kind, i, expected, actual), + CodeLocation: cl, + DocLink: "table-specs", + } +} + +func (g ginkgoErrors) IncorrectVariadicParameterTypeToTableFunction(expected, actual reflect.Type, kind string, cl CodeLocation) error { + return GinkgoError{ + Heading: fmt.Sprintf("Incorrect parameters type passed to %s", kind), + Message: fmt.Sprintf("The %s expected its variadic parameters to be of type <%s> but you passed in <%s>", kind, expected, actual), + CodeLocation: cl, + DocLink: "table-specs", + } +} + +/* Parallel Synchronization errors */ + +func (g ginkgoErrors) AggregatedReportUnavailableDueToNodeDisappearing() error { + return GinkgoError{ + Heading: "Test Report unavailable because a Ginkgo parallel process disappeared", + Message: "The aggregated report could not be fetched for a ReportAfterSuite node. A Ginkgo parallel process disappeared before it could finish reporting.", + } +} + +func (g ginkgoErrors) SynchronizedBeforeSuiteFailedOnProc1() error { + return GinkgoError{ + Heading: "SynchronizedBeforeSuite failed on Ginkgo parallel process #1", + Message: "The first SynchronizedBeforeSuite function running on Ginkgo parallel process #1 failed. This suite will now abort.", + } +} + +func (g ginkgoErrors) SynchronizedBeforeSuiteDisappearedOnProc1() error { + return GinkgoError{ + Heading: "Process #1 disappeared before SynchronizedBeforeSuite could report back", + Message: "Ginkgo parallel process #1 disappeared before the first SynchronizedBeforeSuite function completed. This suite will now abort.", + } +} + +/* Configuration errors */ + +func (g ginkgoErrors) UnknownTypePassedToRunSpecs(value interface{}) error { + return GinkgoError{ + Heading: "Unknown Type passed to RunSpecs", + Message: fmt.Sprintf("RunSpecs() accepts labels, and configuration of type types.SuiteConfig and/or types.ReporterConfig.\n You passed in: %v", value), + } +} + +var sharedParallelErrorMessage = "It looks like you are trying to run specs in parallel with go test.\nThis is unsupported and you should use the ginkgo CLI instead." + +func (g ginkgoErrors) InvalidParallelTotalConfiguration() error { + return GinkgoError{ + Heading: "-ginkgo.parallel.total must be >= 1", + Message: sharedParallelErrorMessage, + DocLink: "spec-parallelization", + } +} + +func (g ginkgoErrors) InvalidParallelProcessConfiguration() error { + return GinkgoError{ + Heading: "-ginkgo.parallel.process is one-indexed and must be <= ginkgo.parallel.total", + Message: sharedParallelErrorMessage, + DocLink: "spec-parallelization", + } +} + +func (g ginkgoErrors) MissingParallelHostConfiguration() error { + return GinkgoError{ + Heading: "-ginkgo.parallel.host is missing", + Message: sharedParallelErrorMessage, + DocLink: "spec-parallelization", + } +} + +func (g ginkgoErrors) UnreachableParallelHost(host string) error { + return GinkgoError{ + Heading: "Could not reach ginkgo.parallel.host:" + host, + Message: sharedParallelErrorMessage, + DocLink: "spec-parallelization", + } +} + +func (g ginkgoErrors) DryRunInParallelConfiguration() error { + return GinkgoError{ + Heading: "Ginkgo only performs -dryRun in serial mode.", + Message: "Please try running ginkgo -dryRun again, but without -p or -procs to ensure the suite is running in series.", + } +} + +func (g ginkgoErrors) GracePeriodCannotBeZero() error { + return GinkgoError{ + Heading: "Ginkgo requires a positive --grace-period.", + Message: "Please set --grace-period to a positive duration. The default is 30s.", + } +} + +func (g ginkgoErrors) ConflictingVerbosityConfiguration() error { + return GinkgoError{ + Heading: "Conflicting reporter verbosity settings.", + Message: "You can't set more than one of -v, -vv and --succinct. Please pick one!", + } +} + +func (g ginkgoErrors) InvalidOutputInterceptorModeConfiguration(value string) error { + return GinkgoError{ + Heading: fmt.Sprintf("Invalid value '%s' for --output-interceptor-mode.", value), + Message: "You must choose one of 'dup', 'swap', or 'none'.", + } +} + +func (g ginkgoErrors) InvalidGoFlagCount() error { + return GinkgoError{ + Heading: "Use of go test -count", + Message: "Ginkgo does not support using go test -count to rerun suites. Only -count=1 is allowed. To repeat suite runs, please use the ginkgo cli and `ginkgo -until-it-fails` or `ginkgo -repeat=N`.", + } +} + +func (g ginkgoErrors) InvalidGoFlagParallel() error { + return GinkgoError{ + Heading: "Use of go test -parallel", + Message: "Go test's implementation of parallelization does not actually parallelize Ginkgo specs. Please use the ginkgo cli and `ginkgo -p` or `ginkgo -procs=N` instead.", + } +} + +func (g ginkgoErrors) BothRepeatAndUntilItFails() error { + return GinkgoError{ + Heading: "--repeat and --until-it-fails are both set", + Message: "--until-it-fails directs Ginkgo to rerun specs indefinitely until they fail. --repeat directs Ginkgo to rerun specs a set number of times. You can't set both... which would you like?", + } +} + +/* Stack-Trace parsing errors */ + +func (g ginkgoErrors) FailedToParseStackTrace(message string) error { + return GinkgoError{ + Heading: "Failed to Parse Stack Trace", + Message: message, + } +} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/file_filter.go b/vendor/github.com/onsi/ginkgo/v2/types/file_filter.go new file mode 100644 index 000000000..cc21df71e --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/types/file_filter.go @@ -0,0 +1,106 @@ +package types + +import ( + "regexp" + "strconv" + "strings" +) + +func ParseFileFilters(filters []string) (FileFilters, error) { + ffs := FileFilters{} + for _, filter := range filters { + ff := FileFilter{} + if filter == "" { + return nil, GinkgoErrors.InvalidFileFilter(filter) + } + components := strings.Split(filter, ":") + if !(len(components) == 1 || len(components) == 2) { + return nil, GinkgoErrors.InvalidFileFilter(filter) + } + + var err error + ff.Filename, err = regexp.Compile(components[0]) + if err != nil { + return nil, err + } + if len(components) == 2 { + lineFilters := strings.Split(components[1], ",") + for _, lineFilter := range lineFilters { + components := strings.Split(lineFilter, "-") + if len(components) == 1 { + line, err := strconv.Atoi(strings.TrimSpace(components[0])) + if err != nil { + return nil, GinkgoErrors.InvalidFileFilter(filter) + } + ff.LineFilters = append(ff.LineFilters, LineFilter{line, line + 1}) + } else if len(components) == 2 { + line1, err := strconv.Atoi(strings.TrimSpace(components[0])) + if err != nil { + return nil, GinkgoErrors.InvalidFileFilter(filter) + } + line2, err := strconv.Atoi(strings.TrimSpace(components[1])) + if err != nil { + return nil, GinkgoErrors.InvalidFileFilter(filter) + } + ff.LineFilters = append(ff.LineFilters, LineFilter{line1, line2}) + } else { + return nil, GinkgoErrors.InvalidFileFilter(filter) + } + } + } + ffs = append(ffs, ff) + } + return ffs, nil +} + +type FileFilter struct { + Filename *regexp.Regexp + LineFilters LineFilters +} + +func (f FileFilter) Matches(locations []CodeLocation) bool { + for _, location := range locations { + if f.Filename.MatchString(location.FileName) && + f.LineFilters.Matches(location.LineNumber) { + return true + } + + } + return false +} + +type FileFilters []FileFilter + +func (ffs FileFilters) Matches(locations []CodeLocation) bool { + for _, ff := range ffs { + if ff.Matches(locations) { + return true + } + } + + return false +} + +type LineFilter struct { + Min int + Max int +} + +func (lf LineFilter) Matches(line int) bool { + return lf.Min <= line && line < lf.Max +} + +type LineFilters []LineFilter + +func (lfs LineFilters) Matches(line int) bool { + if len(lfs) == 0 { + return true + } + + for _, lf := range lfs { + if lf.Matches(line) { + return true + } + } + return false +} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/flags.go b/vendor/github.com/onsi/ginkgo/v2/types/flags.go new file mode 100644 index 000000000..9186ae873 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/types/flags.go @@ -0,0 +1,489 @@ +package types + +import ( + "flag" + "fmt" + "io" + "reflect" + "strings" + "time" + + "github.com/onsi/ginkgo/v2/formatter" +) + +type GinkgoFlag struct { + Name string + KeyPath string + SectionKey string + + Usage string + UsageArgument string + UsageDefaultValue string + + DeprecatedName string + DeprecatedDocLink string + DeprecatedVersion string + + ExportAs string +} + +type GinkgoFlags []GinkgoFlag + +func (f GinkgoFlags) CopyAppend(flags ...GinkgoFlag) GinkgoFlags { + out := GinkgoFlags{} + out = append(out, f...) + out = append(out, flags...) + return out +} + +func (f GinkgoFlags) WithPrefix(prefix string) GinkgoFlags { + if prefix == "" { + return f + } + out := GinkgoFlags{} + for _, flag := range f { + if flag.Name != "" { + flag.Name = prefix + "." + flag.Name + } + if flag.DeprecatedName != "" { + flag.DeprecatedName = prefix + "." + flag.DeprecatedName + } + if flag.ExportAs != "" { + flag.ExportAs = prefix + "." + flag.ExportAs + } + out = append(out, flag) + } + return out +} + +func (f GinkgoFlags) SubsetWithNames(names ...string) GinkgoFlags { + out := GinkgoFlags{} + for _, flag := range f { + for _, name := range names { + if flag.Name == name { + out = append(out, flag) + break + } + } + } + return out +} + +type GinkgoFlagSection struct { + Key string + Style string + Succinct bool + Heading string + Description string +} + +type GinkgoFlagSections []GinkgoFlagSection + +func (gfs GinkgoFlagSections) Lookup(key string) (GinkgoFlagSection, bool) { + for _, section := range gfs { + if section.Key == key { + return section, true + } + } + + return GinkgoFlagSection{}, false +} + +type GinkgoFlagSet struct { + flags GinkgoFlags + bindings interface{} + + sections GinkgoFlagSections + extraGoFlagsSection GinkgoFlagSection + + flagSet *flag.FlagSet +} + +// Call NewGinkgoFlagSet to create GinkgoFlagSet that creates and binds to it's own *flag.FlagSet +func NewGinkgoFlagSet(flags GinkgoFlags, bindings interface{}, sections GinkgoFlagSections) (GinkgoFlagSet, error) { + return bindFlagSet(GinkgoFlagSet{ + flags: flags, + bindings: bindings, + sections: sections, + }, nil) +} + +// Call NewGinkgoFlagSet to create GinkgoFlagSet that extends an existing *flag.FlagSet +func NewAttachedGinkgoFlagSet(flagSet *flag.FlagSet, flags GinkgoFlags, bindings interface{}, sections GinkgoFlagSections, extraGoFlagsSection GinkgoFlagSection) (GinkgoFlagSet, error) { + return bindFlagSet(GinkgoFlagSet{ + flags: flags, + bindings: bindings, + sections: sections, + extraGoFlagsSection: extraGoFlagsSection, + }, flagSet) +} + +func bindFlagSet(f GinkgoFlagSet, flagSet *flag.FlagSet) (GinkgoFlagSet, error) { + if flagSet == nil { + f.flagSet = flag.NewFlagSet("", flag.ContinueOnError) + //suppress all output as Ginkgo is responsible for formatting usage + f.flagSet.SetOutput(io.Discard) + } else { + f.flagSet = flagSet + //we're piggybacking on an existing flagset (typically go test) so we have limited control + //on user feedback + f.flagSet.Usage = f.substituteUsage + } + + for _, flag := range f.flags { + name := flag.Name + + deprecatedUsage := "[DEPRECATED]" + deprecatedName := flag.DeprecatedName + if name != "" { + deprecatedUsage = fmt.Sprintf("[DEPRECATED] use --%s instead", name) + } else if flag.Usage != "" { + deprecatedUsage += " " + flag.Usage + } + + value, ok := valueAtKeyPath(f.bindings, flag.KeyPath) + if !ok { + return GinkgoFlagSet{}, fmt.Errorf("could not load KeyPath: %s", flag.KeyPath) + } + + iface, addr := value.Interface(), value.Addr().Interface() + + switch value.Type() { + case reflect.TypeOf(string("")): + if name != "" { + f.flagSet.StringVar(addr.(*string), name, iface.(string), flag.Usage) + } + if deprecatedName != "" { + f.flagSet.StringVar(addr.(*string), deprecatedName, iface.(string), deprecatedUsage) + } + case reflect.TypeOf(int64(0)): + if name != "" { + f.flagSet.Int64Var(addr.(*int64), name, iface.(int64), flag.Usage) + } + if deprecatedName != "" { + f.flagSet.Int64Var(addr.(*int64), deprecatedName, iface.(int64), deprecatedUsage) + } + case reflect.TypeOf(float64(0)): + if name != "" { + f.flagSet.Float64Var(addr.(*float64), name, iface.(float64), flag.Usage) + } + if deprecatedName != "" { + f.flagSet.Float64Var(addr.(*float64), deprecatedName, iface.(float64), deprecatedUsage) + } + case reflect.TypeOf(int(0)): + if name != "" { + f.flagSet.IntVar(addr.(*int), name, iface.(int), flag.Usage) + } + if deprecatedName != "" { + f.flagSet.IntVar(addr.(*int), deprecatedName, iface.(int), deprecatedUsage) + } + case reflect.TypeOf(bool(true)): + if name != "" { + f.flagSet.BoolVar(addr.(*bool), name, iface.(bool), flag.Usage) + } + if deprecatedName != "" { + f.flagSet.BoolVar(addr.(*bool), deprecatedName, iface.(bool), deprecatedUsage) + } + case reflect.TypeOf(time.Duration(0)): + if name != "" { + f.flagSet.DurationVar(addr.(*time.Duration), name, iface.(time.Duration), flag.Usage) + } + if deprecatedName != "" { + f.flagSet.DurationVar(addr.(*time.Duration), deprecatedName, iface.(time.Duration), deprecatedUsage) + } + + case reflect.TypeOf([]string{}): + if name != "" { + f.flagSet.Var(stringSliceVar{value}, name, flag.Usage) + } + if deprecatedName != "" { + f.flagSet.Var(stringSliceVar{value}, deprecatedName, deprecatedUsage) + } + default: + return GinkgoFlagSet{}, fmt.Errorf("unsupported type %T", iface) + } + } + + return f, nil +} + +func (f GinkgoFlagSet) IsZero() bool { + return f.flagSet == nil +} + +func (f GinkgoFlagSet) WasSet(name string) bool { + found := false + f.flagSet.Visit(func(f *flag.Flag) { + if f.Name == name { + found = true + } + }) + + return found +} + +func (f GinkgoFlagSet) Lookup(name string) *flag.Flag { + return f.flagSet.Lookup(name) +} + +func (f GinkgoFlagSet) Parse(args []string) ([]string, error) { + if f.IsZero() { + return args, nil + } + err := f.flagSet.Parse(args) + if err != nil { + return []string{}, err + } + return f.flagSet.Args(), nil +} + +func (f GinkgoFlagSet) ValidateDeprecations(deprecationTracker *DeprecationTracker) { + if f.IsZero() { + return + } + f.flagSet.Visit(func(flag *flag.Flag) { + for _, ginkgoFlag := range f.flags { + if ginkgoFlag.DeprecatedName != "" && strings.HasSuffix(flag.Name, ginkgoFlag.DeprecatedName) { + message := fmt.Sprintf("--%s is deprecated", ginkgoFlag.DeprecatedName) + if ginkgoFlag.Name != "" { + message = fmt.Sprintf("--%s is deprecated, use --%s instead", ginkgoFlag.DeprecatedName, ginkgoFlag.Name) + } else if ginkgoFlag.Usage != "" { + message += " " + ginkgoFlag.Usage + } + + deprecationTracker.TrackDeprecation(Deprecation{ + Message: message, + DocLink: ginkgoFlag.DeprecatedDocLink, + Version: ginkgoFlag.DeprecatedVersion, + }) + } + } + }) +} + +func (f GinkgoFlagSet) Usage() string { + if f.IsZero() { + return "" + } + groupedFlags := map[GinkgoFlagSection]GinkgoFlags{} + ungroupedFlags := GinkgoFlags{} + managedFlags := map[string]bool{} + extraGoFlags := []*flag.Flag{} + + for _, flag := range f.flags { + managedFlags[flag.Name] = true + managedFlags[flag.DeprecatedName] = true + + if flag.Name == "" { + continue + } + + section, ok := f.sections.Lookup(flag.SectionKey) + if ok { + groupedFlags[section] = append(groupedFlags[section], flag) + } else { + ungroupedFlags = append(ungroupedFlags, flag) + } + } + + f.flagSet.VisitAll(func(flag *flag.Flag) { + if !managedFlags[flag.Name] { + extraGoFlags = append(extraGoFlags, flag) + } + }) + + out := "" + for _, section := range f.sections { + flags := groupedFlags[section] + if len(flags) == 0 { + continue + } + out += f.usageForSection(section) + if section.Succinct { + succinctFlags := []string{} + for _, flag := range flags { + if flag.Name != "" { + succinctFlags = append(succinctFlags, fmt.Sprintf("--%s", flag.Name)) + } + } + out += formatter.Fiw(1, formatter.COLS, section.Style+strings.Join(succinctFlags, ", ")+"{{/}}\n") + } else { + for _, flag := range flags { + out += f.usageForFlag(flag, section.Style) + } + } + out += "\n" + } + if len(ungroupedFlags) > 0 { + for _, flag := range ungroupedFlags { + out += f.usageForFlag(flag, "") + } + out += "\n" + } + if len(extraGoFlags) > 0 { + out += f.usageForSection(f.extraGoFlagsSection) + for _, goFlag := range extraGoFlags { + out += f.usageForGoFlag(goFlag) + } + } + + return out +} + +func (f GinkgoFlagSet) substituteUsage() { + fmt.Fprintln(f.flagSet.Output(), f.Usage()) +} + +func valueAtKeyPath(root interface{}, keyPath string) (reflect.Value, bool) { + if len(keyPath) == 0 { + return reflect.Value{}, false + } + + val := reflect.ValueOf(root) + components := strings.Split(keyPath, ".") + for _, component := range components { + val = reflect.Indirect(val) + switch val.Kind() { + case reflect.Map: + val = val.MapIndex(reflect.ValueOf(component)) + if val.Kind() == reflect.Interface { + val = reflect.ValueOf(val.Interface()) + } + case reflect.Struct: + val = val.FieldByName(component) + default: + return reflect.Value{}, false + } + if (val == reflect.Value{}) { + return reflect.Value{}, false + } + } + + return val, true +} + +func (f GinkgoFlagSet) usageForSection(section GinkgoFlagSection) string { + out := formatter.F(section.Style + "{{bold}}{{underline}}" + section.Heading + "{{/}}\n") + if section.Description != "" { + out += formatter.Fiw(0, formatter.COLS, section.Description+"\n") + } + return out +} + +func (f GinkgoFlagSet) usageForFlag(flag GinkgoFlag, style string) string { + argument := flag.UsageArgument + defValue := flag.UsageDefaultValue + if argument == "" { + value, _ := valueAtKeyPath(f.bindings, flag.KeyPath) + switch value.Type() { + case reflect.TypeOf(string("")): + argument = "string" + case reflect.TypeOf(int64(0)), reflect.TypeOf(int(0)): + argument = "int" + case reflect.TypeOf(time.Duration(0)): + argument = "duration" + case reflect.TypeOf(float64(0)): + argument = "float" + case reflect.TypeOf([]string{}): + argument = "string" + } + } + if argument != "" { + argument = "[" + argument + "] " + } + if defValue != "" { + defValue = fmt.Sprintf("(default: %s)", defValue) + } + hyphens := "--" + if len(flag.Name) == 1 { + hyphens = "-" + } + + out := formatter.Fi(1, style+"%s%s{{/}} %s{{gray}}%s{{/}}\n", hyphens, flag.Name, argument, defValue) + out += formatter.Fiw(2, formatter.COLS, "{{light-gray}}%s{{/}}\n", flag.Usage) + return out +} + +func (f GinkgoFlagSet) usageForGoFlag(goFlag *flag.Flag) string { + //Taken directly from the flag package + out := fmt.Sprintf(" -%s", goFlag.Name) + name, usage := flag.UnquoteUsage(goFlag) + if len(name) > 0 { + out += " " + name + } + if len(out) <= 4 { + out += "\t" + } else { + out += "\n \t" + } + out += strings.ReplaceAll(usage, "\n", "\n \t") + out += "\n" + return out +} + +type stringSliceVar struct { + slice reflect.Value +} + +func (ssv stringSliceVar) String() string { return "" } +func (ssv stringSliceVar) Set(s string) error { + ssv.slice.Set(reflect.AppendSlice(ssv.slice, reflect.ValueOf([]string{s}))) + return nil +} + +//given a set of GinkgoFlags and bindings, generate flag arguments suitable to be passed to an application with that set of flags configured. +func GenerateFlagArgs(flags GinkgoFlags, bindings interface{}) ([]string, error) { + result := []string{} + for _, flag := range flags { + name := flag.ExportAs + if name == "" { + name = flag.Name + } + if name == "" { + continue + } + + value, ok := valueAtKeyPath(bindings, flag.KeyPath) + if !ok { + return []string{}, fmt.Errorf("could not load KeyPath: %s", flag.KeyPath) + } + + iface := value.Interface() + switch value.Type() { + case reflect.TypeOf(string("")): + if iface.(string) != "" { + result = append(result, fmt.Sprintf("--%s=%s", name, iface)) + } + case reflect.TypeOf(int64(0)): + if iface.(int64) != 0 { + result = append(result, fmt.Sprintf("--%s=%d", name, iface)) + } + case reflect.TypeOf(float64(0)): + if iface.(float64) != 0 { + result = append(result, fmt.Sprintf("--%s=%f", name, iface)) + } + case reflect.TypeOf(int(0)): + if iface.(int) != 0 { + result = append(result, fmt.Sprintf("--%s=%d", name, iface)) + } + case reflect.TypeOf(bool(true)): + if iface.(bool) { + result = append(result, fmt.Sprintf("--%s", name)) + } + case reflect.TypeOf(time.Duration(0)): + if iface.(time.Duration) != time.Duration(0) { + result = append(result, fmt.Sprintf("--%s=%s", name, iface)) + } + + case reflect.TypeOf([]string{}): + strings := iface.([]string) + for _, s := range strings { + result = append(result, fmt.Sprintf("--%s=%s", name, s)) + } + default: + return []string{}, fmt.Errorf("unsupported type %T", iface) + } + } + + return result, nil +} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/label_filter.go b/vendor/github.com/onsi/ginkgo/v2/types/label_filter.go new file mode 100644 index 000000000..b0d3b651e --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/types/label_filter.go @@ -0,0 +1,358 @@ +package types + +import ( + "fmt" + "regexp" + "strings" +) + +var DEBUG_LABEL_FILTER_PARSING = false + +type LabelFilter func([]string) bool + +func matchLabelAction(label string) LabelFilter { + expected := strings.ToLower(label) + return func(labels []string) bool { + for i := range labels { + if strings.ToLower(labels[i]) == expected { + return true + } + } + return false + } +} + +func matchLabelRegexAction(regex *regexp.Regexp) LabelFilter { + return func(labels []string) bool { + for i := range labels { + if regex.MatchString(labels[i]) { + return true + } + } + return false + } +} + +func notAction(filter LabelFilter) LabelFilter { + return func(labels []string) bool { return !filter(labels) } +} + +func andAction(a, b LabelFilter) LabelFilter { + return func(labels []string) bool { return a(labels) && b(labels) } +} + +func orAction(a, b LabelFilter) LabelFilter { + return func(labels []string) bool { return a(labels) || b(labels) } +} + +type lfToken uint + +const ( + lfTokenInvalid lfToken = iota + + lfTokenRoot + lfTokenOpenGroup + lfTokenCloseGroup + lfTokenNot + lfTokenAnd + lfTokenOr + lfTokenRegexp + lfTokenLabel + lfTokenEOF +) + +func (l lfToken) Precedence() int { + switch l { + case lfTokenRoot, lfTokenOpenGroup: + return 0 + case lfTokenOr: + return 1 + case lfTokenAnd: + return 2 + case lfTokenNot: + return 3 + } + return -1 +} + +func (l lfToken) String() string { + switch l { + case lfTokenRoot: + return "ROOT" + case lfTokenOpenGroup: + return "(" + case lfTokenCloseGroup: + return ")" + case lfTokenNot: + return "!" + case lfTokenAnd: + return "&&" + case lfTokenOr: + return "||" + case lfTokenRegexp: + return "/regexp/" + case lfTokenLabel: + return "label" + case lfTokenEOF: + return "EOF" + } + return "INVALID" +} + +type treeNode struct { + token lfToken + location int + value string + + parent *treeNode + leftNode *treeNode + rightNode *treeNode +} + +func (tn *treeNode) setRightNode(node *treeNode) { + tn.rightNode = node + node.parent = tn +} + +func (tn *treeNode) setLeftNode(node *treeNode) { + tn.leftNode = node + node.parent = tn +} + +func (tn *treeNode) firstAncestorWithPrecedenceLEQ(precedence int) *treeNode { + if tn.token.Precedence() <= precedence { + return tn + } + return tn.parent.firstAncestorWithPrecedenceLEQ(precedence) +} + +func (tn *treeNode) firstUnmatchedOpenNode() *treeNode { + if tn.token == lfTokenOpenGroup { + return tn + } + if tn.parent == nil { + return nil + } + return tn.parent.firstUnmatchedOpenNode() +} + +func (tn *treeNode) constructLabelFilter(input string) (LabelFilter, error) { + switch tn.token { + case lfTokenOpenGroup: + return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.location, "Mismatched '(' - could not find matching ')'.") + case lfTokenLabel: + return matchLabelAction(tn.value), nil + case lfTokenRegexp: + re, err := regexp.Compile(tn.value) + if err != nil { + return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.location, fmt.Sprintf("RegExp compilation error: %s", err)) + } + return matchLabelRegexAction(re), nil + } + + if tn.rightNode == nil { + return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, -1, "Unexpected EOF.") + } + rightLF, err := tn.rightNode.constructLabelFilter(input) + if err != nil { + return nil, err + } + + switch tn.token { + case lfTokenRoot, lfTokenCloseGroup: + return rightLF, nil + case lfTokenNot: + return notAction(rightLF), nil + } + + if tn.leftNode == nil { + return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.location, fmt.Sprintf("Malformed tree - '%s' is missing left operand.", tn.token)) + } + leftLF, err := tn.leftNode.constructLabelFilter(input) + if err != nil { + return nil, err + } + + switch tn.token { + case lfTokenAnd: + return andAction(leftLF, rightLF), nil + case lfTokenOr: + return orAction(leftLF, rightLF), nil + } + + return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.location, fmt.Sprintf("Invalid token '%s'.", tn.token)) +} + +func (tn *treeNode) tokenString() string { + out := fmt.Sprintf("<%s", tn.token) + if tn.value != "" { + out += " | " + tn.value + } + out += ">" + return out +} + +func (tn *treeNode) toString(indent int) string { + out := tn.tokenString() + "\n" + if tn.leftNode != nil { + out += fmt.Sprintf("%s |_(L)_%s", strings.Repeat(" ", indent), tn.leftNode.toString(indent+1)) + } + if tn.rightNode != nil { + out += fmt.Sprintf("%s |_(R)_%s", strings.Repeat(" ", indent), tn.rightNode.toString(indent+1)) + } + return out +} + +func tokenize(input string) func() (*treeNode, error) { + runes, i := []rune(input), 0 + + peekIs := func(r rune) bool { + if i+1 < len(runes) { + return runes[i+1] == r + } + return false + } + + consumeUntil := func(cutset string) (string, int) { + j := i + for ; j < len(runes); j++ { + if strings.IndexRune(cutset, runes[j]) >= 0 { + break + } + } + return string(runes[i:j]), j - i + } + + return func() (*treeNode, error) { + for i < len(runes) && runes[i] == ' ' { + i += 1 + } + + if i >= len(runes) { + return &treeNode{token: lfTokenEOF}, nil + } + + node := &treeNode{location: i} + switch runes[i] { + case '&': + if !peekIs('&') { + return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i, "Invalid token '&'. Did you mean '&&'?") + } + i += 2 + node.token = lfTokenAnd + case '|': + if !peekIs('|') { + return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i, "Invalid token '|'. Did you mean '||'?") + } + i += 2 + node.token = lfTokenOr + case '!': + i += 1 + node.token = lfTokenNot + case ',': + i += 1 + node.token = lfTokenOr + case '(': + i += 1 + node.token = lfTokenOpenGroup + case ')': + i += 1 + node.token = lfTokenCloseGroup + case '/': + i += 1 + value, n := consumeUntil("/") + i += n + 1 + node.token, node.value = lfTokenRegexp, value + default: + value, n := consumeUntil("&|!,()/") + i += n + node.token, node.value = lfTokenLabel, strings.TrimSpace(value) + } + return node, nil + } +} + +func MustParseLabelFilter(input string) LabelFilter { + filter, err := ParseLabelFilter(input) + if err != nil { + panic(err) + } + return filter +} + +func ParseLabelFilter(input string) (LabelFilter, error) { + if DEBUG_LABEL_FILTER_PARSING { + fmt.Println("\n==============") + fmt.Println("Input: ", input) + fmt.Print("Tokens: ") + } + if input == "" { + return func(_ []string) bool { return true }, nil + } + nextToken := tokenize(input) + + root := &treeNode{token: lfTokenRoot} + current := root +LOOP: + for { + node, err := nextToken() + if err != nil { + return nil, err + } + + if DEBUG_LABEL_FILTER_PARSING { + fmt.Print(node.tokenString() + " ") + } + + switch node.token { + case lfTokenEOF: + break LOOP + case lfTokenLabel, lfTokenRegexp: + if current.rightNode != nil { + return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, "Found two adjacent labels. You need an operator between them.") + } + current.setRightNode(node) + case lfTokenNot, lfTokenOpenGroup: + if current.rightNode != nil { + return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, fmt.Sprintf("Invalid token '%s'.", node.token)) + } + current.setRightNode(node) + current = node + case lfTokenAnd, lfTokenOr: + if current.rightNode == nil { + return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, fmt.Sprintf("Operator '%s' missing left hand operand.", node.token)) + } + nodeToStealFrom := current.firstAncestorWithPrecedenceLEQ(node.token.Precedence()) + node.setLeftNode(nodeToStealFrom.rightNode) + nodeToStealFrom.setRightNode(node) + current = node + case lfTokenCloseGroup: + firstUnmatchedOpenNode := current.firstUnmatchedOpenNode() + if firstUnmatchedOpenNode == nil { + return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, "Mismatched ')' - could not find matching '('.") + } + if firstUnmatchedOpenNode == current && current.rightNode == nil { + return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, "Found empty '()' group.") + } + firstUnmatchedOpenNode.token = lfTokenCloseGroup //signify the group is now closed + current = firstUnmatchedOpenNode.parent + default: + return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, fmt.Sprintf("Unknown token '%s'.", node.token)) + } + } + if DEBUG_LABEL_FILTER_PARSING { + fmt.Printf("\n Tree:\n%s", root.toString(0)) + } + return root.constructLabelFilter(input) +} + +func ValidateAndCleanupLabel(label string, cl CodeLocation) (string, error) { + out := strings.TrimSpace(label) + if out == "" { + return "", GinkgoErrors.InvalidEmptyLabel(cl) + } + if strings.ContainsAny(out, "&|!,()/") { + return "", GinkgoErrors.InvalidLabel(label, cl) + } + return out, nil +} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/report_entry.go b/vendor/github.com/onsi/ginkgo/v2/types/report_entry.go new file mode 100644 index 000000000..7b1524b52 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/types/report_entry.go @@ -0,0 +1,190 @@ +package types + +import ( + "encoding/json" + "fmt" + "time" +) + +// ReportEntryValue wraps a report entry's value ensuring it can be encoded and decoded safely into reports +// and across the network connection when running in parallel +type ReportEntryValue struct { + raw interface{} //unexported to prevent gob from freaking out about unregistered structs + AsJSON string + Representation string +} + +func WrapEntryValue(value interface{}) ReportEntryValue { + return ReportEntryValue{ + raw: value, + } +} + +func (rev ReportEntryValue) GetRawValue() interface{} { + return rev.raw +} + +func (rev ReportEntryValue) String() string { + if rev.raw == nil { + return "" + } + if colorableStringer, ok := rev.raw.(ColorableStringer); ok { + return colorableStringer.ColorableString() + } + + if stringer, ok := rev.raw.(fmt.Stringer); ok { + return stringer.String() + } + if rev.Representation != "" { + return rev.Representation + } + return fmt.Sprintf("%+v", rev.raw) +} + +func (rev ReportEntryValue) MarshalJSON() ([]byte, error) { + //All this to capture the representation at encoding-time, not creating time + //This way users can Report on pointers and get their final values at reporting-time + out := struct { + AsJSON string + Representation string + }{ + Representation: rev.String(), + } + asJSON, err := json.Marshal(rev.raw) + if err != nil { + return nil, err + } + out.AsJSON = string(asJSON) + + return json.Marshal(out) +} + +func (rev *ReportEntryValue) UnmarshalJSON(data []byte) error { + in := struct { + AsJSON string + Representation string + }{} + err := json.Unmarshal(data, &in) + if err != nil { + return err + } + rev.AsJSON = in.AsJSON + rev.Representation = in.Representation + return json.Unmarshal([]byte(in.AsJSON), &(rev.raw)) +} + +func (rev ReportEntryValue) GobEncode() ([]byte, error) { + return rev.MarshalJSON() +} + +func (rev *ReportEntryValue) GobDecode(data []byte) error { + return rev.UnmarshalJSON(data) +} + +// ReportEntry captures information attached to `SpecReport` via `AddReportEntry` +type ReportEntry struct { + // Visibility captures the visibility policy for this ReportEntry + Visibility ReportEntryVisibility + // Location captures the location of the AddReportEntry call + Location CodeLocation + + Time time.Time //need this for backwards compatibility + TimelineLocation TimelineLocation + + // Name captures the name of this report + Name string + // Value captures the (optional) object passed into AddReportEntry - this can be + // anything the user wants. The value passed to AddReportEntry is wrapped in a ReportEntryValue to make + // encoding/decoding the value easier. To access the raw value call entry.GetRawValue() + Value ReportEntryValue +} + +// ColorableStringer is an interface that ReportEntry values can satisfy. If they do then ColorableString() is used to generate their representation. +type ColorableStringer interface { + ColorableString() string +} + +// StringRepresentation() returns the string representation of the value associated with the ReportEntry -- +// if value is nil, empty string is returned +// if value is a `ColorableStringer` then `Value.ColorableString()` is returned +// if value is a `fmt.Stringer` then `Value.String()` is returned +// otherwise the value is formatted with "%+v" +func (entry ReportEntry) StringRepresentation() string { + return entry.Value.String() +} + +// GetRawValue returns the Value object that was passed to AddReportEntry +// If called in-process this will be the same object that was passed into AddReportEntry. +// If used from a rehydrated JSON file _or_ in a ReportAfterSuite when running in parallel this will be +// a JSON-decoded {}interface. If you want to reconstitute your original object you can decode the entry.Value.AsJSON +// field yourself. +func (entry ReportEntry) GetRawValue() interface{} { + return entry.Value.GetRawValue() +} + +func (entry ReportEntry) GetTimelineLocation() TimelineLocation { + return entry.TimelineLocation +} + +type ReportEntries []ReportEntry + +func (re ReportEntries) HasVisibility(visibilities ...ReportEntryVisibility) bool { + for _, entry := range re { + if entry.Visibility.Is(visibilities...) { + return true + } + } + return false +} + +func (re ReportEntries) WithVisibility(visibilities ...ReportEntryVisibility) ReportEntries { + out := ReportEntries{} + + for _, entry := range re { + if entry.Visibility.Is(visibilities...) { + out = append(out, entry) + } + } + + return out +} + +// ReportEntryVisibility governs the visibility of ReportEntries in Ginkgo's console reporter +type ReportEntryVisibility uint + +const ( + // Always print out this ReportEntry + ReportEntryVisibilityAlways ReportEntryVisibility = iota + // Only print out this ReportEntry if the spec fails or if the test is run with -v + ReportEntryVisibilityFailureOrVerbose + // Never print out this ReportEntry (note that ReportEntrys are always encoded in machine readable reports (e.g. JSON, JUnit, etc.)) + ReportEntryVisibilityNever +) + +var revEnumSupport = NewEnumSupport(map[uint]string{ + uint(ReportEntryVisibilityAlways): "always", + uint(ReportEntryVisibilityFailureOrVerbose): "failure-or-verbose", + uint(ReportEntryVisibilityNever): "never", +}) + +func (rev ReportEntryVisibility) String() string { + return revEnumSupport.String(uint(rev)) +} +func (rev *ReportEntryVisibility) UnmarshalJSON(b []byte) error { + out, err := revEnumSupport.UnmarshJSON(b) + *rev = ReportEntryVisibility(out) + return err +} +func (rev ReportEntryVisibility) MarshalJSON() ([]byte, error) { + return revEnumSupport.MarshJSON(uint(rev)) +} + +func (v ReportEntryVisibility) Is(visibilities ...ReportEntryVisibility) bool { + for _, visibility := range visibilities { + if v == visibility { + return true + } + } + + return false +} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/types.go b/vendor/github.com/onsi/ginkgo/v2/types/types.go new file mode 100644 index 000000000..d048a8ada --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/types/types.go @@ -0,0 +1,916 @@ +package types + +import ( + "encoding/json" + "fmt" + "sort" + "strings" + "time" +) + +const GINKGO_FOCUS_EXIT_CODE = 197 +const GINKGO_TIME_FORMAT = "01/02/06 15:04:05.999" + +// Report captures information about a Ginkgo test run +type Report struct { + //SuitePath captures the absolute path to the test suite + SuitePath string + + //SuiteDescription captures the description string passed to the DSL's RunSpecs() function + SuiteDescription string + + //SuiteLabels captures any labels attached to the suite by the DSL's RunSpecs() function + SuiteLabels []string + + //SuiteSucceeded captures the success or failure status of the test run + //If true, the test run is considered successful. + //If false, the test run is considered unsuccessful + SuiteSucceeded bool + + //SuiteHasProgrammaticFocus captures whether the test suite has a test or set of tests that are programmatically focused + //(i.e an `FIt` or an `FDescribe` + SuiteHasProgrammaticFocus bool + + //SpecialSuiteFailureReasons may contain special failure reasons + //For example, a test suite might be considered "failed" even if none of the individual specs + //have a failure state. For example, if the user has configured --fail-on-pending the test suite + //will have failed if there are pending tests even though all non-pending tests may have passed. In such + //cases, Ginkgo populates SpecialSuiteFailureReasons with a clear message indicating the reason for the failure. + //SpecialSuiteFailureReasons is also populated if the test suite is interrupted by the user. + //Since multiple special failure reasons can occur, this field is a slice. + SpecialSuiteFailureReasons []string + + //PreRunStats contains a set of stats captured before the test run begins. This is primarily used + //by Ginkgo's reporter to tell the user how many specs are in the current suite (PreRunStats.TotalSpecs) + //and how many it intends to run (PreRunStats.SpecsThatWillRun) after applying any relevant focus or skip filters. + PreRunStats PreRunStats + + //StartTime and EndTime capture the start and end time of the test run + StartTime time.Time + EndTime time.Time + + //RunTime captures the duration of the test run + RunTime time.Duration + + //SuiteConfig captures the Ginkgo configuration governing this test run + //SuiteConfig includes information necessary for reproducing an identical test run, + //such as the random seed and any filters applied during the test run + SuiteConfig SuiteConfig + + //SpecReports is a list of all SpecReports generated by this test run + //It is empty when the SuiteReport is provided to ReportBeforeSuite + SpecReports SpecReports +} + +// PreRunStats contains a set of stats captured before the test run begins. This is primarily used +// by Ginkgo's reporter to tell the user how many specs are in the current suite (PreRunStats.TotalSpecs) +// and how many it intends to run (PreRunStats.SpecsThatWillRun) after applying any relevant focus or skip filters. +type PreRunStats struct { + TotalSpecs int + SpecsThatWillRun int +} + +// Add is used by Ginkgo's parallel aggregation mechanisms to combine test run reports form individual parallel processes +// to form a complete final report. +func (report Report) Add(other Report) Report { + report.SuiteSucceeded = report.SuiteSucceeded && other.SuiteSucceeded + + if other.StartTime.Before(report.StartTime) { + report.StartTime = other.StartTime + } + + if other.EndTime.After(report.EndTime) { + report.EndTime = other.EndTime + } + + specialSuiteFailureReasons := []string{} + reasonsLookup := map[string]bool{} + for _, reasons := range [][]string{report.SpecialSuiteFailureReasons, other.SpecialSuiteFailureReasons} { + for _, reason := range reasons { + if !reasonsLookup[reason] { + reasonsLookup[reason] = true + specialSuiteFailureReasons = append(specialSuiteFailureReasons, reason) + } + } + } + report.SpecialSuiteFailureReasons = specialSuiteFailureReasons + report.RunTime = report.EndTime.Sub(report.StartTime) + + reports := make(SpecReports, len(report.SpecReports)+len(other.SpecReports)) + for i := range report.SpecReports { + reports[i] = report.SpecReports[i] + } + offset := len(report.SpecReports) + for i := range other.SpecReports { + reports[i+offset] = other.SpecReports[i] + } + + report.SpecReports = reports + return report +} + +// SpecReport captures information about a Ginkgo spec. +type SpecReport struct { + // ContainerHierarchyTexts is a slice containing the text strings of + // all Describe/Context/When containers in this spec's hierarchy. + ContainerHierarchyTexts []string + + // ContainerHierarchyLocations is a slice containing the CodeLocations of + // all Describe/Context/When containers in this spec's hierarchy. + ContainerHierarchyLocations []CodeLocation + + // ContainerHierarchyLabels is a slice containing the labels of + // all Describe/Context/When containers in this spec's hierarchy + ContainerHierarchyLabels [][]string + + // LeafNodeType, LeadNodeLocation, LeafNodeLabels and LeafNodeText capture the NodeType, CodeLocation, and text + // of the Ginkgo node being tested (typically an NodeTypeIt node, though this can also be + // one of the NodeTypesForSuiteLevelNodes node types) + LeafNodeType NodeType + LeafNodeLocation CodeLocation + LeafNodeLabels []string + LeafNodeText string + + // State captures whether the spec has passed, failed, etc. + State SpecState + + // IsSerial captures whether the spec has the Serial decorator + IsSerial bool + + // IsInOrderedContainer captures whether the spec appears in an Ordered container + IsInOrderedContainer bool + + // StartTime and EndTime capture the start and end time of the spec + StartTime time.Time + EndTime time.Time + + // RunTime captures the duration of the spec + RunTime time.Duration + + // ParallelProcess captures the parallel process that this spec ran on + ParallelProcess int + + // RunningInParallel captures whether this spec is part of a suite that ran in parallel + RunningInParallel bool + + //Failure is populated if a spec has failed, panicked, been interrupted, or skipped by the user (e.g. calling Skip()) + //It includes detailed information about the Failure + Failure Failure + + // NumAttempts captures the number of times this Spec was run. + // Flakey specs can be retried with ginkgo --flake-attempts=N or the use of the FlakeAttempts decorator. + // Repeated specs can be retried with the use of the MustPassRepeatedly decorator + NumAttempts int + + // MaxFlakeAttempts captures whether the spec has been retried with ginkgo --flake-attempts=N or the use of the FlakeAttempts decorator. + MaxFlakeAttempts int + + // MaxMustPassRepeatedly captures whether the spec has the MustPassRepeatedly decorator + MaxMustPassRepeatedly int + + // CapturedGinkgoWriterOutput contains text printed to the GinkgoWriter + CapturedGinkgoWriterOutput string + + // CapturedStdOutErr contains text printed to stdout/stderr (when running in parallel) + // This is always empty when running in series or calling CurrentSpecReport() + // It is used internally by Ginkgo's reporter + CapturedStdOutErr string + + // ReportEntries contains any reports added via `AddReportEntry` + ReportEntries ReportEntries + + // ProgressReports contains any progress reports generated during this spec. These can either be manually triggered, or automatically generated by Ginkgo via the PollProgressAfter() decorator + ProgressReports []ProgressReport + + // AdditionalFailures contains any failures that occurred after the initial spec failure. These typically occur in cleanup nodes after the initial failure and are only emitted when running in verbose mode. + AdditionalFailures []AdditionalFailure + + // SpecEvents capture additional events that occur during the spec run + SpecEvents SpecEvents +} + +func (report SpecReport) MarshalJSON() ([]byte, error) { + //All this to avoid emitting an empty Failure struct in the JSON + out := struct { + ContainerHierarchyTexts []string + ContainerHierarchyLocations []CodeLocation + ContainerHierarchyLabels [][]string + LeafNodeType NodeType + LeafNodeLocation CodeLocation + LeafNodeLabels []string + LeafNodeText string + State SpecState + StartTime time.Time + EndTime time.Time + RunTime time.Duration + ParallelProcess int + Failure *Failure `json:",omitempty"` + NumAttempts int + MaxFlakeAttempts int + MaxMustPassRepeatedly int + CapturedGinkgoWriterOutput string `json:",omitempty"` + CapturedStdOutErr string `json:",omitempty"` + ReportEntries ReportEntries `json:",omitempty"` + ProgressReports []ProgressReport `json:",omitempty"` + AdditionalFailures []AdditionalFailure `json:",omitempty"` + SpecEvents SpecEvents `json:",omitempty"` + }{ + ContainerHierarchyTexts: report.ContainerHierarchyTexts, + ContainerHierarchyLocations: report.ContainerHierarchyLocations, + ContainerHierarchyLabels: report.ContainerHierarchyLabels, + LeafNodeType: report.LeafNodeType, + LeafNodeLocation: report.LeafNodeLocation, + LeafNodeLabels: report.LeafNodeLabels, + LeafNodeText: report.LeafNodeText, + State: report.State, + StartTime: report.StartTime, + EndTime: report.EndTime, + RunTime: report.RunTime, + ParallelProcess: report.ParallelProcess, + Failure: nil, + ReportEntries: nil, + NumAttempts: report.NumAttempts, + MaxFlakeAttempts: report.MaxFlakeAttempts, + MaxMustPassRepeatedly: report.MaxMustPassRepeatedly, + CapturedGinkgoWriterOutput: report.CapturedGinkgoWriterOutput, + CapturedStdOutErr: report.CapturedStdOutErr, + } + + if !report.Failure.IsZero() { + out.Failure = &(report.Failure) + } + if len(report.ReportEntries) > 0 { + out.ReportEntries = report.ReportEntries + } + if len(report.ProgressReports) > 0 { + out.ProgressReports = report.ProgressReports + } + if len(report.AdditionalFailures) > 0 { + out.AdditionalFailures = report.AdditionalFailures + } + if len(report.SpecEvents) > 0 { + out.SpecEvents = report.SpecEvents + } + + return json.Marshal(out) +} + +// CombinedOutput returns a single string representation of both CapturedStdOutErr and CapturedGinkgoWriterOutput +// Note that both are empty when using CurrentSpecReport() so CurrentSpecReport().CombinedOutput() will always be empty. +// CombinedOutput() is used internally by Ginkgo's reporter. +func (report SpecReport) CombinedOutput() string { + if report.CapturedStdOutErr == "" { + return report.CapturedGinkgoWriterOutput + } + if report.CapturedGinkgoWriterOutput == "" { + return report.CapturedStdOutErr + } + return report.CapturedStdOutErr + "\n" + report.CapturedGinkgoWriterOutput +} + +// Failed returns true if report.State is one of the SpecStateFailureStates +// (SpecStateFailed, SpecStatePanicked, SpecStateinterrupted, SpecStateAborted) +func (report SpecReport) Failed() bool { + return report.State.Is(SpecStateFailureStates) +} + +// FullText returns a concatenation of all the report.ContainerHierarchyTexts and report.LeafNodeText +func (report SpecReport) FullText() string { + texts := []string{} + texts = append(texts, report.ContainerHierarchyTexts...) + if report.LeafNodeText != "" { + texts = append(texts, report.LeafNodeText) + } + return strings.Join(texts, " ") +} + +// Labels returns a deduped set of all the spec's Labels. +func (report SpecReport) Labels() []string { + out := []string{} + seen := map[string]bool{} + for _, labels := range report.ContainerHierarchyLabels { + for _, label := range labels { + if !seen[label] { + seen[label] = true + out = append(out, label) + } + } + } + for _, label := range report.LeafNodeLabels { + if !seen[label] { + seen[label] = true + out = append(out, label) + } + } + + return out +} + +// MatchesLabelFilter returns true if the spec satisfies the passed in label filter query +func (report SpecReport) MatchesLabelFilter(query string) (bool, error) { + filter, err := ParseLabelFilter(query) + if err != nil { + return false, err + } + return filter(report.Labels()), nil +} + +// FileName() returns the name of the file containing the spec +func (report SpecReport) FileName() string { + return report.LeafNodeLocation.FileName +} + +// LineNumber() returns the line number of the leaf node +func (report SpecReport) LineNumber() int { + return report.LeafNodeLocation.LineNumber +} + +// FailureMessage() returns the failure message (or empty string if the test hasn't failed) +func (report SpecReport) FailureMessage() string { + return report.Failure.Message +} + +// FailureLocation() returns the location of the failure (or an empty CodeLocation if the test hasn't failed) +func (report SpecReport) FailureLocation() CodeLocation { + return report.Failure.Location +} + +// Timeline() returns a timeline view of the report +func (report SpecReport) Timeline() Timeline { + timeline := Timeline{} + if !report.Failure.IsZero() { + timeline = append(timeline, report.Failure) + if report.Failure.AdditionalFailure != nil { + timeline = append(timeline, *(report.Failure.AdditionalFailure)) + } + } + for _, additionalFailure := range report.AdditionalFailures { + timeline = append(timeline, additionalFailure) + } + for _, reportEntry := range report.ReportEntries { + timeline = append(timeline, reportEntry) + } + for _, progressReport := range report.ProgressReports { + timeline = append(timeline, progressReport) + } + for _, specEvent := range report.SpecEvents { + timeline = append(timeline, specEvent) + } + sort.Sort(timeline) + return timeline +} + +type SpecReports []SpecReport + +// WithLeafNodeType returns the subset of SpecReports with LeafNodeType matching one of the requested NodeTypes +func (reports SpecReports) WithLeafNodeType(nodeTypes NodeType) SpecReports { + count := 0 + for i := range reports { + if reports[i].LeafNodeType.Is(nodeTypes) { + count++ + } + } + + out := make(SpecReports, count) + j := 0 + for i := range reports { + if reports[i].LeafNodeType.Is(nodeTypes) { + out[j] = reports[i] + j++ + } + } + return out +} + +// WithState returns the subset of SpecReports with State matching one of the requested SpecStates +func (reports SpecReports) WithState(states SpecState) SpecReports { + count := 0 + for i := range reports { + if reports[i].State.Is(states) { + count++ + } + } + + out, j := make(SpecReports, count), 0 + for i := range reports { + if reports[i].State.Is(states) { + out[j] = reports[i] + j++ + } + } + return out +} + +// CountWithState returns the number of SpecReports with State matching one of the requested SpecStates +func (reports SpecReports) CountWithState(states SpecState) int { + n := 0 + for i := range reports { + if reports[i].State.Is(states) { + n += 1 + } + } + return n +} + +// If the Spec passes, CountOfFlakedSpecs returns the number of SpecReports that failed after multiple attempts. +func (reports SpecReports) CountOfFlakedSpecs() int { + n := 0 + for i := range reports { + if reports[i].MaxFlakeAttempts > 1 && reports[i].State.Is(SpecStatePassed) && reports[i].NumAttempts > 1 { + n += 1 + } + } + return n +} + +// If the Spec fails, CountOfRepeatedSpecs returns the number of SpecReports that passed after multiple attempts +func (reports SpecReports) CountOfRepeatedSpecs() int { + n := 0 + for i := range reports { + if reports[i].MaxMustPassRepeatedly > 1 && reports[i].State.Is(SpecStateFailureStates) && reports[i].NumAttempts > 1 { + n += 1 + } + } + return n +} + +// TimelineLocation captures the location of an event in the spec's timeline +type TimelineLocation struct { + //Offset is the offset (in bytes) of the event relative to the GinkgoWriter stream + Offset int `json:",omitempty"` + + //Order is the order of the event with respect to other events. The absolute value of Order + //is irrelevant. All that matters is that an event with a lower Order occurs before ane vent with a higher Order + Order int `json:",omitempty"` + + Time time.Time +} + +// TimelineEvent represent an event on the timeline +// consumers of Timeline will need to check the concrete type of each entry to determine how to handle it +type TimelineEvent interface { + GetTimelineLocation() TimelineLocation +} + +type Timeline []TimelineEvent + +func (t Timeline) Len() int { return len(t) } +func (t Timeline) Less(i, j int) bool { + return t[i].GetTimelineLocation().Order < t[j].GetTimelineLocation().Order +} +func (t Timeline) Swap(i, j int) { t[i], t[j] = t[j], t[i] } +func (t Timeline) WithoutHiddenReportEntries() Timeline { + out := Timeline{} + for _, event := range t { + if reportEntry, isReportEntry := event.(ReportEntry); isReportEntry && reportEntry.Visibility == ReportEntryVisibilityNever { + continue + } + out = append(out, event) + } + return out +} + +func (t Timeline) WithoutVeryVerboseSpecEvents() Timeline { + out := Timeline{} + for _, event := range t { + if specEvent, isSpecEvent := event.(SpecEvent); isSpecEvent && specEvent.IsOnlyVisibleAtVeryVerbose() { + continue + } + out = append(out, event) + } + return out +} + +// Failure captures failure information for an individual test +type Failure struct { + // Message - the failure message passed into Fail(...). When using a matcher library + // like Gomega, this will contain the failure message generated by Gomega. + // + // Message is also populated if the user has called Skip(...). + Message string + + // Location - the CodeLocation where the failure occurred + // This CodeLocation will include a fully-populated StackTrace + Location CodeLocation + + TimelineLocation TimelineLocation + + // ForwardedPanic - if the failure represents a captured panic (i.e. Summary.State == SpecStatePanicked) + // then ForwardedPanic will be populated with a string representation of the captured panic. + ForwardedPanic string `json:",omitempty"` + + // FailureNodeContext - one of three contexts describing the node in which the failure occurred: + // FailureNodeIsLeafNode means the failure occurred in the leaf node of the associated SpecReport. None of the other FailureNode fields will be populated + // FailureNodeAtTopLevel means the failure occurred in a non-leaf node that is defined at the top-level of the spec (i.e. not in a container). FailureNodeType and FailureNodeLocation will be populated. + // FailureNodeInContainer means the failure occurred in a non-leaf node that is defined within a container. FailureNodeType, FailureNodeLocation, and FailureNodeContainerIndex will be populated. + // + // FailureNodeType will contain the NodeType of the node in which the failure occurred. + // FailureNodeLocation will contain the CodeLocation of the node in which the failure occurred. + // If populated, FailureNodeContainerIndex will be the index into SpecReport.ContainerHierarchyTexts and SpecReport.ContainerHierarchyLocations that represents the parent container of the node in which the failure occurred. + FailureNodeContext FailureNodeContext `json:",omitempty"` + + FailureNodeType NodeType `json:",omitempty"` + + FailureNodeLocation CodeLocation `json:",omitempty"` + + FailureNodeContainerIndex int `json:",omitempty"` + + //ProgressReport is populated if the spec was interrupted or timed out + ProgressReport ProgressReport `json:",omitempty"` + + //AdditionalFailure is non-nil if a follow-on failure occurred within the same node after the primary failure. This only happens when a node has timed out or been interrupted. In such cases the AdditionalFailure can include information about where/why the spec was stuck. + AdditionalFailure *AdditionalFailure `json:",omitempty"` +} + +func (f Failure) IsZero() bool { + return f.Message == "" && (f.Location == CodeLocation{}) +} + +func (f Failure) GetTimelineLocation() TimelineLocation { + return f.TimelineLocation +} + +// FailureNodeContext captures the location context for the node containing the failing line of code +type FailureNodeContext uint + +const ( + FailureNodeContextInvalid FailureNodeContext = iota + + FailureNodeIsLeafNode + FailureNodeAtTopLevel + FailureNodeInContainer +) + +var fncEnumSupport = NewEnumSupport(map[uint]string{ + uint(FailureNodeContextInvalid): "INVALID FAILURE NODE CONTEXT", + uint(FailureNodeIsLeafNode): "leaf-node", + uint(FailureNodeAtTopLevel): "top-level", + uint(FailureNodeInContainer): "in-container", +}) + +func (fnc FailureNodeContext) String() string { + return fncEnumSupport.String(uint(fnc)) +} +func (fnc *FailureNodeContext) UnmarshalJSON(b []byte) error { + out, err := fncEnumSupport.UnmarshJSON(b) + *fnc = FailureNodeContext(out) + return err +} +func (fnc FailureNodeContext) MarshalJSON() ([]byte, error) { + return fncEnumSupport.MarshJSON(uint(fnc)) +} + +// AdditionalFailure capturs any additional failures that occur after the initial failure of a psec +// these typically occur in clean up nodes after the spec has failed. +// We can't simply use Failure as we want to track the SpecState to know what kind of failure this is +type AdditionalFailure struct { + State SpecState + Failure Failure +} + +func (f AdditionalFailure) GetTimelineLocation() TimelineLocation { + return f.Failure.TimelineLocation +} + +// SpecState captures the state of a spec +// To determine if a given `state` represents a failure state, use `state.Is(SpecStateFailureStates)` +type SpecState uint + +const ( + SpecStateInvalid SpecState = 0 + + SpecStatePending SpecState = 1 << iota + SpecStateSkipped + SpecStatePassed + SpecStateFailed + SpecStateAborted + SpecStatePanicked + SpecStateInterrupted + SpecStateTimedout +) + +var ssEnumSupport = NewEnumSupport(map[uint]string{ + uint(SpecStateInvalid): "INVALID SPEC STATE", + uint(SpecStatePending): "pending", + uint(SpecStateSkipped): "skipped", + uint(SpecStatePassed): "passed", + uint(SpecStateFailed): "failed", + uint(SpecStateAborted): "aborted", + uint(SpecStatePanicked): "panicked", + uint(SpecStateInterrupted): "interrupted", + uint(SpecStateTimedout): "timedout", +}) + +func (ss SpecState) String() string { + return ssEnumSupport.String(uint(ss)) +} +func (ss SpecState) GomegaString() string { + return ssEnumSupport.String(uint(ss)) +} +func (ss *SpecState) UnmarshalJSON(b []byte) error { + out, err := ssEnumSupport.UnmarshJSON(b) + *ss = SpecState(out) + return err +} +func (ss SpecState) MarshalJSON() ([]byte, error) { + return ssEnumSupport.MarshJSON(uint(ss)) +} + +var SpecStateFailureStates = SpecStateFailed | SpecStateTimedout | SpecStateAborted | SpecStatePanicked | SpecStateInterrupted + +func (ss SpecState) Is(states SpecState) bool { + return ss&states != 0 +} + +// ProgressReport captures the progress of the current spec. It is, effectively, a structured Ginkgo-aware stack trace +type ProgressReport struct { + Message string `json:",omitempty"` + ParallelProcess int `json:",omitempty"` + RunningInParallel bool `json:",omitempty"` + + ContainerHierarchyTexts []string `json:",omitempty"` + LeafNodeText string `json:",omitempty"` + LeafNodeLocation CodeLocation `json:",omitempty"` + SpecStartTime time.Time `json:",omitempty"` + + CurrentNodeType NodeType `json:",omitempty"` + CurrentNodeText string `json:",omitempty"` + CurrentNodeLocation CodeLocation `json:",omitempty"` + CurrentNodeStartTime time.Time `json:",omitempty"` + + CurrentStepText string `json:",omitempty"` + CurrentStepLocation CodeLocation `json:",omitempty"` + CurrentStepStartTime time.Time `json:",omitempty"` + + AdditionalReports []string `json:",omitempty"` + + CapturedGinkgoWriterOutput string `json:",omitempty"` + TimelineLocation TimelineLocation `json:",omitempty"` + + Goroutines []Goroutine `json:",omitempty"` +} + +func (pr ProgressReport) IsZero() bool { + return pr.CurrentNodeType == NodeTypeInvalid +} + +func (pr ProgressReport) Time() time.Time { + return pr.TimelineLocation.Time +} + +func (pr ProgressReport) SpecGoroutine() Goroutine { + for _, goroutine := range pr.Goroutines { + if goroutine.IsSpecGoroutine { + return goroutine + } + } + return Goroutine{} +} + +func (pr ProgressReport) HighlightedGoroutines() []Goroutine { + out := []Goroutine{} + for _, goroutine := range pr.Goroutines { + if goroutine.IsSpecGoroutine || !goroutine.HasHighlights() { + continue + } + out = append(out, goroutine) + } + return out +} + +func (pr ProgressReport) OtherGoroutines() []Goroutine { + out := []Goroutine{} + for _, goroutine := range pr.Goroutines { + if goroutine.IsSpecGoroutine || goroutine.HasHighlights() { + continue + } + out = append(out, goroutine) + } + return out +} + +func (pr ProgressReport) WithoutCapturedGinkgoWriterOutput() ProgressReport { + out := pr + out.CapturedGinkgoWriterOutput = "" + return out +} + +func (pr ProgressReport) WithoutOtherGoroutines() ProgressReport { + out := pr + filteredGoroutines := []Goroutine{} + for _, goroutine := range pr.Goroutines { + if goroutine.IsSpecGoroutine || goroutine.HasHighlights() { + filteredGoroutines = append(filteredGoroutines, goroutine) + } + } + out.Goroutines = filteredGoroutines + return out +} + +func (pr ProgressReport) GetTimelineLocation() TimelineLocation { + return pr.TimelineLocation +} + +type Goroutine struct { + ID uint64 + State string + Stack []FunctionCall + IsSpecGoroutine bool +} + +func (g Goroutine) IsZero() bool { + return g.ID == 0 +} + +func (g Goroutine) HasHighlights() bool { + for _, fc := range g.Stack { + if fc.Highlight { + return true + } + } + + return false +} + +type FunctionCall struct { + Function string + Filename string + Line int + Highlight bool `json:",omitempty"` + Source []string `json:",omitempty"` + SourceHighlight int `json:",omitempty"` +} + +// NodeType captures the type of a given Ginkgo Node +type NodeType uint + +const ( + NodeTypeInvalid NodeType = 0 + + NodeTypeContainer NodeType = 1 << iota + NodeTypeIt + + NodeTypeBeforeEach + NodeTypeJustBeforeEach + NodeTypeAfterEach + NodeTypeJustAfterEach + + NodeTypeBeforeAll + NodeTypeAfterAll + + NodeTypeBeforeSuite + NodeTypeSynchronizedBeforeSuite + NodeTypeAfterSuite + NodeTypeSynchronizedAfterSuite + + NodeTypeReportBeforeEach + NodeTypeReportAfterEach + NodeTypeReportBeforeSuite + NodeTypeReportAfterSuite + + NodeTypeCleanupInvalid + NodeTypeCleanupAfterEach + NodeTypeCleanupAfterAll + NodeTypeCleanupAfterSuite +) + +var NodeTypesForContainerAndIt = NodeTypeContainer | NodeTypeIt +var NodeTypesForSuiteLevelNodes = NodeTypeBeforeSuite | NodeTypeSynchronizedBeforeSuite | NodeTypeAfterSuite | NodeTypeSynchronizedAfterSuite | NodeTypeReportBeforeSuite | NodeTypeReportAfterSuite | NodeTypeCleanupAfterSuite +var NodeTypesAllowedDuringCleanupInterrupt = NodeTypeAfterEach | NodeTypeJustAfterEach | NodeTypeAfterAll | NodeTypeAfterSuite | NodeTypeSynchronizedAfterSuite | NodeTypeCleanupAfterEach | NodeTypeCleanupAfterAll | NodeTypeCleanupAfterSuite +var NodeTypesAllowedDuringReportInterrupt = NodeTypeReportBeforeEach | NodeTypeReportAfterEach | NodeTypeReportBeforeSuite | NodeTypeReportAfterSuite + +var ntEnumSupport = NewEnumSupport(map[uint]string{ + uint(NodeTypeInvalid): "INVALID NODE TYPE", + uint(NodeTypeContainer): "Container", + uint(NodeTypeIt): "It", + uint(NodeTypeBeforeEach): "BeforeEach", + uint(NodeTypeJustBeforeEach): "JustBeforeEach", + uint(NodeTypeAfterEach): "AfterEach", + uint(NodeTypeJustAfterEach): "JustAfterEach", + uint(NodeTypeBeforeAll): "BeforeAll", + uint(NodeTypeAfterAll): "AfterAll", + uint(NodeTypeBeforeSuite): "BeforeSuite", + uint(NodeTypeSynchronizedBeforeSuite): "SynchronizedBeforeSuite", + uint(NodeTypeAfterSuite): "AfterSuite", + uint(NodeTypeSynchronizedAfterSuite): "SynchronizedAfterSuite", + uint(NodeTypeReportBeforeEach): "ReportBeforeEach", + uint(NodeTypeReportAfterEach): "ReportAfterEach", + uint(NodeTypeReportBeforeSuite): "ReportBeforeSuite", + uint(NodeTypeReportAfterSuite): "ReportAfterSuite", + uint(NodeTypeCleanupInvalid): "DeferCleanup", + uint(NodeTypeCleanupAfterEach): "DeferCleanup (Each)", + uint(NodeTypeCleanupAfterAll): "DeferCleanup (All)", + uint(NodeTypeCleanupAfterSuite): "DeferCleanup (Suite)", +}) + +func (nt NodeType) String() string { + return ntEnumSupport.String(uint(nt)) +} +func (nt *NodeType) UnmarshalJSON(b []byte) error { + out, err := ntEnumSupport.UnmarshJSON(b) + *nt = NodeType(out) + return err +} +func (nt NodeType) MarshalJSON() ([]byte, error) { + return ntEnumSupport.MarshJSON(uint(nt)) +} + +func (nt NodeType) Is(nodeTypes NodeType) bool { + return nt&nodeTypes != 0 +} + +/* +SpecEvent captures a vareity of events that can occur when specs run. See SpecEventType for the list of available events. +*/ +type SpecEvent struct { + SpecEventType SpecEventType + + CodeLocation CodeLocation + TimelineLocation TimelineLocation + + Message string `json:",omitempty"` + Duration time.Duration `json:",omitempty"` + NodeType NodeType `json:",omitempty"` + Attempt int `json:",omitempty"` +} + +func (se SpecEvent) GetTimelineLocation() TimelineLocation { + return se.TimelineLocation +} + +func (se SpecEvent) IsOnlyVisibleAtVeryVerbose() bool { + return se.SpecEventType.Is(SpecEventByEnd | SpecEventNodeStart | SpecEventNodeEnd) +} + +func (se SpecEvent) GomegaString() string { + out := &strings.Builder{} + out.WriteString("[" + se.SpecEventType.String() + " SpecEvent] ") + if se.Message != "" { + out.WriteString("Message=") + out.WriteString(`"` + se.Message + `",`) + } + if se.Duration != 0 { + out.WriteString("Duration=" + se.Duration.String() + ",") + } + if se.NodeType != NodeTypeInvalid { + out.WriteString("NodeType=" + se.NodeType.String() + ",") + } + if se.Attempt != 0 { + out.WriteString(fmt.Sprintf("Attempt=%d", se.Attempt) + ",") + } + out.WriteString("CL=" + se.CodeLocation.String() + ",") + out.WriteString(fmt.Sprintf("TL.Offset=%d", se.TimelineLocation.Offset)) + + return out.String() +} + +type SpecEvents []SpecEvent + +func (se SpecEvents) WithType(seType SpecEventType) SpecEvents { + out := SpecEvents{} + for _, event := range se { + if event.SpecEventType.Is(seType) { + out = append(out, event) + } + } + return out +} + +type SpecEventType uint + +const ( + SpecEventInvalid SpecEventType = 0 + + SpecEventByStart SpecEventType = 1 << iota + SpecEventByEnd + SpecEventNodeStart + SpecEventNodeEnd + SpecEventSpecRepeat + SpecEventSpecRetry +) + +var seEnumSupport = NewEnumSupport(map[uint]string{ + uint(SpecEventInvalid): "INVALID SPEC EVENT", + uint(SpecEventByStart): "By", + uint(SpecEventByEnd): "By (End)", + uint(SpecEventNodeStart): "Node", + uint(SpecEventNodeEnd): "Node (End)", + uint(SpecEventSpecRepeat): "Repeat", + uint(SpecEventSpecRetry): "Retry", +}) + +func (se SpecEventType) String() string { + return seEnumSupport.String(uint(se)) +} +func (se *SpecEventType) UnmarshalJSON(b []byte) error { + out, err := seEnumSupport.UnmarshJSON(b) + *se = SpecEventType(out) + return err +} +func (se SpecEventType) MarshalJSON() ([]byte, error) { + return seEnumSupport.MarshJSON(uint(se)) +} + +func (se SpecEventType) Is(specEventTypes SpecEventType) bool { + return se&specEventTypes != 0 +} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/version.go b/vendor/github.com/onsi/ginkgo/v2/types/version.go new file mode 100644 index 000000000..43066341e --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/types/version.go @@ -0,0 +1,3 @@ +package types + +const VERSION = "2.9.5" diff --git a/vendor/github.com/quic-go/qpack/.codecov.yml b/vendor/github.com/quic-go/qpack/.codecov.yml new file mode 100644 index 000000000..00064af33 --- /dev/null +++ b/vendor/github.com/quic-go/qpack/.codecov.yml @@ -0,0 +1,7 @@ +coverage: + round: nearest + status: + project: + default: + threshold: 1 + patch: false diff --git a/vendor/github.com/quic-go/qpack/.gitignore b/vendor/github.com/quic-go/qpack/.gitignore new file mode 100644 index 000000000..66c189a09 --- /dev/null +++ b/vendor/github.com/quic-go/qpack/.gitignore @@ -0,0 +1,6 @@ +fuzzing/*.zip +fuzzing/coverprofile +fuzzing/crashers +fuzzing/sonarprofile +fuzzing/suppressions +fuzzing/corpus/ diff --git a/vendor/github.com/quic-go/qpack/.gitmodules b/vendor/github.com/quic-go/qpack/.gitmodules new file mode 100644 index 000000000..5ac16f084 --- /dev/null +++ b/vendor/github.com/quic-go/qpack/.gitmodules @@ -0,0 +1,3 @@ +[submodule "integrationtests/interop/qifs"] + path = integrationtests/interop/qifs + url = https://github.com/qpackers/qifs.git diff --git a/vendor/github.com/quic-go/qpack/.golangci.yml b/vendor/github.com/quic-go/qpack/.golangci.yml new file mode 100644 index 000000000..4a91adc77 --- /dev/null +++ b/vendor/github.com/quic-go/qpack/.golangci.yml @@ -0,0 +1,27 @@ +run: +linters-settings: +linters: + disable-all: true + enable: + - asciicheck + - deadcode + - exhaustive + - exportloopref + - goconst + - gofmt # redundant, since gofmt *should* be a no-op after gofumpt + - gofumpt + - goimports + - gosimple + - ineffassign + - misspell + - prealloc + - scopelint + - staticcheck + - stylecheck + - structcheck + - unconvert + - unparam + - unused + - varcheck + - vet + diff --git a/vendor/github.com/quic-go/qpack/LICENSE.md b/vendor/github.com/quic-go/qpack/LICENSE.md new file mode 100644 index 000000000..1ac5a2d9a --- /dev/null +++ b/vendor/github.com/quic-go/qpack/LICENSE.md @@ -0,0 +1,7 @@ +Copyright 2019 Marten Seemann + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/quic-go/qpack/README.md b/vendor/github.com/quic-go/qpack/README.md new file mode 100644 index 000000000..6ba4bad4a --- /dev/null +++ b/vendor/github.com/quic-go/qpack/README.md @@ -0,0 +1,20 @@ +# QPACK + +[![Godoc Reference](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](https://godoc.org/github.com/marten-seemann/qpack) +[![Code Coverage](https://img.shields.io/codecov/c/github/marten-seemann/qpack/master.svg?style=flat-square)](https://codecov.io/gh/marten-seemann/qpack) + +This is a minimal QPACK ([RFC 9204](https://datatracker.ietf.org/doc/html/rfc9204)) implementation in Go. It is minimal in the sense that it doesn't use the dynamic table at all, but just the static table and (Huffman encoded) string literals. Wherever possible, it reuses code from the [HPACK implementation in the Go standard library](https://github.com/golang/net/tree/master/http2/hpack). + +It should be able to interoperate with other QPACK implemetations (both encoders and decoders), however it won't achieve a high compression efficiency. + +## Running the interop tests + +Install the [QPACK interop files](https://github.com/qpackers/qifs/) by running +```bash +git submodule update --init --recursive +``` + +Then run the tests: +```bash +ginkgo -r integrationtests +``` diff --git a/vendor/github.com/quic-go/qpack/decoder.go b/vendor/github.com/quic-go/qpack/decoder.go new file mode 100644 index 000000000..c90019413 --- /dev/null +++ b/vendor/github.com/quic-go/qpack/decoder.go @@ -0,0 +1,271 @@ +package qpack + +import ( + "bytes" + "errors" + "fmt" + "sync" + + "golang.org/x/net/http2/hpack" +) + +// A decodingError is something the spec defines as a decoding error. +type decodingError struct { + err error +} + +func (de decodingError) Error() string { + return fmt.Sprintf("decoding error: %v", de.err) +} + +// An invalidIndexError is returned when an encoder references a table +// entry before the static table or after the end of the dynamic table. +type invalidIndexError int + +func (e invalidIndexError) Error() string { + return fmt.Sprintf("invalid indexed representation index %d", int(e)) +} + +var errNoDynamicTable = decodingError{errors.New("no dynamic table")} + +// errNeedMore is an internal sentinel error value that means the +// buffer is truncated and we need to read more data before we can +// continue parsing. +var errNeedMore = errors.New("need more data") + +// A Decoder is the decoding context for incremental processing of +// header blocks. +type Decoder struct { + mutex sync.Mutex + + emitFunc func(f HeaderField) + + readRequiredInsertCount bool + readDeltaBase bool + + // buf is the unparsed buffer. It's only written to + // saveBuf if it was truncated in the middle of a header + // block. Because it's usually not owned, we can only + // process it under Write. + buf []byte // not owned; only valid during Write + + // saveBuf is previous data passed to Write which we weren't able + // to fully parse before. Unlike buf, we own this data. + saveBuf bytes.Buffer +} + +// NewDecoder returns a new decoder +// The emitFunc will be called for each valid field parsed, +// in the same goroutine as calls to Write, before Write returns. +func NewDecoder(emitFunc func(f HeaderField)) *Decoder { + return &Decoder{emitFunc: emitFunc} +} + +func (d *Decoder) Write(p []byte) (int, error) { + if len(p) == 0 { + return 0, nil + } + + d.mutex.Lock() + n, err := d.writeLocked(p) + d.mutex.Unlock() + return n, err +} + +func (d *Decoder) writeLocked(p []byte) (int, error) { + // Only copy the data if we have to. Optimistically assume + // that p will contain a complete header block. + if d.saveBuf.Len() == 0 { + d.buf = p + } else { + d.saveBuf.Write(p) + d.buf = d.saveBuf.Bytes() + d.saveBuf.Reset() + } + + if err := d.decode(); err != nil { + if err != errNeedMore { + return 0, err + } + // TODO: limit the size of the buffer + d.saveBuf.Write(d.buf) + } + return len(p), nil +} + +// DecodeFull decodes an entire block. +func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error) { + if len(p) == 0 { + return []HeaderField{}, nil + } + + d.mutex.Lock() + defer d.mutex.Unlock() + + saveFunc := d.emitFunc + defer func() { d.emitFunc = saveFunc }() + + var hf []HeaderField + d.emitFunc = func(f HeaderField) { hf = append(hf, f) } + if _, err := d.writeLocked(p); err != nil { + return nil, err + } + if err := d.Close(); err != nil { + return nil, err + } + return hf, nil +} + +// Close declares that the decoding is complete and resets the Decoder +// to be reused again for a new header block. If there is any remaining +// data in the decoder's buffer, Close returns an error. +func (d *Decoder) Close() error { + if d.saveBuf.Len() > 0 { + d.saveBuf.Reset() + return decodingError{errors.New("truncated headers")} + } + d.readRequiredInsertCount = false + d.readDeltaBase = false + return nil +} + +func (d *Decoder) decode() error { + if !d.readRequiredInsertCount { + requiredInsertCount, rest, err := readVarInt(8, d.buf) + if err != nil { + return err + } + d.readRequiredInsertCount = true + if requiredInsertCount != 0 { + return decodingError{errors.New("expected Required Insert Count to be zero")} + } + d.buf = rest + } + if !d.readDeltaBase { + base, rest, err := readVarInt(7, d.buf) + if err != nil { + return err + } + d.readDeltaBase = true + if base != 0 { + return decodingError{errors.New("expected Base to be zero")} + } + d.buf = rest + } + if len(d.buf) == 0 { + return errNeedMore + } + + for len(d.buf) > 0 { + b := d.buf[0] + var err error + switch { + case b&0x80 > 0: // 1xxxxxxx + err = d.parseIndexedHeaderField() + case b&0xc0 == 0x40: // 01xxxxxx + err = d.parseLiteralHeaderField() + case b&0xe0 == 0x20: // 001xxxxx + err = d.parseLiteralHeaderFieldWithoutNameReference() + default: + err = fmt.Errorf("unexpected type byte: %#x", b) + } + if err != nil { + return err + } + } + return nil +} + +func (d *Decoder) parseIndexedHeaderField() error { + buf := d.buf + if buf[0]&0x40 == 0 { + return errNoDynamicTable + } + index, buf, err := readVarInt(6, buf) + if err != nil { + return err + } + hf, ok := d.at(index) + if !ok { + return decodingError{invalidIndexError(index)} + } + d.emitFunc(hf) + d.buf = buf + return nil +} + +func (d *Decoder) parseLiteralHeaderField() error { + buf := d.buf + if buf[0]&0x20 > 0 || buf[0]&0x10 == 0 { + return errNoDynamicTable + } + index, buf, err := readVarInt(4, buf) + if err != nil { + return err + } + hf, ok := d.at(index) + if !ok { + return decodingError{invalidIndexError(index)} + } + if len(buf) == 0 { + return errNeedMore + } + usesHuffman := buf[0]&0x80 > 0 + val, buf, err := d.readString(buf, 7, usesHuffman) + if err != nil { + return err + } + hf.Value = val + d.emitFunc(hf) + d.buf = buf + return nil +} + +func (d *Decoder) parseLiteralHeaderFieldWithoutNameReference() error { + buf := d.buf + usesHuffmanForName := buf[0]&0x8 > 0 + name, buf, err := d.readString(buf, 3, usesHuffmanForName) + if err != nil { + return err + } + if len(buf) == 0 { + return errNeedMore + } + usesHuffmanForVal := buf[0]&0x80 > 0 + val, buf, err := d.readString(buf, 7, usesHuffmanForVal) + if err != nil { + return err + } + d.emitFunc(HeaderField{Name: name, Value: val}) + d.buf = buf + return nil +} + +func (d *Decoder) readString(buf []byte, n uint8, usesHuffman bool) (string, []byte, error) { + l, buf, err := readVarInt(n, buf) + if err != nil { + return "", nil, err + } + if uint64(len(buf)) < l { + return "", nil, errNeedMore + } + var val string + if usesHuffman { + var err error + val, err = hpack.HuffmanDecodeToString(buf[:l]) + if err != nil { + return "", nil, err + } + } else { + val = string(buf[:l]) + } + buf = buf[l:] + return val, buf, nil +} + +func (d *Decoder) at(i uint64) (hf HeaderField, ok bool) { + if i >= uint64(len(staticTableEntries)) { + return + } + return staticTableEntries[i], true +} diff --git a/vendor/github.com/quic-go/qpack/encoder.go b/vendor/github.com/quic-go/qpack/encoder.go new file mode 100644 index 000000000..ad6953537 --- /dev/null +++ b/vendor/github.com/quic-go/qpack/encoder.go @@ -0,0 +1,95 @@ +package qpack + +import ( + "io" + + "golang.org/x/net/http2/hpack" +) + +// An Encoder performs QPACK encoding. +type Encoder struct { + wrotePrefix bool + + w io.Writer + buf []byte +} + +// NewEncoder returns a new Encoder which performs QPACK encoding. An +// encoded data is written to w. +func NewEncoder(w io.Writer) *Encoder { + return &Encoder{w: w} +} + +// WriteField encodes f into a single Write to e's underlying Writer. +// This function may also produce bytes for the Header Block Prefix +// if necessary. If produced, it is done before encoding f. +func (e *Encoder) WriteField(f HeaderField) error { + // write the Header Block Prefix + if !e.wrotePrefix { + e.buf = appendVarInt(e.buf, 8, 0) + e.buf = appendVarInt(e.buf, 7, 0) + e.wrotePrefix = true + } + + idxAndVals, nameFound := encoderMap[f.Name] + if nameFound { + if idxAndVals.values == nil { + if len(f.Value) == 0 { + e.writeIndexedField(idxAndVals.idx) + } else { + e.writeLiteralFieldWithNameReference(&f, idxAndVals.idx) + } + } else { + valIdx, valueFound := idxAndVals.values[f.Value] + if valueFound { + e.writeIndexedField(valIdx) + } else { + e.writeLiteralFieldWithNameReference(&f, idxAndVals.idx) + } + } + } else { + e.writeLiteralFieldWithoutNameReference(f) + } + + _, err := e.w.Write(e.buf) + e.buf = e.buf[:0] + return err +} + +// Close declares that the encoding is complete and resets the Encoder +// to be reused again for a new header block. +func (e *Encoder) Close() error { + e.wrotePrefix = false + return nil +} + +func (e *Encoder) writeLiteralFieldWithoutNameReference(f HeaderField) { + offset := len(e.buf) + e.buf = appendVarInt(e.buf, 3, hpack.HuffmanEncodeLength(f.Name)) + e.buf[offset] ^= 0x20 ^ 0x8 + e.buf = hpack.AppendHuffmanString(e.buf, f.Name) + offset = len(e.buf) + e.buf = appendVarInt(e.buf, 7, hpack.HuffmanEncodeLength(f.Value)) + e.buf[offset] ^= 0x80 + e.buf = hpack.AppendHuffmanString(e.buf, f.Value) +} + +// Encodes a header field whose name is present in one of the tables. +func (e *Encoder) writeLiteralFieldWithNameReference(f *HeaderField, id uint8) { + offset := len(e.buf) + e.buf = appendVarInt(e.buf, 4, uint64(id)) + // Set the 01NTxxxx pattern, forcing N to 0 and T to 1 + e.buf[offset] ^= 0x50 + offset = len(e.buf) + e.buf = appendVarInt(e.buf, 7, hpack.HuffmanEncodeLength(f.Value)) + e.buf[offset] ^= 0x80 + e.buf = hpack.AppendHuffmanString(e.buf, f.Value) +} + +// Encodes an indexed field, meaning it's entirely defined in one of the tables. +func (e *Encoder) writeIndexedField(id uint8) { + offset := len(e.buf) + e.buf = appendVarInt(e.buf, 6, uint64(id)) + // Set the 1Txxxxxx pattern, forcing T to 1 + e.buf[offset] ^= 0xc0 +} diff --git a/vendor/github.com/quic-go/qpack/header_field.go b/vendor/github.com/quic-go/qpack/header_field.go new file mode 100644 index 000000000..4c043a992 --- /dev/null +++ b/vendor/github.com/quic-go/qpack/header_field.go @@ -0,0 +1,16 @@ +package qpack + +// A HeaderField is a name-value pair. Both the name and value are +// treated as opaque sequences of octets. +type HeaderField struct { + Name string + Value string +} + +// IsPseudo reports whether the header field is an HTTP3 pseudo header. +// That is, it reports whether it starts with a colon. +// It is not otherwise guaranteed to be a valid pseudo header field, +// though. +func (hf HeaderField) IsPseudo() bool { + return len(hf.Name) != 0 && hf.Name[0] == ':' +} diff --git a/vendor/github.com/quic-go/qpack/static_table.go b/vendor/github.com/quic-go/qpack/static_table.go new file mode 100644 index 000000000..73c365e1f --- /dev/null +++ b/vendor/github.com/quic-go/qpack/static_table.go @@ -0,0 +1,255 @@ +package qpack + +var staticTableEntries = [...]HeaderField{ + {Name: ":authority"}, + {Name: ":path", Value: "/"}, + {Name: "age", Value: "0"}, + {Name: "content-disposition"}, + {Name: "content-length", Value: "0"}, + {Name: "cookie"}, + {Name: "date"}, + {Name: "etag"}, + {Name: "if-modified-since"}, + {Name: "if-none-match"}, + {Name: "last-modified"}, + {Name: "link"}, + {Name: "location"}, + {Name: "referer"}, + {Name: "set-cookie"}, + {Name: ":method", Value: "CONNECT"}, + {Name: ":method", Value: "DELETE"}, + {Name: ":method", Value: "GET"}, + {Name: ":method", Value: "HEAD"}, + {Name: ":method", Value: "OPTIONS"}, + {Name: ":method", Value: "POST"}, + {Name: ":method", Value: "PUT"}, + {Name: ":scheme", Value: "http"}, + {Name: ":scheme", Value: "https"}, + {Name: ":status", Value: "103"}, + {Name: ":status", Value: "200"}, + {Name: ":status", Value: "304"}, + {Name: ":status", Value: "404"}, + {Name: ":status", Value: "503"}, + {Name: "accept", Value: "*/*"}, + {Name: "accept", Value: "application/dns-message"}, + {Name: "accept-encoding", Value: "gzip, deflate, br"}, + {Name: "accept-ranges", Value: "bytes"}, + {Name: "access-control-allow-headers", Value: "cache-control"}, + {Name: "access-control-allow-headers", Value: "content-type"}, + {Name: "access-control-allow-origin", Value: "*"}, + {Name: "cache-control", Value: "max-age=0"}, + {Name: "cache-control", Value: "max-age=2592000"}, + {Name: "cache-control", Value: "max-age=604800"}, + {Name: "cache-control", Value: "no-cache"}, + {Name: "cache-control", Value: "no-store"}, + {Name: "cache-control", Value: "public, max-age=31536000"}, + {Name: "content-encoding", Value: "br"}, + {Name: "content-encoding", Value: "gzip"}, + {Name: "content-type", Value: "application/dns-message"}, + {Name: "content-type", Value: "application/javascript"}, + {Name: "content-type", Value: "application/json"}, + {Name: "content-type", Value: "application/x-www-form-urlencoded"}, + {Name: "content-type", Value: "image/gif"}, + {Name: "content-type", Value: "image/jpeg"}, + {Name: "content-type", Value: "image/png"}, + {Name: "content-type", Value: "text/css"}, + {Name: "content-type", Value: "text/html; charset=utf-8"}, + {Name: "content-type", Value: "text/plain"}, + {Name: "content-type", Value: "text/plain;charset=utf-8"}, + {Name: "range", Value: "bytes=0-"}, + {Name: "strict-transport-security", Value: "max-age=31536000"}, + {Name: "strict-transport-security", Value: "max-age=31536000; includesubdomains"}, + {Name: "strict-transport-security", Value: "max-age=31536000; includesubdomains; preload"}, + {Name: "vary", Value: "accept-encoding"}, + {Name: "vary", Value: "origin"}, + {Name: "x-content-type-options", Value: "nosniff"}, + {Name: "x-xss-protection", Value: "1; mode=block"}, + {Name: ":status", Value: "100"}, + {Name: ":status", Value: "204"}, + {Name: ":status", Value: "206"}, + {Name: ":status", Value: "302"}, + {Name: ":status", Value: "400"}, + {Name: ":status", Value: "403"}, + {Name: ":status", Value: "421"}, + {Name: ":status", Value: "425"}, + {Name: ":status", Value: "500"}, + {Name: "accept-language"}, + {Name: "access-control-allow-credentials", Value: "FALSE"}, + {Name: "access-control-allow-credentials", Value: "TRUE"}, + {Name: "access-control-allow-headers", Value: "*"}, + {Name: "access-control-allow-methods", Value: "get"}, + {Name: "access-control-allow-methods", Value: "get, post, options"}, + {Name: "access-control-allow-methods", Value: "options"}, + {Name: "access-control-expose-headers", Value: "content-length"}, + {Name: "access-control-request-headers", Value: "content-type"}, + {Name: "access-control-request-method", Value: "get"}, + {Name: "access-control-request-method", Value: "post"}, + {Name: "alt-svc", Value: "clear"}, + {Name: "authorization"}, + {Name: "content-security-policy", Value: "script-src 'none'; object-src 'none'; base-uri 'none'"}, + {Name: "early-data", Value: "1"}, + {Name: "expect-ct"}, + {Name: "forwarded"}, + {Name: "if-range"}, + {Name: "origin"}, + {Name: "purpose", Value: "prefetch"}, + {Name: "server"}, + {Name: "timing-allow-origin", Value: "*"}, + {Name: "upgrade-insecure-requests", Value: "1"}, + {Name: "user-agent"}, + {Name: "x-forwarded-for"}, + {Name: "x-frame-options", Value: "deny"}, + {Name: "x-frame-options", Value: "sameorigin"}, +} + +// Only needed for tests. +// use go:linkname to retrieve the static table. +// +//nolint:deadcode,unused +func getStaticTable() []HeaderField { + return staticTableEntries[:] +} + +type indexAndValues struct { + idx uint8 + values map[string]uint8 +} + +// A map of the header names from the static table to their index in the table. +// This is used by the encoder to quickly find if a header is in the static table +// and what value should be used to encode it. +// There's a second level of mapping for the headers that have some predefined +// values in the static table. +var encoderMap = map[string]indexAndValues{ + ":authority": {0, nil}, + ":path": {1, map[string]uint8{"/": 1}}, + "age": {2, map[string]uint8{"0": 2}}, + "content-disposition": {3, nil}, + "content-length": {4, map[string]uint8{"0": 4}}, + "cookie": {5, nil}, + "date": {6, nil}, + "etag": {7, nil}, + "if-modified-since": {8, nil}, + "if-none-match": {9, nil}, + "last-modified": {10, nil}, + "link": {11, nil}, + "location": {12, nil}, + "referer": {13, nil}, + "set-cookie": {14, nil}, + ":method": {15, map[string]uint8{ + "CONNECT": 15, + "DELETE": 16, + "GET": 17, + "HEAD": 18, + "OPTIONS": 19, + "POST": 20, + "PUT": 21, + }}, + ":scheme": {22, map[string]uint8{ + "http": 22, + "https": 23, + }}, + ":status": {24, map[string]uint8{ + "103": 24, + "200": 25, + "304": 26, + "404": 27, + "503": 28, + "100": 63, + "204": 64, + "206": 65, + "302": 66, + "400": 67, + "403": 68, + "421": 69, + "425": 70, + "500": 71, + }}, + "accept": {29, map[string]uint8{ + "*/*": 29, + "application/dns-message": 30, + }}, + "accept-encoding": {31, map[string]uint8{"gzip, deflate, br": 31}}, + "accept-ranges": {32, map[string]uint8{"bytes": 32}}, + "access-control-allow-headers": {33, map[string]uint8{ + "cache-control": 33, + "content-type": 34, + "*": 75, + }}, + "access-control-allow-origin": {35, map[string]uint8{"*": 35}}, + "cache-control": {36, map[string]uint8{ + "max-age=0": 36, + "max-age=2592000": 37, + "max-age=604800": 38, + "no-cache": 39, + "no-store": 40, + "public, max-age=31536000": 41, + }}, + "content-encoding": {42, map[string]uint8{ + "br": 42, + "gzip": 43, + }}, + "content-type": {44, map[string]uint8{ + "application/dns-message": 44, + "application/javascript": 45, + "application/json": 46, + "application/x-www-form-urlencoded": 47, + "image/gif": 48, + "image/jpeg": 49, + "image/png": 50, + "text/css": 51, + "text/html; charset=utf-8": 52, + "text/plain": 53, + "text/plain;charset=utf-8": 54, + }}, + "range": {55, map[string]uint8{"bytes=0-": 55}}, + "strict-transport-security": {56, map[string]uint8{ + "max-age=31536000": 56, + "max-age=31536000; includesubdomains": 57, + "max-age=31536000; includesubdomains; preload": 58, + }}, + "vary": {59, map[string]uint8{ + "accept-encoding": 59, + "origin": 60, + }}, + "x-content-type-options": {61, map[string]uint8{"nosniff": 61}}, + "x-xss-protection": {62, map[string]uint8{"1; mode=block": 62}}, + // ":status" is duplicated and takes index 63 to 71 + "accept-language": {72, nil}, + "access-control-allow-credentials": {73, map[string]uint8{ + "FALSE": 73, + "TRUE": 74, + }}, + // "access-control-allow-headers" is duplicated and takes index 75 + "access-control-allow-methods": {76, map[string]uint8{ + "get": 76, + "get, post, options": 77, + "options": 78, + }}, + "access-control-expose-headers": {79, map[string]uint8{"content-length": 79}}, + "access-control-request-headers": {80, map[string]uint8{"content-type": 80}}, + "access-control-request-method": {81, map[string]uint8{ + "get": 81, + "post": 82, + }}, + "alt-svc": {83, map[string]uint8{"clear": 83}}, + "authorization": {84, nil}, + "content-security-policy": {85, map[string]uint8{ + "script-src 'none'; object-src 'none'; base-uri 'none'": 85, + }}, + "early-data": {86, map[string]uint8{"1": 86}}, + "expect-ct": {87, nil}, + "forwarded": {88, nil}, + "if-range": {89, nil}, + "origin": {90, nil}, + "purpose": {91, map[string]uint8{"prefetch": 91}}, + "server": {92, nil}, + "timing-allow-origin": {93, map[string]uint8{"*": 93}}, + "upgrade-insecure-requests": {94, map[string]uint8{"1": 94}}, + "user-agent": {95, nil}, + "x-forwarded-for": {96, nil}, + "x-frame-options": {97, map[string]uint8{ + "deny": 97, + "sameorigin": 98, + }}, +} diff --git a/vendor/github.com/quic-go/qpack/tools.go b/vendor/github.com/quic-go/qpack/tools.go new file mode 100644 index 000000000..8f71eea26 --- /dev/null +++ b/vendor/github.com/quic-go/qpack/tools.go @@ -0,0 +1,5 @@ +//go:build tools + +package qpack + +import _ "github.com/onsi/ginkgo/v2/ginkgo" diff --git a/vendor/github.com/quic-go/qpack/varint.go b/vendor/github.com/quic-go/qpack/varint.go new file mode 100644 index 000000000..28d71122e --- /dev/null +++ b/vendor/github.com/quic-go/qpack/varint.go @@ -0,0 +1,66 @@ +package qpack + +// copied from the Go standard library HPACK implementation + +import "errors" + +var errVarintOverflow = errors.New("varint integer overflow") + +// appendVarInt appends i, as encoded in variable integer form using n +// bit prefix, to dst and returns the extended buffer. +// +// See +// http://http2.github.io/http2-spec/compression.html#integer.representation +func appendVarInt(dst []byte, n byte, i uint64) []byte { + k := uint64((1 << n) - 1) + if i < k { + return append(dst, byte(i)) + } + dst = append(dst, byte(k)) + i -= k + for ; i >= 128; i >>= 7 { + dst = append(dst, byte(0x80|(i&0x7f))) + } + return append(dst, byte(i)) +} + +// readVarInt reads an unsigned variable length integer off the +// beginning of p. n is the parameter as described in +// http://http2.github.io/http2-spec/compression.html#rfc.section.5.1. +// +// n must always be between 1 and 8. +// +// The returned remain buffer is either a smaller suffix of p, or err != nil. +// The error is errNeedMore if p doesn't contain a complete integer. +func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) { + if n < 1 || n > 8 { + panic("bad n") + } + if len(p) == 0 { + return 0, p, errNeedMore + } + i = uint64(p[0]) + if n < 8 { + i &= (1 << uint64(n)) - 1 + } + if i < (1< 0 { + b := p[0] + p = p[1:] + i += uint64(b&127) << m + if b&128 == 0 { + return i, p, nil + } + m += 7 + if m >= 63 { // TODO: proper overflow check. making this up. + return 0, origP, errVarintOverflow + } + } + return 0, origP, errNeedMore +} diff --git a/vendor/golang.org/x/xerrors/LICENSE b/vendor/github.com/quic-go/qtls-go1-20/LICENSE similarity index 96% rename from vendor/golang.org/x/xerrors/LICENSE rename to vendor/github.com/quic-go/qtls-go1-20/LICENSE index e4a47e17f..6a66aea5e 100644 --- a/vendor/golang.org/x/xerrors/LICENSE +++ b/vendor/github.com/quic-go/qtls-go1-20/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2019 The Go Authors. All rights reserved. +Copyright (c) 2009 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/vendor/github.com/quic-go/qtls-go1-20/README.md b/vendor/github.com/quic-go/qtls-go1-20/README.md new file mode 100644 index 000000000..2beaa2f23 --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/README.md @@ -0,0 +1,6 @@ +# qtls + +[![Go Reference](https://pkg.go.dev/badge/github.com/quic-go/qtls-go1-20.svg)](https://pkg.go.dev/github.com/quic-go/qtls-go1-20) +[![.github/workflows/go-test.yml](https://github.com/quic-go/qtls-go1-20/actions/workflows/go-test.yml/badge.svg)](https://github.com/quic-go/qtls-go1-20/actions/workflows/go-test.yml) + +This repository contains a modified version of the standard library's TLS implementation, modified for the QUIC protocol. It is used by [quic-go](https://github.com/quic-go/quic-go). diff --git a/vendor/github.com/quic-go/qtls-go1-20/alert.go b/vendor/github.com/quic-go/qtls-go1-20/alert.go new file mode 100644 index 000000000..687ada843 --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/alert.go @@ -0,0 +1,109 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package qtls + +import "strconv" + +// An AlertError is a TLS alert. +// +// When using a QUIC transport, QUICConn methods will return an error +// which wraps AlertError rather than sending a TLS alert. +type AlertError uint8 + +func (e AlertError) Error() string { + return alert(e).String() +} + +type alert uint8 + +const ( + // alert level + alertLevelWarning = 1 + alertLevelError = 2 +) + +const ( + alertCloseNotify alert = 0 + alertUnexpectedMessage alert = 10 + alertBadRecordMAC alert = 20 + alertDecryptionFailed alert = 21 + alertRecordOverflow alert = 22 + alertDecompressionFailure alert = 30 + alertHandshakeFailure alert = 40 + alertBadCertificate alert = 42 + alertUnsupportedCertificate alert = 43 + alertCertificateRevoked alert = 44 + alertCertificateExpired alert = 45 + alertCertificateUnknown alert = 46 + alertIllegalParameter alert = 47 + alertUnknownCA alert = 48 + alertAccessDenied alert = 49 + alertDecodeError alert = 50 + alertDecryptError alert = 51 + alertExportRestriction alert = 60 + alertProtocolVersion alert = 70 + alertInsufficientSecurity alert = 71 + alertInternalError alert = 80 + alertInappropriateFallback alert = 86 + alertUserCanceled alert = 90 + alertNoRenegotiation alert = 100 + alertMissingExtension alert = 109 + alertUnsupportedExtension alert = 110 + alertCertificateUnobtainable alert = 111 + alertUnrecognizedName alert = 112 + alertBadCertificateStatusResponse alert = 113 + alertBadCertificateHashValue alert = 114 + alertUnknownPSKIdentity alert = 115 + alertCertificateRequired alert = 116 + alertNoApplicationProtocol alert = 120 +) + +var alertText = map[alert]string{ + alertCloseNotify: "close notify", + alertUnexpectedMessage: "unexpected message", + alertBadRecordMAC: "bad record MAC", + alertDecryptionFailed: "decryption failed", + alertRecordOverflow: "record overflow", + alertDecompressionFailure: "decompression failure", + alertHandshakeFailure: "handshake failure", + alertBadCertificate: "bad certificate", + alertUnsupportedCertificate: "unsupported certificate", + alertCertificateRevoked: "revoked certificate", + alertCertificateExpired: "expired certificate", + alertCertificateUnknown: "unknown certificate", + alertIllegalParameter: "illegal parameter", + alertUnknownCA: "unknown certificate authority", + alertAccessDenied: "access denied", + alertDecodeError: "error decoding message", + alertDecryptError: "error decrypting message", + alertExportRestriction: "export restriction", + alertProtocolVersion: "protocol version not supported", + alertInsufficientSecurity: "insufficient security level", + alertInternalError: "internal error", + alertInappropriateFallback: "inappropriate fallback", + alertUserCanceled: "user canceled", + alertNoRenegotiation: "no renegotiation", + alertMissingExtension: "missing extension", + alertUnsupportedExtension: "unsupported extension", + alertCertificateUnobtainable: "certificate unobtainable", + alertUnrecognizedName: "unrecognized name", + alertBadCertificateStatusResponse: "bad certificate status response", + alertBadCertificateHashValue: "bad certificate hash value", + alertUnknownPSKIdentity: "unknown PSK identity", + alertCertificateRequired: "certificate required", + alertNoApplicationProtocol: "no application protocol", +} + +func (e alert) String() string { + s, ok := alertText[e] + if ok { + return "tls: " + s + } + return "tls: alert(" + strconv.Itoa(int(e)) + ")" +} + +func (e alert) Error() string { + return e.String() +} diff --git a/vendor/github.com/quic-go/qtls-go1-20/auth.go b/vendor/github.com/quic-go/qtls-go1-20/auth.go new file mode 100644 index 000000000..effc9aced --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/auth.go @@ -0,0 +1,293 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package qtls + +import ( + "bytes" + "crypto" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/elliptic" + "crypto/rsa" + "errors" + "fmt" + "hash" + "io" +) + +// verifyHandshakeSignature verifies a signature against pre-hashed +// (if required) handshake contents. +func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, signed, sig []byte) error { + switch sigType { + case signatureECDSA: + pubKey, ok := pubkey.(*ecdsa.PublicKey) + if !ok { + return fmt.Errorf("expected an ECDSA public key, got %T", pubkey) + } + if !ecdsa.VerifyASN1(pubKey, signed, sig) { + return errors.New("ECDSA verification failure") + } + case signatureEd25519: + pubKey, ok := pubkey.(ed25519.PublicKey) + if !ok { + return fmt.Errorf("expected an Ed25519 public key, got %T", pubkey) + } + if !ed25519.Verify(pubKey, signed, sig) { + return errors.New("Ed25519 verification failure") + } + case signaturePKCS1v15: + pubKey, ok := pubkey.(*rsa.PublicKey) + if !ok { + return fmt.Errorf("expected an RSA public key, got %T", pubkey) + } + if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, signed, sig); err != nil { + return err + } + case signatureRSAPSS: + pubKey, ok := pubkey.(*rsa.PublicKey) + if !ok { + return fmt.Errorf("expected an RSA public key, got %T", pubkey) + } + signOpts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash} + if err := rsa.VerifyPSS(pubKey, hashFunc, signed, sig, signOpts); err != nil { + return err + } + default: + return errors.New("internal error: unknown signature type") + } + return nil +} + +const ( + serverSignatureContext = "TLS 1.3, server CertificateVerify\x00" + clientSignatureContext = "TLS 1.3, client CertificateVerify\x00" +) + +var signaturePadding = []byte{ + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +} + +// signedMessage returns the pre-hashed (if necessary) message to be signed by +// certificate keys in TLS 1.3. See RFC 8446, Section 4.4.3. +func signedMessage(sigHash crypto.Hash, context string, transcript hash.Hash) []byte { + if sigHash == directSigning { + b := &bytes.Buffer{} + b.Write(signaturePadding) + io.WriteString(b, context) + b.Write(transcript.Sum(nil)) + return b.Bytes() + } + h := sigHash.New() + h.Write(signaturePadding) + io.WriteString(h, context) + h.Write(transcript.Sum(nil)) + return h.Sum(nil) +} + +// typeAndHashFromSignatureScheme returns the corresponding signature type and +// crypto.Hash for a given TLS SignatureScheme. +func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) (sigType uint8, hash crypto.Hash, err error) { + switch signatureAlgorithm { + case PKCS1WithSHA1, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512: + sigType = signaturePKCS1v15 + case PSSWithSHA256, PSSWithSHA384, PSSWithSHA512: + sigType = signatureRSAPSS + case ECDSAWithSHA1, ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512: + sigType = signatureECDSA + case Ed25519: + sigType = signatureEd25519 + default: + return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm) + } + switch signatureAlgorithm { + case PKCS1WithSHA1, ECDSAWithSHA1: + hash = crypto.SHA1 + case PKCS1WithSHA256, PSSWithSHA256, ECDSAWithP256AndSHA256: + hash = crypto.SHA256 + case PKCS1WithSHA384, PSSWithSHA384, ECDSAWithP384AndSHA384: + hash = crypto.SHA384 + case PKCS1WithSHA512, PSSWithSHA512, ECDSAWithP521AndSHA512: + hash = crypto.SHA512 + case Ed25519: + hash = directSigning + default: + return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm) + } + return sigType, hash, nil +} + +// legacyTypeAndHashFromPublicKey returns the fixed signature type and crypto.Hash for +// a given public key used with TLS 1.0 and 1.1, before the introduction of +// signature algorithm negotiation. +func legacyTypeAndHashFromPublicKey(pub crypto.PublicKey) (sigType uint8, hash crypto.Hash, err error) { + switch pub.(type) { + case *rsa.PublicKey: + return signaturePKCS1v15, crypto.MD5SHA1, nil + case *ecdsa.PublicKey: + return signatureECDSA, crypto.SHA1, nil + case ed25519.PublicKey: + // RFC 8422 specifies support for Ed25519 in TLS 1.0 and 1.1, + // but it requires holding on to a handshake transcript to do a + // full signature, and not even OpenSSL bothers with the + // complexity, so we can't even test it properly. + return 0, 0, fmt.Errorf("tls: Ed25519 public keys are not supported before TLS 1.2") + default: + return 0, 0, fmt.Errorf("tls: unsupported public key: %T", pub) + } +} + +var rsaSignatureSchemes = []struct { + scheme SignatureScheme + minModulusBytes int + maxVersion uint16 +}{ + // RSA-PSS is used with PSSSaltLengthEqualsHash, and requires + // emLen >= hLen + sLen + 2 + {PSSWithSHA256, crypto.SHA256.Size()*2 + 2, VersionTLS13}, + {PSSWithSHA384, crypto.SHA384.Size()*2 + 2, VersionTLS13}, + {PSSWithSHA512, crypto.SHA512.Size()*2 + 2, VersionTLS13}, + // PKCS #1 v1.5 uses prefixes from hashPrefixes in crypto/rsa, and requires + // emLen >= len(prefix) + hLen + 11 + // TLS 1.3 dropped support for PKCS #1 v1.5 in favor of RSA-PSS. + {PKCS1WithSHA256, 19 + crypto.SHA256.Size() + 11, VersionTLS12}, + {PKCS1WithSHA384, 19 + crypto.SHA384.Size() + 11, VersionTLS12}, + {PKCS1WithSHA512, 19 + crypto.SHA512.Size() + 11, VersionTLS12}, + {PKCS1WithSHA1, 15 + crypto.SHA1.Size() + 11, VersionTLS12}, +} + +// signatureSchemesForCertificate returns the list of supported SignatureSchemes +// for a given certificate, based on the public key and the protocol version, +// and optionally filtered by its explicit SupportedSignatureAlgorithms. +// +// This function must be kept in sync with supportedSignatureAlgorithms. +// FIPS filtering is applied in the caller, selectSignatureScheme. +func signatureSchemesForCertificate(version uint16, cert *Certificate) []SignatureScheme { + priv, ok := cert.PrivateKey.(crypto.Signer) + if !ok { + return nil + } + + var sigAlgs []SignatureScheme + switch pub := priv.Public().(type) { + case *ecdsa.PublicKey: + if version != VersionTLS13 { + // In TLS 1.2 and earlier, ECDSA algorithms are not + // constrained to a single curve. + sigAlgs = []SignatureScheme{ + ECDSAWithP256AndSHA256, + ECDSAWithP384AndSHA384, + ECDSAWithP521AndSHA512, + ECDSAWithSHA1, + } + break + } + switch pub.Curve { + case elliptic.P256(): + sigAlgs = []SignatureScheme{ECDSAWithP256AndSHA256} + case elliptic.P384(): + sigAlgs = []SignatureScheme{ECDSAWithP384AndSHA384} + case elliptic.P521(): + sigAlgs = []SignatureScheme{ECDSAWithP521AndSHA512} + default: + return nil + } + case *rsa.PublicKey: + size := pub.Size() + sigAlgs = make([]SignatureScheme, 0, len(rsaSignatureSchemes)) + for _, candidate := range rsaSignatureSchemes { + if size >= candidate.minModulusBytes && version <= candidate.maxVersion { + sigAlgs = append(sigAlgs, candidate.scheme) + } + } + case ed25519.PublicKey: + sigAlgs = []SignatureScheme{Ed25519} + default: + return nil + } + + if cert.SupportedSignatureAlgorithms != nil { + var filteredSigAlgs []SignatureScheme + for _, sigAlg := range sigAlgs { + if isSupportedSignatureAlgorithm(sigAlg, cert.SupportedSignatureAlgorithms) { + filteredSigAlgs = append(filteredSigAlgs, sigAlg) + } + } + return filteredSigAlgs + } + return sigAlgs +} + +// selectSignatureScheme picks a SignatureScheme from the peer's preference list +// that works with the selected certificate. It's only called for protocol +// versions that support signature algorithms, so TLS 1.2 and 1.3. +func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []SignatureScheme) (SignatureScheme, error) { + supportedAlgs := signatureSchemesForCertificate(vers, c) + if len(supportedAlgs) == 0 { + return 0, unsupportedCertificateError(c) + } + if len(peerAlgs) == 0 && vers == VersionTLS12 { + // For TLS 1.2, if the client didn't send signature_algorithms then we + // can assume that it supports SHA1. See RFC 5246, Section 7.4.1.4.1. + peerAlgs = []SignatureScheme{PKCS1WithSHA1, ECDSAWithSHA1} + } + // Pick signature scheme in the peer's preference order, as our + // preference order is not configurable. + for _, preferredAlg := range peerAlgs { + if needFIPS() && !isSupportedSignatureAlgorithm(preferredAlg, fipsSupportedSignatureAlgorithms) { + continue + } + if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) { + return preferredAlg, nil + } + } + return 0, errors.New("tls: peer doesn't support any of the certificate's signature algorithms") +} + +// unsupportedCertificateError returns a helpful error for certificates with +// an unsupported private key. +func unsupportedCertificateError(cert *Certificate) error { + switch cert.PrivateKey.(type) { + case rsa.PrivateKey, ecdsa.PrivateKey: + return fmt.Errorf("tls: unsupported certificate: private key is %T, expected *%T", + cert.PrivateKey, cert.PrivateKey) + case *ed25519.PrivateKey: + return fmt.Errorf("tls: unsupported certificate: private key is *ed25519.PrivateKey, expected ed25519.PrivateKey") + } + + signer, ok := cert.PrivateKey.(crypto.Signer) + if !ok { + return fmt.Errorf("tls: certificate private key (%T) does not implement crypto.Signer", + cert.PrivateKey) + } + + switch pub := signer.Public().(type) { + case *ecdsa.PublicKey: + switch pub.Curve { + case elliptic.P256(): + case elliptic.P384(): + case elliptic.P521(): + default: + return fmt.Errorf("tls: unsupported certificate curve (%s)", pub.Curve.Params().Name) + } + case *rsa.PublicKey: + return fmt.Errorf("tls: certificate RSA key size too small for supported signature algorithms") + case ed25519.PublicKey: + default: + return fmt.Errorf("tls: unsupported certificate key (%T)", pub) + } + + if cert.SupportedSignatureAlgorithms != nil { + return fmt.Errorf("tls: peer doesn't support the certificate custom signature algorithms") + } + + return fmt.Errorf("tls: internal error: unsupported key (%T)", cert.PrivateKey) +} diff --git a/vendor/github.com/quic-go/qtls-go1-20/cache.go b/vendor/github.com/quic-go/qtls-go1-20/cache.go new file mode 100644 index 000000000..99e0c5fb8 --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/cache.go @@ -0,0 +1,95 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package qtls + +import ( + "crypto/x509" + "runtime" + "sync" + "sync/atomic" +) + +type cacheEntry struct { + refs atomic.Int64 + cert *x509.Certificate +} + +// certCache implements an intern table for reference counted x509.Certificates, +// implemented in a similar fashion to BoringSSL's CRYPTO_BUFFER_POOL. This +// allows for a single x509.Certificate to be kept in memory and referenced from +// multiple Conns. Returned references should not be mutated by callers. Certificates +// are still safe to use after they are removed from the cache. +// +// Certificates are returned wrapped in a activeCert struct that should be held by +// the caller. When references to the activeCert are freed, the number of references +// to the certificate in the cache is decremented. Once the number of references +// reaches zero, the entry is evicted from the cache. +// +// The main difference between this implementation and CRYPTO_BUFFER_POOL is that +// CRYPTO_BUFFER_POOL is a more generic structure which supports blobs of data, +// rather than specific structures. Since we only care about x509.Certificates, +// certCache is implemented as a specific cache, rather than a generic one. +// +// See https://boringssl.googlesource.com/boringssl/+/master/include/openssl/pool.h +// and https://boringssl.googlesource.com/boringssl/+/master/crypto/pool/pool.c +// for the BoringSSL reference. +type certCache struct { + sync.Map +} + +var clientCertCache = new(certCache) + +// activeCert is a handle to a certificate held in the cache. Once there are +// no alive activeCerts for a given certificate, the certificate is removed +// from the cache by a finalizer. +type activeCert struct { + cert *x509.Certificate +} + +// active increments the number of references to the entry, wraps the +// certificate in the entry in a activeCert, and sets the finalizer. +// +// Note that there is a race between active and the finalizer set on the +// returned activeCert, triggered if active is called after the ref count is +// decremented such that refs may be > 0 when evict is called. We consider this +// safe, since the caller holding an activeCert for an entry that is no longer +// in the cache is fine, with the only side effect being the memory overhead of +// there being more than one distinct reference to a certificate alive at once. +func (cc *certCache) active(e *cacheEntry) *activeCert { + e.refs.Add(1) + a := &activeCert{e.cert} + runtime.SetFinalizer(a, func(_ *activeCert) { + if e.refs.Add(-1) == 0 { + cc.evict(e) + } + }) + return a +} + +// evict removes a cacheEntry from the cache. +func (cc *certCache) evict(e *cacheEntry) { + cc.Delete(string(e.cert.Raw)) +} + +// newCert returns a x509.Certificate parsed from der. If there is already a copy +// of the certificate in the cache, a reference to the existing certificate will +// be returned. Otherwise, a fresh certificate will be added to the cache, and +// the reference returned. The returned reference should not be mutated. +func (cc *certCache) newCert(der []byte) (*activeCert, error) { + if entry, ok := cc.Load(string(der)); ok { + return cc.active(entry.(*cacheEntry)), nil + } + + cert, err := x509.ParseCertificate(der) + if err != nil { + return nil, err + } + + entry := &cacheEntry{cert: cert} + if entry, loaded := cc.LoadOrStore(string(der), entry); loaded { + return cc.active(entry.(*cacheEntry)), nil + } + return cc.active(entry), nil +} diff --git a/vendor/github.com/quic-go/qtls-go1-20/cipher_suites.go b/vendor/github.com/quic-go/qtls-go1-20/cipher_suites.go new file mode 100644 index 000000000..2946ffb32 --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/cipher_suites.go @@ -0,0 +1,691 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package qtls + +import ( + "crypto" + "crypto/aes" + "crypto/cipher" + "crypto/des" + "crypto/hmac" + "crypto/rc4" + "crypto/sha1" + "crypto/sha256" + "fmt" + "hash" + "runtime" + + "golang.org/x/crypto/chacha20poly1305" + "golang.org/x/sys/cpu" +) + +// CipherSuite is a TLS cipher suite. Note that most functions in this package +// accept and expose cipher suite IDs instead of this type. +type CipherSuite struct { + ID uint16 + Name string + + // Supported versions is the list of TLS protocol versions that can + // negotiate this cipher suite. + SupportedVersions []uint16 + + // Insecure is true if the cipher suite has known security issues + // due to its primitives, design, or implementation. + Insecure bool +} + +var ( + supportedUpToTLS12 = []uint16{VersionTLS10, VersionTLS11, VersionTLS12} + supportedOnlyTLS12 = []uint16{VersionTLS12} + supportedOnlyTLS13 = []uint16{VersionTLS13} +) + +// CipherSuites returns a list of cipher suites currently implemented by this +// package, excluding those with security issues, which are returned by +// InsecureCipherSuites. +// +// The list is sorted by ID. Note that the default cipher suites selected by +// this package might depend on logic that can't be captured by a static list, +// and might not match those returned by this function. +func CipherSuites() []*CipherSuite { + return []*CipherSuite{ + {TLS_RSA_WITH_AES_128_CBC_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false}, + {TLS_RSA_WITH_AES_256_CBC_SHA, "TLS_RSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false}, + {TLS_RSA_WITH_AES_128_GCM_SHA256, "TLS_RSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false}, + {TLS_RSA_WITH_AES_256_GCM_SHA384, "TLS_RSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false}, + + {TLS_AES_128_GCM_SHA256, "TLS_AES_128_GCM_SHA256", supportedOnlyTLS13, false}, + {TLS_AES_256_GCM_SHA384, "TLS_AES_256_GCM_SHA384", supportedOnlyTLS13, false}, + {TLS_CHACHA20_POLY1305_SHA256, "TLS_CHACHA20_POLY1305_SHA256", supportedOnlyTLS13, false}, + + {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false}, + {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false}, + {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false}, + {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false}, + {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false}, + {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false}, + {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false}, + {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false}, + {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", supportedOnlyTLS12, false}, + {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", supportedOnlyTLS12, false}, + } +} + +// InsecureCipherSuites returns a list of cipher suites currently implemented by +// this package and which have security issues. +// +// Most applications should not use the cipher suites in this list, and should +// only use those returned by CipherSuites. +func InsecureCipherSuites() []*CipherSuite { + // This list includes RC4, CBC_SHA256, and 3DES cipher suites. See + // cipherSuitesPreferenceOrder for details. + return []*CipherSuite{ + {TLS_RSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_RC4_128_SHA", supportedUpToTLS12, true}, + {TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA", supportedUpToTLS12, true}, + {TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true}, + {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", supportedUpToTLS12, true}, + {TLS_ECDHE_RSA_WITH_RC4_128_SHA, "TLS_ECDHE_RSA_WITH_RC4_128_SHA", supportedUpToTLS12, true}, + {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", supportedUpToTLS12, true}, + {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true}, + {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true}, + } +} + +// CipherSuiteName returns the standard name for the passed cipher suite ID +// (e.g. "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"), or a fallback representation +// of the ID value if the cipher suite is not implemented by this package. +func CipherSuiteName(id uint16) string { + for _, c := range CipherSuites() { + if c.ID == id { + return c.Name + } + } + for _, c := range InsecureCipherSuites() { + if c.ID == id { + return c.Name + } + } + return fmt.Sprintf("0x%04X", id) +} + +const ( + // suiteECDHE indicates that the cipher suite involves elliptic curve + // Diffie-Hellman. This means that it should only be selected when the + // client indicates that it supports ECC with a curve and point format + // that we're happy with. + suiteECDHE = 1 << iota + // suiteECSign indicates that the cipher suite involves an ECDSA or + // EdDSA signature and therefore may only be selected when the server's + // certificate is ECDSA or EdDSA. If this is not set then the cipher suite + // is RSA based. + suiteECSign + // suiteTLS12 indicates that the cipher suite should only be advertised + // and accepted when using TLS 1.2. + suiteTLS12 + // suiteSHA384 indicates that the cipher suite uses SHA384 as the + // handshake hash. + suiteSHA384 +) + +// A cipherSuite is a TLS 1.0–1.2 cipher suite, and defines the key exchange +// mechanism, as well as the cipher+MAC pair or the AEAD. +type cipherSuite struct { + id uint16 + // the lengths, in bytes, of the key material needed for each component. + keyLen int + macLen int + ivLen int + ka func(version uint16) keyAgreement + // flags is a bitmask of the suite* values, above. + flags int + cipher func(key, iv []byte, isRead bool) any + mac func(key []byte) hash.Hash + aead func(key, fixedNonce []byte) aead +} + +var cipherSuites = []*cipherSuite{ // TODO: replace with a map, since the order doesn't matter. + {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadChaCha20Poly1305}, + {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadChaCha20Poly1305}, + {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM}, + {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadAESGCM}, + {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, + {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, + {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12, cipherAES, macSHA256, nil}, + {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil}, + {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, cipherAES, macSHA256, nil}, + {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherAES, macSHA1, nil}, + {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil}, + {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherAES, macSHA1, nil}, + {TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM}, + {TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, + {TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12, cipherAES, macSHA256, nil}, + {TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil}, + {TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil}, + {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil}, + {TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil}, + {TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, 0, cipherRC4, macSHA1, nil}, + {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE, cipherRC4, macSHA1, nil}, + {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherRC4, macSHA1, nil}, +} + +// selectCipherSuite returns the first TLS 1.0–1.2 cipher suite from ids which +// is also in supportedIDs and passes the ok filter. +func selectCipherSuite(ids, supportedIDs []uint16, ok func(*cipherSuite) bool) *cipherSuite { + for _, id := range ids { + candidate := cipherSuiteByID(id) + if candidate == nil || !ok(candidate) { + continue + } + + for _, suppID := range supportedIDs { + if id == suppID { + return candidate + } + } + } + return nil +} + +// A cipherSuiteTLS13 defines only the pair of the AEAD algorithm and hash +// algorithm to be used with HKDF. See RFC 8446, Appendix B.4. +type cipherSuiteTLS13 struct { + id uint16 + keyLen int + aead func(key, fixedNonce []byte) aead + hash crypto.Hash +} + +var cipherSuitesTLS13 = []*cipherSuiteTLS13{ // TODO: replace with a map. + {TLS_AES_128_GCM_SHA256, 16, aeadAESGCMTLS13, crypto.SHA256}, + {TLS_CHACHA20_POLY1305_SHA256, 32, aeadChaCha20Poly1305, crypto.SHA256}, + {TLS_AES_256_GCM_SHA384, 32, aeadAESGCMTLS13, crypto.SHA384}, +} + +// cipherSuitesPreferenceOrder is the order in which we'll select (on the +// server) or advertise (on the client) TLS 1.0–1.2 cipher suites. +// +// Cipher suites are filtered but not reordered based on the application and +// peer's preferences, meaning we'll never select a suite lower in this list if +// any higher one is available. This makes it more defensible to keep weaker +// cipher suites enabled, especially on the server side where we get the last +// word, since there are no known downgrade attacks on cipher suites selection. +// +// The list is sorted by applying the following priority rules, stopping at the +// first (most important) applicable one: +// +// - Anything else comes before RC4 +// +// RC4 has practically exploitable biases. See https://www.rc4nomore.com. +// +// - Anything else comes before CBC_SHA256 +// +// SHA-256 variants of the CBC ciphersuites don't implement any Lucky13 +// countermeasures. See http://www.isg.rhul.ac.uk/tls/Lucky13.html and +// https://www.imperialviolet.org/2013/02/04/luckythirteen.html. +// +// - Anything else comes before 3DES +// +// 3DES has 64-bit blocks, which makes it fundamentally susceptible to +// birthday attacks. See https://sweet32.info. +// +// - ECDHE comes before anything else +// +// Once we got the broken stuff out of the way, the most important +// property a cipher suite can have is forward secrecy. We don't +// implement FFDHE, so that means ECDHE. +// +// - AEADs come before CBC ciphers +// +// Even with Lucky13 countermeasures, MAC-then-Encrypt CBC cipher suites +// are fundamentally fragile, and suffered from an endless sequence of +// padding oracle attacks. See https://eprint.iacr.org/2015/1129, +// https://www.imperialviolet.org/2014/12/08/poodleagain.html, and +// https://blog.cloudflare.com/yet-another-padding-oracle-in-openssl-cbc-ciphersuites/. +// +// - AES comes before ChaCha20 +// +// When AES hardware is available, AES-128-GCM and AES-256-GCM are faster +// than ChaCha20Poly1305. +// +// When AES hardware is not available, AES-128-GCM is one or more of: much +// slower, way more complex, and less safe (because not constant time) +// than ChaCha20Poly1305. +// +// We use this list if we think both peers have AES hardware, and +// cipherSuitesPreferenceOrderNoAES otherwise. +// +// - AES-128 comes before AES-256 +// +// The only potential advantages of AES-256 are better multi-target +// margins, and hypothetical post-quantum properties. Neither apply to +// TLS, and AES-256 is slower due to its four extra rounds (which don't +// contribute to the advantages above). +// +// - ECDSA comes before RSA +// +// The relative order of ECDSA and RSA cipher suites doesn't matter, +// as they depend on the certificate. Pick one to get a stable order. +var cipherSuitesPreferenceOrder = []uint16{ + // AEADs w/ ECDHE + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + + // CBC w/ ECDHE + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + + // AEADs w/o ECDHE + TLS_RSA_WITH_AES_128_GCM_SHA256, + TLS_RSA_WITH_AES_256_GCM_SHA384, + + // CBC w/o ECDHE + TLS_RSA_WITH_AES_128_CBC_SHA, + TLS_RSA_WITH_AES_256_CBC_SHA, + + // 3DES + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + TLS_RSA_WITH_3DES_EDE_CBC_SHA, + + // CBC_SHA256 + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + TLS_RSA_WITH_AES_128_CBC_SHA256, + + // RC4 + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, + TLS_RSA_WITH_RC4_128_SHA, +} + +var cipherSuitesPreferenceOrderNoAES = []uint16{ + // ChaCha20Poly1305 + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + + // AES-GCM w/ ECDHE + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + + // The rest of cipherSuitesPreferenceOrder. + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + TLS_RSA_WITH_AES_128_GCM_SHA256, + TLS_RSA_WITH_AES_256_GCM_SHA384, + TLS_RSA_WITH_AES_128_CBC_SHA, + TLS_RSA_WITH_AES_256_CBC_SHA, + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + TLS_RSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + TLS_RSA_WITH_AES_128_CBC_SHA256, + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, + TLS_RSA_WITH_RC4_128_SHA, +} + +// disabledCipherSuites are not used unless explicitly listed in +// Config.CipherSuites. They MUST be at the end of cipherSuitesPreferenceOrder. +var disabledCipherSuites = []uint16{ + // CBC_SHA256 + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + TLS_RSA_WITH_AES_128_CBC_SHA256, + + // RC4 + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, + TLS_RSA_WITH_RC4_128_SHA, +} + +var ( + defaultCipherSuitesLen = len(cipherSuitesPreferenceOrder) - len(disabledCipherSuites) + defaultCipherSuites = cipherSuitesPreferenceOrder[:defaultCipherSuitesLen] +) + +// defaultCipherSuitesTLS13 is also the preference order, since there are no +// disabled by default TLS 1.3 cipher suites. The same AES vs ChaCha20 logic as +// cipherSuitesPreferenceOrder applies. +var defaultCipherSuitesTLS13 = []uint16{ + TLS_AES_128_GCM_SHA256, + TLS_AES_256_GCM_SHA384, + TLS_CHACHA20_POLY1305_SHA256, +} + +var defaultCipherSuitesTLS13NoAES = []uint16{ + TLS_CHACHA20_POLY1305_SHA256, + TLS_AES_128_GCM_SHA256, + TLS_AES_256_GCM_SHA384, +} + +var ( + hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ + hasGCMAsmARM64 = cpu.ARM64.HasAES && cpu.ARM64.HasPMULL + // Keep in sync with crypto/aes/cipher_s390x.go. + hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && + (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM) + + hasAESGCMHardwareSupport = runtime.GOARCH == "amd64" && hasGCMAsmAMD64 || + runtime.GOARCH == "arm64" && hasGCMAsmARM64 || + runtime.GOARCH == "s390x" && hasGCMAsmS390X +) + +var aesgcmCiphers = map[uint16]bool{ + // TLS 1.2 + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: true, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: true, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: true, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: true, + // TLS 1.3 + TLS_AES_128_GCM_SHA256: true, + TLS_AES_256_GCM_SHA384: true, +} + +var nonAESGCMAEADCiphers = map[uint16]bool{ + // TLS 1.2 + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305: true, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: true, + // TLS 1.3 + TLS_CHACHA20_POLY1305_SHA256: true, +} + +// aesgcmPreferred returns whether the first known cipher in the preference list +// is an AES-GCM cipher, implying the peer has hardware support for it. +func aesgcmPreferred(ciphers []uint16) bool { + for _, cID := range ciphers { + if c := cipherSuiteByID(cID); c != nil { + return aesgcmCiphers[cID] + } + if c := cipherSuiteTLS13ByID(cID); c != nil { + return aesgcmCiphers[cID] + } + } + return false +} + +func cipherRC4(key, iv []byte, isRead bool) any { + cipher, _ := rc4.NewCipher(key) + return cipher +} + +func cipher3DES(key, iv []byte, isRead bool) any { + block, _ := des.NewTripleDESCipher(key) + if isRead { + return cipher.NewCBCDecrypter(block, iv) + } + return cipher.NewCBCEncrypter(block, iv) +} + +func cipherAES(key, iv []byte, isRead bool) any { + block, _ := aes.NewCipher(key) + if isRead { + return cipher.NewCBCDecrypter(block, iv) + } + return cipher.NewCBCEncrypter(block, iv) +} + +// macSHA1 returns a SHA-1 based constant time MAC. +func macSHA1(key []byte) hash.Hash { + h := sha1.New + h = newConstantTimeHash(h) + return hmac.New(h, key) +} + +// macSHA256 returns a SHA-256 based MAC. This is only supported in TLS 1.2 and +// is currently only used in disabled-by-default cipher suites. +func macSHA256(key []byte) hash.Hash { + return hmac.New(sha256.New, key) +} + +type aead interface { + cipher.AEAD + + // explicitNonceLen returns the number of bytes of explicit nonce + // included in each record. This is eight for older AEADs and + // zero for modern ones. + explicitNonceLen() int +} + +const ( + aeadNonceLength = 12 + noncePrefixLength = 4 +) + +// prefixNonceAEAD wraps an AEAD and prefixes a fixed portion of the nonce to +// each call. +type prefixNonceAEAD struct { + // nonce contains the fixed part of the nonce in the first four bytes. + nonce [aeadNonceLength]byte + aead cipher.AEAD +} + +func (f *prefixNonceAEAD) NonceSize() int { return aeadNonceLength - noncePrefixLength } +func (f *prefixNonceAEAD) Overhead() int { return f.aead.Overhead() } +func (f *prefixNonceAEAD) explicitNonceLen() int { return f.NonceSize() } + +func (f *prefixNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte { + copy(f.nonce[4:], nonce) + return f.aead.Seal(out, f.nonce[:], plaintext, additionalData) +} + +func (f *prefixNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) { + copy(f.nonce[4:], nonce) + return f.aead.Open(out, f.nonce[:], ciphertext, additionalData) +} + +// xorNonceAEAD wraps an AEAD by XORing in a fixed pattern to the nonce +// before each call. +type xorNonceAEAD struct { + nonceMask [aeadNonceLength]byte + aead cipher.AEAD +} + +func (f *xorNonceAEAD) NonceSize() int { return 8 } // 64-bit sequence number +func (f *xorNonceAEAD) Overhead() int { return f.aead.Overhead() } +func (f *xorNonceAEAD) explicitNonceLen() int { return 0 } + +func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte { + for i, b := range nonce { + f.nonceMask[4+i] ^= b + } + result := f.aead.Seal(out, f.nonceMask[:], plaintext, additionalData) + for i, b := range nonce { + f.nonceMask[4+i] ^= b + } + + return result +} + +func (f *xorNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) { + for i, b := range nonce { + f.nonceMask[4+i] ^= b + } + result, err := f.aead.Open(out, f.nonceMask[:], ciphertext, additionalData) + for i, b := range nonce { + f.nonceMask[4+i] ^= b + } + + return result, err +} + +func aeadAESGCM(key, noncePrefix []byte) aead { + if len(noncePrefix) != noncePrefixLength { + panic("tls: internal error: wrong nonce length") + } + aes, err := aes.NewCipher(key) + if err != nil { + panic(err) + } + var aead cipher.AEAD + aead, err = cipher.NewGCM(aes) + if err != nil { + panic(err) + } + + ret := &prefixNonceAEAD{aead: aead} + copy(ret.nonce[:], noncePrefix) + return ret +} + +func aeadAESGCMTLS13(key, nonceMask []byte) aead { + if len(nonceMask) != aeadNonceLength { + panic("tls: internal error: wrong nonce length") + } + aes, err := aes.NewCipher(key) + if err != nil { + panic(err) + } + aead, err := cipher.NewGCM(aes) + if err != nil { + panic(err) + } + + ret := &xorNonceAEAD{aead: aead} + copy(ret.nonceMask[:], nonceMask) + return ret +} + +func aeadChaCha20Poly1305(key, nonceMask []byte) aead { + if len(nonceMask) != aeadNonceLength { + panic("tls: internal error: wrong nonce length") + } + aead, err := chacha20poly1305.New(key) + if err != nil { + panic(err) + } + + ret := &xorNonceAEAD{aead: aead} + copy(ret.nonceMask[:], nonceMask) + return ret +} + +type constantTimeHash interface { + hash.Hash + ConstantTimeSum(b []byte) []byte +} + +// cthWrapper wraps any hash.Hash that implements ConstantTimeSum, and replaces +// with that all calls to Sum. It's used to obtain a ConstantTimeSum-based HMAC. +type cthWrapper struct { + h constantTimeHash +} + +func (c *cthWrapper) Size() int { return c.h.Size() } +func (c *cthWrapper) BlockSize() int { return c.h.BlockSize() } +func (c *cthWrapper) Reset() { c.h.Reset() } +func (c *cthWrapper) Write(p []byte) (int, error) { return c.h.Write(p) } +func (c *cthWrapper) Sum(b []byte) []byte { return c.h.ConstantTimeSum(b) } + +func newConstantTimeHash(h func() hash.Hash) func() hash.Hash { + return func() hash.Hash { + return &cthWrapper{h().(constantTimeHash)} + } +} + +// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, Section 6.2.3. +func tls10MAC(h hash.Hash, out, seq, header, data, extra []byte) []byte { + h.Reset() + h.Write(seq) + h.Write(header) + h.Write(data) + res := h.Sum(out) + if extra != nil { + h.Write(extra) + } + return res +} + +func rsaKA(version uint16) keyAgreement { + return rsaKeyAgreement{} +} + +func ecdheECDSAKA(version uint16) keyAgreement { + return &ecdheKeyAgreement{ + isRSA: false, + version: version, + } +} + +func ecdheRSAKA(version uint16) keyAgreement { + return &ecdheKeyAgreement{ + isRSA: true, + version: version, + } +} + +// mutualCipherSuite returns a cipherSuite given a list of supported +// ciphersuites and the id requested by the peer. +func mutualCipherSuite(have []uint16, want uint16) *cipherSuite { + for _, id := range have { + if id == want { + return cipherSuiteByID(id) + } + } + return nil +} + +func cipherSuiteByID(id uint16) *cipherSuite { + for _, cipherSuite := range cipherSuites { + if cipherSuite.id == id { + return cipherSuite + } + } + return nil +} + +func mutualCipherSuiteTLS13(have []uint16, want uint16) *cipherSuiteTLS13 { + for _, id := range have { + if id == want { + return cipherSuiteTLS13ByID(id) + } + } + return nil +} + +func cipherSuiteTLS13ByID(id uint16) *cipherSuiteTLS13 { + for _, cipherSuite := range cipherSuitesTLS13 { + if cipherSuite.id == id { + return cipherSuite + } + } + return nil +} + +// A list of cipher suite IDs that are, or have been, implemented by this +// package. +// +// See https://www.iana.org/assignments/tls-parameters/tls-parameters.xml +const ( + // TLS 1.0 - 1.2 cipher suites. + TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005 + TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a + TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f + TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035 + TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003c + TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009c + TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009d + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xc007 + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xc009 + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xc00a + TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xc011 + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012 + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013 + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014 + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc023 + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc027 + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02f + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030 + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcca8 + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcca9 + + // TLS 1.3 cipher suites. + TLS_AES_128_GCM_SHA256 uint16 = 0x1301 + TLS_AES_256_GCM_SHA384 uint16 = 0x1302 + TLS_CHACHA20_POLY1305_SHA256 uint16 = 0x1303 + + // TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator + // that the client is doing version fallback. See RFC 7507. + TLS_FALLBACK_SCSV uint16 = 0x5600 + + // Legacy names for the corresponding cipher suites with the correct _SHA256 + // suffix, retained for backward compatibility. + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 = TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 = TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 +) diff --git a/vendor/github.com/quic-go/qtls-go1-20/common.go b/vendor/github.com/quic-go/qtls-go1-20/common.go new file mode 100644 index 000000000..66901636e --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/common.go @@ -0,0 +1,1466 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package qtls + +import ( + "bytes" + "container/list" + "context" + "crypto" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "crypto/sha512" + "crypto/tls" + "crypto/x509" + "errors" + "fmt" + "io" + "net" + "strings" + "sync" + "time" +) + +const ( + VersionTLS10 = 0x0301 + VersionTLS11 = 0x0302 + VersionTLS12 = 0x0303 + VersionTLS13 = 0x0304 + + // Deprecated: SSLv3 is cryptographically broken, and is no longer + // supported by this package. See golang.org/issue/32716. + VersionSSL30 = 0x0300 +) + +const ( + maxPlaintext = 16384 // maximum plaintext payload length + maxCiphertext = 16384 + 2048 // maximum ciphertext payload length + maxCiphertextTLS13 = 16384 + 256 // maximum ciphertext length in TLS 1.3 + recordHeaderLen = 5 // record header length + maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB) + maxUselessRecords = 16 // maximum number of consecutive non-advancing records +) + +// TLS record types. +type recordType uint8 + +const ( + recordTypeChangeCipherSpec recordType = 20 + recordTypeAlert recordType = 21 + recordTypeHandshake recordType = 22 + recordTypeApplicationData recordType = 23 +) + +// TLS handshake message types. +const ( + typeHelloRequest uint8 = 0 + typeClientHello uint8 = 1 + typeServerHello uint8 = 2 + typeNewSessionTicket uint8 = 4 + typeEndOfEarlyData uint8 = 5 + typeEncryptedExtensions uint8 = 8 + typeCertificate uint8 = 11 + typeServerKeyExchange uint8 = 12 + typeCertificateRequest uint8 = 13 + typeServerHelloDone uint8 = 14 + typeCertificateVerify uint8 = 15 + typeClientKeyExchange uint8 = 16 + typeFinished uint8 = 20 + typeCertificateStatus uint8 = 22 + typeKeyUpdate uint8 = 24 + typeNextProtocol uint8 = 67 // Not IANA assigned + typeMessageHash uint8 = 254 // synthetic message +) + +// TLS compression types. +const ( + compressionNone uint8 = 0 +) + +// TLS extension numbers +const ( + extensionServerName uint16 = 0 + extensionStatusRequest uint16 = 5 + extensionSupportedCurves uint16 = 10 // supported_groups in TLS 1.3, see RFC 8446, Section 4.2.7 + extensionSupportedPoints uint16 = 11 + extensionSignatureAlgorithms uint16 = 13 + extensionALPN uint16 = 16 + extensionSCT uint16 = 18 + extensionSessionTicket uint16 = 35 + extensionPreSharedKey uint16 = 41 + extensionEarlyData uint16 = 42 + extensionSupportedVersions uint16 = 43 + extensionCookie uint16 = 44 + extensionPSKModes uint16 = 45 + extensionCertificateAuthorities uint16 = 47 + extensionSignatureAlgorithmsCert uint16 = 50 + extensionKeyShare uint16 = 51 + extensionQUICTransportParameters uint16 = 57 + extensionRenegotiationInfo uint16 = 0xff01 +) + +// TLS signaling cipher suite values +const ( + scsvRenegotiation uint16 = 0x00ff +) + +// CurveID is a tls.CurveID +type CurveID = tls.CurveID + +const ( + CurveP256 CurveID = 23 + CurveP384 CurveID = 24 + CurveP521 CurveID = 25 + X25519 CurveID = 29 +) + +// TLS 1.3 Key Share. See RFC 8446, Section 4.2.8. +type keyShare struct { + group CurveID + data []byte +} + +// TLS 1.3 PSK Key Exchange Modes. See RFC 8446, Section 4.2.9. +const ( + pskModePlain uint8 = 0 + pskModeDHE uint8 = 1 +) + +// TLS 1.3 PSK Identity. Can be a Session Ticket, or a reference to a saved +// session. See RFC 8446, Section 4.2.11. +type pskIdentity struct { + label []byte + obfuscatedTicketAge uint32 +} + +// TLS Elliptic Curve Point Formats +// https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9 +const ( + pointFormatUncompressed uint8 = 0 +) + +// TLS CertificateStatusType (RFC 3546) +const ( + statusTypeOCSP uint8 = 1 +) + +// Certificate types (for certificateRequestMsg) +const ( + certTypeRSASign = 1 + certTypeECDSASign = 64 // ECDSA or EdDSA keys, see RFC 8422, Section 3. +) + +// Signature algorithms (for internal signaling use). Starting at 225 to avoid overlap with +// TLS 1.2 codepoints (RFC 5246, Appendix A.4.1), with which these have nothing to do. +const ( + signaturePKCS1v15 uint8 = iota + 225 + signatureRSAPSS + signatureECDSA + signatureEd25519 +) + +// directSigning is a standard Hash value that signals that no pre-hashing +// should be performed, and that the input should be signed directly. It is the +// hash function associated with the Ed25519 signature scheme. +var directSigning crypto.Hash = 0 + +// defaultSupportedSignatureAlgorithms contains the signature and hash algorithms that +// the code advertises as supported in a TLS 1.2+ ClientHello and in a TLS 1.2+ +// CertificateRequest. The two fields are merged to match with TLS 1.3. +// Note that in TLS 1.2, the ECDSA algorithms are not constrained to P-256, etc. +var defaultSupportedSignatureAlgorithms = []SignatureScheme{ + PSSWithSHA256, + ECDSAWithP256AndSHA256, + Ed25519, + PSSWithSHA384, + PSSWithSHA512, + PKCS1WithSHA256, + PKCS1WithSHA384, + PKCS1WithSHA512, + ECDSAWithP384AndSHA384, + ECDSAWithP521AndSHA512, + PKCS1WithSHA1, + ECDSAWithSHA1, +} + +// helloRetryRequestRandom is set as the Random value of a ServerHello +// to signal that the message is actually a HelloRetryRequest. +var helloRetryRequestRandom = []byte{ // See RFC 8446, Section 4.1.3. + 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, + 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, + 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, + 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C, +} + +const ( + // downgradeCanaryTLS12 or downgradeCanaryTLS11 is embedded in the server + // random as a downgrade protection if the server would be capable of + // negotiating a higher version. See RFC 8446, Section 4.1.3. + downgradeCanaryTLS12 = "DOWNGRD\x01" + downgradeCanaryTLS11 = "DOWNGRD\x00" +) + +// testingOnlyForceDowngradeCanary is set in tests to force the server side to +// include downgrade canaries even if it's using its highers supported version. +var testingOnlyForceDowngradeCanary bool + +type ConnectionState = tls.ConnectionState + +// ConnectionState records basic TLS details about the connection. +type connectionState struct { + // Version is the TLS version used by the connection (e.g. VersionTLS12). + Version uint16 + + // HandshakeComplete is true if the handshake has concluded. + HandshakeComplete bool + + // DidResume is true if this connection was successfully resumed from a + // previous session with a session ticket or similar mechanism. + DidResume bool + + // CipherSuite is the cipher suite negotiated for the connection (e.g. + // TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_AES_128_GCM_SHA256). + CipherSuite uint16 + + // NegotiatedProtocol is the application protocol negotiated with ALPN. + NegotiatedProtocol string + + // NegotiatedProtocolIsMutual used to indicate a mutual NPN negotiation. + // + // Deprecated: this value is always true. + NegotiatedProtocolIsMutual bool + + // ServerName is the value of the Server Name Indication extension sent by + // the client. It's available both on the server and on the client side. + ServerName string + + // PeerCertificates are the parsed certificates sent by the peer, in the + // order in which they were sent. The first element is the leaf certificate + // that the connection is verified against. + // + // On the client side, it can't be empty. On the server side, it can be + // empty if Config.ClientAuth is not RequireAnyClientCert or + // RequireAndVerifyClientCert. + // + // PeerCertificates and its contents should not be modified. + PeerCertificates []*x509.Certificate + + // VerifiedChains is a list of one or more chains where the first element is + // PeerCertificates[0] and the last element is from Config.RootCAs (on the + // client side) or Config.ClientCAs (on the server side). + // + // On the client side, it's set if Config.InsecureSkipVerify is false. On + // the server side, it's set if Config.ClientAuth is VerifyClientCertIfGiven + // (and the peer provided a certificate) or RequireAndVerifyClientCert. + // + // VerifiedChains and its contents should not be modified. + VerifiedChains [][]*x509.Certificate + + // SignedCertificateTimestamps is a list of SCTs provided by the peer + // through the TLS handshake for the leaf certificate, if any. + SignedCertificateTimestamps [][]byte + + // OCSPResponse is a stapled Online Certificate Status Protocol (OCSP) + // response provided by the peer for the leaf certificate, if any. + OCSPResponse []byte + + // TLSUnique contains the "tls-unique" channel binding value (see RFC 5929, + // Section 3). This value will be nil for TLS 1.3 connections and for all + // resumed connections. + // + // Deprecated: there are conditions in which this value might not be unique + // to a connection. See the Security Considerations sections of RFC 5705 and + // RFC 7627, and https://mitls.org/pages/attacks/3SHAKE#channelbindings. + TLSUnique []byte + + // ekm is a closure exposed via ExportKeyingMaterial. + ekm func(label string, context []byte, length int) ([]byte, error) +} + +// ClientAuthType is tls.ClientAuthType +type ClientAuthType = tls.ClientAuthType + +const ( + NoClientCert = tls.NoClientCert + RequestClientCert = tls.RequestClientCert + RequireAnyClientCert = tls.RequireAnyClientCert + VerifyClientCertIfGiven = tls.VerifyClientCertIfGiven + RequireAndVerifyClientCert = tls.RequireAndVerifyClientCert +) + +// requiresClientCert reports whether the ClientAuthType requires a client +// certificate to be provided. +func requiresClientCert(c ClientAuthType) bool { + switch c { + case RequireAnyClientCert, RequireAndVerifyClientCert: + return true + default: + return false + } +} + +// ClientSessionState contains the state needed by clients to resume TLS +// sessions. +type ClientSessionState = tls.ClientSessionState + +type clientSessionState struct { + sessionTicket []uint8 // Encrypted ticket used for session resumption with server + vers uint16 // TLS version negotiated for the session + cipherSuite uint16 // Ciphersuite negotiated for the session + masterSecret []byte // Full handshake MasterSecret, or TLS 1.3 resumption_master_secret + serverCertificates []*x509.Certificate // Certificate chain presented by the server + verifiedChains [][]*x509.Certificate // Certificate chains we built for verification + receivedAt time.Time // When the session ticket was received from the server + ocspResponse []byte // Stapled OCSP response presented by the server + scts [][]byte // SCTs presented by the server + + // TLS 1.3 fields. + nonce []byte // Ticket nonce sent by the server, to derive PSK + useBy time.Time // Expiration of the ticket lifetime as set by the server + ageAdd uint32 // Random obfuscation factor for sending the ticket age +} + +// ClientSessionCache is a cache of ClientSessionState objects that can be used +// by a client to resume a TLS session with a given server. ClientSessionCache +// implementations should expect to be called concurrently from different +// goroutines. Up to TLS 1.2, only ticket-based resumption is supported, not +// SessionID-based resumption. In TLS 1.3 they were merged into PSK modes, which +// are supported via this interface. +type ClientSessionCache = tls.ClientSessionCache + +// SignatureScheme is a tls.SignatureScheme +type SignatureScheme = tls.SignatureScheme + +const ( + // RSASSA-PKCS1-v1_5 algorithms. + PKCS1WithSHA256 SignatureScheme = 0x0401 + PKCS1WithSHA384 SignatureScheme = 0x0501 + PKCS1WithSHA512 SignatureScheme = 0x0601 + + // RSASSA-PSS algorithms with public key OID rsaEncryption. + PSSWithSHA256 SignatureScheme = 0x0804 + PSSWithSHA384 SignatureScheme = 0x0805 + PSSWithSHA512 SignatureScheme = 0x0806 + + // ECDSA algorithms. Only constrained to a specific curve in TLS 1.3. + ECDSAWithP256AndSHA256 SignatureScheme = 0x0403 + ECDSAWithP384AndSHA384 SignatureScheme = 0x0503 + ECDSAWithP521AndSHA512 SignatureScheme = 0x0603 + + // EdDSA algorithms. + Ed25519 SignatureScheme = 0x0807 + + // Legacy signature and hash algorithms for TLS 1.2. + PKCS1WithSHA1 SignatureScheme = 0x0201 + ECDSAWithSHA1 SignatureScheme = 0x0203 +) + +// ClientHelloInfo contains information from a ClientHello message in order to +// guide application logic in the GetCertificate and GetConfigForClient callbacks. +type ClientHelloInfo = tls.ClientHelloInfo + +type clientHelloInfo struct { + // CipherSuites lists the CipherSuites supported by the client (e.g. + // TLS_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256). + CipherSuites []uint16 + + // ServerName indicates the name of the server requested by the client + // in order to support virtual hosting. ServerName is only set if the + // client is using SNI (see RFC 4366, Section 3.1). + ServerName string + + // SupportedCurves lists the elliptic curves supported by the client. + // SupportedCurves is set only if the Supported Elliptic Curves + // Extension is being used (see RFC 4492, Section 5.1.1). + SupportedCurves []CurveID + + // SupportedPoints lists the point formats supported by the client. + // SupportedPoints is set only if the Supported Point Formats Extension + // is being used (see RFC 4492, Section 5.1.2). + SupportedPoints []uint8 + + // SignatureSchemes lists the signature and hash schemes that the client + // is willing to verify. SignatureSchemes is set only if the Signature + // Algorithms Extension is being used (see RFC 5246, Section 7.4.1.4.1). + SignatureSchemes []SignatureScheme + + // SupportedProtos lists the application protocols supported by the client. + // SupportedProtos is set only if the Application-Layer Protocol + // Negotiation Extension is being used (see RFC 7301, Section 3.1). + // + // Servers can select a protocol by setting Config.NextProtos in a + // GetConfigForClient return value. + SupportedProtos []string + + // SupportedVersions lists the TLS versions supported by the client. + // For TLS versions less than 1.3, this is extrapolated from the max + // version advertised by the client, so values other than the greatest + // might be rejected if used. + SupportedVersions []uint16 + + // Conn is the underlying net.Conn for the connection. Do not read + // from, or write to, this connection; that will cause the TLS + // connection to fail. + Conn net.Conn + + // config is embedded by the GetCertificate or GetConfigForClient caller, + // for use with SupportsCertificate. + config *Config + + // ctx is the context of the handshake that is in progress. + ctx context.Context +} + +// Context returns the context of the handshake that is in progress. +// This context is a child of the context passed to HandshakeContext, +// if any, and is canceled when the handshake concludes. +func (c *clientHelloInfo) Context() context.Context { + return c.ctx +} + +// CertificateRequestInfo contains information from a server's +// CertificateRequest message, which is used to demand a certificate and proof +// of control from a client. +type CertificateRequestInfo = tls.CertificateRequestInfo + +type certificateRequestInfo struct { + // AcceptableCAs contains zero or more, DER-encoded, X.501 + // Distinguished Names. These are the names of root or intermediate CAs + // that the server wishes the returned certificate to be signed by. An + // empty slice indicates that the server has no preference. + AcceptableCAs [][]byte + + // SignatureSchemes lists the signature schemes that the server is + // willing to verify. + SignatureSchemes []SignatureScheme + + // Version is the TLS version that was negotiated for this connection. + Version uint16 + + // ctx is the context of the handshake that is in progress. + ctx context.Context +} + +// Context returns the context of the handshake that is in progress. +// This context is a child of the context passed to HandshakeContext, +// if any, and is canceled when the handshake concludes. +func (c *certificateRequestInfo) Context() context.Context { + return c.ctx +} + +// RenegotiationSupport enumerates the different levels of support for TLS +// renegotiation. TLS renegotiation is the act of performing subsequent +// handshakes on a connection after the first. This significantly complicates +// the state machine and has been the source of numerous, subtle security +// issues. Initiating a renegotiation is not supported, but support for +// accepting renegotiation requests may be enabled. +// +// Even when enabled, the server may not change its identity between handshakes +// (i.e. the leaf certificate must be the same). Additionally, concurrent +// handshake and application data flow is not permitted so renegotiation can +// only be used with protocols that synchronise with the renegotiation, such as +// HTTPS. +// +// Renegotiation is not defined in TLS 1.3. +type RenegotiationSupport = tls.RenegotiationSupport + +const ( + // RenegotiateNever disables renegotiation. + RenegotiateNever = tls.RenegotiateNever + + // RenegotiateOnceAsClient allows a remote server to request + // renegotiation once per connection. + RenegotiateOnceAsClient = tls.RenegotiateOnceAsClient + + // RenegotiateFreelyAsClient allows a remote server to repeatedly + // request renegotiation. + RenegotiateFreelyAsClient = tls.RenegotiateFreelyAsClient +) + +// A Config structure is used to configure a TLS client or server. +// After one has been passed to a TLS function it must not be +// modified. A Config may be reused; the tls package will also not +// modify it. +type Config = tls.Config + +type config struct { + // Rand provides the source of entropy for nonces and RSA blinding. + // If Rand is nil, TLS uses the cryptographic random reader in package + // crypto/rand. + // The Reader must be safe for use by multiple goroutines. + Rand io.Reader + + // Time returns the current time as the number of seconds since the epoch. + // If Time is nil, TLS uses time.Now. + Time func() time.Time + + // Certificates contains one or more certificate chains to present to the + // other side of the connection. The first certificate compatible with the + // peer's requirements is selected automatically. + // + // Server configurations must set one of Certificates, GetCertificate or + // GetConfigForClient. Clients doing client-authentication may set either + // Certificates or GetClientCertificate. + // + // Note: if there are multiple Certificates, and they don't have the + // optional field Leaf set, certificate selection will incur a significant + // per-handshake performance cost. + Certificates []Certificate + + // NameToCertificate maps from a certificate name to an element of + // Certificates. Note that a certificate name can be of the form + // '*.example.com' and so doesn't have to be a domain name as such. + // + // Deprecated: NameToCertificate only allows associating a single + // certificate with a given name. Leave this field nil to let the library + // select the first compatible chain from Certificates. + NameToCertificate map[string]*Certificate + + // GetCertificate returns a Certificate based on the given + // ClientHelloInfo. It will only be called if the client supplies SNI + // information or if Certificates is empty. + // + // If GetCertificate is nil or returns nil, then the certificate is + // retrieved from NameToCertificate. If NameToCertificate is nil, the + // best element of Certificates will be used. + // + // Once a Certificate is returned it should not be modified. + GetCertificate func(*ClientHelloInfo) (*Certificate, error) + + // GetClientCertificate, if not nil, is called when a server requests a + // certificate from a client. If set, the contents of Certificates will + // be ignored. + // + // If GetClientCertificate returns an error, the handshake will be + // aborted and that error will be returned. Otherwise + // GetClientCertificate must return a non-nil Certificate. If + // Certificate.Certificate is empty then no certificate will be sent to + // the server. If this is unacceptable to the server then it may abort + // the handshake. + // + // GetClientCertificate may be called multiple times for the same + // connection if renegotiation occurs or if TLS 1.3 is in use. + // + // Once a Certificate is returned it should not be modified. + GetClientCertificate func(*CertificateRequestInfo) (*Certificate, error) + + // GetConfigForClient, if not nil, is called after a ClientHello is + // received from a client. It may return a non-nil Config in order to + // change the Config that will be used to handle this connection. If + // the returned Config is nil, the original Config will be used. The + // Config returned by this callback may not be subsequently modified. + // + // If GetConfigForClient is nil, the Config passed to Server() will be + // used for all connections. + // + // If SessionTicketKey was explicitly set on the returned Config, or if + // SetSessionTicketKeys was called on the returned Config, those keys will + // be used. Otherwise, the original Config keys will be used (and possibly + // rotated if they are automatically managed). + GetConfigForClient func(*ClientHelloInfo) (*Config, error) + + // VerifyPeerCertificate, if not nil, is called after normal + // certificate verification by either a TLS client or server. It + // receives the raw ASN.1 certificates provided by the peer and also + // any verified chains that normal processing found. If it returns a + // non-nil error, the handshake is aborted and that error results. + // + // If normal verification fails then the handshake will abort before + // considering this callback. If normal verification is disabled by + // setting InsecureSkipVerify, or (for a server) when ClientAuth is + // RequestClientCert or RequireAnyClientCert, then this callback will + // be considered but the verifiedChains argument will always be nil. + // + // verifiedChains and its contents should not be modified. + VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error + + // VerifyConnection, if not nil, is called after normal certificate + // verification and after VerifyPeerCertificate by either a TLS client + // or server. If it returns a non-nil error, the handshake is aborted + // and that error results. + // + // If normal verification fails then the handshake will abort before + // considering this callback. This callback will run for all connections + // regardless of InsecureSkipVerify or ClientAuth settings. + VerifyConnection func(ConnectionState) error + + // RootCAs defines the set of root certificate authorities + // that clients use when verifying server certificates. + // If RootCAs is nil, TLS uses the host's root CA set. + RootCAs *x509.CertPool + + // NextProtos is a list of supported application level protocols, in + // order of preference. If both peers support ALPN, the selected + // protocol will be one from this list, and the connection will fail + // if there is no mutually supported protocol. If NextProtos is empty + // or the peer doesn't support ALPN, the connection will succeed and + // ConnectionState.NegotiatedProtocol will be empty. + NextProtos []string + + // ServerName is used to verify the hostname on the returned + // certificates unless InsecureSkipVerify is given. It is also included + // in the client's handshake to support virtual hosting unless it is + // an IP address. + ServerName string + + // ClientAuth determines the server's policy for + // TLS Client Authentication. The default is NoClientCert. + ClientAuth ClientAuthType + + // ClientCAs defines the set of root certificate authorities + // that servers use if required to verify a client certificate + // by the policy in ClientAuth. + ClientCAs *x509.CertPool + + // InsecureSkipVerify controls whether a client verifies the server's + // certificate chain and host name. If InsecureSkipVerify is true, crypto/tls + // accepts any certificate presented by the server and any host name in that + // certificate. In this mode, TLS is susceptible to machine-in-the-middle + // attacks unless custom verification is used. This should be used only for + // testing or in combination with VerifyConnection or VerifyPeerCertificate. + InsecureSkipVerify bool + + // CipherSuites is a list of enabled TLS 1.0–1.2 cipher suites. The order of + // the list is ignored. Note that TLS 1.3 ciphersuites are not configurable. + // + // If CipherSuites is nil, a safe default list is used. The default cipher + // suites might change over time. + CipherSuites []uint16 + + // PreferServerCipherSuites is a legacy field and has no effect. + // + // It used to control whether the server would follow the client's or the + // server's preference. Servers now select the best mutually supported + // cipher suite based on logic that takes into account inferred client + // hardware, server hardware, and security. + // + // Deprecated: PreferServerCipherSuites is ignored. + PreferServerCipherSuites bool + + // SessionTicketsDisabled may be set to true to disable session ticket and + // PSK (resumption) support. Note that on clients, session ticket support is + // also disabled if ClientSessionCache is nil. + SessionTicketsDisabled bool + + // SessionTicketKey is used by TLS servers to provide session resumption. + // See RFC 5077 and the PSK mode of RFC 8446. If zero, it will be filled + // with random data before the first server handshake. + // + // Deprecated: if this field is left at zero, session ticket keys will be + // automatically rotated every day and dropped after seven days. For + // customizing the rotation schedule or synchronizing servers that are + // terminating connections for the same host, use SetSessionTicketKeys. + SessionTicketKey [32]byte + + // ClientSessionCache is a cache of ClientSessionState entries for TLS + // session resumption. It is only used by clients. + ClientSessionCache ClientSessionCache + + // MinVersion contains the minimum TLS version that is acceptable. + // + // By default, TLS 1.2 is currently used as the minimum when acting as a + // client, and TLS 1.0 when acting as a server. TLS 1.0 is the minimum + // supported by this package, both as a client and as a server. + // + // The client-side default can temporarily be reverted to TLS 1.0 by + // including the value "x509sha1=1" in the GODEBUG environment variable. + // Note that this option will be removed in Go 1.19 (but it will still be + // possible to set this field to VersionTLS10 explicitly). + MinVersion uint16 + + // MaxVersion contains the maximum TLS version that is acceptable. + // + // By default, the maximum version supported by this package is used, + // which is currently TLS 1.3. + MaxVersion uint16 + + // CurvePreferences contains the elliptic curves that will be used in + // an ECDHE handshake, in preference order. If empty, the default will + // be used. The client will use the first preference as the type for + // its key share in TLS 1.3. This may change in the future. + CurvePreferences []CurveID + + // DynamicRecordSizingDisabled disables adaptive sizing of TLS records. + // When true, the largest possible TLS record size is always used. When + // false, the size of TLS records may be adjusted in an attempt to + // improve latency. + DynamicRecordSizingDisabled bool + + // Renegotiation controls what types of renegotiation are supported. + // The default, none, is correct for the vast majority of applications. + Renegotiation RenegotiationSupport + + // KeyLogWriter optionally specifies a destination for TLS master secrets + // in NSS key log format that can be used to allow external programs + // such as Wireshark to decrypt TLS connections. + // See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format. + // Use of KeyLogWriter compromises security and should only be + // used for debugging. + KeyLogWriter io.Writer + + // mutex protects sessionTicketKeys and autoSessionTicketKeys. + mutex sync.RWMutex + // sessionTicketKeys contains zero or more ticket keys. If set, it means + // the keys were set with SessionTicketKey or SetSessionTicketKeys. The + // first key is used for new tickets and any subsequent keys can be used to + // decrypt old tickets. The slice contents are not protected by the mutex + // and are immutable. + sessionTicketKeys []ticketKey + // autoSessionTicketKeys is like sessionTicketKeys but is owned by the + // auto-rotation logic. See Config.ticketKeys. + autoSessionTicketKeys []ticketKey +} + +type ExtraConfig struct { + // If Enable0RTT is enabled, the client will be allowed to send early data when resuming a session. + // + // It has no meaning on the client. + Enable0RTT bool + + // GetAppDataForSessionTicket requests application data to be sent with a session ticket. + // + // It has no meaning on the client. + GetAppDataForSessionTicket func() []byte + + // The Accept0RTT callback is called when the client offers 0-RTT. + // The server then has to decide if it wants to accept or reject 0-RTT. + // It is only used for servers. + Accept0RTT func(appData []byte) bool + + // Is called when the client saves a session ticket to the session ticket. + // This gives the application the opportunity to save some data along with the ticket, + // which can be restored when the session ticket is used. + GetAppDataForSessionState func() []byte + + // Is called when the client uses a session ticket. + // Restores the application data that was saved earlier on GetAppDataForSessionTicket. + SetAppDataFromSessionState func([]byte) +} + +// Clone clones. +func (c *ExtraConfig) Clone() *ExtraConfig { + return &ExtraConfig{ + Enable0RTT: c.Enable0RTT, + GetAppDataForSessionTicket: c.GetAppDataForSessionTicket, + Accept0RTT: c.Accept0RTT, + GetAppDataForSessionState: c.GetAppDataForSessionState, + SetAppDataFromSessionState: c.SetAppDataFromSessionState, + } +} + +const ( + // ticketKeyNameLen is the number of bytes of identifier that is prepended to + // an encrypted session ticket in order to identify the key used to encrypt it. + ticketKeyNameLen = 16 + + // ticketKeyLifetime is how long a ticket key remains valid and can be used to + // resume a client connection. + ticketKeyLifetime = 7 * 24 * time.Hour // 7 days + + // ticketKeyRotation is how often the server should rotate the session ticket key + // that is used for new tickets. + ticketKeyRotation = 24 * time.Hour +) + +// ticketKey is the internal representation of a session ticket key. +type ticketKey struct { + // keyName is an opaque byte string that serves to identify the session + // ticket key. It's exposed as plaintext in every session ticket. + keyName [ticketKeyNameLen]byte + aesKey [16]byte + hmacKey [16]byte + // created is the time at which this ticket key was created. See Config.ticketKeys. + created time.Time +} + +// ticketKeyFromBytes converts from the external representation of a session +// ticket key to a ticketKey. Externally, session ticket keys are 32 random +// bytes and this function expands that into sufficient name and key material. +func (c *config) ticketKeyFromBytes(b [32]byte) (key ticketKey) { + hashed := sha512.Sum512(b[:]) + copy(key.keyName[:], hashed[:ticketKeyNameLen]) + copy(key.aesKey[:], hashed[ticketKeyNameLen:ticketKeyNameLen+16]) + copy(key.hmacKey[:], hashed[ticketKeyNameLen+16:ticketKeyNameLen+32]) + key.created = c.time() + return key +} + +// maxSessionTicketLifetime is the maximum allowed lifetime of a TLS 1.3 session +// ticket, and the lifetime we set for tickets we send. +const maxSessionTicketLifetime = 7 * 24 * time.Hour + +// Clone returns a shallow clone of c or nil if c is nil. It is safe to clone a Config that is +// being used concurrently by a TLS client or server. +func (c *config) Clone() *config { + if c == nil { + return nil + } + c.mutex.RLock() + defer c.mutex.RUnlock() + return &config{ + Rand: c.Rand, + Time: c.Time, + Certificates: c.Certificates, + NameToCertificate: c.NameToCertificate, + GetCertificate: c.GetCertificate, + GetClientCertificate: c.GetClientCertificate, + GetConfigForClient: c.GetConfigForClient, + VerifyPeerCertificate: c.VerifyPeerCertificate, + VerifyConnection: c.VerifyConnection, + RootCAs: c.RootCAs, + NextProtos: c.NextProtos, + ServerName: c.ServerName, + ClientAuth: c.ClientAuth, + ClientCAs: c.ClientCAs, + InsecureSkipVerify: c.InsecureSkipVerify, + CipherSuites: c.CipherSuites, + PreferServerCipherSuites: c.PreferServerCipherSuites, + SessionTicketsDisabled: c.SessionTicketsDisabled, + SessionTicketKey: c.SessionTicketKey, + ClientSessionCache: c.ClientSessionCache, + MinVersion: c.MinVersion, + MaxVersion: c.MaxVersion, + CurvePreferences: c.CurvePreferences, + DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled, + Renegotiation: c.Renegotiation, + KeyLogWriter: c.KeyLogWriter, + sessionTicketKeys: c.sessionTicketKeys, + autoSessionTicketKeys: c.autoSessionTicketKeys, + } +} + +// deprecatedSessionTicketKey is set as the prefix of SessionTicketKey if it was +// randomized for backwards compatibility but is not in use. +var deprecatedSessionTicketKey = []byte("DEPRECATED") + +// initLegacySessionTicketKeyRLocked ensures the legacy SessionTicketKey field is +// randomized if empty, and that sessionTicketKeys is populated from it otherwise. +func (c *config) initLegacySessionTicketKeyRLocked() { + // Don't write if SessionTicketKey is already defined as our deprecated string, + // or if it is defined by the user but sessionTicketKeys is already set. + if c.SessionTicketKey != [32]byte{} && + (bytes.HasPrefix(c.SessionTicketKey[:], deprecatedSessionTicketKey) || len(c.sessionTicketKeys) > 0) { + return + } + + // We need to write some data, so get an exclusive lock and re-check any conditions. + c.mutex.RUnlock() + defer c.mutex.RLock() + c.mutex.Lock() + defer c.mutex.Unlock() + if c.SessionTicketKey == [32]byte{} { + if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil { + panic(fmt.Sprintf("tls: unable to generate random session ticket key: %v", err)) + } + // Write the deprecated prefix at the beginning so we know we created + // it. This key with the DEPRECATED prefix isn't used as an actual + // session ticket key, and is only randomized in case the application + // reuses it for some reason. + copy(c.SessionTicketKey[:], deprecatedSessionTicketKey) + } else if !bytes.HasPrefix(c.SessionTicketKey[:], deprecatedSessionTicketKey) && len(c.sessionTicketKeys) == 0 { + c.sessionTicketKeys = []ticketKey{c.ticketKeyFromBytes(c.SessionTicketKey)} + } + +} + +// ticketKeys returns the ticketKeys for this connection. +// If configForClient has explicitly set keys, those will +// be returned. Otherwise, the keys on c will be used and +// may be rotated if auto-managed. +// During rotation, any expired session ticket keys are deleted from +// c.sessionTicketKeys. If the session ticket key that is currently +// encrypting tickets (ie. the first ticketKey in c.sessionTicketKeys) +// is not fresh, then a new session ticket key will be +// created and prepended to c.sessionTicketKeys. +func (c *config) ticketKeys(configForClient *config) []ticketKey { + // If the ConfigForClient callback returned a Config with explicitly set + // keys, use those, otherwise just use the original Config. + if configForClient != nil { + configForClient.mutex.RLock() + if configForClient.SessionTicketsDisabled { + return nil + } + configForClient.initLegacySessionTicketKeyRLocked() + if len(configForClient.sessionTicketKeys) != 0 { + ret := configForClient.sessionTicketKeys + configForClient.mutex.RUnlock() + return ret + } + configForClient.mutex.RUnlock() + } + + c.mutex.RLock() + defer c.mutex.RUnlock() + if c.SessionTicketsDisabled { + return nil + } + c.initLegacySessionTicketKeyRLocked() + if len(c.sessionTicketKeys) != 0 { + return c.sessionTicketKeys + } + // Fast path for the common case where the key is fresh enough. + if len(c.autoSessionTicketKeys) > 0 && c.time().Sub(c.autoSessionTicketKeys[0].created) < ticketKeyRotation { + return c.autoSessionTicketKeys + } + + // autoSessionTicketKeys are managed by auto-rotation. + c.mutex.RUnlock() + defer c.mutex.RLock() + c.mutex.Lock() + defer c.mutex.Unlock() + // Re-check the condition in case it changed since obtaining the new lock. + if len(c.autoSessionTicketKeys) == 0 || c.time().Sub(c.autoSessionTicketKeys[0].created) >= ticketKeyRotation { + var newKey [32]byte + if _, err := io.ReadFull(c.rand(), newKey[:]); err != nil { + panic(fmt.Sprintf("unable to generate random session ticket key: %v", err)) + } + valid := make([]ticketKey, 0, len(c.autoSessionTicketKeys)+1) + valid = append(valid, c.ticketKeyFromBytes(newKey)) + for _, k := range c.autoSessionTicketKeys { + // While rotating the current key, also remove any expired ones. + if c.time().Sub(k.created) < ticketKeyLifetime { + valid = append(valid, k) + } + } + c.autoSessionTicketKeys = valid + } + return c.autoSessionTicketKeys +} + +// SetSessionTicketKeys updates the session ticket keys for a server. +// +// The first key will be used when creating new tickets, while all keys can be +// used for decrypting tickets. It is safe to call this function while the +// server is running in order to rotate the session ticket keys. The function +// will panic if keys is empty. +// +// Calling this function will turn off automatic session ticket key rotation. +// +// If multiple servers are terminating connections for the same host they should +// all have the same session ticket keys. If the session ticket keys leaks, +// previously recorded and future TLS connections using those keys might be +// compromised. +func (c *config) SetSessionTicketKeys(keys [][32]byte) { + if len(keys) == 0 { + panic("tls: keys must have at least one key") + } + + newKeys := make([]ticketKey, len(keys)) + for i, bytes := range keys { + newKeys[i] = c.ticketKeyFromBytes(bytes) + } + + c.mutex.Lock() + c.sessionTicketKeys = newKeys + c.mutex.Unlock() +} + +func (c *config) rand() io.Reader { + r := c.Rand + if r == nil { + return rand.Reader + } + return r +} + +func (c *config) time() time.Time { + t := c.Time + if t == nil { + t = time.Now + } + return t() +} + +func (c *config) cipherSuites() []uint16 { + if needFIPS() { + return fipsCipherSuites(c) + } + if c.CipherSuites != nil { + return c.CipherSuites + } + return defaultCipherSuites +} + +var supportedVersions = []uint16{ + VersionTLS13, + VersionTLS12, + VersionTLS11, + VersionTLS10, +} + +// roleClient and roleServer are meant to call supportedVersions and parents +// with more readability at the callsite. +const roleClient = true +const roleServer = false + +func (c *config) supportedVersions(isClient bool) []uint16 { + versions := make([]uint16, 0, len(supportedVersions)) + for _, v := range supportedVersions { + if needFIPS() && (v < fipsMinVersion(c) || v > fipsMaxVersion(c)) { + continue + } + if (c == nil || c.MinVersion == 0) && + isClient && v < VersionTLS12 { + continue + } + if c != nil && c.MinVersion != 0 && v < c.MinVersion { + continue + } + if c != nil && c.MaxVersion != 0 && v > c.MaxVersion { + continue + } + versions = append(versions, v) + } + return versions +} + +func (c *config) maxSupportedVersion(isClient bool) uint16 { + supportedVersions := c.supportedVersions(isClient) + if len(supportedVersions) == 0 { + return 0 + } + return supportedVersions[0] +} + +// supportedVersionsFromMax returns a list of supported versions derived from a +// legacy maximum version value. Note that only versions supported by this +// library are returned. Any newer peer will use supportedVersions anyway. +func supportedVersionsFromMax(maxVersion uint16) []uint16 { + versions := make([]uint16, 0, len(supportedVersions)) + for _, v := range supportedVersions { + if v > maxVersion { + continue + } + versions = append(versions, v) + } + return versions +} + +var defaultCurvePreferences = []CurveID{X25519, CurveP256, CurveP384, CurveP521} + +func (c *config) curvePreferences() []CurveID { + if needFIPS() { + return fipsCurvePreferences(c) + } + if c == nil || len(c.CurvePreferences) == 0 { + return defaultCurvePreferences + } + return c.CurvePreferences +} + +func (c *config) supportsCurve(curve CurveID) bool { + for _, cc := range c.curvePreferences() { + if cc == curve { + return true + } + } + return false +} + +// mutualVersion returns the protocol version to use given the advertised +// versions of the peer. Priority is given to the peer preference order. +func (c *config) mutualVersion(isClient bool, peerVersions []uint16) (uint16, bool) { + supportedVersions := c.supportedVersions(isClient) + for _, peerVersion := range peerVersions { + for _, v := range supportedVersions { + if v == peerVersion { + return v, true + } + } + } + return 0, false +} + +var errNoCertificates = errors.New("tls: no certificates configured") + +// getCertificate returns the best certificate for the given ClientHelloInfo, +// defaulting to the first element of c.Certificates. +func (c *config) getCertificate(clientHello *ClientHelloInfo) (*Certificate, error) { + if c.GetCertificate != nil && + (len(c.Certificates) == 0 || len(clientHello.ServerName) > 0) { + cert, err := c.GetCertificate(clientHello) + if cert != nil || err != nil { + return cert, err + } + } + + if len(c.Certificates) == 0 { + return nil, errNoCertificates + } + + if len(c.Certificates) == 1 { + // There's only one choice, so no point doing any work. + return &c.Certificates[0], nil + } + + if c.NameToCertificate != nil { + name := strings.ToLower(clientHello.ServerName) + if cert, ok := c.NameToCertificate[name]; ok { + return cert, nil + } + if len(name) > 0 { + labels := strings.Split(name, ".") + labels[0] = "*" + wildcardName := strings.Join(labels, ".") + if cert, ok := c.NameToCertificate[wildcardName]; ok { + return cert, nil + } + } + } + + for _, cert := range c.Certificates { + if err := clientHello.SupportsCertificate(&cert); err == nil { + return &cert, nil + } + } + + // If nothing matches, return the first certificate. + return &c.Certificates[0], nil +} + +// SupportsCertificate returns nil if the provided certificate is supported by +// the client that sent the ClientHello. Otherwise, it returns an error +// describing the reason for the incompatibility. +// +// If this ClientHelloInfo was passed to a GetConfigForClient or GetCertificate +// callback, this method will take into account the associated Config. Note that +// if GetConfigForClient returns a different Config, the change can't be +// accounted for by this method. +// +// This function will call x509.ParseCertificate unless c.Leaf is set, which can +// incur a significant performance cost. +func (chi *clientHelloInfo) SupportsCertificate(c *Certificate) error { + // Note we don't currently support certificate_authorities nor + // signature_algorithms_cert, and don't check the algorithms of the + // signatures on the chain (which anyway are a SHOULD, see RFC 8446, + // Section 4.4.2.2). + + config := chi.config + if config == nil { + config = &Config{} + } + conf := fromConfig(config) + vers, ok := conf.mutualVersion(roleServer, chi.SupportedVersions) + if !ok { + return errors.New("no mutually supported protocol versions") + } + + // If the client specified the name they are trying to connect to, the + // certificate needs to be valid for it. + if chi.ServerName != "" { + x509Cert, err := leafCertificate(c) + if err != nil { + return fmt.Errorf("failed to parse certificate: %w", err) + } + if err := x509Cert.VerifyHostname(chi.ServerName); err != nil { + return fmt.Errorf("certificate is not valid for requested server name: %w", err) + } + } + + // supportsRSAFallback returns nil if the certificate and connection support + // the static RSA key exchange, and unsupported otherwise. The logic for + // supporting static RSA is completely disjoint from the logic for + // supporting signed key exchanges, so we just check it as a fallback. + supportsRSAFallback := func(unsupported error) error { + // TLS 1.3 dropped support for the static RSA key exchange. + if vers == VersionTLS13 { + return unsupported + } + // The static RSA key exchange works by decrypting a challenge with the + // RSA private key, not by signing, so check the PrivateKey implements + // crypto.Decrypter, like *rsa.PrivateKey does. + if priv, ok := c.PrivateKey.(crypto.Decrypter); ok { + if _, ok := priv.Public().(*rsa.PublicKey); !ok { + return unsupported + } + } else { + return unsupported + } + // Finally, there needs to be a mutual cipher suite that uses the static + // RSA key exchange instead of ECDHE. + rsaCipherSuite := selectCipherSuite(chi.CipherSuites, conf.cipherSuites(), func(c *cipherSuite) bool { + if c.flags&suiteECDHE != 0 { + return false + } + if vers < VersionTLS12 && c.flags&suiteTLS12 != 0 { + return false + } + return true + }) + if rsaCipherSuite == nil { + return unsupported + } + return nil + } + + // If the client sent the signature_algorithms extension, ensure it supports + // schemes we can use with this certificate and TLS version. + if len(chi.SignatureSchemes) > 0 { + if _, err := selectSignatureScheme(vers, c, chi.SignatureSchemes); err != nil { + return supportsRSAFallback(err) + } + } + + // In TLS 1.3 we are done because supported_groups is only relevant to the + // ECDHE computation, point format negotiation is removed, cipher suites are + // only relevant to the AEAD choice, and static RSA does not exist. + if vers == VersionTLS13 { + return nil + } + + // The only signed key exchange we support is ECDHE. + if !supportsECDHE(conf, chi.SupportedCurves, chi.SupportedPoints) { + return supportsRSAFallback(errors.New("client doesn't support ECDHE, can only use legacy RSA key exchange")) + } + + var ecdsaCipherSuite bool + if priv, ok := c.PrivateKey.(crypto.Signer); ok { + switch pub := priv.Public().(type) { + case *ecdsa.PublicKey: + var curve CurveID + switch pub.Curve { + case elliptic.P256(): + curve = CurveP256 + case elliptic.P384(): + curve = CurveP384 + case elliptic.P521(): + curve = CurveP521 + default: + return supportsRSAFallback(unsupportedCertificateError(c)) + } + var curveOk bool + for _, c := range chi.SupportedCurves { + if c == curve && conf.supportsCurve(c) { + curveOk = true + break + } + } + if !curveOk { + return errors.New("client doesn't support certificate curve") + } + ecdsaCipherSuite = true + case ed25519.PublicKey: + if vers < VersionTLS12 || len(chi.SignatureSchemes) == 0 { + return errors.New("connection doesn't support Ed25519") + } + ecdsaCipherSuite = true + case *rsa.PublicKey: + default: + return supportsRSAFallback(unsupportedCertificateError(c)) + } + } else { + return supportsRSAFallback(unsupportedCertificateError(c)) + } + + // Make sure that there is a mutually supported cipher suite that works with + // this certificate. Cipher suite selection will then apply the logic in + // reverse to pick it. See also serverHandshakeState.cipherSuiteOk. + cipherSuite := selectCipherSuite(chi.CipherSuites, conf.cipherSuites(), func(c *cipherSuite) bool { + if c.flags&suiteECDHE == 0 { + return false + } + if c.flags&suiteECSign != 0 { + if !ecdsaCipherSuite { + return false + } + } else { + if ecdsaCipherSuite { + return false + } + } + if vers < VersionTLS12 && c.flags&suiteTLS12 != 0 { + return false + } + return true + }) + if cipherSuite == nil { + return supportsRSAFallback(errors.New("client doesn't support any cipher suites compatible with the certificate")) + } + + return nil +} + +// BuildNameToCertificate parses c.Certificates and builds c.NameToCertificate +// from the CommonName and SubjectAlternateName fields of each of the leaf +// certificates. +// +// Deprecated: NameToCertificate only allows associating a single certificate +// with a given name. Leave that field nil to let the library select the first +// compatible chain from Certificates. +func (c *config) BuildNameToCertificate() { + c.NameToCertificate = make(map[string]*Certificate) + for i := range c.Certificates { + cert := &c.Certificates[i] + x509Cert, err := leafCertificate(cert) + if err != nil { + continue + } + // If SANs are *not* present, some clients will consider the certificate + // valid for the name in the Common Name. + if x509Cert.Subject.CommonName != "" && len(x509Cert.DNSNames) == 0 { + c.NameToCertificate[x509Cert.Subject.CommonName] = cert + } + for _, san := range x509Cert.DNSNames { + c.NameToCertificate[san] = cert + } + } +} + +const ( + keyLogLabelTLS12 = "CLIENT_RANDOM" + keyLogLabelClientHandshake = "CLIENT_HANDSHAKE_TRAFFIC_SECRET" + keyLogLabelServerHandshake = "SERVER_HANDSHAKE_TRAFFIC_SECRET" + keyLogLabelClientTraffic = "CLIENT_TRAFFIC_SECRET_0" + keyLogLabelServerTraffic = "SERVER_TRAFFIC_SECRET_0" +) + +func (c *config) writeKeyLog(label string, clientRandom, secret []byte) error { + if c.KeyLogWriter == nil { + return nil + } + + logLine := fmt.Appendf(nil, "%s %x %x\n", label, clientRandom, secret) + + writerMutex.Lock() + _, err := c.KeyLogWriter.Write(logLine) + writerMutex.Unlock() + + return err +} + +// writerMutex protects all KeyLogWriters globally. It is rarely enabled, +// and is only for debugging, so a global mutex saves space. +var writerMutex sync.Mutex + +// A Certificate is a chain of one or more certificates, leaf first. +type Certificate = tls.Certificate + +// leaf returns the parsed leaf certificate, either from c.Leaf or by parsing +// the corresponding c.Certificate[0]. +func leafCertificate(c *Certificate) (*x509.Certificate, error) { + if c.Leaf != nil { + return c.Leaf, nil + } + return x509.ParseCertificate(c.Certificate[0]) +} + +type handshakeMessage interface { + marshal() ([]byte, error) + unmarshal([]byte) bool +} + +// lruSessionCache is a ClientSessionCache implementation that uses an LRU +// caching strategy. +type lruSessionCache struct { + sync.Mutex + + m map[string]*list.Element + q *list.List + capacity int +} + +type lruSessionCacheEntry struct { + sessionKey string + state *ClientSessionState +} + +// NewLRUClientSessionCache returns a ClientSessionCache with the given +// capacity that uses an LRU strategy. If capacity is < 1, a default capacity +// is used instead. +func NewLRUClientSessionCache(capacity int) ClientSessionCache { + const defaultSessionCacheCapacity = 64 + + if capacity < 1 { + capacity = defaultSessionCacheCapacity + } + return &lruSessionCache{ + m: make(map[string]*list.Element), + q: list.New(), + capacity: capacity, + } +} + +// Put adds the provided (sessionKey, cs) pair to the cache. If cs is nil, the entry +// corresponding to sessionKey is removed from the cache instead. +func (c *lruSessionCache) Put(sessionKey string, cs *ClientSessionState) { + c.Lock() + defer c.Unlock() + + if elem, ok := c.m[sessionKey]; ok { + if cs == nil { + c.q.Remove(elem) + delete(c.m, sessionKey) + } else { + entry := elem.Value.(*lruSessionCacheEntry) + entry.state = cs + c.q.MoveToFront(elem) + } + return + } + + if c.q.Len() < c.capacity { + entry := &lruSessionCacheEntry{sessionKey, cs} + c.m[sessionKey] = c.q.PushFront(entry) + return + } + + elem := c.q.Back() + entry := elem.Value.(*lruSessionCacheEntry) + delete(c.m, entry.sessionKey) + entry.sessionKey = sessionKey + entry.state = cs + c.q.MoveToFront(elem) + c.m[sessionKey] = elem +} + +// Get returns the ClientSessionState value associated with a given key. It +// returns (nil, false) if no value is found. +func (c *lruSessionCache) Get(sessionKey string) (*ClientSessionState, bool) { + c.Lock() + defer c.Unlock() + + if elem, ok := c.m[sessionKey]; ok { + c.q.MoveToFront(elem) + return elem.Value.(*lruSessionCacheEntry).state, true + } + return nil, false +} + +var emptyConfig Config + +func defaultConfig() *Config { + return &emptyConfig +} + +func unexpectedMessageError(wanted, got any) error { + return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted) +} + +func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlgorithms []SignatureScheme) bool { + for _, s := range supportedSignatureAlgorithms { + if s == sigAlg { + return true + } + } + return false +} + +// CertificateVerificationError is returned when certificate verification fails during the handshake. +type CertificateVerificationError struct { + // UnverifiedCertificates and its contents should not be modified. + UnverifiedCertificates []*x509.Certificate + Err error +} + +func (e *CertificateVerificationError) Error() string { + return fmt.Sprintf("tls: failed to verify certificate: %s", e.Err) +} + +func (e *CertificateVerificationError) Unwrap() error { + return e.Err +} diff --git a/vendor/github.com/quic-go/qtls-go1-20/conn.go b/vendor/github.com/quic-go/qtls-go1-20/conn.go new file mode 100644 index 000000000..b7ebdb0a7 --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/conn.go @@ -0,0 +1,1643 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// TLS low level connection and record layer + +package qtls + +import ( + "bytes" + "context" + "crypto/cipher" + "crypto/subtle" + "crypto/x509" + "errors" + "fmt" + "hash" + "io" + "net" + "sync" + "sync/atomic" + "time" +) + +// A Conn represents a secured connection. +// It implements the net.Conn interface. +type Conn struct { + // constant + conn net.Conn + isClient bool + handshakeFn func(context.Context) error // (*Conn).clientHandshake or serverHandshake + quic *quicState // nil for non-QUIC connections + + // isHandshakeComplete is true if the connection is currently transferring + // application data (i.e. is not currently processing a handshake). + // isHandshakeComplete is true implies handshakeErr == nil. + isHandshakeComplete atomic.Bool + // constant after handshake; protected by handshakeMutex + handshakeMutex sync.Mutex + handshakeErr error // error resulting from handshake + vers uint16 // TLS version + haveVers bool // version has been negotiated + config *config // configuration passed to constructor + extraConfig *ExtraConfig + // handshakes counts the number of handshakes performed on the + // connection so far. If renegotiation is disabled then this is either + // zero or one. + handshakes int + didResume bool // whether this connection was a session resumption + cipherSuite uint16 + ocspResponse []byte // stapled OCSP response + scts [][]byte // signed certificate timestamps from server + peerCertificates []*x509.Certificate + // activeCertHandles contains the cache handles to certificates in + // peerCertificates that are used to track active references. + activeCertHandles []*activeCert + // verifiedChains contains the certificate chains that we built, as + // opposed to the ones presented by the server. + verifiedChains [][]*x509.Certificate + // serverName contains the server name indicated by the client, if any. + serverName string + // secureRenegotiation is true if the server echoed the secure + // renegotiation extension. (This is meaningless as a server because + // renegotiation is not supported in that case.) + secureRenegotiation bool + // ekm is a closure for exporting keying material. + ekm func(label string, context []byte, length int) ([]byte, error) + // resumptionSecret is the resumption_master_secret for handling + // or sending NewSessionTicket messages. + resumptionSecret []byte + + // ticketKeys is the set of active session ticket keys for this + // connection. The first one is used to encrypt new tickets and + // all are tried to decrypt tickets. + ticketKeys []ticketKey + + // clientFinishedIsFirst is true if the client sent the first Finished + // message during the most recent handshake. This is recorded because + // the first transmitted Finished message is the tls-unique + // channel-binding value. + clientFinishedIsFirst bool + + // closeNotifyErr is any error from sending the alertCloseNotify record. + closeNotifyErr error + // closeNotifySent is true if the Conn attempted to send an + // alertCloseNotify record. + closeNotifySent bool + + // clientFinished and serverFinished contain the Finished message sent + // by the client or server in the most recent handshake. This is + // retained to support the renegotiation extension and tls-unique + // channel-binding. + clientFinished [12]byte + serverFinished [12]byte + + // clientProtocol is the negotiated ALPN protocol. + clientProtocol string + + // input/output + in, out halfConn + rawInput bytes.Buffer // raw input, starting with a record header + input bytes.Reader // application data waiting to be read, from rawInput.Next + hand bytes.Buffer // handshake data waiting to be read + buffering bool // whether records are buffered in sendBuf + sendBuf []byte // a buffer of records waiting to be sent + + // bytesSent counts the bytes of application data sent. + // packetsSent counts packets. + bytesSent int64 + packetsSent int64 + + // retryCount counts the number of consecutive non-advancing records + // received by Conn.readRecord. That is, records that neither advance the + // handshake, nor deliver application data. Protected by in.Mutex. + retryCount int + + // activeCall indicates whether Close has been call in the low bit. + // the rest of the bits are the number of goroutines in Conn.Write. + activeCall atomic.Int32 + + tmp [16]byte +} + +// Access to net.Conn methods. +// Cannot just embed net.Conn because that would +// export the struct field too. + +// LocalAddr returns the local network address. +func (c *Conn) LocalAddr() net.Addr { + return c.conn.LocalAddr() +} + +// RemoteAddr returns the remote network address. +func (c *Conn) RemoteAddr() net.Addr { + return c.conn.RemoteAddr() +} + +// SetDeadline sets the read and write deadlines associated with the connection. +// A zero value for t means Read and Write will not time out. +// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error. +func (c *Conn) SetDeadline(t time.Time) error { + return c.conn.SetDeadline(t) +} + +// SetReadDeadline sets the read deadline on the underlying connection. +// A zero value for t means Read will not time out. +func (c *Conn) SetReadDeadline(t time.Time) error { + return c.conn.SetReadDeadline(t) +} + +// SetWriteDeadline sets the write deadline on the underlying connection. +// A zero value for t means Write will not time out. +// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error. +func (c *Conn) SetWriteDeadline(t time.Time) error { + return c.conn.SetWriteDeadline(t) +} + +// NetConn returns the underlying connection that is wrapped by c. +// Note that writing to or reading from this connection directly will corrupt the +// TLS session. +func (c *Conn) NetConn() net.Conn { + return c.conn +} + +// A halfConn represents one direction of the record layer +// connection, either sending or receiving. +type halfConn struct { + sync.Mutex + + err error // first permanent error + version uint16 // protocol version + cipher any // cipher algorithm + mac hash.Hash + seq [8]byte // 64-bit sequence number + + scratchBuf [13]byte // to avoid allocs; interface method args escape + + nextCipher any // next encryption state + nextMac hash.Hash // next MAC algorithm + + level QUICEncryptionLevel // current QUIC encryption level + trafficSecret []byte // current TLS 1.3 traffic secret +} + +type permanentError struct { + err net.Error +} + +func (e *permanentError) Error() string { return e.err.Error() } +func (e *permanentError) Unwrap() error { return e.err } +func (e *permanentError) Timeout() bool { return e.err.Timeout() } +func (e *permanentError) Temporary() bool { return false } + +func (hc *halfConn) setErrorLocked(err error) error { + if e, ok := err.(net.Error); ok { + hc.err = &permanentError{err: e} + } else { + hc.err = err + } + return hc.err +} + +// prepareCipherSpec sets the encryption and MAC states +// that a subsequent changeCipherSpec will use. +func (hc *halfConn) prepareCipherSpec(version uint16, cipher any, mac hash.Hash) { + hc.version = version + hc.nextCipher = cipher + hc.nextMac = mac +} + +// changeCipherSpec changes the encryption and MAC states +// to the ones previously passed to prepareCipherSpec. +func (hc *halfConn) changeCipherSpec() error { + if hc.nextCipher == nil || hc.version == VersionTLS13 { + return alertInternalError + } + hc.cipher = hc.nextCipher + hc.mac = hc.nextMac + hc.nextCipher = nil + hc.nextMac = nil + for i := range hc.seq { + hc.seq[i] = 0 + } + return nil +} + +func (hc *halfConn) setTrafficSecret(suite *cipherSuiteTLS13, level QUICEncryptionLevel, secret []byte) { + hc.trafficSecret = secret + hc.level = level + key, iv := suite.trafficKey(secret) + hc.cipher = suite.aead(key, iv) + for i := range hc.seq { + hc.seq[i] = 0 + } +} + +// incSeq increments the sequence number. +func (hc *halfConn) incSeq() { + for i := 7; i >= 0; i-- { + hc.seq[i]++ + if hc.seq[i] != 0 { + return + } + } + + // Not allowed to let sequence number wrap. + // Instead, must renegotiate before it does. + // Not likely enough to bother. + panic("TLS: sequence number wraparound") +} + +// explicitNonceLen returns the number of bytes of explicit nonce or IV included +// in each record. Explicit nonces are present only in CBC modes after TLS 1.0 +// and in certain AEAD modes in TLS 1.2. +func (hc *halfConn) explicitNonceLen() int { + if hc.cipher == nil { + return 0 + } + + switch c := hc.cipher.(type) { + case cipher.Stream: + return 0 + case aead: + return c.explicitNonceLen() + case cbcMode: + // TLS 1.1 introduced a per-record explicit IV to fix the BEAST attack. + if hc.version >= VersionTLS11 { + return c.BlockSize() + } + return 0 + default: + panic("unknown cipher type") + } +} + +// extractPadding returns, in constant time, the length of the padding to remove +// from the end of payload. It also returns a byte which is equal to 255 if the +// padding was valid and 0 otherwise. See RFC 2246, Section 6.2.3.2. +func extractPadding(payload []byte) (toRemove int, good byte) { + if len(payload) < 1 { + return 0, 0 + } + + paddingLen := payload[len(payload)-1] + t := uint(len(payload)-1) - uint(paddingLen) + // if len(payload) >= (paddingLen - 1) then the MSB of t is zero + good = byte(int32(^t) >> 31) + + // The maximum possible padding length plus the actual length field + toCheck := 256 + // The length of the padded data is public, so we can use an if here + if toCheck > len(payload) { + toCheck = len(payload) + } + + for i := 0; i < toCheck; i++ { + t := uint(paddingLen) - uint(i) + // if i <= paddingLen then the MSB of t is zero + mask := byte(int32(^t) >> 31) + b := payload[len(payload)-1-i] + good &^= mask&paddingLen ^ mask&b + } + + // We AND together the bits of good and replicate the result across + // all the bits. + good &= good << 4 + good &= good << 2 + good &= good << 1 + good = uint8(int8(good) >> 7) + + // Zero the padding length on error. This ensures any unchecked bytes + // are included in the MAC. Otherwise, an attacker that could + // distinguish MAC failures from padding failures could mount an attack + // similar to POODLE in SSL 3.0: given a good ciphertext that uses a + // full block's worth of padding, replace the final block with another + // block. If the MAC check passed but the padding check failed, the + // last byte of that block decrypted to the block size. + // + // See also macAndPaddingGood logic below. + paddingLen &= good + + toRemove = int(paddingLen) + 1 + return +} + +func roundUp(a, b int) int { + return a + (b-a%b)%b +} + +// cbcMode is an interface for block ciphers using cipher block chaining. +type cbcMode interface { + cipher.BlockMode + SetIV([]byte) +} + +// decrypt authenticates and decrypts the record if protection is active at +// this stage. The returned plaintext might overlap with the input. +func (hc *halfConn) decrypt(record []byte) ([]byte, recordType, error) { + var plaintext []byte + typ := recordType(record[0]) + payload := record[recordHeaderLen:] + + // In TLS 1.3, change_cipher_spec messages are to be ignored without being + // decrypted. See RFC 8446, Appendix D.4. + if hc.version == VersionTLS13 && typ == recordTypeChangeCipherSpec { + return payload, typ, nil + } + + paddingGood := byte(255) + paddingLen := 0 + + explicitNonceLen := hc.explicitNonceLen() + + if hc.cipher != nil { + switch c := hc.cipher.(type) { + case cipher.Stream: + c.XORKeyStream(payload, payload) + case aead: + if len(payload) < explicitNonceLen { + return nil, 0, alertBadRecordMAC + } + nonce := payload[:explicitNonceLen] + if len(nonce) == 0 { + nonce = hc.seq[:] + } + payload = payload[explicitNonceLen:] + + var additionalData []byte + if hc.version == VersionTLS13 { + additionalData = record[:recordHeaderLen] + } else { + additionalData = append(hc.scratchBuf[:0], hc.seq[:]...) + additionalData = append(additionalData, record[:3]...) + n := len(payload) - c.Overhead() + additionalData = append(additionalData, byte(n>>8), byte(n)) + } + + var err error + plaintext, err = c.Open(payload[:0], nonce, payload, additionalData) + if err != nil { + return nil, 0, alertBadRecordMAC + } + case cbcMode: + blockSize := c.BlockSize() + minPayload := explicitNonceLen + roundUp(hc.mac.Size()+1, blockSize) + if len(payload)%blockSize != 0 || len(payload) < minPayload { + return nil, 0, alertBadRecordMAC + } + + if explicitNonceLen > 0 { + c.SetIV(payload[:explicitNonceLen]) + payload = payload[explicitNonceLen:] + } + c.CryptBlocks(payload, payload) + + // In a limited attempt to protect against CBC padding oracles like + // Lucky13, the data past paddingLen (which is secret) is passed to + // the MAC function as extra data, to be fed into the HMAC after + // computing the digest. This makes the MAC roughly constant time as + // long as the digest computation is constant time and does not + // affect the subsequent write, modulo cache effects. + paddingLen, paddingGood = extractPadding(payload) + default: + panic("unknown cipher type") + } + + if hc.version == VersionTLS13 { + if typ != recordTypeApplicationData { + return nil, 0, alertUnexpectedMessage + } + if len(plaintext) > maxPlaintext+1 { + return nil, 0, alertRecordOverflow + } + // Remove padding and find the ContentType scanning from the end. + for i := len(plaintext) - 1; i >= 0; i-- { + if plaintext[i] != 0 { + typ = recordType(plaintext[i]) + plaintext = plaintext[:i] + break + } + if i == 0 { + return nil, 0, alertUnexpectedMessage + } + } + } + } else { + plaintext = payload + } + + if hc.mac != nil { + macSize := hc.mac.Size() + if len(payload) < macSize { + return nil, 0, alertBadRecordMAC + } + + n := len(payload) - macSize - paddingLen + n = subtle.ConstantTimeSelect(int(uint32(n)>>31), 0, n) // if n < 0 { n = 0 } + record[3] = byte(n >> 8) + record[4] = byte(n) + remoteMAC := payload[n : n+macSize] + localMAC := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload[:n], payload[n+macSize:]) + + // This is equivalent to checking the MACs and paddingGood + // separately, but in constant-time to prevent distinguishing + // padding failures from MAC failures. Depending on what value + // of paddingLen was returned on bad padding, distinguishing + // bad MAC from bad padding can lead to an attack. + // + // See also the logic at the end of extractPadding. + macAndPaddingGood := subtle.ConstantTimeCompare(localMAC, remoteMAC) & int(paddingGood) + if macAndPaddingGood != 1 { + return nil, 0, alertBadRecordMAC + } + + plaintext = payload[:n] + } + + hc.incSeq() + return plaintext, typ, nil +} + +// sliceForAppend extends the input slice by n bytes. head is the full extended +// slice, while tail is the appended part. If the original slice has sufficient +// capacity no allocation is performed. +func sliceForAppend(in []byte, n int) (head, tail []byte) { + if total := len(in) + n; cap(in) >= total { + head = in[:total] + } else { + head = make([]byte, total) + copy(head, in) + } + tail = head[len(in):] + return +} + +// encrypt encrypts payload, adding the appropriate nonce and/or MAC, and +// appends it to record, which must already contain the record header. +func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, error) { + if hc.cipher == nil { + return append(record, payload...), nil + } + + var explicitNonce []byte + if explicitNonceLen := hc.explicitNonceLen(); explicitNonceLen > 0 { + record, explicitNonce = sliceForAppend(record, explicitNonceLen) + if _, isCBC := hc.cipher.(cbcMode); !isCBC && explicitNonceLen < 16 { + // The AES-GCM construction in TLS has an explicit nonce so that the + // nonce can be random. However, the nonce is only 8 bytes which is + // too small for a secure, random nonce. Therefore we use the + // sequence number as the nonce. The 3DES-CBC construction also has + // an 8 bytes nonce but its nonces must be unpredictable (see RFC + // 5246, Appendix F.3), forcing us to use randomness. That's not + // 3DES' biggest problem anyway because the birthday bound on block + // collision is reached first due to its similarly small block size + // (see the Sweet32 attack). + copy(explicitNonce, hc.seq[:]) + } else { + if _, err := io.ReadFull(rand, explicitNonce); err != nil { + return nil, err + } + } + } + + var dst []byte + switch c := hc.cipher.(type) { + case cipher.Stream: + mac := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload, nil) + record, dst = sliceForAppend(record, len(payload)+len(mac)) + c.XORKeyStream(dst[:len(payload)], payload) + c.XORKeyStream(dst[len(payload):], mac) + case aead: + nonce := explicitNonce + if len(nonce) == 0 { + nonce = hc.seq[:] + } + + if hc.version == VersionTLS13 { + record = append(record, payload...) + + // Encrypt the actual ContentType and replace the plaintext one. + record = append(record, record[0]) + record[0] = byte(recordTypeApplicationData) + + n := len(payload) + 1 + c.Overhead() + record[3] = byte(n >> 8) + record[4] = byte(n) + + record = c.Seal(record[:recordHeaderLen], + nonce, record[recordHeaderLen:], record[:recordHeaderLen]) + } else { + additionalData := append(hc.scratchBuf[:0], hc.seq[:]...) + additionalData = append(additionalData, record[:recordHeaderLen]...) + record = c.Seal(record, nonce, payload, additionalData) + } + case cbcMode: + mac := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload, nil) + blockSize := c.BlockSize() + plaintextLen := len(payload) + len(mac) + paddingLen := blockSize - plaintextLen%blockSize + record, dst = sliceForAppend(record, plaintextLen+paddingLen) + copy(dst, payload) + copy(dst[len(payload):], mac) + for i := plaintextLen; i < len(dst); i++ { + dst[i] = byte(paddingLen - 1) + } + if len(explicitNonce) > 0 { + c.SetIV(explicitNonce) + } + c.CryptBlocks(dst, dst) + default: + panic("unknown cipher type") + } + + // Update length to include nonce, MAC and any block padding needed. + n := len(record) - recordHeaderLen + record[3] = byte(n >> 8) + record[4] = byte(n) + hc.incSeq() + + return record, nil +} + +// RecordHeaderError is returned when a TLS record header is invalid. +type RecordHeaderError struct { + // Msg contains a human readable string that describes the error. + Msg string + // RecordHeader contains the five bytes of TLS record header that + // triggered the error. + RecordHeader [5]byte + // Conn provides the underlying net.Conn in the case that a client + // sent an initial handshake that didn't look like TLS. + // It is nil if there's already been a handshake or a TLS alert has + // been written to the connection. + Conn net.Conn +} + +func (e RecordHeaderError) Error() string { return "tls: " + e.Msg } + +func (c *Conn) newRecordHeaderError(conn net.Conn, msg string) (err RecordHeaderError) { + err.Msg = msg + err.Conn = conn + copy(err.RecordHeader[:], c.rawInput.Bytes()) + return err +} + +func (c *Conn) readRecord() error { + return c.readRecordOrCCS(false) +} + +func (c *Conn) readChangeCipherSpec() error { + return c.readRecordOrCCS(true) +} + +// readRecordOrCCS reads one or more TLS records from the connection and +// updates the record layer state. Some invariants: +// - c.in must be locked +// - c.input must be empty +// +// During the handshake one and only one of the following will happen: +// - c.hand grows +// - c.in.changeCipherSpec is called +// - an error is returned +// +// After the handshake one and only one of the following will happen: +// - c.hand grows +// - c.input is set +// - an error is returned +func (c *Conn) readRecordOrCCS(expectChangeCipherSpec bool) error { + if c.in.err != nil { + return c.in.err + } + handshakeComplete := c.isHandshakeComplete.Load() + + // This function modifies c.rawInput, which owns the c.input memory. + if c.input.Len() != 0 { + return c.in.setErrorLocked(errors.New("tls: internal error: attempted to read record with pending application data")) + } + c.input.Reset(nil) + + if c.quic != nil { + return c.in.setErrorLocked(errors.New("tls: internal error: attempted to read record with QUIC transport")) + } + + // Read header, payload. + if err := c.readFromUntil(c.conn, recordHeaderLen); err != nil { + // RFC 8446, Section 6.1 suggests that EOF without an alertCloseNotify + // is an error, but popular web sites seem to do this, so we accept it + // if and only if at the record boundary. + if err == io.ErrUnexpectedEOF && c.rawInput.Len() == 0 { + err = io.EOF + } + if e, ok := err.(net.Error); !ok || !e.Temporary() { + c.in.setErrorLocked(err) + } + return err + } + hdr := c.rawInput.Bytes()[:recordHeaderLen] + typ := recordType(hdr[0]) + + // No valid TLS record has a type of 0x80, however SSLv2 handshakes + // start with a uint16 length where the MSB is set and the first record + // is always < 256 bytes long. Therefore typ == 0x80 strongly suggests + // an SSLv2 client. + if !handshakeComplete && typ == 0x80 { + c.sendAlert(alertProtocolVersion) + return c.in.setErrorLocked(c.newRecordHeaderError(nil, "unsupported SSLv2 handshake received")) + } + + vers := uint16(hdr[1])<<8 | uint16(hdr[2]) + n := int(hdr[3])<<8 | int(hdr[4]) + if c.haveVers && c.vers != VersionTLS13 && vers != c.vers { + c.sendAlert(alertProtocolVersion) + msg := fmt.Sprintf("received record with version %x when expecting version %x", vers, c.vers) + return c.in.setErrorLocked(c.newRecordHeaderError(nil, msg)) + } + if !c.haveVers { + // First message, be extra suspicious: this might not be a TLS + // client. Bail out before reading a full 'body', if possible. + // The current max version is 3.3 so if the version is >= 16.0, + // it's probably not real. + if (typ != recordTypeAlert && typ != recordTypeHandshake) || vers >= 0x1000 { + return c.in.setErrorLocked(c.newRecordHeaderError(c.conn, "first record does not look like a TLS handshake")) + } + } + if c.vers == VersionTLS13 && n > maxCiphertextTLS13 || n > maxCiphertext { + c.sendAlert(alertRecordOverflow) + msg := fmt.Sprintf("oversized record received with length %d", n) + return c.in.setErrorLocked(c.newRecordHeaderError(nil, msg)) + } + if err := c.readFromUntil(c.conn, recordHeaderLen+n); err != nil { + if e, ok := err.(net.Error); !ok || !e.Temporary() { + c.in.setErrorLocked(err) + } + return err + } + + // Process message. + record := c.rawInput.Next(recordHeaderLen + n) + data, typ, err := c.in.decrypt(record) + if err != nil { + return c.in.setErrorLocked(c.sendAlert(err.(alert))) + } + if len(data) > maxPlaintext { + return c.in.setErrorLocked(c.sendAlert(alertRecordOverflow)) + } + + // Application Data messages are always protected. + if c.in.cipher == nil && typ == recordTypeApplicationData { + return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + } + + if typ != recordTypeAlert && typ != recordTypeChangeCipherSpec && len(data) > 0 { + // This is a state-advancing message: reset the retry count. + c.retryCount = 0 + } + + // Handshake messages MUST NOT be interleaved with other record types in TLS 1.3. + if c.vers == VersionTLS13 && typ != recordTypeHandshake && c.hand.Len() > 0 { + return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + } + + switch typ { + default: + return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + + case recordTypeAlert: + if c.quic != nil { + return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + } + if len(data) != 2 { + return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + } + if alert(data[1]) == alertCloseNotify { + return c.in.setErrorLocked(io.EOF) + } + if c.vers == VersionTLS13 { + return c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])}) + } + switch data[0] { + case alertLevelWarning: + // Drop the record on the floor and retry. + return c.retryReadRecord(expectChangeCipherSpec) + case alertLevelError: + return c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])}) + default: + return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + } + + case recordTypeChangeCipherSpec: + if len(data) != 1 || data[0] != 1 { + return c.in.setErrorLocked(c.sendAlert(alertDecodeError)) + } + // Handshake messages are not allowed to fragment across the CCS. + if c.hand.Len() > 0 { + return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + } + // In TLS 1.3, change_cipher_spec records are ignored until the + // Finished. See RFC 8446, Appendix D.4. Note that according to Section + // 5, a server can send a ChangeCipherSpec before its ServerHello, when + // c.vers is still unset. That's not useful though and suspicious if the + // server then selects a lower protocol version, so don't allow that. + if c.vers == VersionTLS13 { + return c.retryReadRecord(expectChangeCipherSpec) + } + if !expectChangeCipherSpec { + return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + } + if err := c.in.changeCipherSpec(); err != nil { + return c.in.setErrorLocked(c.sendAlert(err.(alert))) + } + + case recordTypeApplicationData: + if !handshakeComplete || expectChangeCipherSpec { + return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + } + // Some OpenSSL servers send empty records in order to randomize the + // CBC IV. Ignore a limited number of empty records. + if len(data) == 0 { + return c.retryReadRecord(expectChangeCipherSpec) + } + // Note that data is owned by c.rawInput, following the Next call above, + // to avoid copying the plaintext. This is safe because c.rawInput is + // not read from or written to until c.input is drained. + c.input.Reset(data) + + case recordTypeHandshake: + if len(data) == 0 || expectChangeCipherSpec { + return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + } + c.hand.Write(data) + } + + return nil +} + +// retryReadRecord recurs into readRecordOrCCS to drop a non-advancing record, like +// a warning alert, empty application_data, or a change_cipher_spec in TLS 1.3. +func (c *Conn) retryReadRecord(expectChangeCipherSpec bool) error { + c.retryCount++ + if c.retryCount > maxUselessRecords { + c.sendAlert(alertUnexpectedMessage) + return c.in.setErrorLocked(errors.New("tls: too many ignored records")) + } + return c.readRecordOrCCS(expectChangeCipherSpec) +} + +// atLeastReader reads from R, stopping with EOF once at least N bytes have been +// read. It is different from an io.LimitedReader in that it doesn't cut short +// the last Read call, and in that it considers an early EOF an error. +type atLeastReader struct { + R io.Reader + N int64 +} + +func (r *atLeastReader) Read(p []byte) (int, error) { + if r.N <= 0 { + return 0, io.EOF + } + n, err := r.R.Read(p) + r.N -= int64(n) // won't underflow unless len(p) >= n > 9223372036854775809 + if r.N > 0 && err == io.EOF { + return n, io.ErrUnexpectedEOF + } + if r.N <= 0 && err == nil { + return n, io.EOF + } + return n, err +} + +// readFromUntil reads from r into c.rawInput until c.rawInput contains +// at least n bytes or else returns an error. +func (c *Conn) readFromUntil(r io.Reader, n int) error { + if c.rawInput.Len() >= n { + return nil + } + needs := n - c.rawInput.Len() + // There might be extra input waiting on the wire. Make a best effort + // attempt to fetch it so that it can be used in (*Conn).Read to + // "predict" closeNotify alerts. + c.rawInput.Grow(needs + bytes.MinRead) + _, err := c.rawInput.ReadFrom(&atLeastReader{r, int64(needs)}) + return err +} + +// sendAlert sends a TLS alert message. +func (c *Conn) sendAlertLocked(err alert) error { + if c.quic != nil { + return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err}) + } + switch err { + case alertNoRenegotiation, alertCloseNotify: + c.tmp[0] = alertLevelWarning + default: + c.tmp[0] = alertLevelError + } + c.tmp[1] = byte(err) + + _, writeErr := c.writeRecordLocked(recordTypeAlert, c.tmp[0:2]) + if err == alertCloseNotify { + // closeNotify is a special case in that it isn't an error. + return writeErr + } + + return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err}) +} + +// sendAlert sends a TLS alert message. +func (c *Conn) sendAlert(err alert) error { + c.out.Lock() + defer c.out.Unlock() + return c.sendAlertLocked(err) +} + +const ( + // tcpMSSEstimate is a conservative estimate of the TCP maximum segment + // size (MSS). A constant is used, rather than querying the kernel for + // the actual MSS, to avoid complexity. The value here is the IPv6 + // minimum MTU (1280 bytes) minus the overhead of an IPv6 header (40 + // bytes) and a TCP header with timestamps (32 bytes). + tcpMSSEstimate = 1208 + + // recordSizeBoostThreshold is the number of bytes of application data + // sent after which the TLS record size will be increased to the + // maximum. + recordSizeBoostThreshold = 128 * 1024 +) + +// maxPayloadSizeForWrite returns the maximum TLS payload size to use for the +// next application data record. There is the following trade-off: +// +// - For latency-sensitive applications, such as web browsing, each TLS +// record should fit in one TCP segment. +// - For throughput-sensitive applications, such as large file transfers, +// larger TLS records better amortize framing and encryption overheads. +// +// A simple heuristic that works well in practice is to use small records for +// the first 1MB of data, then use larger records for subsequent data, and +// reset back to smaller records after the connection becomes idle. See "High +// Performance Web Networking", Chapter 4, or: +// https://www.igvita.com/2013/10/24/optimizing-tls-record-size-and-buffering-latency/ +// +// In the interests of simplicity and determinism, this code does not attempt +// to reset the record size once the connection is idle, however. +func (c *Conn) maxPayloadSizeForWrite(typ recordType) int { + if c.config.DynamicRecordSizingDisabled || typ != recordTypeApplicationData { + return maxPlaintext + } + + if c.bytesSent >= recordSizeBoostThreshold { + return maxPlaintext + } + + // Subtract TLS overheads to get the maximum payload size. + payloadBytes := tcpMSSEstimate - recordHeaderLen - c.out.explicitNonceLen() + if c.out.cipher != nil { + switch ciph := c.out.cipher.(type) { + case cipher.Stream: + payloadBytes -= c.out.mac.Size() + case cipher.AEAD: + payloadBytes -= ciph.Overhead() + case cbcMode: + blockSize := ciph.BlockSize() + // The payload must fit in a multiple of blockSize, with + // room for at least one padding byte. + payloadBytes = (payloadBytes & ^(blockSize - 1)) - 1 + // The MAC is appended before padding so affects the + // payload size directly. + payloadBytes -= c.out.mac.Size() + default: + panic("unknown cipher type") + } + } + if c.vers == VersionTLS13 { + payloadBytes-- // encrypted ContentType + } + + // Allow packet growth in arithmetic progression up to max. + pkt := c.packetsSent + c.packetsSent++ + if pkt > 1000 { + return maxPlaintext // avoid overflow in multiply below + } + + n := payloadBytes * int(pkt+1) + if n > maxPlaintext { + n = maxPlaintext + } + return n +} + +func (c *Conn) write(data []byte) (int, error) { + if c.buffering { + c.sendBuf = append(c.sendBuf, data...) + return len(data), nil + } + + n, err := c.conn.Write(data) + c.bytesSent += int64(n) + return n, err +} + +func (c *Conn) flush() (int, error) { + if len(c.sendBuf) == 0 { + return 0, nil + } + + n, err := c.conn.Write(c.sendBuf) + c.bytesSent += int64(n) + c.sendBuf = nil + c.buffering = false + return n, err +} + +// outBufPool pools the record-sized scratch buffers used by writeRecordLocked. +var outBufPool = sync.Pool{ + New: func() any { + return new([]byte) + }, +} + +// writeRecordLocked writes a TLS record with the given type and payload to the +// connection and updates the record layer state. +func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) { + if c.quic != nil { + if typ != recordTypeHandshake { + return 0, errors.New("tls: internal error: sending non-handshake message to QUIC transport") + } + c.quicWriteCryptoData(c.out.level, data) + if !c.buffering { + if _, err := c.flush(); err != nil { + return 0, err + } + } + return len(data), nil + } + + outBufPtr := outBufPool.Get().(*[]byte) + outBuf := *outBufPtr + defer func() { + // You might be tempted to simplify this by just passing &outBuf to Put, + // but that would make the local copy of the outBuf slice header escape + // to the heap, causing an allocation. Instead, we keep around the + // pointer to the slice header returned by Get, which is already on the + // heap, and overwrite and return that. + *outBufPtr = outBuf + outBufPool.Put(outBufPtr) + }() + + var n int + for len(data) > 0 { + m := len(data) + if maxPayload := c.maxPayloadSizeForWrite(typ); m > maxPayload { + m = maxPayload + } + + _, outBuf = sliceForAppend(outBuf[:0], recordHeaderLen) + outBuf[0] = byte(typ) + vers := c.vers + if vers == 0 { + // Some TLS servers fail if the record version is + // greater than TLS 1.0 for the initial ClientHello. + vers = VersionTLS10 + } else if vers == VersionTLS13 { + // TLS 1.3 froze the record layer version to 1.2. + // See RFC 8446, Section 5.1. + vers = VersionTLS12 + } + outBuf[1] = byte(vers >> 8) + outBuf[2] = byte(vers) + outBuf[3] = byte(m >> 8) + outBuf[4] = byte(m) + + var err error + outBuf, err = c.out.encrypt(outBuf, data[:m], c.config.rand()) + if err != nil { + return n, err + } + if _, err := c.write(outBuf); err != nil { + return n, err + } + n += m + data = data[m:] + } + + if typ == recordTypeChangeCipherSpec && c.vers != VersionTLS13 { + if err := c.out.changeCipherSpec(); err != nil { + return n, c.sendAlertLocked(err.(alert)) + } + } + + return n, nil +} + +// writeHandshakeRecord writes a handshake message to the connection and updates +// the record layer state. If transcript is non-nil the marshalled message is +// written to it. +func (c *Conn) writeHandshakeRecord(msg handshakeMessage, transcript transcriptHash) (int, error) { + c.out.Lock() + defer c.out.Unlock() + + data, err := msg.marshal() + if err != nil { + return 0, err + } + if transcript != nil { + transcript.Write(data) + } + + return c.writeRecordLocked(recordTypeHandshake, data) +} + +// writeChangeCipherRecord writes a ChangeCipherSpec message to the connection and +// updates the record layer state. +func (c *Conn) writeChangeCipherRecord() error { + c.out.Lock() + defer c.out.Unlock() + _, err := c.writeRecordLocked(recordTypeChangeCipherSpec, []byte{1}) + return err +} + +// readHandshakeBytes reads handshake data until c.hand contains at least n bytes. +func (c *Conn) readHandshakeBytes(n int) error { + if c.quic != nil { + return c.quicReadHandshakeBytes(n) + } + for c.hand.Len() < n { + if err := c.readRecord(); err != nil { + return err + } + } + return nil +} + +// readHandshake reads the next handshake message from +// the record layer. If transcript is non-nil, the message +// is written to the passed transcriptHash. +func (c *Conn) readHandshake(transcript transcriptHash) (any, error) { + if err := c.readHandshakeBytes(4); err != nil { + return nil, err + } + data := c.hand.Bytes() + n := int(data[1])<<16 | int(data[2])<<8 | int(data[3]) + if n > maxHandshake { + c.sendAlertLocked(alertInternalError) + return nil, c.in.setErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake)) + } + if err := c.readHandshakeBytes(4 + n); err != nil { + return nil, err + } + data = c.hand.Next(4 + n) + return c.unmarshalHandshakeMessage(data, transcript) +} + +func (c *Conn) unmarshalHandshakeMessage(data []byte, transcript transcriptHash) (handshakeMessage, error) { + var m handshakeMessage + switch data[0] { + case typeHelloRequest: + m = new(helloRequestMsg) + case typeClientHello: + m = new(clientHelloMsg) + case typeServerHello: + m = new(serverHelloMsg) + case typeNewSessionTicket: + if c.vers == VersionTLS13 { + m = new(newSessionTicketMsgTLS13) + } else { + m = new(newSessionTicketMsg) + } + case typeCertificate: + if c.vers == VersionTLS13 { + m = new(certificateMsgTLS13) + } else { + m = new(certificateMsg) + } + case typeCertificateRequest: + if c.vers == VersionTLS13 { + m = new(certificateRequestMsgTLS13) + } else { + m = &certificateRequestMsg{ + hasSignatureAlgorithm: c.vers >= VersionTLS12, + } + } + case typeCertificateStatus: + m = new(certificateStatusMsg) + case typeServerKeyExchange: + m = new(serverKeyExchangeMsg) + case typeServerHelloDone: + m = new(serverHelloDoneMsg) + case typeClientKeyExchange: + m = new(clientKeyExchangeMsg) + case typeCertificateVerify: + m = &certificateVerifyMsg{ + hasSignatureAlgorithm: c.vers >= VersionTLS12, + } + case typeFinished: + m = new(finishedMsg) + case typeEncryptedExtensions: + m = new(encryptedExtensionsMsg) + case typeEndOfEarlyData: + m = new(endOfEarlyDataMsg) + case typeKeyUpdate: + m = new(keyUpdateMsg) + default: + return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + } + + // The handshake message unmarshalers + // expect to be able to keep references to data, + // so pass in a fresh copy that won't be overwritten. + data = append([]byte(nil), data...) + + if !m.unmarshal(data) { + return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + } + + if transcript != nil { + transcript.Write(data) + } + + return m, nil +} + +var ( + errShutdown = errors.New("tls: protocol is shutdown") +) + +// Write writes data to the connection. +// +// As Write calls Handshake, in order to prevent indefinite blocking a deadline +// must be set for both Read and Write before Write is called when the handshake +// has not yet completed. See SetDeadline, SetReadDeadline, and +// SetWriteDeadline. +func (c *Conn) Write(b []byte) (int, error) { + // interlock with Close below + for { + x := c.activeCall.Load() + if x&1 != 0 { + return 0, net.ErrClosed + } + if c.activeCall.CompareAndSwap(x, x+2) { + break + } + } + defer c.activeCall.Add(-2) + + if err := c.Handshake(); err != nil { + return 0, err + } + + c.out.Lock() + defer c.out.Unlock() + + if err := c.out.err; err != nil { + return 0, err + } + + if !c.isHandshakeComplete.Load() { + return 0, alertInternalError + } + + if c.closeNotifySent { + return 0, errShutdown + } + + // TLS 1.0 is susceptible to a chosen-plaintext + // attack when using block mode ciphers due to predictable IVs. + // This can be prevented by splitting each Application Data + // record into two records, effectively randomizing the IV. + // + // https://www.openssl.org/~bodo/tls-cbc.txt + // https://bugzilla.mozilla.org/show_bug.cgi?id=665814 + // https://www.imperialviolet.org/2012/01/15/beastfollowup.html + + var m int + if len(b) > 1 && c.vers == VersionTLS10 { + if _, ok := c.out.cipher.(cipher.BlockMode); ok { + n, err := c.writeRecordLocked(recordTypeApplicationData, b[:1]) + if err != nil { + return n, c.out.setErrorLocked(err) + } + m, b = 1, b[1:] + } + } + + n, err := c.writeRecordLocked(recordTypeApplicationData, b) + return n + m, c.out.setErrorLocked(err) +} + +// handleRenegotiation processes a HelloRequest handshake message. +func (c *Conn) handleRenegotiation() error { + if c.vers == VersionTLS13 { + return errors.New("tls: internal error: unexpected renegotiation") + } + + msg, err := c.readHandshake(nil) + if err != nil { + return err + } + + helloReq, ok := msg.(*helloRequestMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(helloReq, msg) + } + + if !c.isClient { + return c.sendAlert(alertNoRenegotiation) + } + + switch c.config.Renegotiation { + case RenegotiateNever: + return c.sendAlert(alertNoRenegotiation) + case RenegotiateOnceAsClient: + if c.handshakes > 1 { + return c.sendAlert(alertNoRenegotiation) + } + case RenegotiateFreelyAsClient: + // Ok. + default: + c.sendAlert(alertInternalError) + return errors.New("tls: unknown Renegotiation value") + } + + c.handshakeMutex.Lock() + defer c.handshakeMutex.Unlock() + + c.isHandshakeComplete.Store(false) + if c.handshakeErr = c.clientHandshake(context.Background()); c.handshakeErr == nil { + c.handshakes++ + } + return c.handshakeErr +} + +// handlePostHandshakeMessage processes a handshake message arrived after the +// handshake is complete. Up to TLS 1.2, it indicates the start of a renegotiation. +func (c *Conn) handlePostHandshakeMessage() error { + if c.vers != VersionTLS13 { + return c.handleRenegotiation() + } + + msg, err := c.readHandshake(nil) + if err != nil { + return err + } + c.retryCount++ + if c.retryCount > maxUselessRecords { + c.sendAlert(alertUnexpectedMessage) + return c.in.setErrorLocked(errors.New("tls: too many non-advancing records")) + } + + switch msg := msg.(type) { + case *newSessionTicketMsgTLS13: + return c.handleNewSessionTicket(msg) + case *keyUpdateMsg: + return c.handleKeyUpdate(msg) + } + // The QUIC layer is supposed to treat an unexpected post-handshake CertificateRequest + // as a QUIC-level PROTOCOL_VIOLATION error (RFC 9001, Section 4.4). Returning an + // unexpected_message alert here doesn't provide it with enough information to distinguish + // this condition from other unexpected messages. This is probably fine. + c.sendAlert(alertUnexpectedMessage) + return fmt.Errorf("tls: received unexpected handshake message of type %T", msg) +} + +func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error { + if c.quic != nil { + c.sendAlert(alertUnexpectedMessage) + return c.in.setErrorLocked(errors.New("tls: received unexpected key update message")) + } + + cipherSuite := cipherSuiteTLS13ByID(c.cipherSuite) + if cipherSuite == nil { + return c.in.setErrorLocked(c.sendAlert(alertInternalError)) + } + + newSecret := cipherSuite.nextTrafficSecret(c.in.trafficSecret) + c.in.setTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret) + + if keyUpdate.updateRequested { + c.out.Lock() + defer c.out.Unlock() + + msg := &keyUpdateMsg{} + msgBytes, err := msg.marshal() + if err != nil { + return err + } + _, err = c.writeRecordLocked(recordTypeHandshake, msgBytes) + if err != nil { + // Surface the error at the next write. + c.out.setErrorLocked(err) + return nil + } + + newSecret := cipherSuite.nextTrafficSecret(c.out.trafficSecret) + c.out.setTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret) + } + + return nil +} + +// Read reads data from the connection. +// +// As Read calls Handshake, in order to prevent indefinite blocking a deadline +// must be set for both Read and Write before Read is called when the handshake +// has not yet completed. See SetDeadline, SetReadDeadline, and +// SetWriteDeadline. +func (c *Conn) Read(b []byte) (int, error) { + if err := c.Handshake(); err != nil { + return 0, err + } + if len(b) == 0 { + // Put this after Handshake, in case people were calling + // Read(nil) for the side effect of the Handshake. + return 0, nil + } + + c.in.Lock() + defer c.in.Unlock() + + for c.input.Len() == 0 { + if err := c.readRecord(); err != nil { + return 0, err + } + for c.hand.Len() > 0 { + if err := c.handlePostHandshakeMessage(); err != nil { + return 0, err + } + } + } + + n, _ := c.input.Read(b) + + // If a close-notify alert is waiting, read it so that we can return (n, + // EOF) instead of (n, nil), to signal to the HTTP response reading + // goroutine that the connection is now closed. This eliminates a race + // where the HTTP response reading goroutine would otherwise not observe + // the EOF until its next read, by which time a client goroutine might + // have already tried to reuse the HTTP connection for a new request. + // See https://golang.org/cl/76400046 and https://golang.org/issue/3514 + if n != 0 && c.input.Len() == 0 && c.rawInput.Len() > 0 && + recordType(c.rawInput.Bytes()[0]) == recordTypeAlert { + if err := c.readRecord(); err != nil { + return n, err // will be io.EOF on closeNotify + } + } + + return n, nil +} + +// Close closes the connection. +func (c *Conn) Close() error { + // Interlock with Conn.Write above. + var x int32 + for { + x = c.activeCall.Load() + if x&1 != 0 { + return net.ErrClosed + } + if c.activeCall.CompareAndSwap(x, x|1) { + break + } + } + if x != 0 { + // io.Writer and io.Closer should not be used concurrently. + // If Close is called while a Write is currently in-flight, + // interpret that as a sign that this Close is really just + // being used to break the Write and/or clean up resources and + // avoid sending the alertCloseNotify, which may block + // waiting on handshakeMutex or the c.out mutex. + return c.conn.Close() + } + + var alertErr error + if c.isHandshakeComplete.Load() { + if err := c.closeNotify(); err != nil { + alertErr = fmt.Errorf("tls: failed to send closeNotify alert (but connection was closed anyway): %w", err) + } + } + + if err := c.conn.Close(); err != nil { + return err + } + return alertErr +} + +var errEarlyCloseWrite = errors.New("tls: CloseWrite called before handshake complete") + +// CloseWrite shuts down the writing side of the connection. It should only be +// called once the handshake has completed and does not call CloseWrite on the +// underlying connection. Most callers should just use Close. +func (c *Conn) CloseWrite() error { + if !c.isHandshakeComplete.Load() { + return errEarlyCloseWrite + } + + return c.closeNotify() +} + +func (c *Conn) closeNotify() error { + c.out.Lock() + defer c.out.Unlock() + + if !c.closeNotifySent { + // Set a Write Deadline to prevent possibly blocking forever. + c.SetWriteDeadline(time.Now().Add(time.Second * 5)) + c.closeNotifyErr = c.sendAlertLocked(alertCloseNotify) + c.closeNotifySent = true + // Any subsequent writes will fail. + c.SetWriteDeadline(time.Now()) + } + return c.closeNotifyErr +} + +// Handshake runs the client or server handshake +// protocol if it has not yet been run. +// +// Most uses of this package need not call Handshake explicitly: the +// first Read or Write will call it automatically. +// +// For control over canceling or setting a timeout on a handshake, use +// HandshakeContext or the Dialer's DialContext method instead. +func (c *Conn) Handshake() error { + return c.HandshakeContext(context.Background()) +} + +// HandshakeContext runs the client or server handshake +// protocol if it has not yet been run. +// +// The provided Context must be non-nil. If the context is canceled before +// the handshake is complete, the handshake is interrupted and an error is returned. +// Once the handshake has completed, cancellation of the context will not affect the +// connection. +// +// Most uses of this package need not call HandshakeContext explicitly: the +// first Read or Write will call it automatically. +func (c *Conn) HandshakeContext(ctx context.Context) error { + // Delegate to unexported method for named return + // without confusing documented signature. + return c.handshakeContext(ctx) +} + +func (c *Conn) handshakeContext(ctx context.Context) (ret error) { + // Fast sync/atomic-based exit if there is no handshake in flight and the + // last one succeeded without an error. Avoids the expensive context setup + // and mutex for most Read and Write calls. + if c.isHandshakeComplete.Load() { + return nil + } + + handshakeCtx, cancel := context.WithCancel(ctx) + // Note: defer this before starting the "interrupter" goroutine + // so that we can tell the difference between the input being canceled and + // this cancellation. In the former case, we need to close the connection. + defer cancel() + + if c.quic != nil { + c.quic.cancelc = handshakeCtx.Done() + c.quic.cancel = cancel + } else if ctx.Done() != nil { + // Start the "interrupter" goroutine, if this context might be canceled. + // (The background context cannot). + // + // The interrupter goroutine waits for the input context to be done and + // closes the connection if this happens before the function returns. + done := make(chan struct{}) + interruptRes := make(chan error, 1) + defer func() { + close(done) + if ctxErr := <-interruptRes; ctxErr != nil { + // Return context error to user. + ret = ctxErr + } + }() + go func() { + select { + case <-handshakeCtx.Done(): + // Close the connection, discarding the error + _ = c.conn.Close() + interruptRes <- handshakeCtx.Err() + case <-done: + interruptRes <- nil + } + }() + } + + c.handshakeMutex.Lock() + defer c.handshakeMutex.Unlock() + + if err := c.handshakeErr; err != nil { + return err + } + if c.isHandshakeComplete.Load() { + return nil + } + + c.in.Lock() + defer c.in.Unlock() + + c.handshakeErr = c.handshakeFn(handshakeCtx) + if c.handshakeErr == nil { + c.handshakes++ + } else { + // If an error occurred during the handshake try to flush the + // alert that might be left in the buffer. + c.flush() + } + + if c.handshakeErr == nil && !c.isHandshakeComplete.Load() { + c.handshakeErr = errors.New("tls: internal error: handshake should have had a result") + } + if c.handshakeErr != nil && c.isHandshakeComplete.Load() { + panic("tls: internal error: handshake returned an error but is marked successful") + } + + if c.quic != nil { + if c.handshakeErr == nil { + c.quicHandshakeComplete() + // Provide the 1-RTT read secret now that the handshake is complete. + // The QUIC layer MUST NOT decrypt 1-RTT packets prior to completing + // the handshake (RFC 9001, Section 5.7). + c.quicSetReadSecret(QUICEncryptionLevelApplication, c.cipherSuite, c.in.trafficSecret) + } else { + var a alert + c.out.Lock() + if !errors.As(c.out.err, &a) { + a = alertInternalError + } + c.out.Unlock() + // Return an error which wraps both the handshake error and + // any alert error we may have sent, or alertInternalError + // if we didn't send an alert. + // Truncate the text of the alert to 0 characters. + c.handshakeErr = fmt.Errorf("%w%.0w", c.handshakeErr, AlertError(a)) + } + close(c.quic.blockedc) + close(c.quic.signalc) + } + + return c.handshakeErr +} + +// ConnectionState returns basic TLS details about the connection. +func (c *Conn) ConnectionState() ConnectionState { + c.handshakeMutex.Lock() + defer c.handshakeMutex.Unlock() + return c.connectionStateLocked() +} + +func (c *Conn) connectionStateLocked() ConnectionState { + var state connectionState + state.HandshakeComplete = c.isHandshakeComplete.Load() + state.Version = c.vers + state.NegotiatedProtocol = c.clientProtocol + state.DidResume = c.didResume + state.NegotiatedProtocolIsMutual = true + state.ServerName = c.serverName + state.CipherSuite = c.cipherSuite + state.PeerCertificates = c.peerCertificates + state.VerifiedChains = c.verifiedChains + state.SignedCertificateTimestamps = c.scts + state.OCSPResponse = c.ocspResponse + if !c.didResume && c.vers != VersionTLS13 { + if c.clientFinishedIsFirst { + state.TLSUnique = c.clientFinished[:] + } else { + state.TLSUnique = c.serverFinished[:] + } + } + if c.config.Renegotiation != RenegotiateNever { + state.ekm = noExportedKeyingMaterial + } else { + state.ekm = c.ekm + } + return toConnectionState(state) +} + +// OCSPResponse returns the stapled OCSP response from the TLS server, if +// any. (Only valid for client connections.) +func (c *Conn) OCSPResponse() []byte { + c.handshakeMutex.Lock() + defer c.handshakeMutex.Unlock() + + return c.ocspResponse +} + +// VerifyHostname checks that the peer certificate chain is valid for +// connecting to host. If so, it returns nil; if not, it returns an error +// describing the problem. +func (c *Conn) VerifyHostname(host string) error { + c.handshakeMutex.Lock() + defer c.handshakeMutex.Unlock() + if !c.isClient { + return errors.New("tls: VerifyHostname called on TLS server connection") + } + if !c.isHandshakeComplete.Load() { + return errors.New("tls: handshake has not yet been performed") + } + if len(c.verifiedChains) == 0 { + return errors.New("tls: handshake did not verify certificate chain") + } + return c.peerCertificates[0].VerifyHostname(host) +} diff --git a/vendor/github.com/quic-go/qtls-go1-20/handshake_client.go b/vendor/github.com/quic-go/qtls-go1-20/handshake_client.go new file mode 100644 index 000000000..ad1be6bdb --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/handshake_client.go @@ -0,0 +1,1122 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package qtls + +import ( + "bytes" + "context" + "crypto" + "crypto/ecdh" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "crypto/subtle" + "crypto/x509" + "errors" + "fmt" + "hash" + "io" + "net" + "strings" + "time" + + "golang.org/x/crypto/cryptobyte" +) + +const clientSessionStateVersion = 1 + +type clientHandshakeState struct { + c *Conn + ctx context.Context + serverHello *serverHelloMsg + hello *clientHelloMsg + suite *cipherSuite + finishedHash finishedHash + masterSecret []byte + session *clientSessionState +} + +var testingOnlyForceClientHelloSignatureAlgorithms []SignatureScheme + +func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { + config := c.config + if len(config.ServerName) == 0 && !config.InsecureSkipVerify { + return nil, nil, errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config") + } + + nextProtosLength := 0 + for _, proto := range config.NextProtos { + if l := len(proto); l == 0 || l > 255 { + return nil, nil, errors.New("tls: invalid NextProtos value") + } else { + nextProtosLength += 1 + l + } + } + if nextProtosLength > 0xffff { + return nil, nil, errors.New("tls: NextProtos values too large") + } + + supportedVersions := config.supportedVersions(roleClient) + if len(supportedVersions) == 0 { + return nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion") + } + + clientHelloVersion := config.maxSupportedVersion(roleClient) + // The version at the beginning of the ClientHello was capped at TLS 1.2 + // for compatibility reasons. The supported_versions extension is used + // to negotiate versions now. See RFC 8446, Section 4.2.1. + if clientHelloVersion > VersionTLS12 { + clientHelloVersion = VersionTLS12 + } + + hello := &clientHelloMsg{ + vers: clientHelloVersion, + compressionMethods: []uint8{compressionNone}, + random: make([]byte, 32), + ocspStapling: true, + scts: true, + serverName: hostnameInSNI(config.ServerName), + supportedCurves: config.curvePreferences(), + supportedPoints: []uint8{pointFormatUncompressed}, + secureRenegotiationSupported: true, + alpnProtocols: config.NextProtos, + supportedVersions: supportedVersions, + } + + if c.handshakes > 0 { + hello.secureRenegotiation = c.clientFinished[:] + } + + preferenceOrder := cipherSuitesPreferenceOrder + if !hasAESGCMHardwareSupport { + preferenceOrder = cipherSuitesPreferenceOrderNoAES + } + configCipherSuites := config.cipherSuites() + hello.cipherSuites = make([]uint16, 0, len(configCipherSuites)) + + for _, suiteId := range preferenceOrder { + suite := mutualCipherSuite(configCipherSuites, suiteId) + if suite == nil { + continue + } + // Don't advertise TLS 1.2-only cipher suites unless + // we're attempting TLS 1.2. + if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 { + continue + } + hello.cipherSuites = append(hello.cipherSuites, suiteId) + } + + _, err := io.ReadFull(config.rand(), hello.random) + if err != nil { + return nil, nil, errors.New("tls: short read from Rand: " + err.Error()) + } + + // A random session ID is used to detect when the server accepted a ticket + // and is resuming a session (see RFC 5077). In TLS 1.3, it's always set as + // a compatibility measure (see RFC 8446, Section 4.1.2). + // + // The session ID is not set for QUIC connections (see RFC 9001, Section 8.4). + if c.quic == nil { + hello.sessionId = make([]byte, 32) + if _, err := io.ReadFull(config.rand(), hello.sessionId); err != nil { + return nil, nil, errors.New("tls: short read from Rand: " + err.Error()) + } + } + + if hello.vers >= VersionTLS12 { + hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms() + } + if testingOnlyForceClientHelloSignatureAlgorithms != nil { + hello.supportedSignatureAlgorithms = testingOnlyForceClientHelloSignatureAlgorithms + } + + var key *ecdh.PrivateKey + if hello.supportedVersions[0] == VersionTLS13 { + if len(hello.supportedVersions) == 1 { + hello.cipherSuites = hello.cipherSuites[:0] + } + if hasAESGCMHardwareSupport { + hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...) + } else { + hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...) + } + + curveID := config.curvePreferences()[0] + if _, ok := curveForCurveID(curveID); !ok { + return nil, nil, errors.New("tls: CurvePreferences includes unsupported curve") + } + key, err = generateECDHEKey(config.rand(), curveID) + if err != nil { + return nil, nil, err + } + hello.keyShares = []keyShare{{group: curveID, data: key.PublicKey().Bytes()}} + } + + if c.quic != nil { + p, err := c.quicGetTransportParameters() + if err != nil { + return nil, nil, err + } + if p == nil { + p = []byte{} + } + hello.quicTransportParameters = p + } + + return hello, key, nil +} + +func (c *Conn) clientHandshake(ctx context.Context) (err error) { + if c.config == nil { + c.config = fromConfig(defaultConfig()) + } + + // This may be a renegotiation handshake, in which case some fields + // need to be reset. + c.didResume = false + + hello, ecdheKey, err := c.makeClientHello() + if err != nil { + return err + } + c.serverName = hello.serverName + + cacheKey, session, earlySecret, binderKey, err := c.loadSession(hello) + if err != nil { + return err + } + if cacheKey != "" && session != nil { + defer func() { + // If we got a handshake failure when resuming a session, throw away + // the session ticket. See RFC 5077, Section 3.2. + // + // RFC 8446 makes no mention of dropping tickets on failure, but it + // does require servers to abort on invalid binders, so we need to + // delete tickets to recover from a corrupted PSK. + if err != nil { + c.config.ClientSessionCache.Put(cacheKey, nil) + } + }() + } + + if _, err := c.writeHandshakeRecord(hello, nil); err != nil { + return err + } + + if hello.earlyData { + suite := cipherSuiteTLS13ByID(session.cipherSuite) + transcript := suite.hash.New() + if err := transcriptMsg(hello, transcript); err != nil { + return err + } + earlyTrafficSecret := suite.deriveSecret(earlySecret, clientEarlyTrafficLabel, transcript) + c.quicSetWriteSecret(QUICEncryptionLevelEarly, suite.id, earlyTrafficSecret) + } + + // serverHelloMsg is not included in the transcript + msg, err := c.readHandshake(nil) + if err != nil { + return err + } + + serverHello, ok := msg.(*serverHelloMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(serverHello, msg) + } + + if err := c.pickTLSVersion(serverHello); err != nil { + return err + } + + // If we are negotiating a protocol version that's lower than what we + // support, check for the server downgrade canaries. + // See RFC 8446, Section 4.1.3. + maxVers := c.config.maxSupportedVersion(roleClient) + tls12Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS12 + tls11Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS11 + if maxVers == VersionTLS13 && c.vers <= VersionTLS12 && (tls12Downgrade || tls11Downgrade) || + maxVers == VersionTLS12 && c.vers <= VersionTLS11 && tls11Downgrade { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: downgrade attempt detected, possibly due to a MitM attack or a broken middlebox") + } + + if c.vers == VersionTLS13 { + hs := &clientHandshakeStateTLS13{ + c: c, + ctx: ctx, + serverHello: serverHello, + hello: hello, + ecdheKey: ecdheKey, + session: session, + earlySecret: earlySecret, + binderKey: binderKey, + } + + // In TLS 1.3, session tickets are delivered after the handshake. + return hs.handshake() + } + + hs := &clientHandshakeState{ + c: c, + ctx: ctx, + serverHello: serverHello, + hello: hello, + session: session, + } + + if err := hs.handshake(); err != nil { + return err + } + + // If we had a successful handshake and hs.session is different from + // the one already cached - cache a new one. + if cacheKey != "" && hs.session != nil && session != hs.session { + c.config.ClientSessionCache.Put(cacheKey, toClientSessionState(hs.session)) + } + + return nil +} + +// extract the app data saved in the session.nonce, +// and set the session.nonce to the actual nonce value +func (c *Conn) decodeSessionState(session *clientSessionState) (uint32 /* max early data */, []byte /* app data */, bool /* ok */) { + s := cryptobyte.String(session.nonce) + var version uint16 + if !s.ReadUint16(&version) { + return 0, nil, false + } + if version != clientSessionStateVersion { + return 0, nil, false + } + var maxEarlyData uint32 + if !s.ReadUint32(&maxEarlyData) { + return 0, nil, false + } + var appData []byte + if !readUint16LengthPrefixed(&s, &appData) { + return 0, nil, false + } + var nonce []byte + if !readUint16LengthPrefixed(&s, &nonce) { + return 0, nil, false + } + session.nonce = nonce + return maxEarlyData, appData, true +} + +func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string, + session *clientSessionState, earlySecret, binderKey []byte, err error) { + if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil { + return "", nil, nil, nil, nil + } + + hello.ticketSupported = true + + if hello.supportedVersions[0] == VersionTLS13 { + // Require DHE on resumption as it guarantees forward secrecy against + // compromise of the session ticket key. See RFC 8446, Section 4.2.9. + hello.pskModes = []uint8{pskModeDHE} + } + + // Session resumption is not allowed if renegotiating because + // renegotiation is primarily used to allow a client to send a client + // certificate, which would be skipped if session resumption occurred. + if c.handshakes != 0 { + return "", nil, nil, nil, nil + } + + // Try to resume a previously negotiated TLS session, if available. + cacheKey = c.clientSessionCacheKey() + if cacheKey == "" { + return "", nil, nil, nil, nil + } + sess, ok := c.config.ClientSessionCache.Get(cacheKey) + if !ok || sess == nil { + return cacheKey, nil, nil, nil, nil + } + session = fromClientSessionState(sess) + + var appData []byte + var maxEarlyData uint32 + if session.vers == VersionTLS13 { + var ok bool + maxEarlyData, appData, ok = c.decodeSessionState(session) + if !ok { // delete it, if parsing failed + c.config.ClientSessionCache.Put(cacheKey, nil) + return cacheKey, nil, nil, nil, nil + } + } + + // Check that version used for the previous session is still valid. + versOk := false + for _, v := range hello.supportedVersions { + if v == session.vers { + versOk = true + break + } + } + if !versOk { + return cacheKey, nil, nil, nil, nil + } + + // Check that the cached server certificate is not expired, and that it's + // valid for the ServerName. This should be ensured by the cache key, but + // protect the application from a faulty ClientSessionCache implementation. + if !c.config.InsecureSkipVerify { + if len(session.verifiedChains) == 0 { + // The original connection had InsecureSkipVerify, while this doesn't. + return cacheKey, nil, nil, nil, nil + } + serverCert := session.serverCertificates[0] + if c.config.time().After(serverCert.NotAfter) { + // Expired certificate, delete the entry. + c.config.ClientSessionCache.Put(cacheKey, nil) + return cacheKey, nil, nil, nil, nil + } + if err := serverCert.VerifyHostname(c.config.ServerName); err != nil { + return cacheKey, nil, nil, nil, nil + } + } + + if session.vers != VersionTLS13 { + // In TLS 1.2 the cipher suite must match the resumed session. Ensure we + // are still offering it. + if mutualCipherSuite(hello.cipherSuites, session.cipherSuite) == nil { + return cacheKey, nil, nil, nil, nil + } + + hello.sessionTicket = session.sessionTicket + return + } + + // Check that the session ticket is not expired. + if c.config.time().After(session.useBy) { + c.config.ClientSessionCache.Put(cacheKey, nil) + return cacheKey, nil, nil, nil, nil + } + + // In TLS 1.3 the KDF hash must match the resumed session. Ensure we + // offer at least one cipher suite with that hash. + cipherSuite := cipherSuiteTLS13ByID(session.cipherSuite) + if cipherSuite == nil { + return cacheKey, nil, nil, nil, nil + } + cipherSuiteOk := false + for _, offeredID := range hello.cipherSuites { + offeredSuite := cipherSuiteTLS13ByID(offeredID) + if offeredSuite != nil && offeredSuite.hash == cipherSuite.hash { + cipherSuiteOk = true + break + } + } + if !cipherSuiteOk { + return cacheKey, nil, nil, nil, nil + } + + if c.quic != nil && maxEarlyData > 0 { + // For 0-RTT, the cipher suite has to match exactly. + if mutualCipherSuiteTLS13(hello.cipherSuites, session.cipherSuite) != nil { + hello.earlyData = true + } + } + + // Set the pre_shared_key extension. See RFC 8446, Section 4.2.11.1. + ticketAge := uint32(c.config.time().Sub(session.receivedAt) / time.Millisecond) + identity := pskIdentity{ + label: session.sessionTicket, + obfuscatedTicketAge: ticketAge + session.ageAdd, + } + hello.pskIdentities = []pskIdentity{identity} + hello.pskBinders = [][]byte{make([]byte, cipherSuite.hash.Size())} + + // Compute the PSK binders. See RFC 8446, Section 4.2.11.2. + psk := cipherSuite.expandLabel(session.masterSecret, "resumption", + session.nonce, cipherSuite.hash.Size()) + earlySecret = cipherSuite.extract(psk, nil) + binderKey = cipherSuite.deriveSecret(earlySecret, resumptionBinderLabel, nil) + transcript := cipherSuite.hash.New() + helloBytes, err := hello.marshalWithoutBinders() + if err != nil { + return "", nil, nil, nil, err + } + transcript.Write(helloBytes) + pskBinders := [][]byte{cipherSuite.finishedHash(binderKey, transcript)} + if err := hello.updateBinders(pskBinders); err != nil { + return "", nil, nil, nil, err + } + + if session.vers == VersionTLS13 && c.extraConfig != nil && c.extraConfig.SetAppDataFromSessionState != nil { + c.extraConfig.SetAppDataFromSessionState(appData) + } + return +} + +func (c *Conn) pickTLSVersion(serverHello *serverHelloMsg) error { + peerVersion := serverHello.vers + if serverHello.supportedVersion != 0 { + peerVersion = serverHello.supportedVersion + } + + vers, ok := c.config.mutualVersion(roleClient, []uint16{peerVersion}) + if !ok { + c.sendAlert(alertProtocolVersion) + return fmt.Errorf("tls: server selected unsupported protocol version %x", peerVersion) + } + + c.vers = vers + c.haveVers = true + c.in.version = vers + c.out.version = vers + + return nil +} + +// Does the handshake, either a full one or resumes old session. Requires hs.c, +// hs.hello, hs.serverHello, and, optionally, hs.session to be set. +func (hs *clientHandshakeState) handshake() error { + c := hs.c + + isResume, err := hs.processServerHello() + if err != nil { + return err + } + + hs.finishedHash = newFinishedHash(c.vers, hs.suite) + + // No signatures of the handshake are needed in a resumption. + // Otherwise, in a full handshake, if we don't have any certificates + // configured then we will never send a CertificateVerify message and + // thus no signatures are needed in that case either. + if isResume || (len(c.config.Certificates) == 0 && c.config.GetClientCertificate == nil) { + hs.finishedHash.discardHandshakeBuffer() + } + + if err := transcriptMsg(hs.hello, &hs.finishedHash); err != nil { + return err + } + if err := transcriptMsg(hs.serverHello, &hs.finishedHash); err != nil { + return err + } + + c.buffering = true + c.didResume = isResume + if isResume { + if err := hs.establishKeys(); err != nil { + return err + } + if err := hs.readSessionTicket(); err != nil { + return err + } + if err := hs.readFinished(c.serverFinished[:]); err != nil { + return err + } + c.clientFinishedIsFirst = false + // Make sure the connection is still being verified whether or not this + // is a resumption. Resumptions currently don't reverify certificates so + // they don't call verifyServerCertificate. See Issue 31641. + if c.config.VerifyConnection != nil { + if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil { + c.sendAlert(alertBadCertificate) + return err + } + } + if err := hs.sendFinished(c.clientFinished[:]); err != nil { + return err + } + if _, err := c.flush(); err != nil { + return err + } + } else { + if err := hs.doFullHandshake(); err != nil { + return err + } + if err := hs.establishKeys(); err != nil { + return err + } + if err := hs.sendFinished(c.clientFinished[:]); err != nil { + return err + } + if _, err := c.flush(); err != nil { + return err + } + c.clientFinishedIsFirst = true + if err := hs.readSessionTicket(); err != nil { + return err + } + if err := hs.readFinished(c.serverFinished[:]); err != nil { + return err + } + } + + c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random) + c.isHandshakeComplete.Store(true) + + return nil +} + +func (hs *clientHandshakeState) pickCipherSuite() error { + if hs.suite = mutualCipherSuite(hs.hello.cipherSuites, hs.serverHello.cipherSuite); hs.suite == nil { + hs.c.sendAlert(alertHandshakeFailure) + return errors.New("tls: server chose an unconfigured cipher suite") + } + + hs.c.cipherSuite = hs.suite.id + return nil +} + +func (hs *clientHandshakeState) doFullHandshake() error { + c := hs.c + + msg, err := c.readHandshake(&hs.finishedHash) + if err != nil { + return err + } + certMsg, ok := msg.(*certificateMsg) + if !ok || len(certMsg.certificates) == 0 { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(certMsg, msg) + } + + msg, err = c.readHandshake(&hs.finishedHash) + if err != nil { + return err + } + + cs, ok := msg.(*certificateStatusMsg) + if ok { + // RFC4366 on Certificate Status Request: + // The server MAY return a "certificate_status" message. + + if !hs.serverHello.ocspStapling { + // If a server returns a "CertificateStatus" message, then the + // server MUST have included an extension of type "status_request" + // with empty "extension_data" in the extended server hello. + + c.sendAlert(alertUnexpectedMessage) + return errors.New("tls: received unexpected CertificateStatus message") + } + + c.ocspResponse = cs.response + + msg, err = c.readHandshake(&hs.finishedHash) + if err != nil { + return err + } + } + + if c.handshakes == 0 { + // If this is the first handshake on a connection, process and + // (optionally) verify the server's certificates. + if err := c.verifyServerCertificate(certMsg.certificates); err != nil { + return err + } + } else { + // This is a renegotiation handshake. We require that the + // server's identity (i.e. leaf certificate) is unchanged and + // thus any previous trust decision is still valid. + // + // See https://mitls.org/pages/attacks/3SHAKE for the + // motivation behind this requirement. + if !bytes.Equal(c.peerCertificates[0].Raw, certMsg.certificates[0]) { + c.sendAlert(alertBadCertificate) + return errors.New("tls: server's identity changed during renegotiation") + } + } + + keyAgreement := hs.suite.ka(c.vers) + + skx, ok := msg.(*serverKeyExchangeMsg) + if ok { + err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, c.peerCertificates[0], skx) + if err != nil { + c.sendAlert(alertUnexpectedMessage) + return err + } + + msg, err = c.readHandshake(&hs.finishedHash) + if err != nil { + return err + } + } + + var chainToSend *Certificate + var certRequested bool + certReq, ok := msg.(*certificateRequestMsg) + if ok { + certRequested = true + + cri := certificateRequestInfoFromMsg(hs.ctx, c.vers, certReq) + if chainToSend, err = c.getClientCertificate(cri); err != nil { + c.sendAlert(alertInternalError) + return err + } + + msg, err = c.readHandshake(&hs.finishedHash) + if err != nil { + return err + } + } + + shd, ok := msg.(*serverHelloDoneMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(shd, msg) + } + + // If the server requested a certificate then we have to send a + // Certificate message, even if it's empty because we don't have a + // certificate to send. + if certRequested { + certMsg = new(certificateMsg) + certMsg.certificates = chainToSend.Certificate + if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); err != nil { + return err + } + } + + preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, c.peerCertificates[0]) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + if ckx != nil { + if _, err := hs.c.writeHandshakeRecord(ckx, &hs.finishedHash); err != nil { + return err + } + } + + if chainToSend != nil && len(chainToSend.Certificate) > 0 { + certVerify := &certificateVerifyMsg{} + + key, ok := chainToSend.PrivateKey.(crypto.Signer) + if !ok { + c.sendAlert(alertInternalError) + return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey) + } + + var sigType uint8 + var sigHash crypto.Hash + if c.vers >= VersionTLS12 { + signatureAlgorithm, err := selectSignatureScheme(c.vers, chainToSend, certReq.supportedSignatureAlgorithms) + if err != nil { + c.sendAlert(alertIllegalParameter) + return err + } + sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm) + if err != nil { + return c.sendAlert(alertInternalError) + } + certVerify.hasSignatureAlgorithm = true + certVerify.signatureAlgorithm = signatureAlgorithm + } else { + sigType, sigHash, err = legacyTypeAndHashFromPublicKey(key.Public()) + if err != nil { + c.sendAlert(alertIllegalParameter) + return err + } + } + + signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash) + signOpts := crypto.SignerOpts(sigHash) + if sigType == signatureRSAPSS { + signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash} + } + certVerify.signature, err = key.Sign(c.config.rand(), signed, signOpts) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + + if _, err := hs.c.writeHandshakeRecord(certVerify, &hs.finishedHash); err != nil { + return err + } + } + + hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random) + if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.hello.random, hs.masterSecret); err != nil { + c.sendAlert(alertInternalError) + return errors.New("tls: failed to write to key log: " + err.Error()) + } + + hs.finishedHash.discardHandshakeBuffer() + + return nil +} + +func (hs *clientHandshakeState) establishKeys() error { + c := hs.c + + clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := + keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen) + var clientCipher, serverCipher any + var clientHash, serverHash hash.Hash + if hs.suite.cipher != nil { + clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */) + clientHash = hs.suite.mac(clientMAC) + serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */) + serverHash = hs.suite.mac(serverMAC) + } else { + clientCipher = hs.suite.aead(clientKey, clientIV) + serverCipher = hs.suite.aead(serverKey, serverIV) + } + + c.in.prepareCipherSpec(c.vers, serverCipher, serverHash) + c.out.prepareCipherSpec(c.vers, clientCipher, clientHash) + return nil +} + +func (hs *clientHandshakeState) serverResumedSession() bool { + // If the server responded with the same sessionId then it means the + // sessionTicket is being used to resume a TLS session. + return hs.session != nil && hs.hello.sessionId != nil && + bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId) +} + +func (hs *clientHandshakeState) processServerHello() (bool, error) { + c := hs.c + + if err := hs.pickCipherSuite(); err != nil { + return false, err + } + + if hs.serverHello.compressionMethod != compressionNone { + c.sendAlert(alertUnexpectedMessage) + return false, errors.New("tls: server selected unsupported compression format") + } + + if c.handshakes == 0 && hs.serverHello.secureRenegotiationSupported { + c.secureRenegotiation = true + if len(hs.serverHello.secureRenegotiation) != 0 { + c.sendAlert(alertHandshakeFailure) + return false, errors.New("tls: initial handshake had non-empty renegotiation extension") + } + } + + if c.handshakes > 0 && c.secureRenegotiation { + var expectedSecureRenegotiation [24]byte + copy(expectedSecureRenegotiation[:], c.clientFinished[:]) + copy(expectedSecureRenegotiation[12:], c.serverFinished[:]) + if !bytes.Equal(hs.serverHello.secureRenegotiation, expectedSecureRenegotiation[:]) { + c.sendAlert(alertHandshakeFailure) + return false, errors.New("tls: incorrect renegotiation extension contents") + } + } + + if err := checkALPN(hs.hello.alpnProtocols, hs.serverHello.alpnProtocol, false); err != nil { + c.sendAlert(alertUnsupportedExtension) + return false, err + } + c.clientProtocol = hs.serverHello.alpnProtocol + + c.scts = hs.serverHello.scts + + if !hs.serverResumedSession() { + return false, nil + } + + if hs.session.vers != c.vers { + c.sendAlert(alertHandshakeFailure) + return false, errors.New("tls: server resumed a session with a different version") + } + + if hs.session.cipherSuite != hs.suite.id { + c.sendAlert(alertHandshakeFailure) + return false, errors.New("tls: server resumed a session with a different cipher suite") + } + + // Restore masterSecret, peerCerts, and ocspResponse from previous state + hs.masterSecret = hs.session.masterSecret + c.peerCertificates = hs.session.serverCertificates + c.verifiedChains = hs.session.verifiedChains + c.ocspResponse = hs.session.ocspResponse + // Let the ServerHello SCTs override the session SCTs from the original + // connection, if any are provided + if len(c.scts) == 0 && len(hs.session.scts) != 0 { + c.scts = hs.session.scts + } + + return true, nil +} + +// checkALPN ensure that the server's choice of ALPN protocol is compatible with +// the protocols that we advertised in the Client Hello. +func checkALPN(clientProtos []string, serverProto string, quic bool) error { + if serverProto == "" { + if quic && len(clientProtos) > 0 { + // RFC 9001, Section 8.1 + return errors.New("tls: server did not select an ALPN protocol") + } + return nil + } + if len(clientProtos) == 0 { + return errors.New("tls: server advertised unrequested ALPN extension") + } + for _, proto := range clientProtos { + if proto == serverProto { + return nil + } + } + return errors.New("tls: server selected unadvertised ALPN protocol") +} + +func (hs *clientHandshakeState) readFinished(out []byte) error { + c := hs.c + + if err := c.readChangeCipherSpec(); err != nil { + return err + } + + // finishedMsg is included in the transcript, but not until after we + // check the client version, since the state before this message was + // sent is used during verification. + msg, err := c.readHandshake(nil) + if err != nil { + return err + } + serverFinished, ok := msg.(*finishedMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(serverFinished, msg) + } + + verify := hs.finishedHash.serverSum(hs.masterSecret) + if len(verify) != len(serverFinished.verifyData) || + subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 { + c.sendAlert(alertHandshakeFailure) + return errors.New("tls: server's Finished message was incorrect") + } + + if err := transcriptMsg(serverFinished, &hs.finishedHash); err != nil { + return err + } + + copy(out, verify) + return nil +} + +func (hs *clientHandshakeState) readSessionTicket() error { + if !hs.serverHello.ticketSupported { + return nil + } + + c := hs.c + msg, err := c.readHandshake(&hs.finishedHash) + if err != nil { + return err + } + sessionTicketMsg, ok := msg.(*newSessionTicketMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(sessionTicketMsg, msg) + } + + hs.session = &clientSessionState{ + sessionTicket: sessionTicketMsg.ticket, + vers: c.vers, + cipherSuite: hs.suite.id, + masterSecret: hs.masterSecret, + serverCertificates: c.peerCertificates, + verifiedChains: c.verifiedChains, + receivedAt: c.config.time(), + ocspResponse: c.ocspResponse, + scts: c.scts, + } + + return nil +} + +func (hs *clientHandshakeState) sendFinished(out []byte) error { + c := hs.c + + if err := c.writeChangeCipherRecord(); err != nil { + return err + } + + finished := new(finishedMsg) + finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret) + if _, err := hs.c.writeHandshakeRecord(finished, &hs.finishedHash); err != nil { + return err + } + copy(out, finished.verifyData) + return nil +} + +// verifyServerCertificate parses and verifies the provided chain, setting +// c.verifiedChains and c.peerCertificates or sending the appropriate alert. +func (c *Conn) verifyServerCertificate(certificates [][]byte) error { + activeHandles := make([]*activeCert, len(certificates)) + certs := make([]*x509.Certificate, len(certificates)) + for i, asn1Data := range certificates { + cert, err := clientCertCache.newCert(asn1Data) + if err != nil { + c.sendAlert(alertBadCertificate) + return errors.New("tls: failed to parse certificate from server: " + err.Error()) + } + activeHandles[i] = cert + certs[i] = cert.cert + } + + if !c.config.InsecureSkipVerify { + opts := x509.VerifyOptions{ + Roots: c.config.RootCAs, + CurrentTime: c.config.time(), + DNSName: c.config.ServerName, + Intermediates: x509.NewCertPool(), + } + + for _, cert := range certs[1:] { + opts.Intermediates.AddCert(cert) + } + var err error + c.verifiedChains, err = certs[0].Verify(opts) + if err != nil { + c.sendAlert(alertBadCertificate) + return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err} + } + } + + switch certs[0].PublicKey.(type) { + case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey: + break + default: + c.sendAlert(alertUnsupportedCertificate) + return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey) + } + + c.activeCertHandles = activeHandles + c.peerCertificates = certs + + if c.config.VerifyPeerCertificate != nil { + if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil { + c.sendAlert(alertBadCertificate) + return err + } + } + + if c.config.VerifyConnection != nil { + if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil { + c.sendAlert(alertBadCertificate) + return err + } + } + + return nil +} + +// certificateRequestInfoFromMsg generates a CertificateRequestInfo from a TLS +// <= 1.2 CertificateRequest, making an effort to fill in missing information. +func certificateRequestInfoFromMsg(ctx context.Context, vers uint16, certReq *certificateRequestMsg) *CertificateRequestInfo { + cri := &certificateRequestInfo{ + AcceptableCAs: certReq.certificateAuthorities, + Version: vers, + ctx: ctx, + } + + var rsaAvail, ecAvail bool + for _, certType := range certReq.certificateTypes { + switch certType { + case certTypeRSASign: + rsaAvail = true + case certTypeECDSASign: + ecAvail = true + } + } + + if !certReq.hasSignatureAlgorithm { + // Prior to TLS 1.2, signature schemes did not exist. In this case we + // make up a list based on the acceptable certificate types, to help + // GetClientCertificate and SupportsCertificate select the right certificate. + // The hash part of the SignatureScheme is a lie here, because + // TLS 1.0 and 1.1 always use MD5+SHA1 for RSA and SHA1 for ECDSA. + switch { + case rsaAvail && ecAvail: + cri.SignatureSchemes = []SignatureScheme{ + ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512, + PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1, + } + case rsaAvail: + cri.SignatureSchemes = []SignatureScheme{ + PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1, + } + case ecAvail: + cri.SignatureSchemes = []SignatureScheme{ + ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512, + } + } + return toCertificateRequestInfo(cri) + } + + // Filter the signature schemes based on the certificate types. + // See RFC 5246, Section 7.4.4 (where it calls this "somewhat complicated"). + cri.SignatureSchemes = make([]SignatureScheme, 0, len(certReq.supportedSignatureAlgorithms)) + for _, sigScheme := range certReq.supportedSignatureAlgorithms { + sigType, _, err := typeAndHashFromSignatureScheme(sigScheme) + if err != nil { + continue + } + switch sigType { + case signatureECDSA, signatureEd25519: + if ecAvail { + cri.SignatureSchemes = append(cri.SignatureSchemes, sigScheme) + } + case signatureRSAPSS, signaturePKCS1v15: + if rsaAvail { + cri.SignatureSchemes = append(cri.SignatureSchemes, sigScheme) + } + } + } + + return toCertificateRequestInfo(cri) +} + +func (c *Conn) getClientCertificate(cri *CertificateRequestInfo) (*Certificate, error) { + if c.config.GetClientCertificate != nil { + return c.config.GetClientCertificate(cri) + } + + for _, chain := range c.config.Certificates { + if err := cri.SupportsCertificate(&chain); err != nil { + continue + } + return &chain, nil + } + + // No acceptable certificate found. Don't send a certificate. + return new(Certificate), nil +} + +// clientSessionCacheKey returns a key used to cache sessionTickets that could +// be used to resume previously negotiated TLS sessions with a server. +func (c *Conn) clientSessionCacheKey() string { + if len(c.config.ServerName) > 0 { + return c.config.ServerName + } + if c.conn != nil { + return c.conn.RemoteAddr().String() + } + return "" +} + +// hostnameInSNI converts name into an appropriate hostname for SNI. +// Literal IP addresses and absolute FQDNs are not permitted as SNI values. +// See RFC 6066, Section 3. +func hostnameInSNI(name string) string { + host := name + if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' { + host = host[1 : len(host)-1] + } + if i := strings.LastIndex(host, "%"); i > 0 { + host = host[:i] + } + if net.ParseIP(host) != nil { + return "" + } + for len(name) > 0 && name[len(name)-1] == '.' { + name = name[:len(name)-1] + } + return name +} diff --git a/vendor/github.com/quic-go/qtls-go1-20/handshake_client_tls13.go b/vendor/github.com/quic-go/qtls-go1-20/handshake_client_tls13.go new file mode 100644 index 000000000..e9d0a533e --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/handshake_client_tls13.go @@ -0,0 +1,782 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package qtls + +import ( + "bytes" + "context" + "crypto" + "crypto/ecdh" + "crypto/hmac" + "crypto/rsa" + "encoding/binary" + "errors" + "hash" + "time" + + "golang.org/x/crypto/cryptobyte" +) + +type clientHandshakeStateTLS13 struct { + c *Conn + ctx context.Context + serverHello *serverHelloMsg + hello *clientHelloMsg + ecdheKey *ecdh.PrivateKey + + session *clientSessionState + earlySecret []byte + binderKey []byte + + certReq *certificateRequestMsgTLS13 + usingPSK bool + sentDummyCCS bool + suite *cipherSuiteTLS13 + transcript hash.Hash + masterSecret []byte + trafficSecret []byte // client_application_traffic_secret_0 +} + +// handshake requires hs.c, hs.hello, hs.serverHello, hs.ecdheKey, and, +// optionally, hs.session, hs.earlySecret and hs.binderKey to be set. +func (hs *clientHandshakeStateTLS13) handshake() error { + c := hs.c + + if needFIPS() { + return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode") + } + + // The server must not select TLS 1.3 in a renegotiation. See RFC 8446, + // sections 4.1.2 and 4.1.3. + if c.handshakes > 0 { + c.sendAlert(alertProtocolVersion) + return errors.New("tls: server selected TLS 1.3 in a renegotiation") + } + + // Consistency check on the presence of a keyShare and its parameters. + if hs.ecdheKey == nil || len(hs.hello.keyShares) != 1 { + return c.sendAlert(alertInternalError) + } + + if err := hs.checkServerHelloOrHRR(); err != nil { + return err + } + + hs.transcript = hs.suite.hash.New() + + if err := transcriptMsg(hs.hello, hs.transcript); err != nil { + return err + } + + if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) { + if err := hs.sendDummyChangeCipherSpec(); err != nil { + return err + } + if err := hs.processHelloRetryRequest(); err != nil { + return err + } + } + + if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil { + return err + } + + c.buffering = true + if err := hs.processServerHello(); err != nil { + return err + } + if err := hs.sendDummyChangeCipherSpec(); err != nil { + return err + } + if err := hs.establishHandshakeKeys(); err != nil { + return err + } + if err := hs.readServerParameters(); err != nil { + return err + } + if err := hs.readServerCertificate(); err != nil { + return err + } + if err := hs.readServerFinished(); err != nil { + return err + } + if err := hs.sendClientCertificate(); err != nil { + return err + } + if err := hs.sendClientFinished(); err != nil { + return err + } + if _, err := c.flush(); err != nil { + return err + } + + c.isHandshakeComplete.Store(true) + + return nil +} + +// checkServerHelloOrHRR does validity checks that apply to both ServerHello and +// HelloRetryRequest messages. It sets hs.suite. +func (hs *clientHandshakeStateTLS13) checkServerHelloOrHRR() error { + c := hs.c + + if hs.serverHello.supportedVersion == 0 { + c.sendAlert(alertMissingExtension) + return errors.New("tls: server selected TLS 1.3 using the legacy version field") + } + + if hs.serverHello.supportedVersion != VersionTLS13 { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: server selected an invalid version after a HelloRetryRequest") + } + + if hs.serverHello.vers != VersionTLS12 { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: server sent an incorrect legacy version") + } + + if hs.serverHello.ocspStapling || + hs.serverHello.ticketSupported || + hs.serverHello.secureRenegotiationSupported || + len(hs.serverHello.secureRenegotiation) != 0 || + len(hs.serverHello.alpnProtocol) != 0 || + len(hs.serverHello.scts) != 0 { + c.sendAlert(alertUnsupportedExtension) + return errors.New("tls: server sent a ServerHello extension forbidden in TLS 1.3") + } + + if !bytes.Equal(hs.hello.sessionId, hs.serverHello.sessionId) { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: server did not echo the legacy session ID") + } + + if hs.serverHello.compressionMethod != compressionNone { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: server selected unsupported compression format") + } + + selectedSuite := mutualCipherSuiteTLS13(hs.hello.cipherSuites, hs.serverHello.cipherSuite) + if hs.suite != nil && selectedSuite != hs.suite { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: server changed cipher suite after a HelloRetryRequest") + } + if selectedSuite == nil { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: server chose an unconfigured cipher suite") + } + hs.suite = selectedSuite + c.cipherSuite = hs.suite.id + + return nil +} + +// sendDummyChangeCipherSpec sends a ChangeCipherSpec record for compatibility +// with middleboxes that didn't implement TLS correctly. See RFC 8446, Appendix D.4. +func (hs *clientHandshakeStateTLS13) sendDummyChangeCipherSpec() error { + if hs.c.quic != nil { + return nil + } + if hs.sentDummyCCS { + return nil + } + hs.sentDummyCCS = true + + return hs.c.writeChangeCipherRecord() +} + +// processHelloRetryRequest handles the HRR in hs.serverHello, modifies and +// resends hs.hello, and reads the new ServerHello into hs.serverHello. +func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { + c := hs.c + + // The first ClientHello gets double-hashed into the transcript upon a + // HelloRetryRequest. (The idea is that the server might offload transcript + // storage to the client in the cookie.) See RFC 8446, Section 4.4.1. + chHash := hs.transcript.Sum(nil) + hs.transcript.Reset() + hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))}) + hs.transcript.Write(chHash) + if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil { + return err + } + + // The only HelloRetryRequest extensions we support are key_share and + // cookie, and clients must abort the handshake if the HRR would not result + // in any change in the ClientHello. + if hs.serverHello.selectedGroup == 0 && hs.serverHello.cookie == nil { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: server sent an unnecessary HelloRetryRequest message") + } + + if hs.serverHello.cookie != nil { + hs.hello.cookie = hs.serverHello.cookie + } + + if hs.serverHello.serverShare.group != 0 { + c.sendAlert(alertDecodeError) + return errors.New("tls: received malformed key_share extension") + } + + // If the server sent a key_share extension selecting a group, ensure it's + // a group we advertised but did not send a key share for, and send a key + // share for it this time. + if curveID := hs.serverHello.selectedGroup; curveID != 0 { + curveOK := false + for _, id := range hs.hello.supportedCurves { + if id == curveID { + curveOK = true + break + } + } + if !curveOK { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: server selected unsupported group") + } + if sentID, _ := curveIDForCurve(hs.ecdheKey.Curve()); sentID == curveID { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: server sent an unnecessary HelloRetryRequest key_share") + } + if _, ok := curveForCurveID(curveID); !ok { + c.sendAlert(alertInternalError) + return errors.New("tls: CurvePreferences includes unsupported curve") + } + key, err := generateECDHEKey(c.config.rand(), curveID) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + hs.ecdheKey = key + hs.hello.keyShares = []keyShare{{group: curveID, data: key.PublicKey().Bytes()}} + } + + hs.hello.raw = nil + if len(hs.hello.pskIdentities) > 0 { + pskSuite := cipherSuiteTLS13ByID(hs.session.cipherSuite) + if pskSuite == nil { + return c.sendAlert(alertInternalError) + } + if pskSuite.hash == hs.suite.hash { + // Update binders and obfuscated_ticket_age. + ticketAge := uint32(c.config.time().Sub(hs.session.receivedAt) / time.Millisecond) + hs.hello.pskIdentities[0].obfuscatedTicketAge = ticketAge + hs.session.ageAdd + + transcript := hs.suite.hash.New() + transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))}) + transcript.Write(chHash) + if err := transcriptMsg(hs.serverHello, transcript); err != nil { + return err + } + helloBytes, err := hs.hello.marshalWithoutBinders() + if err != nil { + return err + } + transcript.Write(helloBytes) + pskBinders := [][]byte{hs.suite.finishedHash(hs.binderKey, transcript)} + if err := hs.hello.updateBinders(pskBinders); err != nil { + return err + } + } else { + // Server selected a cipher suite incompatible with the PSK. + hs.hello.pskIdentities = nil + hs.hello.pskBinders = nil + } + } + + if hs.hello.earlyData { + hs.hello.earlyData = false + c.quicRejectedEarlyData() + } + + if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil { + return err + } + + // serverHelloMsg is not included in the transcript + msg, err := c.readHandshake(nil) + if err != nil { + return err + } + + serverHello, ok := msg.(*serverHelloMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(serverHello, msg) + } + hs.serverHello = serverHello + + if err := hs.checkServerHelloOrHRR(); err != nil { + return err + } + + return nil +} + +func (hs *clientHandshakeStateTLS13) processServerHello() error { + c := hs.c + + if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) { + c.sendAlert(alertUnexpectedMessage) + return errors.New("tls: server sent two HelloRetryRequest messages") + } + + if len(hs.serverHello.cookie) != 0 { + c.sendAlert(alertUnsupportedExtension) + return errors.New("tls: server sent a cookie in a normal ServerHello") + } + + if hs.serverHello.selectedGroup != 0 { + c.sendAlert(alertDecodeError) + return errors.New("tls: malformed key_share extension") + } + + if hs.serverHello.serverShare.group == 0 { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: server did not send a key share") + } + if sentID, _ := curveIDForCurve(hs.ecdheKey.Curve()); hs.serverHello.serverShare.group != sentID { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: server selected unsupported group") + } + + if !hs.serverHello.selectedIdentityPresent { + return nil + } + + if int(hs.serverHello.selectedIdentity) >= len(hs.hello.pskIdentities) { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: server selected an invalid PSK") + } + + if len(hs.hello.pskIdentities) != 1 || hs.session == nil { + return c.sendAlert(alertInternalError) + } + pskSuite := cipherSuiteTLS13ByID(hs.session.cipherSuite) + if pskSuite == nil { + return c.sendAlert(alertInternalError) + } + if pskSuite.hash != hs.suite.hash { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: server selected an invalid PSK and cipher suite pair") + } + + hs.usingPSK = true + c.didResume = true + c.peerCertificates = hs.session.serverCertificates + c.verifiedChains = hs.session.verifiedChains + c.ocspResponse = hs.session.ocspResponse + c.scts = hs.session.scts + return nil +} + +func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error { + c := hs.c + + peerKey, err := hs.ecdheKey.Curve().NewPublicKey(hs.serverHello.serverShare.data) + if err != nil { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: invalid server key share") + } + sharedKey, err := hs.ecdheKey.ECDH(peerKey) + if err != nil { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: invalid server key share") + } + + earlySecret := hs.earlySecret + if !hs.usingPSK { + earlySecret = hs.suite.extract(nil, nil) + } + + handshakeSecret := hs.suite.extract(sharedKey, + hs.suite.deriveSecret(earlySecret, "derived", nil)) + + clientSecret := hs.suite.deriveSecret(handshakeSecret, + clientHandshakeTrafficLabel, hs.transcript) + c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret) + serverSecret := hs.suite.deriveSecret(handshakeSecret, + serverHandshakeTrafficLabel, hs.transcript) + c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret) + + if c.quic != nil { + if c.hand.Len() != 0 { + c.sendAlert(alertUnexpectedMessage) + } + c.quicSetWriteSecret(QUICEncryptionLevelHandshake, hs.suite.id, clientSecret) + c.quicSetReadSecret(QUICEncryptionLevelHandshake, hs.suite.id, serverSecret) + } + + err = c.config.writeKeyLog(keyLogLabelClientHandshake, hs.hello.random, clientSecret) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + err = c.config.writeKeyLog(keyLogLabelServerHandshake, hs.hello.random, serverSecret) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + + hs.masterSecret = hs.suite.extract(nil, + hs.suite.deriveSecret(handshakeSecret, "derived", nil)) + + return nil +} + +func (hs *clientHandshakeStateTLS13) readServerParameters() error { + c := hs.c + + msg, err := c.readHandshake(hs.transcript) + if err != nil { + return err + } + + encryptedExtensions, ok := msg.(*encryptedExtensionsMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(encryptedExtensions, msg) + } + + if err := checkALPN(hs.hello.alpnProtocols, encryptedExtensions.alpnProtocol, c.quic != nil); err != nil { + // RFC 8446 specifies that no_application_protocol is sent by servers, but + // does not specify how clients handle the selection of an incompatible protocol. + // RFC 9001 Section 8.1 specifies that QUIC clients send no_application_protocol + // in this case. Always sending no_application_protocol seems reasonable. + c.sendAlert(alertNoApplicationProtocol) + return err + } + c.clientProtocol = encryptedExtensions.alpnProtocol + + if c.quic != nil { + if encryptedExtensions.quicTransportParameters == nil { + // RFC 9001 Section 8.2. + c.sendAlert(alertMissingExtension) + return errors.New("tls: server did not send a quic_transport_parameters extension") + } + c.quicSetTransportParameters(encryptedExtensions.quicTransportParameters) + } else { + if encryptedExtensions.quicTransportParameters != nil { + c.sendAlert(alertUnsupportedExtension) + return errors.New("tls: server sent an unexpected quic_transport_parameters extension") + } + } + + if hs.hello.earlyData && !encryptedExtensions.earlyData { + c.quicRejectedEarlyData() + } + + return nil +} + +func (hs *clientHandshakeStateTLS13) readServerCertificate() error { + c := hs.c + + // Either a PSK or a certificate is always used, but not both. + // See RFC 8446, Section 4.1.1. + if hs.usingPSK { + // Make sure the connection is still being verified whether or not this + // is a resumption. Resumptions currently don't reverify certificates so + // they don't call verifyServerCertificate. See Issue 31641. + if c.config.VerifyConnection != nil { + if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil { + c.sendAlert(alertBadCertificate) + return err + } + } + return nil + } + + msg, err := c.readHandshake(hs.transcript) + if err != nil { + return err + } + + certReq, ok := msg.(*certificateRequestMsgTLS13) + if ok { + hs.certReq = certReq + + msg, err = c.readHandshake(hs.transcript) + if err != nil { + return err + } + } + + certMsg, ok := msg.(*certificateMsgTLS13) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(certMsg, msg) + } + if len(certMsg.certificate.Certificate) == 0 { + c.sendAlert(alertDecodeError) + return errors.New("tls: received empty certificates message") + } + + c.scts = certMsg.certificate.SignedCertificateTimestamps + c.ocspResponse = certMsg.certificate.OCSPStaple + + if err := c.verifyServerCertificate(certMsg.certificate.Certificate); err != nil { + return err + } + + // certificateVerifyMsg is included in the transcript, but not until + // after we verify the handshake signature, since the state before + // this message was sent is used. + msg, err = c.readHandshake(nil) + if err != nil { + return err + } + + certVerify, ok := msg.(*certificateVerifyMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(certVerify, msg) + } + + // See RFC 8446, Section 4.4.3. + if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: certificate used with invalid signature algorithm") + } + sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm) + if err != nil { + return c.sendAlert(alertInternalError) + } + if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: certificate used with invalid signature algorithm") + } + signed := signedMessage(sigHash, serverSignatureContext, hs.transcript) + if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey, + sigHash, signed, certVerify.signature); err != nil { + c.sendAlert(alertDecryptError) + return errors.New("tls: invalid signature by the server certificate: " + err.Error()) + } + + if err := transcriptMsg(certVerify, hs.transcript); err != nil { + return err + } + + return nil +} + +func (hs *clientHandshakeStateTLS13) readServerFinished() error { + c := hs.c + + // finishedMsg is included in the transcript, but not until after we + // check the client version, since the state before this message was + // sent is used during verification. + msg, err := c.readHandshake(nil) + if err != nil { + return err + } + + finished, ok := msg.(*finishedMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(finished, msg) + } + + expectedMAC := hs.suite.finishedHash(c.in.trafficSecret, hs.transcript) + if !hmac.Equal(expectedMAC, finished.verifyData) { + c.sendAlert(alertDecryptError) + return errors.New("tls: invalid server finished hash") + } + + if err := transcriptMsg(finished, hs.transcript); err != nil { + return err + } + + // Derive secrets that take context through the server Finished. + + hs.trafficSecret = hs.suite.deriveSecret(hs.masterSecret, + clientApplicationTrafficLabel, hs.transcript) + serverSecret := hs.suite.deriveSecret(hs.masterSecret, + serverApplicationTrafficLabel, hs.transcript) + c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret) + + err = c.config.writeKeyLog(keyLogLabelClientTraffic, hs.hello.random, hs.trafficSecret) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + err = c.config.writeKeyLog(keyLogLabelServerTraffic, hs.hello.random, serverSecret) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + + c.ekm = hs.suite.exportKeyingMaterial(hs.masterSecret, hs.transcript) + + return nil +} + +func (hs *clientHandshakeStateTLS13) sendClientCertificate() error { + c := hs.c + + if hs.certReq == nil { + return nil + } + + cert, err := c.getClientCertificate(toCertificateRequestInfo(&certificateRequestInfo{ + AcceptableCAs: hs.certReq.certificateAuthorities, + SignatureSchemes: hs.certReq.supportedSignatureAlgorithms, + Version: c.vers, + ctx: hs.ctx, + })) + if err != nil { + return err + } + + certMsg := new(certificateMsgTLS13) + + certMsg.certificate = *cert + certMsg.scts = hs.certReq.scts && len(cert.SignedCertificateTimestamps) > 0 + certMsg.ocspStapling = hs.certReq.ocspStapling && len(cert.OCSPStaple) > 0 + + if _, err := hs.c.writeHandshakeRecord(certMsg, hs.transcript); err != nil { + return err + } + + // If we sent an empty certificate message, skip the CertificateVerify. + if len(cert.Certificate) == 0 { + return nil + } + + certVerifyMsg := new(certificateVerifyMsg) + certVerifyMsg.hasSignatureAlgorithm = true + + certVerifyMsg.signatureAlgorithm, err = selectSignatureScheme(c.vers, cert, hs.certReq.supportedSignatureAlgorithms) + if err != nil { + // getClientCertificate returned a certificate incompatible with the + // CertificateRequestInfo supported signature algorithms. + c.sendAlert(alertHandshakeFailure) + return err + } + + sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerifyMsg.signatureAlgorithm) + if err != nil { + return c.sendAlert(alertInternalError) + } + + signed := signedMessage(sigHash, clientSignatureContext, hs.transcript) + signOpts := crypto.SignerOpts(sigHash) + if sigType == signatureRSAPSS { + signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash} + } + sig, err := cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), signed, signOpts) + if err != nil { + c.sendAlert(alertInternalError) + return errors.New("tls: failed to sign handshake: " + err.Error()) + } + certVerifyMsg.signature = sig + + if _, err := hs.c.writeHandshakeRecord(certVerifyMsg, hs.transcript); err != nil { + return err + } + + return nil +} + +func (hs *clientHandshakeStateTLS13) sendClientFinished() error { + c := hs.c + + finished := &finishedMsg{ + verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript), + } + + if _, err := hs.c.writeHandshakeRecord(finished, hs.transcript); err != nil { + return err + } + + c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret) + + if !c.config.SessionTicketsDisabled && c.config.ClientSessionCache != nil { + c.resumptionSecret = hs.suite.deriveSecret(hs.masterSecret, + resumptionLabel, hs.transcript) + } + + if c.quic != nil { + if c.hand.Len() != 0 { + c.sendAlert(alertUnexpectedMessage) + } + c.quicSetWriteSecret(QUICEncryptionLevelApplication, hs.suite.id, hs.trafficSecret) + } + + return nil +} + +func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error { + if !c.isClient { + c.sendAlert(alertUnexpectedMessage) + return errors.New("tls: received new session ticket from a client") + } + + if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil { + return nil + } + + // See RFC 8446, Section 4.6.1. + if msg.lifetime == 0 { + return nil + } + lifetime := time.Duration(msg.lifetime) * time.Second + if lifetime > maxSessionTicketLifetime { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: received a session ticket with invalid lifetime") + } + + cipherSuite := cipherSuiteTLS13ByID(c.cipherSuite) + if cipherSuite == nil || c.resumptionSecret == nil { + return c.sendAlert(alertInternalError) + } + + // We need to save the max_early_data_size that the server sent us, in order + // to decide if we're going to try 0-RTT with this ticket. + // However, at the same time, the qtls.ClientSessionTicket needs to be equal to + // the tls.ClientSessionTicket, so we can't just add a new field to the struct. + // We therefore abuse the nonce field (which is a byte slice) + nonceWithEarlyData := make([]byte, len(msg.nonce)+4) + binary.BigEndian.PutUint32(nonceWithEarlyData, msg.maxEarlyData) + copy(nonceWithEarlyData[4:], msg.nonce) + + var appData []byte + if c.extraConfig != nil && c.extraConfig.GetAppDataForSessionState != nil { + appData = c.extraConfig.GetAppDataForSessionState() + } + var b cryptobyte.Builder + b.AddUint16(clientSessionStateVersion) // revision + b.AddUint32(msg.maxEarlyData) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(appData) + }) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(msg.nonce) + }) + + // Save the resumption_master_secret and nonce instead of deriving the PSK + // to do the least amount of work on NewSessionTicket messages before we + // know if the ticket will be used. Forward secrecy of resumed connections + // is guaranteed by the requirement for pskModeDHE. + session := &clientSessionState{ + sessionTicket: msg.label, + vers: c.vers, + cipherSuite: c.cipherSuite, + masterSecret: c.resumptionSecret, + serverCertificates: c.peerCertificates, + verifiedChains: c.verifiedChains, + receivedAt: c.config.time(), + nonce: b.BytesOrPanic(), + useBy: c.config.time().Add(lifetime), + ageAdd: msg.ageAdd, + ocspResponse: c.ocspResponse, + scts: c.scts, + } + + cacheKey := c.clientSessionCacheKey() + if cacheKey != "" { + c.config.ClientSessionCache.Put(cacheKey, toClientSessionState(session)) + } + + return nil +} diff --git a/vendor/github.com/quic-go/qtls-go1-20/handshake_messages.go b/vendor/github.com/quic-go/qtls-go1-20/handshake_messages.go new file mode 100644 index 000000000..37b012363 --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/handshake_messages.go @@ -0,0 +1,1886 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package qtls + +import ( + "errors" + "fmt" + "strings" + + "golang.org/x/crypto/cryptobyte" +) + +// The marshalingFunction type is an adapter to allow the use of ordinary +// functions as cryptobyte.MarshalingValue. +type marshalingFunction func(b *cryptobyte.Builder) error + +func (f marshalingFunction) Marshal(b *cryptobyte.Builder) error { + return f(b) +} + +// addBytesWithLength appends a sequence of bytes to the cryptobyte.Builder. If +// the length of the sequence is not the value specified, it produces an error. +func addBytesWithLength(b *cryptobyte.Builder, v []byte, n int) { + b.AddValue(marshalingFunction(func(b *cryptobyte.Builder) error { + if len(v) != n { + return fmt.Errorf("invalid value length: expected %d, got %d", n, len(v)) + } + b.AddBytes(v) + return nil + })) +} + +// addUint64 appends a big-endian, 64-bit value to the cryptobyte.Builder. +func addUint64(b *cryptobyte.Builder, v uint64) { + b.AddUint32(uint32(v >> 32)) + b.AddUint32(uint32(v)) +} + +// readUint64 decodes a big-endian, 64-bit value into out and advances over it. +// It reports whether the read was successful. +func readUint64(s *cryptobyte.String, out *uint64) bool { + var hi, lo uint32 + if !s.ReadUint32(&hi) || !s.ReadUint32(&lo) { + return false + } + *out = uint64(hi)<<32 | uint64(lo) + return true +} + +// readUint8LengthPrefixed acts like s.ReadUint8LengthPrefixed, but targets a +// []byte instead of a cryptobyte.String. +func readUint8LengthPrefixed(s *cryptobyte.String, out *[]byte) bool { + return s.ReadUint8LengthPrefixed((*cryptobyte.String)(out)) +} + +// readUint16LengthPrefixed acts like s.ReadUint16LengthPrefixed, but targets a +// []byte instead of a cryptobyte.String. +func readUint16LengthPrefixed(s *cryptobyte.String, out *[]byte) bool { + return s.ReadUint16LengthPrefixed((*cryptobyte.String)(out)) +} + +// readUint24LengthPrefixed acts like s.ReadUint24LengthPrefixed, but targets a +// []byte instead of a cryptobyte.String. +func readUint24LengthPrefixed(s *cryptobyte.String, out *[]byte) bool { + return s.ReadUint24LengthPrefixed((*cryptobyte.String)(out)) +} + +type clientHelloMsg struct { + raw []byte + vers uint16 + random []byte + sessionId []byte + cipherSuites []uint16 + compressionMethods []uint8 + serverName string + ocspStapling bool + supportedCurves []CurveID + supportedPoints []uint8 + ticketSupported bool + sessionTicket []uint8 + supportedSignatureAlgorithms []SignatureScheme + supportedSignatureAlgorithmsCert []SignatureScheme + secureRenegotiationSupported bool + secureRenegotiation []byte + alpnProtocols []string + scts bool + supportedVersions []uint16 + cookie []byte + keyShares []keyShare + earlyData bool + pskModes []uint8 + pskIdentities []pskIdentity + pskBinders [][]byte + quicTransportParameters []byte +} + +func (m *clientHelloMsg) marshal() ([]byte, error) { + if m.raw != nil { + return m.raw, nil + } + + var exts cryptobyte.Builder + if len(m.serverName) > 0 { + // RFC 6066, Section 3 + exts.AddUint16(extensionServerName) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint8(0) // name_type = host_name + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes([]byte(m.serverName)) + }) + }) + }) + } + if m.ocspStapling { + // RFC 4366, Section 3.6 + exts.AddUint16(extensionStatusRequest) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint8(1) // status_type = ocsp + exts.AddUint16(0) // empty responder_id_list + exts.AddUint16(0) // empty request_extensions + }) + } + if len(m.supportedCurves) > 0 { + // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7 + exts.AddUint16(extensionSupportedCurves) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, curve := range m.supportedCurves { + exts.AddUint16(uint16(curve)) + } + }) + }) + } + if len(m.supportedPoints) > 0 { + // RFC 4492, Section 5.1.2 + exts.AddUint16(extensionSupportedPoints) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.supportedPoints) + }) + }) + } + if m.ticketSupported { + // RFC 5077, Section 3.2 + exts.AddUint16(extensionSessionTicket) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.sessionTicket) + }) + } + if len(m.supportedSignatureAlgorithms) > 0 { + // RFC 5246, Section 7.4.1.4.1 + exts.AddUint16(extensionSignatureAlgorithms) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, sigAlgo := range m.supportedSignatureAlgorithms { + exts.AddUint16(uint16(sigAlgo)) + } + }) + }) + } + if len(m.supportedSignatureAlgorithmsCert) > 0 { + // RFC 8446, Section 4.2.3 + exts.AddUint16(extensionSignatureAlgorithmsCert) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, sigAlgo := range m.supportedSignatureAlgorithmsCert { + exts.AddUint16(uint16(sigAlgo)) + } + }) + }) + } + if m.secureRenegotiationSupported { + // RFC 5746, Section 3.2 + exts.AddUint16(extensionRenegotiationInfo) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.secureRenegotiation) + }) + }) + } + if len(m.alpnProtocols) > 0 { + // RFC 7301, Section 3.1 + exts.AddUint16(extensionALPN) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, proto := range m.alpnProtocols { + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes([]byte(proto)) + }) + } + }) + }) + } + if m.scts { + // RFC 6962, Section 3.3.1 + exts.AddUint16(extensionSCT) + exts.AddUint16(0) // empty extension_data + } + if len(m.supportedVersions) > 0 { + // RFC 8446, Section 4.2.1 + exts.AddUint16(extensionSupportedVersions) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, vers := range m.supportedVersions { + exts.AddUint16(vers) + } + }) + }) + } + if len(m.cookie) > 0 { + // RFC 8446, Section 4.2.2 + exts.AddUint16(extensionCookie) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.cookie) + }) + }) + } + if len(m.keyShares) > 0 { + // RFC 8446, Section 4.2.8 + exts.AddUint16(extensionKeyShare) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, ks := range m.keyShares { + exts.AddUint16(uint16(ks.group)) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(ks.data) + }) + } + }) + }) + } + if m.earlyData { + // RFC 8446, Section 4.2.10 + exts.AddUint16(extensionEarlyData) + exts.AddUint16(0) // empty extension_data + } + if len(m.pskModes) > 0 { + // RFC 8446, Section 4.2.9 + exts.AddUint16(extensionPSKModes) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.pskModes) + }) + }) + } + if m.quicTransportParameters != nil { // marshal zero-length parameters when present + // RFC 9001, Section 8.2 + exts.AddUint16(extensionQUICTransportParameters) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.quicTransportParameters) + }) + } + if len(m.pskIdentities) > 0 { // pre_shared_key must be the last extension + // RFC 8446, Section 4.2.11 + exts.AddUint16(extensionPreSharedKey) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, psk := range m.pskIdentities { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(psk.label) + }) + exts.AddUint32(psk.obfuscatedTicketAge) + } + }) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, binder := range m.pskBinders { + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(binder) + }) + } + }) + }) + } + extBytes, err := exts.Bytes() + if err != nil { + return nil, err + } + + var b cryptobyte.Builder + b.AddUint8(typeClientHello) + b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddUint16(m.vers) + addBytesWithLength(b, m.random, 32) + b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(m.sessionId) + }) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + for _, suite := range m.cipherSuites { + b.AddUint16(suite) + } + }) + b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(m.compressionMethods) + }) + + if len(extBytes) > 0 { + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(extBytes) + }) + } + }) + + m.raw, err = b.Bytes() + return m.raw, err +} + +// marshalWithoutBinders returns the ClientHello through the +// PreSharedKeyExtension.identities field, according to RFC 8446, Section +// 4.2.11.2. Note that m.pskBinders must be set to slices of the correct length. +func (m *clientHelloMsg) marshalWithoutBinders() ([]byte, error) { + bindersLen := 2 // uint16 length prefix + for _, binder := range m.pskBinders { + bindersLen += 1 // uint8 length prefix + bindersLen += len(binder) + } + + fullMessage, err := m.marshal() + if err != nil { + return nil, err + } + return fullMessage[:len(fullMessage)-bindersLen], nil +} + +// updateBinders updates the m.pskBinders field, if necessary updating the +// cached marshaled representation. The supplied binders must have the same +// length as the current m.pskBinders. +func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) error { + if len(pskBinders) != len(m.pskBinders) { + return errors.New("tls: internal error: pskBinders length mismatch") + } + for i := range m.pskBinders { + if len(pskBinders[i]) != len(m.pskBinders[i]) { + return errors.New("tls: internal error: pskBinders length mismatch") + } + } + m.pskBinders = pskBinders + if m.raw != nil { + helloBytes, err := m.marshalWithoutBinders() + if err != nil { + return err + } + lenWithoutBinders := len(helloBytes) + b := cryptobyte.NewFixedBuilder(m.raw[:lenWithoutBinders]) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + for _, binder := range m.pskBinders { + b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(binder) + }) + } + }) + if out, err := b.Bytes(); err != nil || len(out) != len(m.raw) { + return errors.New("tls: internal error: failed to update binders") + } + } + + return nil +} + +func (m *clientHelloMsg) unmarshal(data []byte) bool { + *m = clientHelloMsg{raw: data} + s := cryptobyte.String(data) + + if !s.Skip(4) || // message type and uint24 length field + !s.ReadUint16(&m.vers) || !s.ReadBytes(&m.random, 32) || + !readUint8LengthPrefixed(&s, &m.sessionId) { + return false + } + + var cipherSuites cryptobyte.String + if !s.ReadUint16LengthPrefixed(&cipherSuites) { + return false + } + m.cipherSuites = []uint16{} + m.secureRenegotiationSupported = false + for !cipherSuites.Empty() { + var suite uint16 + if !cipherSuites.ReadUint16(&suite) { + return false + } + if suite == scsvRenegotiation { + m.secureRenegotiationSupported = true + } + m.cipherSuites = append(m.cipherSuites, suite) + } + + if !readUint8LengthPrefixed(&s, &m.compressionMethods) { + return false + } + + if s.Empty() { + // ClientHello is optionally followed by extension data + return true + } + + var extensions cryptobyte.String + if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() { + return false + } + + seenExts := make(map[uint16]bool) + for !extensions.Empty() { + var extension uint16 + var extData cryptobyte.String + if !extensions.ReadUint16(&extension) || + !extensions.ReadUint16LengthPrefixed(&extData) { + return false + } + + if seenExts[extension] { + return false + } + seenExts[extension] = true + + switch extension { + case extensionServerName: + // RFC 6066, Section 3 + var nameList cryptobyte.String + if !extData.ReadUint16LengthPrefixed(&nameList) || nameList.Empty() { + return false + } + for !nameList.Empty() { + var nameType uint8 + var serverName cryptobyte.String + if !nameList.ReadUint8(&nameType) || + !nameList.ReadUint16LengthPrefixed(&serverName) || + serverName.Empty() { + return false + } + if nameType != 0 { + continue + } + if len(m.serverName) != 0 { + // Multiple names of the same name_type are prohibited. + return false + } + m.serverName = string(serverName) + // An SNI value may not include a trailing dot. + if strings.HasSuffix(m.serverName, ".") { + return false + } + } + case extensionStatusRequest: + // RFC 4366, Section 3.6 + var statusType uint8 + var ignored cryptobyte.String + if !extData.ReadUint8(&statusType) || + !extData.ReadUint16LengthPrefixed(&ignored) || + !extData.ReadUint16LengthPrefixed(&ignored) { + return false + } + m.ocspStapling = statusType == statusTypeOCSP + case extensionSupportedCurves: + // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7 + var curves cryptobyte.String + if !extData.ReadUint16LengthPrefixed(&curves) || curves.Empty() { + return false + } + for !curves.Empty() { + var curve uint16 + if !curves.ReadUint16(&curve) { + return false + } + m.supportedCurves = append(m.supportedCurves, CurveID(curve)) + } + case extensionSupportedPoints: + // RFC 4492, Section 5.1.2 + if !readUint8LengthPrefixed(&extData, &m.supportedPoints) || + len(m.supportedPoints) == 0 { + return false + } + case extensionSessionTicket: + // RFC 5077, Section 3.2 + m.ticketSupported = true + extData.ReadBytes(&m.sessionTicket, len(extData)) + case extensionSignatureAlgorithms: + // RFC 5246, Section 7.4.1.4.1 + var sigAndAlgs cryptobyte.String + if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() { + return false + } + for !sigAndAlgs.Empty() { + var sigAndAlg uint16 + if !sigAndAlgs.ReadUint16(&sigAndAlg) { + return false + } + m.supportedSignatureAlgorithms = append( + m.supportedSignatureAlgorithms, SignatureScheme(sigAndAlg)) + } + case extensionSignatureAlgorithmsCert: + // RFC 8446, Section 4.2.3 + var sigAndAlgs cryptobyte.String + if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() { + return false + } + for !sigAndAlgs.Empty() { + var sigAndAlg uint16 + if !sigAndAlgs.ReadUint16(&sigAndAlg) { + return false + } + m.supportedSignatureAlgorithmsCert = append( + m.supportedSignatureAlgorithmsCert, SignatureScheme(sigAndAlg)) + } + case extensionRenegotiationInfo: + // RFC 5746, Section 3.2 + if !readUint8LengthPrefixed(&extData, &m.secureRenegotiation) { + return false + } + m.secureRenegotiationSupported = true + case extensionALPN: + // RFC 7301, Section 3.1 + var protoList cryptobyte.String + if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() { + return false + } + for !protoList.Empty() { + var proto cryptobyte.String + if !protoList.ReadUint8LengthPrefixed(&proto) || proto.Empty() { + return false + } + m.alpnProtocols = append(m.alpnProtocols, string(proto)) + } + case extensionSCT: + // RFC 6962, Section 3.3.1 + m.scts = true + case extensionSupportedVersions: + // RFC 8446, Section 4.2.1 + var versList cryptobyte.String + if !extData.ReadUint8LengthPrefixed(&versList) || versList.Empty() { + return false + } + for !versList.Empty() { + var vers uint16 + if !versList.ReadUint16(&vers) { + return false + } + m.supportedVersions = append(m.supportedVersions, vers) + } + case extensionCookie: + // RFC 8446, Section 4.2.2 + if !readUint16LengthPrefixed(&extData, &m.cookie) || + len(m.cookie) == 0 { + return false + } + case extensionKeyShare: + // RFC 8446, Section 4.2.8 + var clientShares cryptobyte.String + if !extData.ReadUint16LengthPrefixed(&clientShares) { + return false + } + for !clientShares.Empty() { + var ks keyShare + if !clientShares.ReadUint16((*uint16)(&ks.group)) || + !readUint16LengthPrefixed(&clientShares, &ks.data) || + len(ks.data) == 0 { + return false + } + m.keyShares = append(m.keyShares, ks) + } + case extensionEarlyData: + // RFC 8446, Section 4.2.10 + m.earlyData = true + case extensionPSKModes: + // RFC 8446, Section 4.2.9 + if !readUint8LengthPrefixed(&extData, &m.pskModes) { + return false + } + case extensionQUICTransportParameters: + m.quicTransportParameters = make([]byte, len(extData)) + if !extData.CopyBytes(m.quicTransportParameters) { + return false + } + case extensionPreSharedKey: + // RFC 8446, Section 4.2.11 + if !extensions.Empty() { + return false // pre_shared_key must be the last extension + } + var identities cryptobyte.String + if !extData.ReadUint16LengthPrefixed(&identities) || identities.Empty() { + return false + } + for !identities.Empty() { + var psk pskIdentity + if !readUint16LengthPrefixed(&identities, &psk.label) || + !identities.ReadUint32(&psk.obfuscatedTicketAge) || + len(psk.label) == 0 { + return false + } + m.pskIdentities = append(m.pskIdentities, psk) + } + var binders cryptobyte.String + if !extData.ReadUint16LengthPrefixed(&binders) || binders.Empty() { + return false + } + for !binders.Empty() { + var binder []byte + if !readUint8LengthPrefixed(&binders, &binder) || + len(binder) == 0 { + return false + } + m.pskBinders = append(m.pskBinders, binder) + } + default: + // Ignore unknown extensions. + continue + } + + if !extData.Empty() { + return false + } + } + + return true +} + +type serverHelloMsg struct { + raw []byte + vers uint16 + random []byte + sessionId []byte + cipherSuite uint16 + compressionMethod uint8 + ocspStapling bool + ticketSupported bool + secureRenegotiationSupported bool + secureRenegotiation []byte + alpnProtocol string + scts [][]byte + supportedVersion uint16 + serverShare keyShare + selectedIdentityPresent bool + selectedIdentity uint16 + supportedPoints []uint8 + + // HelloRetryRequest extensions + cookie []byte + selectedGroup CurveID +} + +func (m *serverHelloMsg) marshal() ([]byte, error) { + if m.raw != nil { + return m.raw, nil + } + + var exts cryptobyte.Builder + if m.ocspStapling { + exts.AddUint16(extensionStatusRequest) + exts.AddUint16(0) // empty extension_data + } + if m.ticketSupported { + exts.AddUint16(extensionSessionTicket) + exts.AddUint16(0) // empty extension_data + } + if m.secureRenegotiationSupported { + exts.AddUint16(extensionRenegotiationInfo) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.secureRenegotiation) + }) + }) + } + if len(m.alpnProtocol) > 0 { + exts.AddUint16(extensionALPN) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes([]byte(m.alpnProtocol)) + }) + }) + }) + } + if len(m.scts) > 0 { + exts.AddUint16(extensionSCT) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, sct := range m.scts { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(sct) + }) + } + }) + }) + } + if m.supportedVersion != 0 { + exts.AddUint16(extensionSupportedVersions) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16(m.supportedVersion) + }) + } + if m.serverShare.group != 0 { + exts.AddUint16(extensionKeyShare) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16(uint16(m.serverShare.group)) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.serverShare.data) + }) + }) + } + if m.selectedIdentityPresent { + exts.AddUint16(extensionPreSharedKey) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16(m.selectedIdentity) + }) + } + + if len(m.cookie) > 0 { + exts.AddUint16(extensionCookie) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.cookie) + }) + }) + } + if m.selectedGroup != 0 { + exts.AddUint16(extensionKeyShare) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16(uint16(m.selectedGroup)) + }) + } + if len(m.supportedPoints) > 0 { + exts.AddUint16(extensionSupportedPoints) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.supportedPoints) + }) + }) + } + + extBytes, err := exts.Bytes() + if err != nil { + return nil, err + } + + var b cryptobyte.Builder + b.AddUint8(typeServerHello) + b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddUint16(m.vers) + addBytesWithLength(b, m.random, 32) + b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(m.sessionId) + }) + b.AddUint16(m.cipherSuite) + b.AddUint8(m.compressionMethod) + + if len(extBytes) > 0 { + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(extBytes) + }) + } + }) + + m.raw, err = b.Bytes() + return m.raw, err +} + +func (m *serverHelloMsg) unmarshal(data []byte) bool { + *m = serverHelloMsg{raw: data} + s := cryptobyte.String(data) + + if !s.Skip(4) || // message type and uint24 length field + !s.ReadUint16(&m.vers) || !s.ReadBytes(&m.random, 32) || + !readUint8LengthPrefixed(&s, &m.sessionId) || + !s.ReadUint16(&m.cipherSuite) || + !s.ReadUint8(&m.compressionMethod) { + return false + } + + if s.Empty() { + // ServerHello is optionally followed by extension data + return true + } + + var extensions cryptobyte.String + if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() { + return false + } + + seenExts := make(map[uint16]bool) + for !extensions.Empty() { + var extension uint16 + var extData cryptobyte.String + if !extensions.ReadUint16(&extension) || + !extensions.ReadUint16LengthPrefixed(&extData) { + return false + } + + if seenExts[extension] { + return false + } + seenExts[extension] = true + + switch extension { + case extensionStatusRequest: + m.ocspStapling = true + case extensionSessionTicket: + m.ticketSupported = true + case extensionRenegotiationInfo: + if !readUint8LengthPrefixed(&extData, &m.secureRenegotiation) { + return false + } + m.secureRenegotiationSupported = true + case extensionALPN: + var protoList cryptobyte.String + if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() { + return false + } + var proto cryptobyte.String + if !protoList.ReadUint8LengthPrefixed(&proto) || + proto.Empty() || !protoList.Empty() { + return false + } + m.alpnProtocol = string(proto) + case extensionSCT: + var sctList cryptobyte.String + if !extData.ReadUint16LengthPrefixed(&sctList) || sctList.Empty() { + return false + } + for !sctList.Empty() { + var sct []byte + if !readUint16LengthPrefixed(&sctList, &sct) || + len(sct) == 0 { + return false + } + m.scts = append(m.scts, sct) + } + case extensionSupportedVersions: + if !extData.ReadUint16(&m.supportedVersion) { + return false + } + case extensionCookie: + if !readUint16LengthPrefixed(&extData, &m.cookie) || + len(m.cookie) == 0 { + return false + } + case extensionKeyShare: + // This extension has different formats in SH and HRR, accept either + // and let the handshake logic decide. See RFC 8446, Section 4.2.8. + if len(extData) == 2 { + if !extData.ReadUint16((*uint16)(&m.selectedGroup)) { + return false + } + } else { + if !extData.ReadUint16((*uint16)(&m.serverShare.group)) || + !readUint16LengthPrefixed(&extData, &m.serverShare.data) { + return false + } + } + case extensionPreSharedKey: + m.selectedIdentityPresent = true + if !extData.ReadUint16(&m.selectedIdentity) { + return false + } + case extensionSupportedPoints: + // RFC 4492, Section 5.1.2 + if !readUint8LengthPrefixed(&extData, &m.supportedPoints) || + len(m.supportedPoints) == 0 { + return false + } + default: + // Ignore unknown extensions. + continue + } + + if !extData.Empty() { + return false + } + } + + return true +} + +type encryptedExtensionsMsg struct { + raw []byte + alpnProtocol string + quicTransportParameters []byte + earlyData bool +} + +func (m *encryptedExtensionsMsg) marshal() ([]byte, error) { + if m.raw != nil { + return m.raw, nil + } + + var b cryptobyte.Builder + b.AddUint8(typeEncryptedExtensions) + b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + if len(m.alpnProtocol) > 0 { + b.AddUint16(extensionALPN) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes([]byte(m.alpnProtocol)) + }) + }) + }) + } + if m.quicTransportParameters != nil { // marshal zero-length parameters when present + // draft-ietf-quic-tls-32, Section 8.2 + b.AddUint16(extensionQUICTransportParameters) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(m.quicTransportParameters) + }) + } + if m.earlyData { + // RFC 8446, Section 4.2.10 + b.AddUint16(extensionEarlyData) + b.AddUint16(0) // empty extension_data + } + }) + }) + + var err error + m.raw, err = b.Bytes() + return m.raw, err +} + +func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool { + *m = encryptedExtensionsMsg{raw: data} + s := cryptobyte.String(data) + + var extensions cryptobyte.String + if !s.Skip(4) || // message type and uint24 length field + !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() { + return false + } + + for !extensions.Empty() { + var extension uint16 + var extData cryptobyte.String + if !extensions.ReadUint16(&extension) || + !extensions.ReadUint16LengthPrefixed(&extData) { + return false + } + + switch extension { + case extensionALPN: + var protoList cryptobyte.String + if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() { + return false + } + var proto cryptobyte.String + if !protoList.ReadUint8LengthPrefixed(&proto) || + proto.Empty() || !protoList.Empty() { + return false + } + m.alpnProtocol = string(proto) + case extensionQUICTransportParameters: + m.quicTransportParameters = make([]byte, len(extData)) + if !extData.CopyBytes(m.quicTransportParameters) { + return false + } + case extensionEarlyData: + m.earlyData = true + default: + // Ignore unknown extensions. + continue + } + + if !extData.Empty() { + return false + } + } + + return true +} + +type endOfEarlyDataMsg struct{} + +func (m *endOfEarlyDataMsg) marshal() ([]byte, error) { + x := make([]byte, 4) + x[0] = typeEndOfEarlyData + return x, nil +} + +func (m *endOfEarlyDataMsg) unmarshal(data []byte) bool { + return len(data) == 4 +} + +type keyUpdateMsg struct { + raw []byte + updateRequested bool +} + +func (m *keyUpdateMsg) marshal() ([]byte, error) { + if m.raw != nil { + return m.raw, nil + } + + var b cryptobyte.Builder + b.AddUint8(typeKeyUpdate) + b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { + if m.updateRequested { + b.AddUint8(1) + } else { + b.AddUint8(0) + } + }) + + var err error + m.raw, err = b.Bytes() + return m.raw, err +} + +func (m *keyUpdateMsg) unmarshal(data []byte) bool { + m.raw = data + s := cryptobyte.String(data) + + var updateRequested uint8 + if !s.Skip(4) || // message type and uint24 length field + !s.ReadUint8(&updateRequested) || !s.Empty() { + return false + } + switch updateRequested { + case 0: + m.updateRequested = false + case 1: + m.updateRequested = true + default: + return false + } + return true +} + +type newSessionTicketMsgTLS13 struct { + raw []byte + lifetime uint32 + ageAdd uint32 + nonce []byte + label []byte + maxEarlyData uint32 +} + +func (m *newSessionTicketMsgTLS13) marshal() ([]byte, error) { + if m.raw != nil { + return m.raw, nil + } + + var b cryptobyte.Builder + b.AddUint8(typeNewSessionTicket) + b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddUint32(m.lifetime) + b.AddUint32(m.ageAdd) + b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(m.nonce) + }) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(m.label) + }) + + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + if m.maxEarlyData > 0 { + b.AddUint16(extensionEarlyData) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddUint32(m.maxEarlyData) + }) + } + }) + }) + + var err error + m.raw, err = b.Bytes() + return m.raw, err +} + +func (m *newSessionTicketMsgTLS13) unmarshal(data []byte) bool { + *m = newSessionTicketMsgTLS13{raw: data} + s := cryptobyte.String(data) + + var extensions cryptobyte.String + if !s.Skip(4) || // message type and uint24 length field + !s.ReadUint32(&m.lifetime) || + !s.ReadUint32(&m.ageAdd) || + !readUint8LengthPrefixed(&s, &m.nonce) || + !readUint16LengthPrefixed(&s, &m.label) || + !s.ReadUint16LengthPrefixed(&extensions) || + !s.Empty() { + return false + } + + for !extensions.Empty() { + var extension uint16 + var extData cryptobyte.String + if !extensions.ReadUint16(&extension) || + !extensions.ReadUint16LengthPrefixed(&extData) { + return false + } + + switch extension { + case extensionEarlyData: + if !extData.ReadUint32(&m.maxEarlyData) { + return false + } + default: + // Ignore unknown extensions. + continue + } + + if !extData.Empty() { + return false + } + } + + return true +} + +type certificateRequestMsgTLS13 struct { + raw []byte + ocspStapling bool + scts bool + supportedSignatureAlgorithms []SignatureScheme + supportedSignatureAlgorithmsCert []SignatureScheme + certificateAuthorities [][]byte +} + +func (m *certificateRequestMsgTLS13) marshal() ([]byte, error) { + if m.raw != nil { + return m.raw, nil + } + + var b cryptobyte.Builder + b.AddUint8(typeCertificateRequest) + b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { + // certificate_request_context (SHALL be zero length unless used for + // post-handshake authentication) + b.AddUint8(0) + + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + if m.ocspStapling { + b.AddUint16(extensionStatusRequest) + b.AddUint16(0) // empty extension_data + } + if m.scts { + // RFC 8446, Section 4.4.2.1 makes no mention of + // signed_certificate_timestamp in CertificateRequest, but + // "Extensions in the Certificate message from the client MUST + // correspond to extensions in the CertificateRequest message + // from the server." and it appears in the table in Section 4.2. + b.AddUint16(extensionSCT) + b.AddUint16(0) // empty extension_data + } + if len(m.supportedSignatureAlgorithms) > 0 { + b.AddUint16(extensionSignatureAlgorithms) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + for _, sigAlgo := range m.supportedSignatureAlgorithms { + b.AddUint16(uint16(sigAlgo)) + } + }) + }) + } + if len(m.supportedSignatureAlgorithmsCert) > 0 { + b.AddUint16(extensionSignatureAlgorithmsCert) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + for _, sigAlgo := range m.supportedSignatureAlgorithmsCert { + b.AddUint16(uint16(sigAlgo)) + } + }) + }) + } + if len(m.certificateAuthorities) > 0 { + b.AddUint16(extensionCertificateAuthorities) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + for _, ca := range m.certificateAuthorities { + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(ca) + }) + } + }) + }) + } + }) + }) + + var err error + m.raw, err = b.Bytes() + return m.raw, err +} + +func (m *certificateRequestMsgTLS13) unmarshal(data []byte) bool { + *m = certificateRequestMsgTLS13{raw: data} + s := cryptobyte.String(data) + + var context, extensions cryptobyte.String + if !s.Skip(4) || // message type and uint24 length field + !s.ReadUint8LengthPrefixed(&context) || !context.Empty() || + !s.ReadUint16LengthPrefixed(&extensions) || + !s.Empty() { + return false + } + + for !extensions.Empty() { + var extension uint16 + var extData cryptobyte.String + if !extensions.ReadUint16(&extension) || + !extensions.ReadUint16LengthPrefixed(&extData) { + return false + } + + switch extension { + case extensionStatusRequest: + m.ocspStapling = true + case extensionSCT: + m.scts = true + case extensionSignatureAlgorithms: + var sigAndAlgs cryptobyte.String + if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() { + return false + } + for !sigAndAlgs.Empty() { + var sigAndAlg uint16 + if !sigAndAlgs.ReadUint16(&sigAndAlg) { + return false + } + m.supportedSignatureAlgorithms = append( + m.supportedSignatureAlgorithms, SignatureScheme(sigAndAlg)) + } + case extensionSignatureAlgorithmsCert: + var sigAndAlgs cryptobyte.String + if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() { + return false + } + for !sigAndAlgs.Empty() { + var sigAndAlg uint16 + if !sigAndAlgs.ReadUint16(&sigAndAlg) { + return false + } + m.supportedSignatureAlgorithmsCert = append( + m.supportedSignatureAlgorithmsCert, SignatureScheme(sigAndAlg)) + } + case extensionCertificateAuthorities: + var auths cryptobyte.String + if !extData.ReadUint16LengthPrefixed(&auths) || auths.Empty() { + return false + } + for !auths.Empty() { + var ca []byte + if !readUint16LengthPrefixed(&auths, &ca) || len(ca) == 0 { + return false + } + m.certificateAuthorities = append(m.certificateAuthorities, ca) + } + default: + // Ignore unknown extensions. + continue + } + + if !extData.Empty() { + return false + } + } + + return true +} + +type certificateMsg struct { + raw []byte + certificates [][]byte +} + +func (m *certificateMsg) marshal() ([]byte, error) { + if m.raw != nil { + return m.raw, nil + } + + var i int + for _, slice := range m.certificates { + i += len(slice) + } + + length := 3 + 3*len(m.certificates) + i + x := make([]byte, 4+length) + x[0] = typeCertificate + x[1] = uint8(length >> 16) + x[2] = uint8(length >> 8) + x[3] = uint8(length) + + certificateOctets := length - 3 + x[4] = uint8(certificateOctets >> 16) + x[5] = uint8(certificateOctets >> 8) + x[6] = uint8(certificateOctets) + + y := x[7:] + for _, slice := range m.certificates { + y[0] = uint8(len(slice) >> 16) + y[1] = uint8(len(slice) >> 8) + y[2] = uint8(len(slice)) + copy(y[3:], slice) + y = y[3+len(slice):] + } + + m.raw = x + return m.raw, nil +} + +func (m *certificateMsg) unmarshal(data []byte) bool { + if len(data) < 7 { + return false + } + + m.raw = data + certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6]) + if uint32(len(data)) != certsLen+7 { + return false + } + + numCerts := 0 + d := data[7:] + for certsLen > 0 { + if len(d) < 4 { + return false + } + certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2]) + if uint32(len(d)) < 3+certLen { + return false + } + d = d[3+certLen:] + certsLen -= 3 + certLen + numCerts++ + } + + m.certificates = make([][]byte, numCerts) + d = data[7:] + for i := 0; i < numCerts; i++ { + certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2]) + m.certificates[i] = d[3 : 3+certLen] + d = d[3+certLen:] + } + + return true +} + +type certificateMsgTLS13 struct { + raw []byte + certificate Certificate + ocspStapling bool + scts bool +} + +func (m *certificateMsgTLS13) marshal() ([]byte, error) { + if m.raw != nil { + return m.raw, nil + } + + var b cryptobyte.Builder + b.AddUint8(typeCertificate) + b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddUint8(0) // certificate_request_context + + certificate := m.certificate + if !m.ocspStapling { + certificate.OCSPStaple = nil + } + if !m.scts { + certificate.SignedCertificateTimestamps = nil + } + marshalCertificate(b, certificate) + }) + + var err error + m.raw, err = b.Bytes() + return m.raw, err +} + +func marshalCertificate(b *cryptobyte.Builder, certificate Certificate) { + b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { + for i, cert := range certificate.Certificate { + b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(cert) + }) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + if i > 0 { + // This library only supports OCSP and SCT for leaf certificates. + return + } + if certificate.OCSPStaple != nil { + b.AddUint16(extensionStatusRequest) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddUint8(statusTypeOCSP) + b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(certificate.OCSPStaple) + }) + }) + } + if certificate.SignedCertificateTimestamps != nil { + b.AddUint16(extensionSCT) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + for _, sct := range certificate.SignedCertificateTimestamps { + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(sct) + }) + } + }) + }) + } + }) + } + }) +} + +func (m *certificateMsgTLS13) unmarshal(data []byte) bool { + *m = certificateMsgTLS13{raw: data} + s := cryptobyte.String(data) + + var context cryptobyte.String + if !s.Skip(4) || // message type and uint24 length field + !s.ReadUint8LengthPrefixed(&context) || !context.Empty() || + !unmarshalCertificate(&s, &m.certificate) || + !s.Empty() { + return false + } + + m.scts = m.certificate.SignedCertificateTimestamps != nil + m.ocspStapling = m.certificate.OCSPStaple != nil + + return true +} + +func unmarshalCertificate(s *cryptobyte.String, certificate *Certificate) bool { + var certList cryptobyte.String + if !s.ReadUint24LengthPrefixed(&certList) { + return false + } + for !certList.Empty() { + var cert []byte + var extensions cryptobyte.String + if !readUint24LengthPrefixed(&certList, &cert) || + !certList.ReadUint16LengthPrefixed(&extensions) { + return false + } + certificate.Certificate = append(certificate.Certificate, cert) + for !extensions.Empty() { + var extension uint16 + var extData cryptobyte.String + if !extensions.ReadUint16(&extension) || + !extensions.ReadUint16LengthPrefixed(&extData) { + return false + } + if len(certificate.Certificate) > 1 { + // This library only supports OCSP and SCT for leaf certificates. + continue + } + + switch extension { + case extensionStatusRequest: + var statusType uint8 + if !extData.ReadUint8(&statusType) || statusType != statusTypeOCSP || + !readUint24LengthPrefixed(&extData, &certificate.OCSPStaple) || + len(certificate.OCSPStaple) == 0 { + return false + } + case extensionSCT: + var sctList cryptobyte.String + if !extData.ReadUint16LengthPrefixed(&sctList) || sctList.Empty() { + return false + } + for !sctList.Empty() { + var sct []byte + if !readUint16LengthPrefixed(&sctList, &sct) || + len(sct) == 0 { + return false + } + certificate.SignedCertificateTimestamps = append( + certificate.SignedCertificateTimestamps, sct) + } + default: + // Ignore unknown extensions. + continue + } + + if !extData.Empty() { + return false + } + } + } + return true +} + +type serverKeyExchangeMsg struct { + raw []byte + key []byte +} + +func (m *serverKeyExchangeMsg) marshal() ([]byte, error) { + if m.raw != nil { + return m.raw, nil + } + length := len(m.key) + x := make([]byte, length+4) + x[0] = typeServerKeyExchange + x[1] = uint8(length >> 16) + x[2] = uint8(length >> 8) + x[3] = uint8(length) + copy(x[4:], m.key) + + m.raw = x + return x, nil +} + +func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool { + m.raw = data + if len(data) < 4 { + return false + } + m.key = data[4:] + return true +} + +type certificateStatusMsg struct { + raw []byte + response []byte +} + +func (m *certificateStatusMsg) marshal() ([]byte, error) { + if m.raw != nil { + return m.raw, nil + } + + var b cryptobyte.Builder + b.AddUint8(typeCertificateStatus) + b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddUint8(statusTypeOCSP) + b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(m.response) + }) + }) + + var err error + m.raw, err = b.Bytes() + return m.raw, err +} + +func (m *certificateStatusMsg) unmarshal(data []byte) bool { + m.raw = data + s := cryptobyte.String(data) + + var statusType uint8 + if !s.Skip(4) || // message type and uint24 length field + !s.ReadUint8(&statusType) || statusType != statusTypeOCSP || + !readUint24LengthPrefixed(&s, &m.response) || + len(m.response) == 0 || !s.Empty() { + return false + } + return true +} + +type serverHelloDoneMsg struct{} + +func (m *serverHelloDoneMsg) marshal() ([]byte, error) { + x := make([]byte, 4) + x[0] = typeServerHelloDone + return x, nil +} + +func (m *serverHelloDoneMsg) unmarshal(data []byte) bool { + return len(data) == 4 +} + +type clientKeyExchangeMsg struct { + raw []byte + ciphertext []byte +} + +func (m *clientKeyExchangeMsg) marshal() ([]byte, error) { + if m.raw != nil { + return m.raw, nil + } + length := len(m.ciphertext) + x := make([]byte, length+4) + x[0] = typeClientKeyExchange + x[1] = uint8(length >> 16) + x[2] = uint8(length >> 8) + x[3] = uint8(length) + copy(x[4:], m.ciphertext) + + m.raw = x + return x, nil +} + +func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool { + m.raw = data + if len(data) < 4 { + return false + } + l := int(data[1])<<16 | int(data[2])<<8 | int(data[3]) + if l != len(data)-4 { + return false + } + m.ciphertext = data[4:] + return true +} + +type finishedMsg struct { + raw []byte + verifyData []byte +} + +func (m *finishedMsg) marshal() ([]byte, error) { + if m.raw != nil { + return m.raw, nil + } + + var b cryptobyte.Builder + b.AddUint8(typeFinished) + b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(m.verifyData) + }) + + var err error + m.raw, err = b.Bytes() + return m.raw, err +} + +func (m *finishedMsg) unmarshal(data []byte) bool { + m.raw = data + s := cryptobyte.String(data) + return s.Skip(1) && + readUint24LengthPrefixed(&s, &m.verifyData) && + s.Empty() +} + +type certificateRequestMsg struct { + raw []byte + // hasSignatureAlgorithm indicates whether this message includes a list of + // supported signature algorithms. This change was introduced with TLS 1.2. + hasSignatureAlgorithm bool + + certificateTypes []byte + supportedSignatureAlgorithms []SignatureScheme + certificateAuthorities [][]byte +} + +func (m *certificateRequestMsg) marshal() ([]byte, error) { + if m.raw != nil { + return m.raw, nil + } + + // See RFC 4346, Section 7.4.4. + length := 1 + len(m.certificateTypes) + 2 + casLength := 0 + for _, ca := range m.certificateAuthorities { + casLength += 2 + len(ca) + } + length += casLength + + if m.hasSignatureAlgorithm { + length += 2 + 2*len(m.supportedSignatureAlgorithms) + } + + x := make([]byte, 4+length) + x[0] = typeCertificateRequest + x[1] = uint8(length >> 16) + x[2] = uint8(length >> 8) + x[3] = uint8(length) + + x[4] = uint8(len(m.certificateTypes)) + + copy(x[5:], m.certificateTypes) + y := x[5+len(m.certificateTypes):] + + if m.hasSignatureAlgorithm { + n := len(m.supportedSignatureAlgorithms) * 2 + y[0] = uint8(n >> 8) + y[1] = uint8(n) + y = y[2:] + for _, sigAlgo := range m.supportedSignatureAlgorithms { + y[0] = uint8(sigAlgo >> 8) + y[1] = uint8(sigAlgo) + y = y[2:] + } + } + + y[0] = uint8(casLength >> 8) + y[1] = uint8(casLength) + y = y[2:] + for _, ca := range m.certificateAuthorities { + y[0] = uint8(len(ca) >> 8) + y[1] = uint8(len(ca)) + y = y[2:] + copy(y, ca) + y = y[len(ca):] + } + + m.raw = x + return m.raw, nil +} + +func (m *certificateRequestMsg) unmarshal(data []byte) bool { + m.raw = data + + if len(data) < 5 { + return false + } + + length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) + if uint32(len(data))-4 != length { + return false + } + + numCertTypes := int(data[4]) + data = data[5:] + if numCertTypes == 0 || len(data) <= numCertTypes { + return false + } + + m.certificateTypes = make([]byte, numCertTypes) + if copy(m.certificateTypes, data) != numCertTypes { + return false + } + + data = data[numCertTypes:] + + if m.hasSignatureAlgorithm { + if len(data) < 2 { + return false + } + sigAndHashLen := uint16(data[0])<<8 | uint16(data[1]) + data = data[2:] + if sigAndHashLen&1 != 0 { + return false + } + if len(data) < int(sigAndHashLen) { + return false + } + numSigAlgos := sigAndHashLen / 2 + m.supportedSignatureAlgorithms = make([]SignatureScheme, numSigAlgos) + for i := range m.supportedSignatureAlgorithms { + m.supportedSignatureAlgorithms[i] = SignatureScheme(data[0])<<8 | SignatureScheme(data[1]) + data = data[2:] + } + } + + if len(data) < 2 { + return false + } + casLength := uint16(data[0])<<8 | uint16(data[1]) + data = data[2:] + if len(data) < int(casLength) { + return false + } + cas := make([]byte, casLength) + copy(cas, data) + data = data[casLength:] + + m.certificateAuthorities = nil + for len(cas) > 0 { + if len(cas) < 2 { + return false + } + caLen := uint16(cas[0])<<8 | uint16(cas[1]) + cas = cas[2:] + + if len(cas) < int(caLen) { + return false + } + + m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen]) + cas = cas[caLen:] + } + + return len(data) == 0 +} + +type certificateVerifyMsg struct { + raw []byte + hasSignatureAlgorithm bool // format change introduced in TLS 1.2 + signatureAlgorithm SignatureScheme + signature []byte +} + +func (m *certificateVerifyMsg) marshal() ([]byte, error) { + if m.raw != nil { + return m.raw, nil + } + + var b cryptobyte.Builder + b.AddUint8(typeCertificateVerify) + b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { + if m.hasSignatureAlgorithm { + b.AddUint16(uint16(m.signatureAlgorithm)) + } + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(m.signature) + }) + }) + + var err error + m.raw, err = b.Bytes() + return m.raw, err +} + +func (m *certificateVerifyMsg) unmarshal(data []byte) bool { + m.raw = data + s := cryptobyte.String(data) + + if !s.Skip(4) { // message type and uint24 length field + return false + } + if m.hasSignatureAlgorithm { + if !s.ReadUint16((*uint16)(&m.signatureAlgorithm)) { + return false + } + } + return readUint16LengthPrefixed(&s, &m.signature) && s.Empty() +} + +type newSessionTicketMsg struct { + raw []byte + ticket []byte +} + +func (m *newSessionTicketMsg) marshal() ([]byte, error) { + if m.raw != nil { + return m.raw, nil + } + + // See RFC 5077, Section 3.3. + ticketLen := len(m.ticket) + length := 2 + 4 + ticketLen + x := make([]byte, 4+length) + x[0] = typeNewSessionTicket + x[1] = uint8(length >> 16) + x[2] = uint8(length >> 8) + x[3] = uint8(length) + x[8] = uint8(ticketLen >> 8) + x[9] = uint8(ticketLen) + copy(x[10:], m.ticket) + + m.raw = x + + return m.raw, nil +} + +func (m *newSessionTicketMsg) unmarshal(data []byte) bool { + m.raw = data + + if len(data) < 10 { + return false + } + + length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) + if uint32(len(data))-4 != length { + return false + } + + ticketLen := int(data[8])<<8 + int(data[9]) + if len(data)-10 != ticketLen { + return false + } + + m.ticket = data[10:] + + return true +} + +type helloRequestMsg struct { +} + +func (*helloRequestMsg) marshal() ([]byte, error) { + return []byte{typeHelloRequest, 0, 0, 0}, nil +} + +func (*helloRequestMsg) unmarshal(data []byte) bool { + return len(data) == 4 +} + +type transcriptHash interface { + Write([]byte) (int, error) +} + +// transcriptMsg is a helper used to marshal and hash messages which typically +// are not written to the wire, and as such aren't hashed during Conn.writeRecord. +func transcriptMsg(msg handshakeMessage, h transcriptHash) error { + data, err := msg.marshal() + if err != nil { + return err + } + h.Write(data) + return nil +} diff --git a/vendor/github.com/quic-go/qtls-go1-20/handshake_server.go b/vendor/github.com/quic-go/qtls-go1-20/handshake_server.go new file mode 100644 index 000000000..ae7cb835b --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/handshake_server.go @@ -0,0 +1,895 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package qtls + +import ( + "context" + "crypto" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "crypto/subtle" + "crypto/x509" + "errors" + "fmt" + "hash" + "io" + "time" +) + +// serverHandshakeState contains details of a server handshake in progress. +// It's discarded once the handshake has completed. +type serverHandshakeState struct { + c *Conn + ctx context.Context + clientHello *clientHelloMsg + hello *serverHelloMsg + suite *cipherSuite + ecdheOk bool + ecSignOk bool + rsaDecryptOk bool + rsaSignOk bool + sessionState *sessionState + finishedHash finishedHash + masterSecret []byte + cert *Certificate +} + +// serverHandshake performs a TLS handshake as a server. +func (c *Conn) serverHandshake(ctx context.Context) error { + clientHello, err := c.readClientHello(ctx) + if err != nil { + return err + } + + if c.vers == VersionTLS13 { + hs := serverHandshakeStateTLS13{ + c: c, + ctx: ctx, + clientHello: clientHello, + } + return hs.handshake() + } + + hs := serverHandshakeState{ + c: c, + ctx: ctx, + clientHello: clientHello, + } + return hs.handshake() +} + +func (hs *serverHandshakeState) handshake() error { + c := hs.c + + if err := hs.processClientHello(); err != nil { + return err + } + + // For an overview of TLS handshaking, see RFC 5246, Section 7.3. + c.buffering = true + if hs.checkForResumption() { + // The client has included a session ticket and so we do an abbreviated handshake. + c.didResume = true + if err := hs.doResumeHandshake(); err != nil { + return err + } + if err := hs.establishKeys(); err != nil { + return err + } + if err := hs.sendSessionTicket(); err != nil { + return err + } + if err := hs.sendFinished(c.serverFinished[:]); err != nil { + return err + } + if _, err := c.flush(); err != nil { + return err + } + c.clientFinishedIsFirst = false + if err := hs.readFinished(nil); err != nil { + return err + } + } else { + // The client didn't include a session ticket, or it wasn't + // valid so we do a full handshake. + if err := hs.pickCipherSuite(); err != nil { + return err + } + if err := hs.doFullHandshake(); err != nil { + return err + } + if err := hs.establishKeys(); err != nil { + return err + } + if err := hs.readFinished(c.clientFinished[:]); err != nil { + return err + } + c.clientFinishedIsFirst = true + c.buffering = true + if err := hs.sendSessionTicket(); err != nil { + return err + } + if err := hs.sendFinished(nil); err != nil { + return err + } + if _, err := c.flush(); err != nil { + return err + } + } + + c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random) + c.isHandshakeComplete.Store(true) + + return nil +} + +// readClientHello reads a ClientHello message and selects the protocol version. +func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) { + // clientHelloMsg is included in the transcript, but we haven't initialized + // it yet. The respective handshake functions will record it themselves. + msg, err := c.readHandshake(nil) + if err != nil { + return nil, err + } + clientHello, ok := msg.(*clientHelloMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return nil, unexpectedMessageError(clientHello, msg) + } + + var configForClient *config + originalConfig := c.config + if c.config.GetConfigForClient != nil { + chi := newClientHelloInfo(ctx, c, clientHello) + if cfc, err := c.config.GetConfigForClient(chi); err != nil { + c.sendAlert(alertInternalError) + return nil, err + } else if cfc != nil { + configForClient = fromConfig(cfc) + c.config = configForClient + } + } + c.ticketKeys = originalConfig.ticketKeys(configForClient) + + clientVersions := clientHello.supportedVersions + if len(clientHello.supportedVersions) == 0 { + clientVersions = supportedVersionsFromMax(clientHello.vers) + } + c.vers, ok = c.config.mutualVersion(roleServer, clientVersions) + if !ok { + c.sendAlert(alertProtocolVersion) + return nil, fmt.Errorf("tls: client offered only unsupported versions: %x", clientVersions) + } + c.haveVers = true + c.in.version = c.vers + c.out.version = c.vers + + return clientHello, nil +} + +func (hs *serverHandshakeState) processClientHello() error { + c := hs.c + + hs.hello = new(serverHelloMsg) + hs.hello.vers = c.vers + + foundCompression := false + // We only support null compression, so check that the client offered it. + for _, compression := range hs.clientHello.compressionMethods { + if compression == compressionNone { + foundCompression = true + break + } + } + + if !foundCompression { + c.sendAlert(alertHandshakeFailure) + return errors.New("tls: client does not support uncompressed connections") + } + + hs.hello.random = make([]byte, 32) + serverRandom := hs.hello.random + // Downgrade protection canaries. See RFC 8446, Section 4.1.3. + maxVers := c.config.maxSupportedVersion(roleServer) + if maxVers >= VersionTLS12 && c.vers < maxVers || testingOnlyForceDowngradeCanary { + if c.vers == VersionTLS12 { + copy(serverRandom[24:], downgradeCanaryTLS12) + } else { + copy(serverRandom[24:], downgradeCanaryTLS11) + } + serverRandom = serverRandom[:24] + } + _, err := io.ReadFull(c.config.rand(), serverRandom) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + + if len(hs.clientHello.secureRenegotiation) != 0 { + c.sendAlert(alertHandshakeFailure) + return errors.New("tls: initial handshake had non-empty renegotiation extension") + } + + hs.hello.secureRenegotiationSupported = hs.clientHello.secureRenegotiationSupported + hs.hello.compressionMethod = compressionNone + if len(hs.clientHello.serverName) > 0 { + c.serverName = hs.clientHello.serverName + } + + selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols, false) + if err != nil { + c.sendAlert(alertNoApplicationProtocol) + return err + } + hs.hello.alpnProtocol = selectedProto + c.clientProtocol = selectedProto + + hs.cert, err = c.config.getCertificate(newClientHelloInfo(hs.ctx, c, hs.clientHello)) + if err != nil { + if err == errNoCertificates { + c.sendAlert(alertUnrecognizedName) + } else { + c.sendAlert(alertInternalError) + } + return err + } + if hs.clientHello.scts { + hs.hello.scts = hs.cert.SignedCertificateTimestamps + } + + hs.ecdheOk = supportsECDHE(c.config, hs.clientHello.supportedCurves, hs.clientHello.supportedPoints) + + if hs.ecdheOk && len(hs.clientHello.supportedPoints) > 0 { + // Although omitting the ec_point_formats extension is permitted, some + // old OpenSSL version will refuse to handshake if not present. + // + // Per RFC 4492, section 5.1.2, implementations MUST support the + // uncompressed point format. See golang.org/issue/31943. + hs.hello.supportedPoints = []uint8{pointFormatUncompressed} + } + + if priv, ok := hs.cert.PrivateKey.(crypto.Signer); ok { + switch priv.Public().(type) { + case *ecdsa.PublicKey: + hs.ecSignOk = true + case ed25519.PublicKey: + hs.ecSignOk = true + case *rsa.PublicKey: + hs.rsaSignOk = true + default: + c.sendAlert(alertInternalError) + return fmt.Errorf("tls: unsupported signing key type (%T)", priv.Public()) + } + } + if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok { + switch priv.Public().(type) { + case *rsa.PublicKey: + hs.rsaDecryptOk = true + default: + c.sendAlert(alertInternalError) + return fmt.Errorf("tls: unsupported decryption key type (%T)", priv.Public()) + } + } + + return nil +} + +// negotiateALPN picks a shared ALPN protocol that both sides support in server +// preference order. If ALPN is not configured or the peer doesn't support it, +// it returns "" and no error. +func negotiateALPN(serverProtos, clientProtos []string, quic bool) (string, error) { + if len(serverProtos) == 0 || len(clientProtos) == 0 { + if quic && len(serverProtos) != 0 { + // RFC 9001, Section 8.1 + return "", fmt.Errorf("tls: client did not request an application protocol") + } + return "", nil + } + var http11fallback bool + for _, s := range serverProtos { + for _, c := range clientProtos { + if s == c { + return s, nil + } + if s == "h2" && c == "http/1.1" { + http11fallback = true + } + } + } + // As a special case, let http/1.1 clients connect to h2 servers as if they + // didn't support ALPN. We used not to enforce protocol overlap, so over + // time a number of HTTP servers were configured with only "h2", but + // expected to accept connections from "http/1.1" clients. See Issue 46310. + if http11fallback { + return "", nil + } + return "", fmt.Errorf("tls: client requested unsupported application protocols (%s)", clientProtos) +} + +// supportsECDHE returns whether ECDHE key exchanges can be used with this +// pre-TLS 1.3 client. +func supportsECDHE(c *config, supportedCurves []CurveID, supportedPoints []uint8) bool { + supportsCurve := false + for _, curve := range supportedCurves { + if c.supportsCurve(curve) { + supportsCurve = true + break + } + } + + supportsPointFormat := false + for _, pointFormat := range supportedPoints { + if pointFormat == pointFormatUncompressed { + supportsPointFormat = true + break + } + } + // Per RFC 8422, Section 5.1.2, if the Supported Point Formats extension is + // missing, uncompressed points are supported. If supportedPoints is empty, + // the extension must be missing, as an empty extension body is rejected by + // the parser. See https://go.dev/issue/49126. + if len(supportedPoints) == 0 { + supportsPointFormat = true + } + + return supportsCurve && supportsPointFormat +} + +func (hs *serverHandshakeState) pickCipherSuite() error { + c := hs.c + + preferenceOrder := cipherSuitesPreferenceOrder + if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) { + preferenceOrder = cipherSuitesPreferenceOrderNoAES + } + + configCipherSuites := c.config.cipherSuites() + preferenceList := make([]uint16, 0, len(configCipherSuites)) + for _, suiteID := range preferenceOrder { + for _, id := range configCipherSuites { + if id == suiteID { + preferenceList = append(preferenceList, id) + break + } + } + } + + hs.suite = selectCipherSuite(preferenceList, hs.clientHello.cipherSuites, hs.cipherSuiteOk) + if hs.suite == nil { + c.sendAlert(alertHandshakeFailure) + return errors.New("tls: no cipher suite supported by both client and server") + } + c.cipherSuite = hs.suite.id + + for _, id := range hs.clientHello.cipherSuites { + if id == TLS_FALLBACK_SCSV { + // The client is doing a fallback connection. See RFC 7507. + if hs.clientHello.vers < c.config.maxSupportedVersion(roleServer) { + c.sendAlert(alertInappropriateFallback) + return errors.New("tls: client using inappropriate protocol fallback") + } + break + } + } + + return nil +} + +func (hs *serverHandshakeState) cipherSuiteOk(c *cipherSuite) bool { + if c.flags&suiteECDHE != 0 { + if !hs.ecdheOk { + return false + } + if c.flags&suiteECSign != 0 { + if !hs.ecSignOk { + return false + } + } else if !hs.rsaSignOk { + return false + } + } else if !hs.rsaDecryptOk { + return false + } + if hs.c.vers < VersionTLS12 && c.flags&suiteTLS12 != 0 { + return false + } + return true +} + +// checkForResumption reports whether we should perform resumption on this connection. +func (hs *serverHandshakeState) checkForResumption() bool { + c := hs.c + + if c.config.SessionTicketsDisabled { + return false + } + + plaintext, usedOldKey := c.decryptTicket(hs.clientHello.sessionTicket) + if plaintext == nil { + return false + } + hs.sessionState = &sessionState{usedOldKey: usedOldKey} + ok := hs.sessionState.unmarshal(plaintext) + if !ok { + return false + } + + createdAt := time.Unix(int64(hs.sessionState.createdAt), 0) + if c.config.time().Sub(createdAt) > maxSessionTicketLifetime { + return false + } + + // Never resume a session for a different TLS version. + if c.vers != hs.sessionState.vers { + return false + } + + cipherSuiteOk := false + // Check that the client is still offering the ciphersuite in the session. + for _, id := range hs.clientHello.cipherSuites { + if id == hs.sessionState.cipherSuite { + cipherSuiteOk = true + break + } + } + if !cipherSuiteOk { + return false + } + + // Check that we also support the ciphersuite from the session. + hs.suite = selectCipherSuite([]uint16{hs.sessionState.cipherSuite}, + c.config.cipherSuites(), hs.cipherSuiteOk) + if hs.suite == nil { + return false + } + + sessionHasClientCerts := len(hs.sessionState.certificates) != 0 + needClientCerts := requiresClientCert(c.config.ClientAuth) + if needClientCerts && !sessionHasClientCerts { + return false + } + if sessionHasClientCerts && c.config.ClientAuth == NoClientCert { + return false + } + + return true +} + +func (hs *serverHandshakeState) doResumeHandshake() error { + c := hs.c + + hs.hello.cipherSuite = hs.suite.id + c.cipherSuite = hs.suite.id + // We echo the client's session ID in the ServerHello to let it know + // that we're doing a resumption. + hs.hello.sessionId = hs.clientHello.sessionId + hs.hello.ticketSupported = hs.sessionState.usedOldKey + hs.finishedHash = newFinishedHash(c.vers, hs.suite) + hs.finishedHash.discardHandshakeBuffer() + if err := transcriptMsg(hs.clientHello, &hs.finishedHash); err != nil { + return err + } + if _, err := hs.c.writeHandshakeRecord(hs.hello, &hs.finishedHash); err != nil { + return err + } + + if err := c.processCertsFromClient(Certificate{ + Certificate: hs.sessionState.certificates, + }); err != nil { + return err + } + + if c.config.VerifyConnection != nil { + if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil { + c.sendAlert(alertBadCertificate) + return err + } + } + + hs.masterSecret = hs.sessionState.masterSecret + + return nil +} + +func (hs *serverHandshakeState) doFullHandshake() error { + c := hs.c + + if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 { + hs.hello.ocspStapling = true + } + + hs.hello.ticketSupported = hs.clientHello.ticketSupported && !c.config.SessionTicketsDisabled + hs.hello.cipherSuite = hs.suite.id + + hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite) + if c.config.ClientAuth == NoClientCert { + // No need to keep a full record of the handshake if client + // certificates won't be used. + hs.finishedHash.discardHandshakeBuffer() + } + if err := transcriptMsg(hs.clientHello, &hs.finishedHash); err != nil { + return err + } + if _, err := hs.c.writeHandshakeRecord(hs.hello, &hs.finishedHash); err != nil { + return err + } + + certMsg := new(certificateMsg) + certMsg.certificates = hs.cert.Certificate + if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); err != nil { + return err + } + + if hs.hello.ocspStapling { + certStatus := new(certificateStatusMsg) + certStatus.response = hs.cert.OCSPStaple + if _, err := hs.c.writeHandshakeRecord(certStatus, &hs.finishedHash); err != nil { + return err + } + } + + keyAgreement := hs.suite.ka(c.vers) + skx, err := keyAgreement.generateServerKeyExchange(c.config, hs.cert, hs.clientHello, hs.hello) + if err != nil { + c.sendAlert(alertHandshakeFailure) + return err + } + if skx != nil { + if _, err := hs.c.writeHandshakeRecord(skx, &hs.finishedHash); err != nil { + return err + } + } + + var certReq *certificateRequestMsg + if c.config.ClientAuth >= RequestClientCert { + // Request a client certificate + certReq = new(certificateRequestMsg) + certReq.certificateTypes = []byte{ + byte(certTypeRSASign), + byte(certTypeECDSASign), + } + if c.vers >= VersionTLS12 { + certReq.hasSignatureAlgorithm = true + certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms() + } + + // An empty list of certificateAuthorities signals to + // the client that it may send any certificate in response + // to our request. When we know the CAs we trust, then + // we can send them down, so that the client can choose + // an appropriate certificate to give to us. + if c.config.ClientCAs != nil { + certReq.certificateAuthorities = c.config.ClientCAs.Subjects() + } + if _, err := hs.c.writeHandshakeRecord(certReq, &hs.finishedHash); err != nil { + return err + } + } + + helloDone := new(serverHelloDoneMsg) + if _, err := hs.c.writeHandshakeRecord(helloDone, &hs.finishedHash); err != nil { + return err + } + + if _, err := c.flush(); err != nil { + return err + } + + var pub crypto.PublicKey // public key for client auth, if any + + msg, err := c.readHandshake(&hs.finishedHash) + if err != nil { + return err + } + + // If we requested a client certificate, then the client must send a + // certificate message, even if it's empty. + if c.config.ClientAuth >= RequestClientCert { + certMsg, ok := msg.(*certificateMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(certMsg, msg) + } + + if err := c.processCertsFromClient(Certificate{ + Certificate: certMsg.certificates, + }); err != nil { + return err + } + if len(certMsg.certificates) != 0 { + pub = c.peerCertificates[0].PublicKey + } + + msg, err = c.readHandshake(&hs.finishedHash) + if err != nil { + return err + } + } + if c.config.VerifyConnection != nil { + if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil { + c.sendAlert(alertBadCertificate) + return err + } + } + + // Get client key exchange + ckx, ok := msg.(*clientKeyExchangeMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(ckx, msg) + } + + preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.cert, ckx, c.vers) + if err != nil { + c.sendAlert(alertHandshakeFailure) + return err + } + hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random) + if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.clientHello.random, hs.masterSecret); err != nil { + c.sendAlert(alertInternalError) + return err + } + + // If we received a client cert in response to our certificate request message, + // the client will send us a certificateVerifyMsg immediately after the + // clientKeyExchangeMsg. This message is a digest of all preceding + // handshake-layer messages that is signed using the private key corresponding + // to the client's certificate. This allows us to verify that the client is in + // possession of the private key of the certificate. + if len(c.peerCertificates) > 0 { + // certificateVerifyMsg is included in the transcript, but not until + // after we verify the handshake signature, since the state before + // this message was sent is used. + msg, err = c.readHandshake(nil) + if err != nil { + return err + } + certVerify, ok := msg.(*certificateVerifyMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(certVerify, msg) + } + + var sigType uint8 + var sigHash crypto.Hash + if c.vers >= VersionTLS12 { + if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, certReq.supportedSignatureAlgorithms) { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: client certificate used with invalid signature algorithm") + } + sigType, sigHash, err = typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm) + if err != nil { + return c.sendAlert(alertInternalError) + } + } else { + sigType, sigHash, err = legacyTypeAndHashFromPublicKey(pub) + if err != nil { + c.sendAlert(alertIllegalParameter) + return err + } + } + + signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash) + if err := verifyHandshakeSignature(sigType, pub, sigHash, signed, certVerify.signature); err != nil { + c.sendAlert(alertDecryptError) + return errors.New("tls: invalid signature by the client certificate: " + err.Error()) + } + + if err := transcriptMsg(certVerify, &hs.finishedHash); err != nil { + return err + } + } + + hs.finishedHash.discardHandshakeBuffer() + + return nil +} + +func (hs *serverHandshakeState) establishKeys() error { + c := hs.c + + clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := + keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen) + + var clientCipher, serverCipher any + var clientHash, serverHash hash.Hash + + if hs.suite.aead == nil { + clientCipher = hs.suite.cipher(clientKey, clientIV, true /* for reading */) + clientHash = hs.suite.mac(clientMAC) + serverCipher = hs.suite.cipher(serverKey, serverIV, false /* not for reading */) + serverHash = hs.suite.mac(serverMAC) + } else { + clientCipher = hs.suite.aead(clientKey, clientIV) + serverCipher = hs.suite.aead(serverKey, serverIV) + } + + c.in.prepareCipherSpec(c.vers, clientCipher, clientHash) + c.out.prepareCipherSpec(c.vers, serverCipher, serverHash) + + return nil +} + +func (hs *serverHandshakeState) readFinished(out []byte) error { + c := hs.c + + if err := c.readChangeCipherSpec(); err != nil { + return err + } + + // finishedMsg is included in the transcript, but not until after we + // check the client version, since the state before this message was + // sent is used during verification. + msg, err := c.readHandshake(nil) + if err != nil { + return err + } + clientFinished, ok := msg.(*finishedMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(clientFinished, msg) + } + + verify := hs.finishedHash.clientSum(hs.masterSecret) + if len(verify) != len(clientFinished.verifyData) || + subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 { + c.sendAlert(alertHandshakeFailure) + return errors.New("tls: client's Finished message is incorrect") + } + + if err := transcriptMsg(clientFinished, &hs.finishedHash); err != nil { + return err + } + + copy(out, verify) + return nil +} + +func (hs *serverHandshakeState) sendSessionTicket() error { + // ticketSupported is set in a resumption handshake if the + // ticket from the client was encrypted with an old session + // ticket key and thus a refreshed ticket should be sent. + if !hs.hello.ticketSupported { + return nil + } + + c := hs.c + m := new(newSessionTicketMsg) + + createdAt := uint64(c.config.time().Unix()) + if hs.sessionState != nil { + // If this is re-wrapping an old key, then keep + // the original time it was created. + createdAt = hs.sessionState.createdAt + } + + var certsFromClient [][]byte + for _, cert := range c.peerCertificates { + certsFromClient = append(certsFromClient, cert.Raw) + } + state := sessionState{ + vers: c.vers, + cipherSuite: hs.suite.id, + createdAt: createdAt, + masterSecret: hs.masterSecret, + certificates: certsFromClient, + } + stateBytes, err := state.marshal() + if err != nil { + return err + } + m.ticket, err = c.encryptTicket(stateBytes) + if err != nil { + return err + } + + if _, err := hs.c.writeHandshakeRecord(m, &hs.finishedHash); err != nil { + return err + } + + return nil +} + +func (hs *serverHandshakeState) sendFinished(out []byte) error { + c := hs.c + + if err := c.writeChangeCipherRecord(); err != nil { + return err + } + + finished := new(finishedMsg) + finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret) + if _, err := hs.c.writeHandshakeRecord(finished, &hs.finishedHash); err != nil { + return err + } + + copy(out, finished.verifyData) + + return nil +} + +// processCertsFromClient takes a chain of client certificates either from a +// Certificates message or from a sessionState and verifies them. It returns +// the public key of the leaf certificate. +func (c *Conn) processCertsFromClient(certificate Certificate) error { + certificates := certificate.Certificate + certs := make([]*x509.Certificate, len(certificates)) + var err error + for i, asn1Data := range certificates { + if certs[i], err = x509.ParseCertificate(asn1Data); err != nil { + c.sendAlert(alertBadCertificate) + return errors.New("tls: failed to parse client certificate: " + err.Error()) + } + } + + if len(certs) == 0 && requiresClientCert(c.config.ClientAuth) { + c.sendAlert(alertBadCertificate) + return errors.New("tls: client didn't provide a certificate") + } + + if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 { + opts := x509.VerifyOptions{ + Roots: c.config.ClientCAs, + CurrentTime: c.config.time(), + Intermediates: x509.NewCertPool(), + KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, + } + + for _, cert := range certs[1:] { + opts.Intermediates.AddCert(cert) + } + + chains, err := certs[0].Verify(opts) + if err != nil { + c.sendAlert(alertBadCertificate) + return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err} + } + + c.verifiedChains = chains + } + + c.peerCertificates = certs + c.ocspResponse = certificate.OCSPStaple + c.scts = certificate.SignedCertificateTimestamps + + if len(certs) > 0 { + switch certs[0].PublicKey.(type) { + case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey: + default: + c.sendAlert(alertUnsupportedCertificate) + return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", certs[0].PublicKey) + } + } + + if c.config.VerifyPeerCertificate != nil { + if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil { + c.sendAlert(alertBadCertificate) + return err + } + } + + return nil +} + +func newClientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo { + supportedVersions := clientHello.supportedVersions + if len(clientHello.supportedVersions) == 0 { + supportedVersions = supportedVersionsFromMax(clientHello.vers) + } + + return toClientHelloInfo(&clientHelloInfo{ + CipherSuites: clientHello.cipherSuites, + ServerName: clientHello.serverName, + SupportedCurves: clientHello.supportedCurves, + SupportedPoints: clientHello.supportedPoints, + SignatureSchemes: clientHello.supportedSignatureAlgorithms, + SupportedProtos: clientHello.alpnProtocols, + SupportedVersions: supportedVersions, + Conn: c.conn, + config: toConfig(c.config), + ctx: ctx, + }) +} diff --git a/vendor/github.com/quic-go/qtls-go1-20/handshake_server_tls13.go b/vendor/github.com/quic-go/qtls-go1-20/handshake_server_tls13.go new file mode 100644 index 000000000..03bc5eb51 --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/handshake_server_tls13.go @@ -0,0 +1,979 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package qtls + +import ( + "bytes" + "context" + "crypto" + "crypto/hmac" + "crypto/rsa" + "errors" + "hash" + "io" + "time" +) + +// maxClientPSKIdentities is the number of client PSK identities the server will +// attempt to validate. It will ignore the rest not to let cheap ClientHello +// messages cause too much work in session ticket decryption attempts. +const maxClientPSKIdentities = 5 + +type serverHandshakeStateTLS13 struct { + c *Conn + ctx context.Context + clientHello *clientHelloMsg + hello *serverHelloMsg + alpnNegotiationErr error + encryptedExtensions *encryptedExtensionsMsg + sentDummyCCS bool + usingPSK bool + suite *cipherSuiteTLS13 + cert *Certificate + sigAlg SignatureScheme + earlySecret []byte + sharedKey []byte + handshakeSecret []byte + masterSecret []byte + trafficSecret []byte // client_application_traffic_secret_0 + transcript hash.Hash + clientFinished []byte + earlyData bool +} + +func (hs *serverHandshakeStateTLS13) handshake() error { + c := hs.c + + if needFIPS() { + return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode") + } + + // For an overview of the TLS 1.3 handshake, see RFC 8446, Section 2. + if err := hs.processClientHello(); err != nil { + return err + } + if err := hs.checkForResumption(); err != nil { + return err + } + if err := hs.pickCertificate(); err != nil { + return err + } + c.buffering = true + if err := hs.sendServerParameters(); err != nil { + return err + } + if err := hs.sendServerCertificate(); err != nil { + return err + } + if err := hs.sendServerFinished(); err != nil { + return err + } + // Note that at this point we could start sending application data without + // waiting for the client's second flight, but the application might not + // expect the lack of replay protection of the ClientHello parameters. + if _, err := c.flush(); err != nil { + return err + } + if err := hs.readClientCertificate(); err != nil { + return err + } + if err := hs.readClientFinished(); err != nil { + return err + } + + c.isHandshakeComplete.Store(true) + + return nil +} + +func (hs *serverHandshakeStateTLS13) processClientHello() error { + c := hs.c + + hs.hello = new(serverHelloMsg) + hs.encryptedExtensions = new(encryptedExtensionsMsg) + + // TLS 1.3 froze the ServerHello.legacy_version field, and uses + // supported_versions instead. See RFC 8446, sections 4.1.3 and 4.2.1. + hs.hello.vers = VersionTLS12 + hs.hello.supportedVersion = c.vers + + if len(hs.clientHello.supportedVersions) == 0 { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: client used the legacy version field to negotiate TLS 1.3") + } + + // Abort if the client is doing a fallback and landing lower than what we + // support. See RFC 7507, which however does not specify the interaction + // with supported_versions. The only difference is that with + // supported_versions a client has a chance to attempt a [TLS 1.2, TLS 1.4] + // handshake in case TLS 1.3 is broken but 1.2 is not. Alas, in that case, + // it will have to drop the TLS_FALLBACK_SCSV protection if it falls back to + // TLS 1.2, because a TLS 1.3 server would abort here. The situation before + // supported_versions was not better because there was just no way to do a + // TLS 1.4 handshake without risking the server selecting TLS 1.3. + for _, id := range hs.clientHello.cipherSuites { + if id == TLS_FALLBACK_SCSV { + // Use c.vers instead of max(supported_versions) because an attacker + // could defeat this by adding an arbitrary high version otherwise. + if c.vers < c.config.maxSupportedVersion(roleServer) { + c.sendAlert(alertInappropriateFallback) + return errors.New("tls: client using inappropriate protocol fallback") + } + break + } + } + + if len(hs.clientHello.compressionMethods) != 1 || + hs.clientHello.compressionMethods[0] != compressionNone { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: TLS 1.3 client supports illegal compression methods") + } + + hs.hello.random = make([]byte, 32) + if _, err := io.ReadFull(c.config.rand(), hs.hello.random); err != nil { + c.sendAlert(alertInternalError) + return err + } + + if len(hs.clientHello.secureRenegotiation) != 0 { + c.sendAlert(alertHandshakeFailure) + return errors.New("tls: initial handshake had non-empty renegotiation extension") + } + + hs.hello.sessionId = hs.clientHello.sessionId + hs.hello.compressionMethod = compressionNone + + preferenceList := defaultCipherSuitesTLS13 + if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) { + preferenceList = defaultCipherSuitesTLS13NoAES + } + for _, suiteID := range preferenceList { + hs.suite = mutualCipherSuiteTLS13(hs.clientHello.cipherSuites, suiteID) + if hs.suite != nil { + break + } + } + if hs.suite == nil { + c.sendAlert(alertHandshakeFailure) + return errors.New("tls: no cipher suite supported by both client and server") + } + c.cipherSuite = hs.suite.id + hs.hello.cipherSuite = hs.suite.id + hs.transcript = hs.suite.hash.New() + + // Pick the ECDHE group in server preference order, but give priority to + // groups with a key share, to avoid a HelloRetryRequest round-trip. + var selectedGroup CurveID + var clientKeyShare *keyShare +GroupSelection: + for _, preferredGroup := range c.config.curvePreferences() { + for _, ks := range hs.clientHello.keyShares { + if ks.group == preferredGroup { + selectedGroup = ks.group + clientKeyShare = &ks + break GroupSelection + } + } + if selectedGroup != 0 { + continue + } + for _, group := range hs.clientHello.supportedCurves { + if group == preferredGroup { + selectedGroup = group + break + } + } + } + if selectedGroup == 0 { + c.sendAlert(alertHandshakeFailure) + return errors.New("tls: no ECDHE curve supported by both client and server") + } + if clientKeyShare == nil { + if err := hs.doHelloRetryRequest(selectedGroup); err != nil { + return err + } + clientKeyShare = &hs.clientHello.keyShares[0] + } + + if _, ok := curveForCurveID(selectedGroup); !ok { + c.sendAlert(alertInternalError) + return errors.New("tls: CurvePreferences includes unsupported curve") + } + key, err := generateECDHEKey(c.config.rand(), selectedGroup) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + hs.hello.serverShare = keyShare{group: selectedGroup, data: key.PublicKey().Bytes()} + peerKey, err := key.Curve().NewPublicKey(clientKeyShare.data) + if err != nil { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: invalid client key share") + } + hs.sharedKey, err = key.ECDH(peerKey) + if err != nil { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: invalid client key share") + } + + if c.quic != nil { + if hs.clientHello.quicTransportParameters == nil { + // RFC 9001 Section 8.2. + c.sendAlert(alertMissingExtension) + return errors.New("tls: client did not send a quic_transport_parameters extension") + } + c.quicSetTransportParameters(hs.clientHello.quicTransportParameters) + } else { + if hs.clientHello.quicTransportParameters != nil { + c.sendAlert(alertUnsupportedExtension) + return errors.New("tls: client sent an unexpected quic_transport_parameters extension") + } + } + + c.serverName = hs.clientHello.serverName + + selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols, c.quic != nil) + if err != nil { + hs.alpnNegotiationErr = err + } + hs.encryptedExtensions.alpnProtocol = selectedProto + c.clientProtocol = selectedProto + + return nil +} + +func (hs *serverHandshakeStateTLS13) checkForResumption() error { + c := hs.c + + if c.config.SessionTicketsDisabled { + return nil + } + + modeOK := false + for _, mode := range hs.clientHello.pskModes { + if mode == pskModeDHE { + modeOK = true + break + } + } + if !modeOK { + return nil + } + + if len(hs.clientHello.pskIdentities) != len(hs.clientHello.pskBinders) { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: invalid or missing PSK binders") + } + if len(hs.clientHello.pskIdentities) == 0 { + return nil + } + + for i, identity := range hs.clientHello.pskIdentities { + if i >= maxClientPSKIdentities { + break + } + + plaintext, _ := c.decryptTicket(identity.label) + if plaintext == nil { + continue + } + sessionState := new(sessionStateTLS13) + if ok := sessionState.unmarshal(plaintext); !ok { + continue + } + + if hs.clientHello.earlyData { + if sessionState.maxEarlyData == 0 { + c.sendAlert(alertUnsupportedExtension) + return errors.New("tls: client sent unexpected early data") + } + + if hs.alpnNegotiationErr == nil && sessionState.alpn == c.clientProtocol && + c.extraConfig != nil && c.extraConfig.Enable0RTT && + c.extraConfig.Accept0RTT != nil && c.extraConfig.Accept0RTT(sessionState.appData) { + hs.encryptedExtensions.earlyData = true + } + } + + createdAt := time.Unix(int64(sessionState.createdAt), 0) + if c.config.time().Sub(createdAt) > maxSessionTicketLifetime { + continue + } + + // We don't check the obfuscated ticket age because it's affected by + // clock skew and it's only a freshness signal useful for shrinking the + // window for replay attacks, which don't affect us as we don't do 0-RTT. + + pskSuite := cipherSuiteTLS13ByID(sessionState.cipherSuite) + if pskSuite == nil || pskSuite.hash != hs.suite.hash { + continue + } + + // PSK connections don't re-establish client certificates, but carry + // them over in the session ticket. Ensure the presence of client certs + // in the ticket is consistent with the configured requirements. + sessionHasClientCerts := len(sessionState.certificate.Certificate) != 0 + needClientCerts := requiresClientCert(c.config.ClientAuth) + if needClientCerts && !sessionHasClientCerts { + continue + } + if sessionHasClientCerts && c.config.ClientAuth == NoClientCert { + continue + } + + psk := hs.suite.expandLabel(sessionState.resumptionSecret, "resumption", + nil, hs.suite.hash.Size()) + hs.earlySecret = hs.suite.extract(psk, nil) + binderKey := hs.suite.deriveSecret(hs.earlySecret, resumptionBinderLabel, nil) + // Clone the transcript in case a HelloRetryRequest was recorded. + transcript := cloneHash(hs.transcript, hs.suite.hash) + if transcript == nil { + c.sendAlert(alertInternalError) + return errors.New("tls: internal error: failed to clone hash") + } + clientHelloBytes, err := hs.clientHello.marshalWithoutBinders() + if err != nil { + c.sendAlert(alertInternalError) + return err + } + transcript.Write(clientHelloBytes) + pskBinder := hs.suite.finishedHash(binderKey, transcript) + if !hmac.Equal(hs.clientHello.pskBinders[i], pskBinder) { + c.sendAlert(alertDecryptError) + return errors.New("tls: invalid PSK binder") + } + + if c.quic != nil && hs.clientHello.earlyData && hs.encryptedExtensions.earlyData && i == 0 && + sessionState.maxEarlyData > 0 && sessionState.cipherSuite == hs.suite.id { + hs.earlyData = true + + transcript := hs.suite.hash.New() + if err := transcriptMsg(hs.clientHello, transcript); err != nil { + return err + } + earlyTrafficSecret := hs.suite.deriveSecret(hs.earlySecret, clientEarlyTrafficLabel, transcript) + c.quicSetReadSecret(QUICEncryptionLevelEarly, hs.suite.id, earlyTrafficSecret) + } + + c.didResume = true + if err := c.processCertsFromClient(sessionState.certificate); err != nil { + return err + } + + hs.hello.selectedIdentityPresent = true + hs.hello.selectedIdentity = uint16(i) + hs.usingPSK = true + return nil + } + + return nil +} + +// cloneHash uses the encoding.BinaryMarshaler and encoding.BinaryUnmarshaler +// interfaces implemented by standard library hashes to clone the state of in +// to a new instance of h. It returns nil if the operation fails. +func cloneHash(in hash.Hash, h crypto.Hash) hash.Hash { + // Recreate the interface to avoid importing encoding. + type binaryMarshaler interface { + MarshalBinary() (data []byte, err error) + UnmarshalBinary(data []byte) error + } + marshaler, ok := in.(binaryMarshaler) + if !ok { + return nil + } + state, err := marshaler.MarshalBinary() + if err != nil { + return nil + } + out := h.New() + unmarshaler, ok := out.(binaryMarshaler) + if !ok { + return nil + } + if err := unmarshaler.UnmarshalBinary(state); err != nil { + return nil + } + return out +} + +func (hs *serverHandshakeStateTLS13) pickCertificate() error { + c := hs.c + + // Only one of PSK and certificates are used at a time. + if hs.usingPSK { + return nil + } + + // signature_algorithms is required in TLS 1.3. See RFC 8446, Section 4.2.3. + if len(hs.clientHello.supportedSignatureAlgorithms) == 0 { + return c.sendAlert(alertMissingExtension) + } + + certificate, err := c.config.getCertificate(newClientHelloInfo(hs.ctx, c, hs.clientHello)) + if err != nil { + if err == errNoCertificates { + c.sendAlert(alertUnrecognizedName) + } else { + c.sendAlert(alertInternalError) + } + return err + } + hs.sigAlg, err = selectSignatureScheme(c.vers, certificate, hs.clientHello.supportedSignatureAlgorithms) + if err != nil { + // getCertificate returned a certificate that is unsupported or + // incompatible with the client's signature algorithms. + c.sendAlert(alertHandshakeFailure) + return err + } + hs.cert = certificate + + return nil +} + +// sendDummyChangeCipherSpec sends a ChangeCipherSpec record for compatibility +// with middleboxes that didn't implement TLS correctly. See RFC 8446, Appendix D.4. +func (hs *serverHandshakeStateTLS13) sendDummyChangeCipherSpec() error { + if hs.c.quic != nil { + return nil + } + if hs.sentDummyCCS { + return nil + } + hs.sentDummyCCS = true + + return hs.c.writeChangeCipherRecord() +} + +func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) error { + c := hs.c + + // The first ClientHello gets double-hashed into the transcript upon a + // HelloRetryRequest. See RFC 8446, Section 4.4.1. + if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil { + return err + } + chHash := hs.transcript.Sum(nil) + hs.transcript.Reset() + hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))}) + hs.transcript.Write(chHash) + + helloRetryRequest := &serverHelloMsg{ + vers: hs.hello.vers, + random: helloRetryRequestRandom, + sessionId: hs.hello.sessionId, + cipherSuite: hs.hello.cipherSuite, + compressionMethod: hs.hello.compressionMethod, + supportedVersion: hs.hello.supportedVersion, + selectedGroup: selectedGroup, + } + + if _, err := hs.c.writeHandshakeRecord(helloRetryRequest, hs.transcript); err != nil { + return err + } + + if err := hs.sendDummyChangeCipherSpec(); err != nil { + return err + } + + // clientHelloMsg is not included in the transcript. + msg, err := c.readHandshake(nil) + if err != nil { + return err + } + + clientHello, ok := msg.(*clientHelloMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(clientHello, msg) + } + + if len(clientHello.keyShares) != 1 || clientHello.keyShares[0].group != selectedGroup { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: client sent invalid key share in second ClientHello") + } + + if clientHello.earlyData { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: client indicated early data in second ClientHello") + } + + if illegalClientHelloChange(clientHello, hs.clientHello) { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: client illegally modified second ClientHello") + } + + if illegalClientHelloChange(clientHello, hs.clientHello) { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: client illegally modified second ClientHello") + } + + hs.clientHello = clientHello + return nil +} + +// illegalClientHelloChange reports whether the two ClientHello messages are +// different, with the exception of the changes allowed before and after a +// HelloRetryRequest. See RFC 8446, Section 4.1.2. +func illegalClientHelloChange(ch, ch1 *clientHelloMsg) bool { + if len(ch.supportedVersions) != len(ch1.supportedVersions) || + len(ch.cipherSuites) != len(ch1.cipherSuites) || + len(ch.supportedCurves) != len(ch1.supportedCurves) || + len(ch.supportedSignatureAlgorithms) != len(ch1.supportedSignatureAlgorithms) || + len(ch.supportedSignatureAlgorithmsCert) != len(ch1.supportedSignatureAlgorithmsCert) || + len(ch.alpnProtocols) != len(ch1.alpnProtocols) { + return true + } + for i := range ch.supportedVersions { + if ch.supportedVersions[i] != ch1.supportedVersions[i] { + return true + } + } + for i := range ch.cipherSuites { + if ch.cipherSuites[i] != ch1.cipherSuites[i] { + return true + } + } + for i := range ch.supportedCurves { + if ch.supportedCurves[i] != ch1.supportedCurves[i] { + return true + } + } + for i := range ch.supportedSignatureAlgorithms { + if ch.supportedSignatureAlgorithms[i] != ch1.supportedSignatureAlgorithms[i] { + return true + } + } + for i := range ch.supportedSignatureAlgorithmsCert { + if ch.supportedSignatureAlgorithmsCert[i] != ch1.supportedSignatureAlgorithmsCert[i] { + return true + } + } + for i := range ch.alpnProtocols { + if ch.alpnProtocols[i] != ch1.alpnProtocols[i] { + return true + } + } + return ch.vers != ch1.vers || + !bytes.Equal(ch.random, ch1.random) || + !bytes.Equal(ch.sessionId, ch1.sessionId) || + !bytes.Equal(ch.compressionMethods, ch1.compressionMethods) || + ch.serverName != ch1.serverName || + ch.ocspStapling != ch1.ocspStapling || + !bytes.Equal(ch.supportedPoints, ch1.supportedPoints) || + ch.ticketSupported != ch1.ticketSupported || + !bytes.Equal(ch.sessionTicket, ch1.sessionTicket) || + ch.secureRenegotiationSupported != ch1.secureRenegotiationSupported || + !bytes.Equal(ch.secureRenegotiation, ch1.secureRenegotiation) || + ch.scts != ch1.scts || + !bytes.Equal(ch.cookie, ch1.cookie) || + !bytes.Equal(ch.pskModes, ch1.pskModes) +} + +func (hs *serverHandshakeStateTLS13) sendServerParameters() error { + c := hs.c + + if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil { + return err + } + if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil { + return err + } + + if err := hs.sendDummyChangeCipherSpec(); err != nil { + return err + } + + earlySecret := hs.earlySecret + if earlySecret == nil { + earlySecret = hs.suite.extract(nil, nil) + } + hs.handshakeSecret = hs.suite.extract(hs.sharedKey, + hs.suite.deriveSecret(earlySecret, "derived", nil)) + + clientSecret := hs.suite.deriveSecret(hs.handshakeSecret, + clientHandshakeTrafficLabel, hs.transcript) + c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret) + serverSecret := hs.suite.deriveSecret(hs.handshakeSecret, + serverHandshakeTrafficLabel, hs.transcript) + c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret) + + if c.quic != nil { + if c.hand.Len() != 0 { + c.sendAlert(alertUnexpectedMessage) + } + c.quicSetWriteSecret(QUICEncryptionLevelHandshake, hs.suite.id, serverSecret) + c.quicSetReadSecret(QUICEncryptionLevelHandshake, hs.suite.id, clientSecret) + } + + err := c.config.writeKeyLog(keyLogLabelClientHandshake, hs.clientHello.random, clientSecret) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + err = c.config.writeKeyLog(keyLogLabelServerHandshake, hs.clientHello.random, serverSecret) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + + selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols, c.quic != nil) + if err != nil { + c.sendAlert(alertNoApplicationProtocol) + return err + } + hs.encryptedExtensions.alpnProtocol = selectedProto + c.clientProtocol = selectedProto + + if c.quic != nil { + p, err := c.quicGetTransportParameters() + if err != nil { + return err + } + hs.encryptedExtensions.quicTransportParameters = p + } + + if _, err := hs.c.writeHandshakeRecord(hs.encryptedExtensions, hs.transcript); err != nil { + return err + } + + return nil +} + +func (hs *serverHandshakeStateTLS13) requestClientCert() bool { + return hs.c.config.ClientAuth >= RequestClientCert && !hs.usingPSK +} + +func (hs *serverHandshakeStateTLS13) sendServerCertificate() error { + c := hs.c + + // Only one of PSK and certificates are used at a time. + if hs.usingPSK { + return nil + } + + if hs.requestClientCert() { + // Request a client certificate + certReq := new(certificateRequestMsgTLS13) + certReq.ocspStapling = true + certReq.scts = true + certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms() + if c.config.ClientCAs != nil { + certReq.certificateAuthorities = c.config.ClientCAs.Subjects() + } + + if _, err := hs.c.writeHandshakeRecord(certReq, hs.transcript); err != nil { + return err + } + } + + certMsg := new(certificateMsgTLS13) + + certMsg.certificate = *hs.cert + certMsg.scts = hs.clientHello.scts && len(hs.cert.SignedCertificateTimestamps) > 0 + certMsg.ocspStapling = hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 + + if _, err := hs.c.writeHandshakeRecord(certMsg, hs.transcript); err != nil { + return err + } + + certVerifyMsg := new(certificateVerifyMsg) + certVerifyMsg.hasSignatureAlgorithm = true + certVerifyMsg.signatureAlgorithm = hs.sigAlg + + sigType, sigHash, err := typeAndHashFromSignatureScheme(hs.sigAlg) + if err != nil { + return c.sendAlert(alertInternalError) + } + + signed := signedMessage(sigHash, serverSignatureContext, hs.transcript) + signOpts := crypto.SignerOpts(sigHash) + if sigType == signatureRSAPSS { + signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash} + } + sig, err := hs.cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), signed, signOpts) + if err != nil { + public := hs.cert.PrivateKey.(crypto.Signer).Public() + if rsaKey, ok := public.(*rsa.PublicKey); ok && sigType == signatureRSAPSS && + rsaKey.N.BitLen()/8 < sigHash.Size()*2+2 { // key too small for RSA-PSS + c.sendAlert(alertHandshakeFailure) + } else { + c.sendAlert(alertInternalError) + } + return errors.New("tls: failed to sign handshake: " + err.Error()) + } + certVerifyMsg.signature = sig + + if _, err := hs.c.writeHandshakeRecord(certVerifyMsg, hs.transcript); err != nil { + return err + } + + return nil +} + +func (hs *serverHandshakeStateTLS13) sendServerFinished() error { + c := hs.c + + finished := &finishedMsg{ + verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript), + } + + if _, err := hs.c.writeHandshakeRecord(finished, hs.transcript); err != nil { + return err + } + + // Derive secrets that take context through the server Finished. + + hs.masterSecret = hs.suite.extract(nil, + hs.suite.deriveSecret(hs.handshakeSecret, "derived", nil)) + + hs.trafficSecret = hs.suite.deriveSecret(hs.masterSecret, + clientApplicationTrafficLabel, hs.transcript) + serverSecret := hs.suite.deriveSecret(hs.masterSecret, + serverApplicationTrafficLabel, hs.transcript) + c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret) + + if c.quic != nil { + if c.hand.Len() != 0 { + // TODO: Handle this in setTrafficSecret? + c.sendAlert(alertUnexpectedMessage) + } + c.quicSetWriteSecret(QUICEncryptionLevelApplication, hs.suite.id, serverSecret) + } + + err := c.config.writeKeyLog(keyLogLabelClientTraffic, hs.clientHello.random, hs.trafficSecret) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + err = c.config.writeKeyLog(keyLogLabelServerTraffic, hs.clientHello.random, serverSecret) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + + c.ekm = hs.suite.exportKeyingMaterial(hs.masterSecret, hs.transcript) + + // If we did not request client certificates, at this point we can + // precompute the client finished and roll the transcript forward to send + // session tickets in our first flight. + if !hs.requestClientCert() { + if err := hs.sendSessionTickets(); err != nil { + return err + } + } + + return nil +} + +func (hs *serverHandshakeStateTLS13) shouldSendSessionTickets() bool { + if hs.c.config.SessionTicketsDisabled { + return false + } + + // QUIC tickets are sent by QUICConn.SendSessionTicket, not automatically. + if hs.c.quic != nil { + return false + } + // Don't send tickets the client wouldn't use. See RFC 8446, Section 4.2.9. + for _, pskMode := range hs.clientHello.pskModes { + if pskMode == pskModeDHE { + return true + } + } + return false +} + +func (hs *serverHandshakeStateTLS13) sendSessionTickets() error { + c := hs.c + + hs.clientFinished = hs.suite.finishedHash(c.in.trafficSecret, hs.transcript) + finishedMsg := &finishedMsg{ + verifyData: hs.clientFinished, + } + if err := transcriptMsg(finishedMsg, hs.transcript); err != nil { + return err + } + c.resumptionSecret = hs.suite.deriveSecret(hs.masterSecret, + resumptionLabel, hs.transcript) + + if !hs.shouldSendSessionTickets() { + return nil + } + return c.sendSessionTicket(false) +} + +func (c *Conn) sendSessionTicket(earlyData bool) error { + suite := cipherSuiteTLS13ByID(c.cipherSuite) + if suite == nil { + return errors.New("tls: internal error: unknown cipher suite") + } + + m := new(newSessionTicketMsgTLS13) + + var certsFromClient [][]byte + for _, cert := range c.peerCertificates { + certsFromClient = append(certsFromClient, cert.Raw) + } + state := sessionStateTLS13{ + cipherSuite: suite.id, + createdAt: uint64(c.config.time().Unix()), + resumptionSecret: c.resumptionSecret, + certificate: Certificate{ + Certificate: certsFromClient, + OCSPStaple: c.ocspResponse, + SignedCertificateTimestamps: c.scts, + }, + alpn: c.clientProtocol, + } + if earlyData { + state.maxEarlyData = 0xffffffff + state.appData = c.extraConfig.GetAppDataForSessionTicket() + } + stateBytes, err := state.marshal() + if err != nil { + c.sendAlert(alertInternalError) + return err + } + m.label, err = c.encryptTicket(stateBytes) + if err != nil { + return err + } + m.lifetime = uint32(maxSessionTicketLifetime / time.Second) + + // ticket_age_add is a random 32-bit value. See RFC 8446, section 4.6.1 + // The value is not stored anywhere; we never need to check the ticket age + // because 0-RTT is not supported. + ageAdd := make([]byte, 4) + _, err = c.config.rand().Read(ageAdd) + if err != nil { + return err + } + + if earlyData { + // RFC 9001, Section 4.6.1 + m.maxEarlyData = 0xffffffff + } + + if _, err := c.writeHandshakeRecord(m, nil); err != nil { + return err + } + + return nil +} + +func (hs *serverHandshakeStateTLS13) readClientCertificate() error { + c := hs.c + + if !hs.requestClientCert() { + // Make sure the connection is still being verified whether or not + // the server requested a client certificate. + if c.config.VerifyConnection != nil { + if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil { + c.sendAlert(alertBadCertificate) + return err + } + } + return nil + } + + // If we requested a client certificate, then the client must send a + // certificate message. If it's empty, no CertificateVerify is sent. + + msg, err := c.readHandshake(hs.transcript) + if err != nil { + return err + } + + certMsg, ok := msg.(*certificateMsgTLS13) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(certMsg, msg) + } + + if err := c.processCertsFromClient(certMsg.certificate); err != nil { + return err + } + + if c.config.VerifyConnection != nil { + if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil { + c.sendAlert(alertBadCertificate) + return err + } + } + + if len(certMsg.certificate.Certificate) != 0 { + // certificateVerifyMsg is included in the transcript, but not until + // after we verify the handshake signature, since the state before + // this message was sent is used. + msg, err = c.readHandshake(nil) + if err != nil { + return err + } + + certVerify, ok := msg.(*certificateVerifyMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(certVerify, msg) + } + + // See RFC 8446, Section 4.4.3. + if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: client certificate used with invalid signature algorithm") + } + sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm) + if err != nil { + return c.sendAlert(alertInternalError) + } + if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: client certificate used with invalid signature algorithm") + } + signed := signedMessage(sigHash, clientSignatureContext, hs.transcript) + if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey, + sigHash, signed, certVerify.signature); err != nil { + c.sendAlert(alertDecryptError) + return errors.New("tls: invalid signature by the client certificate: " + err.Error()) + } + + if err := transcriptMsg(certVerify, hs.transcript); err != nil { + return err + } + } + + // If we waited until the client certificates to send session tickets, we + // are ready to do it now. + if err := hs.sendSessionTickets(); err != nil { + return err + } + + return nil +} + +func (hs *serverHandshakeStateTLS13) readClientFinished() error { + c := hs.c + + // finishedMsg is not included in the transcript. + msg, err := c.readHandshake(nil) + if err != nil { + return err + } + + finished, ok := msg.(*finishedMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(finished, msg) + } + + if !hmac.Equal(hs.clientFinished, finished.verifyData) { + c.sendAlert(alertDecryptError) + return errors.New("tls: invalid client finished hash") + } + + c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret) + + return nil +} diff --git a/vendor/github.com/quic-go/qtls-go1-20/key_agreement.go b/vendor/github.com/quic-go/qtls-go1-20/key_agreement.go new file mode 100644 index 000000000..f926869a1 --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/key_agreement.go @@ -0,0 +1,366 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package qtls + +import ( + "crypto" + "crypto/ecdh" + "crypto/md5" + "crypto/rsa" + "crypto/sha1" + "crypto/x509" + "errors" + "fmt" + "io" +) + +// a keyAgreement implements the client and server side of a TLS key agreement +// protocol by generating and processing key exchange messages. +type keyAgreement interface { + // On the server side, the first two methods are called in order. + + // In the case that the key agreement protocol doesn't use a + // ServerKeyExchange message, generateServerKeyExchange can return nil, + // nil. + generateServerKeyExchange(*config, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error) + processClientKeyExchange(*config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error) + + // On the client side, the next two methods are called in order. + + // This method may not be called if the server doesn't send a + // ServerKeyExchange message. + processServerKeyExchange(*config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) error + generateClientKeyExchange(*config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) +} + +var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message") +var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message") + +// rsaKeyAgreement implements the standard TLS key agreement where the client +// encrypts the pre-master secret to the server's public key. +type rsaKeyAgreement struct{} + +func (ka rsaKeyAgreement) generateServerKeyExchange(config *config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { + return nil, nil +} + +func (ka rsaKeyAgreement) processClientKeyExchange(config *config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { + if len(ckx.ciphertext) < 2 { + return nil, errClientKeyExchange + } + ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1]) + if ciphertextLen != len(ckx.ciphertext)-2 { + return nil, errClientKeyExchange + } + ciphertext := ckx.ciphertext[2:] + + priv, ok := cert.PrivateKey.(crypto.Decrypter) + if !ok { + return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter") + } + // Perform constant time RSA PKCS #1 v1.5 decryption + preMasterSecret, err := priv.Decrypt(config.rand(), ciphertext, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: 48}) + if err != nil { + return nil, err + } + // We don't check the version number in the premaster secret. For one, + // by checking it, we would leak information about the validity of the + // encrypted pre-master secret. Secondly, it provides only a small + // benefit against a downgrade attack and some implementations send the + // wrong version anyway. See the discussion at the end of section + // 7.4.7.1 of RFC 4346. + return preMasterSecret, nil +} + +func (ka rsaKeyAgreement) processServerKeyExchange(config *config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error { + return errors.New("tls: unexpected ServerKeyExchange") +} + +func (ka rsaKeyAgreement) generateClientKeyExchange(config *config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { + preMasterSecret := make([]byte, 48) + preMasterSecret[0] = byte(clientHello.vers >> 8) + preMasterSecret[1] = byte(clientHello.vers) + _, err := io.ReadFull(config.rand(), preMasterSecret[2:]) + if err != nil { + return nil, nil, err + } + + rsaKey, ok := cert.PublicKey.(*rsa.PublicKey) + if !ok { + return nil, nil, errors.New("tls: server certificate contains incorrect key type for selected ciphersuite") + } + encrypted, err := rsa.EncryptPKCS1v15(config.rand(), rsaKey, preMasterSecret) + if err != nil { + return nil, nil, err + } + ckx := new(clientKeyExchangeMsg) + ckx.ciphertext = make([]byte, len(encrypted)+2) + ckx.ciphertext[0] = byte(len(encrypted) >> 8) + ckx.ciphertext[1] = byte(len(encrypted)) + copy(ckx.ciphertext[2:], encrypted) + return preMasterSecret, ckx, nil +} + +// sha1Hash calculates a SHA1 hash over the given byte slices. +func sha1Hash(slices [][]byte) []byte { + hsha1 := sha1.New() + for _, slice := range slices { + hsha1.Write(slice) + } + return hsha1.Sum(nil) +} + +// md5SHA1Hash implements TLS 1.0's hybrid hash function which consists of the +// concatenation of an MD5 and SHA1 hash. +func md5SHA1Hash(slices [][]byte) []byte { + md5sha1 := make([]byte, md5.Size+sha1.Size) + hmd5 := md5.New() + for _, slice := range slices { + hmd5.Write(slice) + } + copy(md5sha1, hmd5.Sum(nil)) + copy(md5sha1[md5.Size:], sha1Hash(slices)) + return md5sha1 +} + +// hashForServerKeyExchange hashes the given slices and returns their digest +// using the given hash function (for >= TLS 1.2) or using a default based on +// the sigType (for earlier TLS versions). For Ed25519 signatures, which don't +// do pre-hashing, it returns the concatenation of the slices. +func hashForServerKeyExchange(sigType uint8, hashFunc crypto.Hash, version uint16, slices ...[]byte) []byte { + if sigType == signatureEd25519 { + var signed []byte + for _, slice := range slices { + signed = append(signed, slice...) + } + return signed + } + if version >= VersionTLS12 { + h := hashFunc.New() + for _, slice := range slices { + h.Write(slice) + } + digest := h.Sum(nil) + return digest + } + if sigType == signatureECDSA { + return sha1Hash(slices) + } + return md5SHA1Hash(slices) +} + +// ecdheKeyAgreement implements a TLS key agreement where the server +// generates an ephemeral EC public/private key pair and signs it. The +// pre-master secret is then calculated using ECDH. The signature may +// be ECDSA, Ed25519 or RSA. +type ecdheKeyAgreement struct { + version uint16 + isRSA bool + key *ecdh.PrivateKey + + // ckx and preMasterSecret are generated in processServerKeyExchange + // and returned in generateClientKeyExchange. + ckx *clientKeyExchangeMsg + preMasterSecret []byte +} + +func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { + var curveID CurveID + for _, c := range clientHello.supportedCurves { + if config.supportsCurve(c) { + curveID = c + break + } + } + + if curveID == 0 { + return nil, errors.New("tls: no supported elliptic curves offered") + } + if _, ok := curveForCurveID(curveID); !ok { + return nil, errors.New("tls: CurvePreferences includes unsupported curve") + } + + key, err := generateECDHEKey(config.rand(), curveID) + if err != nil { + return nil, err + } + ka.key = key + + // See RFC 4492, Section 5.4. + ecdhePublic := key.PublicKey().Bytes() + serverECDHEParams := make([]byte, 1+2+1+len(ecdhePublic)) + serverECDHEParams[0] = 3 // named curve + serverECDHEParams[1] = byte(curveID >> 8) + serverECDHEParams[2] = byte(curveID) + serverECDHEParams[3] = byte(len(ecdhePublic)) + copy(serverECDHEParams[4:], ecdhePublic) + + priv, ok := cert.PrivateKey.(crypto.Signer) + if !ok { + return nil, fmt.Errorf("tls: certificate private key of type %T does not implement crypto.Signer", cert.PrivateKey) + } + + var signatureAlgorithm SignatureScheme + var sigType uint8 + var sigHash crypto.Hash + if ka.version >= VersionTLS12 { + signatureAlgorithm, err = selectSignatureScheme(ka.version, cert, clientHello.supportedSignatureAlgorithms) + if err != nil { + return nil, err + } + sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm) + if err != nil { + return nil, err + } + } else { + sigType, sigHash, err = legacyTypeAndHashFromPublicKey(priv.Public()) + if err != nil { + return nil, err + } + } + if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA { + return nil, errors.New("tls: certificate cannot be used with the selected cipher suite") + } + + signed := hashForServerKeyExchange(sigType, sigHash, ka.version, clientHello.random, hello.random, serverECDHEParams) + + signOpts := crypto.SignerOpts(sigHash) + if sigType == signatureRSAPSS { + signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash} + } + sig, err := priv.Sign(config.rand(), signed, signOpts) + if err != nil { + return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error()) + } + + skx := new(serverKeyExchangeMsg) + sigAndHashLen := 0 + if ka.version >= VersionTLS12 { + sigAndHashLen = 2 + } + skx.key = make([]byte, len(serverECDHEParams)+sigAndHashLen+2+len(sig)) + copy(skx.key, serverECDHEParams) + k := skx.key[len(serverECDHEParams):] + if ka.version >= VersionTLS12 { + k[0] = byte(signatureAlgorithm >> 8) + k[1] = byte(signatureAlgorithm) + k = k[2:] + } + k[0] = byte(len(sig) >> 8) + k[1] = byte(len(sig)) + copy(k[2:], sig) + + return skx, nil +} + +func (ka *ecdheKeyAgreement) processClientKeyExchange(config *config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { + if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 { + return nil, errClientKeyExchange + } + + peerKey, err := ka.key.Curve().NewPublicKey(ckx.ciphertext[1:]) + if err != nil { + return nil, errClientKeyExchange + } + preMasterSecret, err := ka.key.ECDH(peerKey) + if err != nil { + return nil, errClientKeyExchange + } + + return preMasterSecret, nil +} + +func (ka *ecdheKeyAgreement) processServerKeyExchange(config *config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error { + if len(skx.key) < 4 { + return errServerKeyExchange + } + if skx.key[0] != 3 { // named curve + return errors.New("tls: server selected unsupported curve") + } + curveID := CurveID(skx.key[1])<<8 | CurveID(skx.key[2]) + + publicLen := int(skx.key[3]) + if publicLen+4 > len(skx.key) { + return errServerKeyExchange + } + serverECDHEParams := skx.key[:4+publicLen] + publicKey := serverECDHEParams[4:] + + sig := skx.key[4+publicLen:] + if len(sig) < 2 { + return errServerKeyExchange + } + + if _, ok := curveForCurveID(curveID); !ok { + return errors.New("tls: server selected unsupported curve") + } + + key, err := generateECDHEKey(config.rand(), curveID) + if err != nil { + return err + } + ka.key = key + + peerKey, err := key.Curve().NewPublicKey(publicKey) + if err != nil { + return errServerKeyExchange + } + ka.preMasterSecret, err = key.ECDH(peerKey) + if err != nil { + return errServerKeyExchange + } + + ourPublicKey := key.PublicKey().Bytes() + ka.ckx = new(clientKeyExchangeMsg) + ka.ckx.ciphertext = make([]byte, 1+len(ourPublicKey)) + ka.ckx.ciphertext[0] = byte(len(ourPublicKey)) + copy(ka.ckx.ciphertext[1:], ourPublicKey) + + var sigType uint8 + var sigHash crypto.Hash + if ka.version >= VersionTLS12 { + signatureAlgorithm := SignatureScheme(sig[0])<<8 | SignatureScheme(sig[1]) + sig = sig[2:] + if len(sig) < 2 { + return errServerKeyExchange + } + + if !isSupportedSignatureAlgorithm(signatureAlgorithm, clientHello.supportedSignatureAlgorithms) { + return errors.New("tls: certificate used with invalid signature algorithm") + } + sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm) + if err != nil { + return err + } + } else { + sigType, sigHash, err = legacyTypeAndHashFromPublicKey(cert.PublicKey) + if err != nil { + return err + } + } + if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA { + return errServerKeyExchange + } + + sigLen := int(sig[0])<<8 | int(sig[1]) + if sigLen+2 != len(sig) { + return errServerKeyExchange + } + sig = sig[2:] + + signed := hashForServerKeyExchange(sigType, sigHash, ka.version, clientHello.random, serverHello.random, serverECDHEParams) + if err := verifyHandshakeSignature(sigType, cert.PublicKey, sigHash, signed, sig); err != nil { + return errors.New("tls: invalid signature by the server certificate: " + err.Error()) + } + return nil +} + +func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { + if ka.ckx == nil { + return nil, nil, errors.New("tls: missing ServerKeyExchange message") + } + + return ka.preMasterSecret, ka.ckx, nil +} diff --git a/vendor/github.com/quic-go/qtls-go1-20/key_schedule.go b/vendor/github.com/quic-go/qtls-go1-20/key_schedule.go new file mode 100644 index 000000000..a4568933d --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/key_schedule.go @@ -0,0 +1,159 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package qtls + +import ( + "crypto/ecdh" + "crypto/hmac" + "errors" + "fmt" + "hash" + "io" + + "golang.org/x/crypto/cryptobyte" + "golang.org/x/crypto/hkdf" +) + +// This file contains the functions necessary to compute the TLS 1.3 key +// schedule. See RFC 8446, Section 7. + +const ( + resumptionBinderLabel = "res binder" + clientEarlyTrafficLabel = "c e traffic" + clientHandshakeTrafficLabel = "c hs traffic" + serverHandshakeTrafficLabel = "s hs traffic" + clientApplicationTrafficLabel = "c ap traffic" + serverApplicationTrafficLabel = "s ap traffic" + exporterLabel = "exp master" + resumptionLabel = "res master" + trafficUpdateLabel = "traffic upd" +) + +// expandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1. +func (c *cipherSuiteTLS13) expandLabel(secret []byte, label string, context []byte, length int) []byte { + var hkdfLabel cryptobyte.Builder + hkdfLabel.AddUint16(uint16(length)) + hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes([]byte("tls13 ")) + b.AddBytes([]byte(label)) + }) + hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(context) + }) + hkdfLabelBytes, err := hkdfLabel.Bytes() + if err != nil { + // Rather than calling BytesOrPanic, we explicitly handle this error, in + // order to provide a reasonable error message. It should be basically + // impossible for this to panic, and routing errors back through the + // tree rooted in this function is quite painful. The labels are fixed + // size, and the context is either a fixed-length computed hash, or + // parsed from a field which has the same length limitation. As such, an + // error here is likely to only be caused during development. + // + // NOTE: another reasonable approach here might be to return a + // randomized slice if we encounter an error, which would break the + // connection, but avoid panicking. This would perhaps be safer but + // significantly more confusing to users. + panic(fmt.Errorf("failed to construct HKDF label: %s", err)) + } + out := make([]byte, length) + n, err := hkdf.Expand(c.hash.New, secret, hkdfLabelBytes).Read(out) + if err != nil || n != length { + panic("tls: HKDF-Expand-Label invocation failed unexpectedly") + } + return out +} + +// deriveSecret implements Derive-Secret from RFC 8446, Section 7.1. +func (c *cipherSuiteTLS13) deriveSecret(secret []byte, label string, transcript hash.Hash) []byte { + if transcript == nil { + transcript = c.hash.New() + } + return c.expandLabel(secret, label, transcript.Sum(nil), c.hash.Size()) +} + +// extract implements HKDF-Extract with the cipher suite hash. +func (c *cipherSuiteTLS13) extract(newSecret, currentSecret []byte) []byte { + if newSecret == nil { + newSecret = make([]byte, c.hash.Size()) + } + return hkdf.Extract(c.hash.New, newSecret, currentSecret) +} + +// nextTrafficSecret generates the next traffic secret, given the current one, +// according to RFC 8446, Section 7.2. +func (c *cipherSuiteTLS13) nextTrafficSecret(trafficSecret []byte) []byte { + return c.expandLabel(trafficSecret, trafficUpdateLabel, nil, c.hash.Size()) +} + +// trafficKey generates traffic keys according to RFC 8446, Section 7.3. +func (c *cipherSuiteTLS13) trafficKey(trafficSecret []byte) (key, iv []byte) { + key = c.expandLabel(trafficSecret, "key", nil, c.keyLen) + iv = c.expandLabel(trafficSecret, "iv", nil, aeadNonceLength) + return +} + +// finishedHash generates the Finished verify_data or PskBinderEntry according +// to RFC 8446, Section 4.4.4. See sections 4.4 and 4.2.11.2 for the baseKey +// selection. +func (c *cipherSuiteTLS13) finishedHash(baseKey []byte, transcript hash.Hash) []byte { + finishedKey := c.expandLabel(baseKey, "finished", nil, c.hash.Size()) + verifyData := hmac.New(c.hash.New, finishedKey) + verifyData.Write(transcript.Sum(nil)) + return verifyData.Sum(nil) +} + +// exportKeyingMaterial implements RFC5705 exporters for TLS 1.3 according to +// RFC 8446, Section 7.5. +func (c *cipherSuiteTLS13) exportKeyingMaterial(masterSecret []byte, transcript hash.Hash) func(string, []byte, int) ([]byte, error) { + expMasterSecret := c.deriveSecret(masterSecret, exporterLabel, transcript) + return func(label string, context []byte, length int) ([]byte, error) { + secret := c.deriveSecret(expMasterSecret, label, nil) + h := c.hash.New() + h.Write(context) + return c.expandLabel(secret, "exporter", h.Sum(nil), length), nil + } +} + +// generateECDHEKey returns a PrivateKey that implements Diffie-Hellman +// according to RFC 8446, Section 4.2.8.2. +func generateECDHEKey(rand io.Reader, curveID CurveID) (*ecdh.PrivateKey, error) { + curve, ok := curveForCurveID(curveID) + if !ok { + return nil, errors.New("tls: internal error: unsupported curve") + } + + return curve.GenerateKey(rand) +} + +func curveForCurveID(id CurveID) (ecdh.Curve, bool) { + switch id { + case X25519: + return ecdh.X25519(), true + case CurveP256: + return ecdh.P256(), true + case CurveP384: + return ecdh.P384(), true + case CurveP521: + return ecdh.P521(), true + default: + return nil, false + } +} + +func curveIDForCurve(curve ecdh.Curve) (CurveID, bool) { + switch curve { + case ecdh.X25519(): + return X25519, true + case ecdh.P256(): + return CurveP256, true + case ecdh.P384(): + return CurveP384, true + case ecdh.P521(): + return CurveP521, true + default: + return 0, false + } +} diff --git a/vendor/github.com/quic-go/qtls-go1-20/notboring.go b/vendor/github.com/quic-go/qtls-go1-20/notboring.go new file mode 100644 index 000000000..f292e4f02 --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/notboring.go @@ -0,0 +1,18 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package qtls + +func needFIPS() bool { return false } + +func supportedSignatureAlgorithms() []SignatureScheme { + return defaultSupportedSignatureAlgorithms +} + +func fipsMinVersion(c *config) uint16 { panic("fipsMinVersion") } +func fipsMaxVersion(c *config) uint16 { panic("fipsMaxVersion") } +func fipsCurvePreferences(c *config) []CurveID { panic("fipsCurvePreferences") } +func fipsCipherSuites(c *config) []uint16 { panic("fipsCipherSuites") } + +var fipsSupportedSignatureAlgorithms []SignatureScheme diff --git a/vendor/github.com/quic-go/qtls-go1-20/prf.go b/vendor/github.com/quic-go/qtls-go1-20/prf.go new file mode 100644 index 000000000..147128918 --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/prf.go @@ -0,0 +1,283 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package qtls + +import ( + "crypto" + "crypto/hmac" + "crypto/md5" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" + "errors" + "fmt" + "hash" +) + +// Split a premaster secret in two as specified in RFC 4346, Section 5. +func splitPreMasterSecret(secret []byte) (s1, s2 []byte) { + s1 = secret[0 : (len(secret)+1)/2] + s2 = secret[len(secret)/2:] + return +} + +// pHash implements the P_hash function, as defined in RFC 4346, Section 5. +func pHash(result, secret, seed []byte, hash func() hash.Hash) { + h := hmac.New(hash, secret) + h.Write(seed) + a := h.Sum(nil) + + j := 0 + for j < len(result) { + h.Reset() + h.Write(a) + h.Write(seed) + b := h.Sum(nil) + copy(result[j:], b) + j += len(b) + + h.Reset() + h.Write(a) + a = h.Sum(nil) + } +} + +// prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, Section 5. +func prf10(result, secret, label, seed []byte) { + hashSHA1 := sha1.New + hashMD5 := md5.New + + labelAndSeed := make([]byte, len(label)+len(seed)) + copy(labelAndSeed, label) + copy(labelAndSeed[len(label):], seed) + + s1, s2 := splitPreMasterSecret(secret) + pHash(result, s1, labelAndSeed, hashMD5) + result2 := make([]byte, len(result)) + pHash(result2, s2, labelAndSeed, hashSHA1) + + for i, b := range result2 { + result[i] ^= b + } +} + +// prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, Section 5. +func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) { + return func(result, secret, label, seed []byte) { + labelAndSeed := make([]byte, len(label)+len(seed)) + copy(labelAndSeed, label) + copy(labelAndSeed[len(label):], seed) + + pHash(result, secret, labelAndSeed, hashFunc) + } +} + +const ( + masterSecretLength = 48 // Length of a master secret in TLS 1.1. + finishedVerifyLength = 12 // Length of verify_data in a Finished message. +) + +var masterSecretLabel = []byte("master secret") +var keyExpansionLabel = []byte("key expansion") +var clientFinishedLabel = []byte("client finished") +var serverFinishedLabel = []byte("server finished") + +func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) { + switch version { + case VersionTLS10, VersionTLS11: + return prf10, crypto.Hash(0) + case VersionTLS12: + if suite.flags&suiteSHA384 != 0 { + return prf12(sha512.New384), crypto.SHA384 + } + return prf12(sha256.New), crypto.SHA256 + default: + panic("unknown version") + } +} + +func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) { + prf, _ := prfAndHashForVersion(version, suite) + return prf +} + +// masterFromPreMasterSecret generates the master secret from the pre-master +// secret. See RFC 5246, Section 8.1. +func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte { + seed := make([]byte, 0, len(clientRandom)+len(serverRandom)) + seed = append(seed, clientRandom...) + seed = append(seed, serverRandom...) + + masterSecret := make([]byte, masterSecretLength) + prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed) + return masterSecret +} + +// keysFromMasterSecret generates the connection keys from the master +// secret, given the lengths of the MAC key, cipher key and IV, as defined in +// RFC 2246, Section 6.3. +func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) { + seed := make([]byte, 0, len(serverRandom)+len(clientRandom)) + seed = append(seed, serverRandom...) + seed = append(seed, clientRandom...) + + n := 2*macLen + 2*keyLen + 2*ivLen + keyMaterial := make([]byte, n) + prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed) + clientMAC = keyMaterial[:macLen] + keyMaterial = keyMaterial[macLen:] + serverMAC = keyMaterial[:macLen] + keyMaterial = keyMaterial[macLen:] + clientKey = keyMaterial[:keyLen] + keyMaterial = keyMaterial[keyLen:] + serverKey = keyMaterial[:keyLen] + keyMaterial = keyMaterial[keyLen:] + clientIV = keyMaterial[:ivLen] + keyMaterial = keyMaterial[ivLen:] + serverIV = keyMaterial[:ivLen] + return +} + +func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash { + var buffer []byte + if version >= VersionTLS12 { + buffer = []byte{} + } + + prf, hash := prfAndHashForVersion(version, cipherSuite) + if hash != 0 { + return finishedHash{hash.New(), hash.New(), nil, nil, buffer, version, prf} + } + + return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), buffer, version, prf} +} + +// A finishedHash calculates the hash of a set of handshake messages suitable +// for including in a Finished message. +type finishedHash struct { + client hash.Hash + server hash.Hash + + // Prior to TLS 1.2, an additional MD5 hash is required. + clientMD5 hash.Hash + serverMD5 hash.Hash + + // In TLS 1.2, a full buffer is sadly required. + buffer []byte + + version uint16 + prf func(result, secret, label, seed []byte) +} + +func (h *finishedHash) Write(msg []byte) (n int, err error) { + h.client.Write(msg) + h.server.Write(msg) + + if h.version < VersionTLS12 { + h.clientMD5.Write(msg) + h.serverMD5.Write(msg) + } + + if h.buffer != nil { + h.buffer = append(h.buffer, msg...) + } + + return len(msg), nil +} + +func (h finishedHash) Sum() []byte { + if h.version >= VersionTLS12 { + return h.client.Sum(nil) + } + + out := make([]byte, 0, md5.Size+sha1.Size) + out = h.clientMD5.Sum(out) + return h.client.Sum(out) +} + +// clientSum returns the contents of the verify_data member of a client's +// Finished message. +func (h finishedHash) clientSum(masterSecret []byte) []byte { + out := make([]byte, finishedVerifyLength) + h.prf(out, masterSecret, clientFinishedLabel, h.Sum()) + return out +} + +// serverSum returns the contents of the verify_data member of a server's +// Finished message. +func (h finishedHash) serverSum(masterSecret []byte) []byte { + out := make([]byte, finishedVerifyLength) + h.prf(out, masterSecret, serverFinishedLabel, h.Sum()) + return out +} + +// hashForClientCertificate returns the handshake messages so far, pre-hashed if +// necessary, suitable for signing by a TLS client certificate. +func (h finishedHash) hashForClientCertificate(sigType uint8, hashAlg crypto.Hash) []byte { + if (h.version >= VersionTLS12 || sigType == signatureEd25519) && h.buffer == nil { + panic("tls: handshake hash for a client certificate requested after discarding the handshake buffer") + } + + if sigType == signatureEd25519 { + return h.buffer + } + + if h.version >= VersionTLS12 { + hash := hashAlg.New() + hash.Write(h.buffer) + return hash.Sum(nil) + } + + if sigType == signatureECDSA { + return h.server.Sum(nil) + } + + return h.Sum() +} + +// discardHandshakeBuffer is called when there is no more need to +// buffer the entirety of the handshake messages. +func (h *finishedHash) discardHandshakeBuffer() { + h.buffer = nil +} + +// noExportedKeyingMaterial is used as a value of +// ConnectionState.ekm when renegotiation is enabled and thus +// we wish to fail all key-material export requests. +func noExportedKeyingMaterial(label string, context []byte, length int) ([]byte, error) { + return nil, errors.New("crypto/tls: ExportKeyingMaterial is unavailable when renegotiation is enabled") +} + +// ekmFromMasterSecret generates exported keying material as defined in RFC 5705. +func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte) func(string, []byte, int) ([]byte, error) { + return func(label string, context []byte, length int) ([]byte, error) { + switch label { + case "client finished", "server finished", "master secret", "key expansion": + // These values are reserved and may not be used. + return nil, fmt.Errorf("crypto/tls: reserved ExportKeyingMaterial label: %s", label) + } + + seedLen := len(serverRandom) + len(clientRandom) + if context != nil { + seedLen += 2 + len(context) + } + seed := make([]byte, 0, seedLen) + + seed = append(seed, clientRandom...) + seed = append(seed, serverRandom...) + + if context != nil { + if len(context) >= 1<<16 { + return nil, fmt.Errorf("crypto/tls: ExportKeyingMaterial context too long") + } + seed = append(seed, byte(len(context)>>8), byte(len(context))) + seed = append(seed, context...) + } + + keyMaterial := make([]byte, length) + prfForVersion(version, suite)(keyMaterial, masterSecret, []byte(label), seed) + return keyMaterial, nil + } +} diff --git a/vendor/github.com/quic-go/qtls-go1-20/quic.go b/vendor/github.com/quic-go/qtls-go1-20/quic.go new file mode 100644 index 000000000..6be1e9196 --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/quic.go @@ -0,0 +1,412 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package qtls + +import ( + "context" + "errors" + "fmt" +) + +// QUICEncryptionLevel represents a QUIC encryption level used to transmit +// handshake messages. +type QUICEncryptionLevel int + +const ( + QUICEncryptionLevelInitial = QUICEncryptionLevel(iota) + QUICEncryptionLevelEarly + QUICEncryptionLevelHandshake + QUICEncryptionLevelApplication +) + +func (l QUICEncryptionLevel) String() string { + switch l { + case QUICEncryptionLevelInitial: + return "Initial" + case QUICEncryptionLevelEarly: + return "Early" + case QUICEncryptionLevelHandshake: + return "Handshake" + case QUICEncryptionLevelApplication: + return "Application" + default: + return fmt.Sprintf("QUICEncryptionLevel(%v)", int(l)) + } +} + +// A QUICConn represents a connection which uses a QUIC implementation as the underlying +// transport as described in RFC 9001. +// +// Methods of QUICConn are not safe for concurrent use. +type QUICConn struct { + conn *Conn + + sessionTicketSent bool +} + +// A QUICConfig configures a QUICConn. +type QUICConfig struct { + TLSConfig *Config + ExtraConfig *ExtraConfig +} + +// A QUICEventKind is a type of operation on a QUIC connection. +type QUICEventKind int + +const ( + // QUICNoEvent indicates that there are no events available. + QUICNoEvent QUICEventKind = iota + + // QUICSetReadSecret and QUICSetWriteSecret provide the read and write + // secrets for a given encryption level. + // QUICEvent.Level, QUICEvent.Data, and QUICEvent.Suite are set. + // + // Secrets for the Initial encryption level are derived from the initial + // destination connection ID, and are not provided by the QUICConn. + QUICSetReadSecret + QUICSetWriteSecret + + // QUICWriteData provides data to send to the peer in CRYPTO frames. + // QUICEvent.Data is set. + QUICWriteData + + // QUICTransportParameters provides the peer's QUIC transport parameters. + // QUICEvent.Data is set. + QUICTransportParameters + + // QUICTransportParametersRequired indicates that the caller must provide + // QUIC transport parameters to send to the peer. The caller should set + // the transport parameters with QUICConn.SetTransportParameters and call + // QUICConn.NextEvent again. + // + // If transport parameters are set before calling QUICConn.Start, the + // connection will never generate a QUICTransportParametersRequired event. + QUICTransportParametersRequired + + // QUICRejectedEarlyData indicates that the server rejected 0-RTT data even + // if we offered it. It's returned before QUICEncryptionLevelApplication + // keys are returned. + QUICRejectedEarlyData + + // QUICHandshakeDone indicates that the TLS handshake has completed. + QUICHandshakeDone +) + +// A QUICEvent is an event occurring on a QUIC connection. +// +// The type of event is specified by the Kind field. +// The contents of the other fields are kind-specific. +type QUICEvent struct { + Kind QUICEventKind + + // Set for QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData. + Level QUICEncryptionLevel + + // Set for QUICTransportParameters, QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData. + // The contents are owned by crypto/tls, and are valid until the next NextEvent call. + Data []byte + + // Set for QUICSetReadSecret and QUICSetWriteSecret. + Suite uint16 +} + +type quicState struct { + events []QUICEvent + nextEvent int + + // eventArr is a statically allocated event array, large enough to handle + // the usual maximum number of events resulting from a single call: transport + // parameters, Initial data, Early read secret, Handshake write and read + // secrets, Handshake data, Application write secret, Application data. + eventArr [8]QUICEvent + + started bool + signalc chan struct{} // handshake data is available to be read + blockedc chan struct{} // handshake is waiting for data, closed when done + cancelc <-chan struct{} // handshake has been canceled + cancel context.CancelFunc + + // readbuf is shared between HandleData and the handshake goroutine. + // HandshakeCryptoData passes ownership to the handshake goroutine by + // reading from signalc, and reclaims ownership by reading from blockedc. + readbuf []byte + + transportParams []byte // to send to the peer +} + +// QUICClient returns a new TLS client side connection using QUICTransport as the +// underlying transport. The config cannot be nil. +// +// The config's MinVersion must be at least TLS 1.3. +func QUICClient(config *QUICConfig) *QUICConn { + return newQUICConn(Client(nil, config.TLSConfig), config.ExtraConfig) +} + +// QUICServer returns a new TLS server side connection using QUICTransport as the +// underlying transport. The config cannot be nil. +// +// The config's MinVersion must be at least TLS 1.3. +func QUICServer(config *QUICConfig) *QUICConn { + return newQUICConn(Server(nil, config.TLSConfig), config.ExtraConfig) +} + +func newQUICConn(conn *Conn, extraConfig *ExtraConfig) *QUICConn { + conn.quic = &quicState{ + signalc: make(chan struct{}), + blockedc: make(chan struct{}), + } + conn.quic.events = conn.quic.eventArr[:0] + conn.extraConfig = extraConfig + return &QUICConn{ + conn: conn, + } +} + +// Start starts the client or server handshake protocol. +// It may produce connection events, which may be read with NextEvent. +// +// Start must be called at most once. +func (q *QUICConn) Start(ctx context.Context) error { + if q.conn.quic.started { + return quicError(errors.New("tls: Start called more than once")) + } + q.conn.quic.started = true + if q.conn.config.MinVersion < VersionTLS13 { + return quicError(errors.New("tls: Config MinVersion must be at least TLS 1.13")) + } + go q.conn.HandshakeContext(ctx) + if _, ok := <-q.conn.quic.blockedc; !ok { + return q.conn.handshakeErr + } + return nil +} + +// NextEvent returns the next event occurring on the connection. +// It returns an event with a Kind of QUICNoEvent when no events are available. +func (q *QUICConn) NextEvent() QUICEvent { + qs := q.conn.quic + if last := qs.nextEvent - 1; last >= 0 && len(qs.events[last].Data) > 0 { + // Write over some of the previous event's data, + // to catch callers erroniously retaining it. + qs.events[last].Data[0] = 0 + } + if qs.nextEvent >= len(qs.events) { + qs.events = qs.events[:0] + qs.nextEvent = 0 + return QUICEvent{Kind: QUICNoEvent} + } + e := qs.events[qs.nextEvent] + qs.events[qs.nextEvent] = QUICEvent{} // zero out references to data + qs.nextEvent++ + return e +} + +// Close closes the connection and stops any in-progress handshake. +func (q *QUICConn) Close() error { + if q.conn.quic.cancel == nil { + return nil // never started + } + q.conn.quic.cancel() + for range q.conn.quic.blockedc { + // Wait for the handshake goroutine to return. + } + return q.conn.handshakeErr +} + +// HandleData handles handshake bytes received from the peer. +// It may produce connection events, which may be read with NextEvent. +func (q *QUICConn) HandleData(level QUICEncryptionLevel, data []byte) error { + c := q.conn + if c.in.level != level { + return quicError(c.in.setErrorLocked(errors.New("tls: handshake data received at wrong level"))) + } + c.quic.readbuf = data + <-c.quic.signalc + _, ok := <-c.quic.blockedc + if ok { + // The handshake goroutine is waiting for more data. + return nil + } + // The handshake goroutine has exited. + c.hand.Write(c.quic.readbuf) + c.quic.readbuf = nil + for q.conn.hand.Len() >= 4 && q.conn.handshakeErr == nil { + b := q.conn.hand.Bytes() + n := int(b[1])<<16 | int(b[2])<<8 | int(b[3]) + if 4+n < len(b) { + return nil + } + if err := q.conn.handlePostHandshakeMessage(); err != nil { + return quicError(err) + } + } + if q.conn.handshakeErr != nil { + return quicError(q.conn.handshakeErr) + } + return nil +} + +// SendSessionTicket sends a session ticket to the client. +// It produces connection events, which may be read with NextEvent. +// Currently, it can only be called once. +func (q *QUICConn) SendSessionTicket(earlyData bool) error { + c := q.conn + if !c.isHandshakeComplete.Load() { + return quicError(errors.New("tls: SendSessionTicket called before handshake completed")) + } + if c.isClient { + return quicError(errors.New("tls: SendSessionTicket called on the client")) + } + if q.sessionTicketSent { + return quicError(errors.New("tls: SendSessionTicket called multiple times")) + } + q.sessionTicketSent = true + return quicError(c.sendSessionTicket(earlyData)) +} + +// ConnectionState returns basic TLS details about the connection. +func (q *QUICConn) ConnectionState() ConnectionState { + return q.conn.ConnectionState() +} + +// SetTransportParameters sets the transport parameters to send to the peer. +// +// Server connections may delay setting the transport parameters until after +// receiving the client's transport parameters. See QUICTransportParametersRequired. +func (q *QUICConn) SetTransportParameters(params []byte) { + if params == nil { + params = []byte{} + } + q.conn.quic.transportParams = params + if q.conn.quic.started { + <-q.conn.quic.signalc + <-q.conn.quic.blockedc + } +} + +// quicError ensures err is an AlertError. +// If err is not already, quicError wraps it with alertInternalError. +func quicError(err error) error { + if err == nil { + return nil + } + var ae AlertError + if errors.As(err, &ae) { + return err + } + var a alert + if !errors.As(err, &a) { + a = alertInternalError + } + // Return an error wrapping the original error and an AlertError. + // Truncate the text of the alert to 0 characters. + return fmt.Errorf("%w%.0w", err, AlertError(a)) +} + +func (c *Conn) quicReadHandshakeBytes(n int) error { + for c.hand.Len() < n { + if err := c.quicWaitForSignal(); err != nil { + return err + } + } + return nil +} + +func (c *Conn) quicSetReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) { + c.quic.events = append(c.quic.events, QUICEvent{ + Kind: QUICSetReadSecret, + Level: level, + Suite: suite, + Data: secret, + }) +} + +func (c *Conn) quicSetWriteSecret(level QUICEncryptionLevel, suite uint16, secret []byte) { + c.quic.events = append(c.quic.events, QUICEvent{ + Kind: QUICSetWriteSecret, + Level: level, + Suite: suite, + Data: secret, + }) +} + +func (c *Conn) quicWriteCryptoData(level QUICEncryptionLevel, data []byte) { + var last *QUICEvent + if len(c.quic.events) > 0 { + last = &c.quic.events[len(c.quic.events)-1] + } + if last == nil || last.Kind != QUICWriteData || last.Level != level { + c.quic.events = append(c.quic.events, QUICEvent{ + Kind: QUICWriteData, + Level: level, + }) + last = &c.quic.events[len(c.quic.events)-1] + } + last.Data = append(last.Data, data...) +} + +func (c *Conn) quicSetTransportParameters(params []byte) { + c.quic.events = append(c.quic.events, QUICEvent{ + Kind: QUICTransportParameters, + Data: params, + }) +} + +func (c *Conn) quicGetTransportParameters() ([]byte, error) { + if c.quic.transportParams == nil { + c.quic.events = append(c.quic.events, QUICEvent{ + Kind: QUICTransportParametersRequired, + }) + } + for c.quic.transportParams == nil { + if err := c.quicWaitForSignal(); err != nil { + return nil, err + } + } + return c.quic.transportParams, nil +} + +func (c *Conn) quicHandshakeComplete() { + c.quic.events = append(c.quic.events, QUICEvent{ + Kind: QUICHandshakeDone, + }) +} + +func (c *Conn) quicRejectedEarlyData() { + c.quic.events = append(c.quic.events, QUICEvent{ + Kind: QUICRejectedEarlyData, + }) +} + +// quicWaitForSignal notifies the QUICConn that handshake progress is blocked, +// and waits for a signal that the handshake should proceed. +// +// The handshake may become blocked waiting for handshake bytes +// or for the user to provide transport parameters. +func (c *Conn) quicWaitForSignal() error { + // Drop the handshake mutex while blocked to allow the user + // to call ConnectionState before the handshake completes. + c.handshakeMutex.Unlock() + defer c.handshakeMutex.Lock() + // Send on blockedc to notify the QUICConn that the handshake is blocked. + // Exported methods of QUICConn wait for the handshake to become blocked + // before returning to the user. + select { + case c.quic.blockedc <- struct{}{}: + case <-c.quic.cancelc: + return c.sendAlertLocked(alertCloseNotify) + } + // The QUICConn reads from signalc to notify us that the handshake may + // be able to proceed. (The QUICConn reads, because we close signalc to + // indicate that the handshake has completed.) + select { + case c.quic.signalc <- struct{}{}: + c.hand.Write(c.quic.readbuf) + c.quic.readbuf = nil + case <-c.quic.cancelc: + return c.sendAlertLocked(alertCloseNotify) + } + return nil +} diff --git a/vendor/github.com/quic-go/qtls-go1-20/ticket.go b/vendor/github.com/quic-go/qtls-go1-20/ticket.go new file mode 100644 index 000000000..366620707 --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/ticket.go @@ -0,0 +1,203 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package qtls + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/hmac" + "crypto/sha256" + "crypto/subtle" + "errors" + "golang.org/x/crypto/cryptobyte" + "io" +) + +// sessionState contains the information that is serialized into a session +// ticket in order to later resume a connection. +type sessionState struct { + vers uint16 + cipherSuite uint16 + createdAt uint64 + masterSecret []byte // opaque master_secret<1..2^16-1>; + // struct { opaque certificate<1..2^24-1> } Certificate; + certificates [][]byte // Certificate certificate_list<0..2^24-1>; + + // usedOldKey is true if the ticket from which this session came from + // was encrypted with an older key and thus should be refreshed. + usedOldKey bool +} + +func (m *sessionState) marshal() ([]byte, error) { + var b cryptobyte.Builder + b.AddUint16(m.vers) + b.AddUint16(m.cipherSuite) + addUint64(&b, m.createdAt) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(m.masterSecret) + }) + b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { + for _, cert := range m.certificates { + b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(cert) + }) + } + }) + return b.Bytes() +} + +func (m *sessionState) unmarshal(data []byte) bool { + *m = sessionState{usedOldKey: m.usedOldKey} + s := cryptobyte.String(data) + if ok := s.ReadUint16(&m.vers) && + s.ReadUint16(&m.cipherSuite) && + readUint64(&s, &m.createdAt) && + readUint16LengthPrefixed(&s, &m.masterSecret) && + len(m.masterSecret) != 0; !ok { + return false + } + var certList cryptobyte.String + if !s.ReadUint24LengthPrefixed(&certList) { + return false + } + for !certList.Empty() { + var cert []byte + if !readUint24LengthPrefixed(&certList, &cert) { + return false + } + m.certificates = append(m.certificates, cert) + } + return s.Empty() +} + +// sessionStateTLS13 is the content of a TLS 1.3 session ticket. Its first +// version (revision = 0) doesn't carry any of the information needed for 0-RTT +// validation and the nonce is always empty. +// version (revision = 1) carries the max_early_data_size sent in the ticket. +// version (revision = 2) carries the ALPN sent in the ticket. +type sessionStateTLS13 struct { + // uint8 version = 0x0304; + // uint8 revision = 2; + cipherSuite uint16 + createdAt uint64 + resumptionSecret []byte // opaque resumption_master_secret<1..2^8-1>; + certificate Certificate // CertificateEntry certificate_list<0..2^24-1>; + maxEarlyData uint32 + alpn string + + appData []byte +} + +func (m *sessionStateTLS13) marshal() ([]byte, error) { + var b cryptobyte.Builder + b.AddUint16(VersionTLS13) + b.AddUint8(2) // revision + b.AddUint16(m.cipherSuite) + addUint64(&b, m.createdAt) + b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(m.resumptionSecret) + }) + marshalCertificate(&b, m.certificate) + b.AddUint32(m.maxEarlyData) + b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes([]byte(m.alpn)) + }) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(m.appData) + }) + return b.Bytes() +} + +func (m *sessionStateTLS13) unmarshal(data []byte) bool { + *m = sessionStateTLS13{} + s := cryptobyte.String(data) + var version uint16 + var revision uint8 + var alpn []byte + ret := s.ReadUint16(&version) && + version == VersionTLS13 && + s.ReadUint8(&revision) && + revision == 2 && + s.ReadUint16(&m.cipherSuite) && + readUint64(&s, &m.createdAt) && + readUint8LengthPrefixed(&s, &m.resumptionSecret) && + len(m.resumptionSecret) != 0 && + unmarshalCertificate(&s, &m.certificate) && + s.ReadUint32(&m.maxEarlyData) && + readUint8LengthPrefixed(&s, &alpn) && + readUint16LengthPrefixed(&s, &m.appData) && + s.Empty() + m.alpn = string(alpn) + return ret +} + +func (c *Conn) encryptTicket(state []byte) ([]byte, error) { + if len(c.ticketKeys) == 0 { + return nil, errors.New("tls: internal error: session ticket keys unavailable") + } + + encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(state)+sha256.Size) + keyName := encrypted[:ticketKeyNameLen] + iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize] + macBytes := encrypted[len(encrypted)-sha256.Size:] + + if _, err := io.ReadFull(c.config.rand(), iv); err != nil { + return nil, err + } + key := c.ticketKeys[0] + copy(keyName, key.keyName[:]) + block, err := aes.NewCipher(key.aesKey[:]) + if err != nil { + return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error()) + } + cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], state) + + mac := hmac.New(sha256.New, key.hmacKey[:]) + mac.Write(encrypted[:len(encrypted)-sha256.Size]) + mac.Sum(macBytes[:0]) + + return encrypted, nil +} + +func (c *Conn) decryptTicket(encrypted []byte) (plaintext []byte, usedOldKey bool) { + if len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size { + return nil, false + } + + keyName := encrypted[:ticketKeyNameLen] + iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize] + macBytes := encrypted[len(encrypted)-sha256.Size:] + ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size] + + keyIndex := -1 + for i, candidateKey := range c.ticketKeys { + if bytes.Equal(keyName, candidateKey.keyName[:]) { + keyIndex = i + break + } + } + if keyIndex == -1 { + return nil, false + } + key := &c.ticketKeys[keyIndex] + + mac := hmac.New(sha256.New, key.hmacKey[:]) + mac.Write(encrypted[:len(encrypted)-sha256.Size]) + expected := mac.Sum(nil) + + if subtle.ConstantTimeCompare(macBytes, expected) != 1 { + return nil, false + } + + block, err := aes.NewCipher(key.aesKey[:]) + if err != nil { + return nil, false + } + plaintext = make([]byte, len(ciphertext)) + cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext) + + return plaintext, keyIndex > 0 +} diff --git a/vendor/github.com/quic-go/qtls-go1-20/tls.go b/vendor/github.com/quic-go/qtls-go1-20/tls.go new file mode 100644 index 000000000..47eed0855 --- /dev/null +++ b/vendor/github.com/quic-go/qtls-go1-20/tls.go @@ -0,0 +1,356 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// package qtls partially implements TLS 1.2, as specified in RFC 5246, +// and TLS 1.3, as specified in RFC 8446. +package qtls + +// BUG(agl): The crypto/tls package only implements some countermeasures +// against Lucky13 attacks on CBC-mode encryption, and only on SHA1 +// variants. See http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and +// https://www.imperialviolet.org/2013/02/04/luckythirteen.html. + +import ( + "bytes" + "context" + "crypto" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + "net" + "os" + "strings" +) + +// Server returns a new TLS server side connection +// using conn as the underlying transport. +// The configuration config must be non-nil and must include +// at least one certificate or else set GetCertificate. +func Server(conn net.Conn, config *Config) *Conn { + c := &Conn{ + conn: conn, + config: fromConfig(config), + } + c.handshakeFn = c.serverHandshake + return c +} + +// Client returns a new TLS client side connection +// using conn as the underlying transport. +// The config cannot be nil: users must set either ServerName or +// InsecureSkipVerify in the config. +func Client(conn net.Conn, config *Config) *Conn { + c := &Conn{ + conn: conn, + config: fromConfig(config), + isClient: true, + } + c.handshakeFn = c.clientHandshake + return c +} + +// A listener implements a network listener (net.Listener) for TLS connections. +type listener struct { + net.Listener + config *Config +} + +// Accept waits for and returns the next incoming TLS connection. +// The returned connection is of type *Conn. +func (l *listener) Accept() (net.Conn, error) { + c, err := l.Listener.Accept() + if err != nil { + return nil, err + } + return Server(c, l.config), nil +} + +// NewListener creates a Listener which accepts connections from an inner +// Listener and wraps each connection with Server. +// The configuration config must be non-nil and must include +// at least one certificate or else set GetCertificate. +func NewListener(inner net.Listener, config *Config) net.Listener { + l := new(listener) + l.Listener = inner + l.config = config + return l +} + +// Listen creates a TLS listener accepting connections on the +// given network address using net.Listen. +// The configuration config must be non-nil and must include +// at least one certificate or else set GetCertificate. +func Listen(network, laddr string, config *Config) (net.Listener, error) { + if config == nil || len(config.Certificates) == 0 && + config.GetCertificate == nil && config.GetConfigForClient == nil { + return nil, errors.New("tls: neither Certificates, GetCertificate, nor GetConfigForClient set in Config") + } + l, err := net.Listen(network, laddr) + if err != nil { + return nil, err + } + return NewListener(l, config), nil +} + +type timeoutError struct{} + +func (timeoutError) Error() string { return "tls: DialWithDialer timed out" } +func (timeoutError) Timeout() bool { return true } +func (timeoutError) Temporary() bool { return true } + +// DialWithDialer connects to the given network address using dialer.Dial and +// then initiates a TLS handshake, returning the resulting TLS connection. Any +// timeout or deadline given in the dialer apply to connection and TLS +// handshake as a whole. +// +// DialWithDialer interprets a nil configuration as equivalent to the zero +// configuration; see the documentation of Config for the defaults. +// +// DialWithDialer uses context.Background internally; to specify the context, +// use Dialer.DialContext with NetDialer set to the desired dialer. +func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) { + return dial(context.Background(), dialer, network, addr, config) +} + +func dial(ctx context.Context, netDialer *net.Dialer, network, addr string, config *Config) (*Conn, error) { + if netDialer.Timeout != 0 { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, netDialer.Timeout) + defer cancel() + } + + if !netDialer.Deadline.IsZero() { + var cancel context.CancelFunc + ctx, cancel = context.WithDeadline(ctx, netDialer.Deadline) + defer cancel() + } + + rawConn, err := netDialer.DialContext(ctx, network, addr) + if err != nil { + return nil, err + } + + colonPos := strings.LastIndex(addr, ":") + if colonPos == -1 { + colonPos = len(addr) + } + hostname := addr[:colonPos] + + if config == nil { + config = defaultConfig() + } + // If no ServerName is set, infer the ServerName + // from the hostname we're connecting to. + if config.ServerName == "" { + // Make a copy to avoid polluting argument or default. + c := config.Clone() + c.ServerName = hostname + config = c + } + + conn := Client(rawConn, config) + if err := conn.HandshakeContext(ctx); err != nil { + rawConn.Close() + return nil, err + } + return conn, nil +} + +// Dial connects to the given network address using net.Dial +// and then initiates a TLS handshake, returning the resulting +// TLS connection. +// Dial interprets a nil configuration as equivalent to +// the zero configuration; see the documentation of Config +// for the defaults. +func Dial(network, addr string, config *Config) (*Conn, error) { + return DialWithDialer(new(net.Dialer), network, addr, config) +} + +// Dialer dials TLS connections given a configuration and a Dialer for the +// underlying connection. +type Dialer struct { + // NetDialer is the optional dialer to use for the TLS connections' + // underlying TCP connections. + // A nil NetDialer is equivalent to the net.Dialer zero value. + NetDialer *net.Dialer + + // Config is the TLS configuration to use for new connections. + // A nil configuration is equivalent to the zero + // configuration; see the documentation of Config for the + // defaults. + Config *Config +} + +// Dial connects to the given network address and initiates a TLS +// handshake, returning the resulting TLS connection. +// +// The returned Conn, if any, will always be of type *Conn. +// +// Dial uses context.Background internally; to specify the context, +// use DialContext. +func (d *Dialer) Dial(network, addr string) (net.Conn, error) { + return d.DialContext(context.Background(), network, addr) +} + +func (d *Dialer) netDialer() *net.Dialer { + if d.NetDialer != nil { + return d.NetDialer + } + return new(net.Dialer) +} + +// DialContext connects to the given network address and initiates a TLS +// handshake, returning the resulting TLS connection. +// +// The provided Context must be non-nil. If the context expires before +// the connection is complete, an error is returned. Once successfully +// connected, any expiration of the context will not affect the +// connection. +// +// The returned Conn, if any, will always be of type *Conn. +func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) { + c, err := dial(ctx, d.netDialer(), network, addr, d.Config) + if err != nil { + // Don't return c (a typed nil) in an interface. + return nil, err + } + return c, nil +} + +// LoadX509KeyPair reads and parses a public/private key pair from a pair +// of files. The files must contain PEM encoded data. The certificate file +// may contain intermediate certificates following the leaf certificate to +// form a certificate chain. On successful return, Certificate.Leaf will +// be nil because the parsed form of the certificate is not retained. +func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) { + certPEMBlock, err := os.ReadFile(certFile) + if err != nil { + return Certificate{}, err + } + keyPEMBlock, err := os.ReadFile(keyFile) + if err != nil { + return Certificate{}, err + } + return X509KeyPair(certPEMBlock, keyPEMBlock) +} + +// X509KeyPair parses a public/private key pair from a pair of +// PEM encoded data. On successful return, Certificate.Leaf will be nil because +// the parsed form of the certificate is not retained. +func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) { + fail := func(err error) (Certificate, error) { return Certificate{}, err } + + var cert Certificate + var skippedBlockTypes []string + for { + var certDERBlock *pem.Block + certDERBlock, certPEMBlock = pem.Decode(certPEMBlock) + if certDERBlock == nil { + break + } + if certDERBlock.Type == "CERTIFICATE" { + cert.Certificate = append(cert.Certificate, certDERBlock.Bytes) + } else { + skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type) + } + } + + if len(cert.Certificate) == 0 { + if len(skippedBlockTypes) == 0 { + return fail(errors.New("tls: failed to find any PEM data in certificate input")) + } + if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") { + return fail(errors.New("tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched")) + } + return fail(fmt.Errorf("tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes)) + } + + skippedBlockTypes = skippedBlockTypes[:0] + var keyDERBlock *pem.Block + for { + keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock) + if keyDERBlock == nil { + if len(skippedBlockTypes) == 0 { + return fail(errors.New("tls: failed to find any PEM data in key input")) + } + if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" { + return fail(errors.New("tls: found a certificate rather than a key in the PEM for the private key")) + } + return fail(fmt.Errorf("tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes)) + } + if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") { + break + } + skippedBlockTypes = append(skippedBlockTypes, keyDERBlock.Type) + } + + // We don't need to parse the public key for TLS, but we so do anyway + // to check that it looks sane and matches the private key. + x509Cert, err := x509.ParseCertificate(cert.Certificate[0]) + if err != nil { + return fail(err) + } + + cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes) + if err != nil { + return fail(err) + } + + switch pub := x509Cert.PublicKey.(type) { + case *rsa.PublicKey: + priv, ok := cert.PrivateKey.(*rsa.PrivateKey) + if !ok { + return fail(errors.New("tls: private key type does not match public key type")) + } + if pub.N.Cmp(priv.N) != 0 { + return fail(errors.New("tls: private key does not match public key")) + } + case *ecdsa.PublicKey: + priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey) + if !ok { + return fail(errors.New("tls: private key type does not match public key type")) + } + if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 { + return fail(errors.New("tls: private key does not match public key")) + } + case ed25519.PublicKey: + priv, ok := cert.PrivateKey.(ed25519.PrivateKey) + if !ok { + return fail(errors.New("tls: private key type does not match public key type")) + } + if !bytes.Equal(priv.Public().(ed25519.PublicKey), pub) { + return fail(errors.New("tls: private key does not match public key")) + } + default: + return fail(errors.New("tls: unknown public key algorithm")) + } + + return cert, nil +} + +// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates +// PKCS #1 private keys by default, while OpenSSL 1.0.0 generates PKCS #8 keys. +// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three. +func parsePrivateKey(der []byte) (crypto.PrivateKey, error) { + if key, err := x509.ParsePKCS1PrivateKey(der); err == nil { + return key, nil + } + if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { + switch key := key.(type) { + case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey: + return key, nil + default: + return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping") + } + } + if key, err := x509.ParseECPrivateKey(der); err == nil { + return key, nil + } + + return nil, errors.New("tls: failed to parse private key") +} diff --git a/vendor/github.com/quic-go/qtls-go1-20/tls.test b/vendor/github.com/quic-go/qtls-go1-20/tls.test new file mode 100644 index 0000000000000000000000000000000000000000..9bc2bcd3e16751cd78b3caec7727e23993115601 GIT binary patch literal 7881666 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
  • #XHXj`%j*_di29 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%0D{a?bw`=48F^P*9XDF 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%0DUp_ctzo5ap!5#EMmcWZ}mmjVI7cWs`G!Bnw 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

    |C@fKff?NR^YuU6!73pCV3{3ZhK+h+zFvkH9W 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

    m@B5X$?r3C8R*!s#?^ciCb1Y7drY`hF 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

    ^dKy4Cy-Z2GbOXU^F))1jm2 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 ArJ2|R{vBHwF_WH{@R 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