Compare commits

..

1 commit

Author SHA1 Message Date
Victor Dyotte 54e2d35be2
Merge 40c33ccc49 into 02470db5f6 2024-10-06 19:38:59 +01:00
62 changed files with 436 additions and 873 deletions

14
go.mod
View file

@ -12,7 +12,7 @@ require (
codeberg.org/gruf/go-debug v1.3.0 codeberg.org/gruf/go-debug v1.3.0
codeberg.org/gruf/go-errors/v2 v2.3.2 codeberg.org/gruf/go-errors/v2 v2.3.2
codeberg.org/gruf/go-fastcopy v1.1.3 codeberg.org/gruf/go-fastcopy v1.1.3
codeberg.org/gruf/go-ffmpreg v0.3.1 codeberg.org/gruf/go-ffmpreg v0.2.6
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf
codeberg.org/gruf/go-kv v1.6.5 codeberg.org/gruf/go-kv v1.6.5
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f
@ -55,7 +55,7 @@ require (
github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB.0.20230227143000-f4900831d6c8 github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB.0.20230227143000-f4900831d6c8
github.com/tdewolff/minify/v2 v2.20.37 github.com/tdewolff/minify/v2 v2.20.37
github.com/technologize/otel-go-contrib v1.1.1 github.com/technologize/otel-go-contrib v1.1.1
github.com/tetratelabs/wazero v1.8.1 github.com/tetratelabs/wazero v1.8.0
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
github.com/ulule/limiter/v3 v3.11.2 github.com/ulule/limiter/v3 v3.11.2
github.com/uptrace/bun v1.2.1 github.com/uptrace/bun v1.2.1
@ -73,11 +73,11 @@ require (
go.opentelemetry.io/otel/sdk/metric v1.29.0 go.opentelemetry.io/otel/sdk/metric v1.29.0
go.opentelemetry.io/otel/trace v1.29.0 go.opentelemetry.io/otel/trace v1.29.0
go.uber.org/automaxprocs v1.6.0 go.uber.org/automaxprocs v1.6.0
golang.org/x/crypto v0.28.0 golang.org/x/crypto v0.27.0
golang.org/x/image v0.21.0 golang.org/x/image v0.20.0
golang.org/x/net v0.30.0 golang.org/x/net v0.29.0
golang.org/x/oauth2 v0.23.0 golang.org/x/oauth2 v0.23.0
golang.org/x/text v0.19.0 golang.org/x/text v0.18.0
gopkg.in/mcuadros/go-syslog.v2 v2.3.0 gopkg.in/mcuadros/go-syslog.v2 v2.3.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
modernc.org/sqlite v0.0.0-00010101000000-000000000000 modernc.org/sqlite v0.0.0-00010101000000-000000000000
@ -213,7 +213,7 @@ require (
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
golang.org/x/mod v0.18.0 // indirect golang.org/x/mod v0.18.0 // indirect
golang.org/x/sync v0.8.0 // indirect golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.26.0 // indirect golang.org/x/sys v0.25.0 // indirect
golang.org/x/tools v0.22.0 // indirect golang.org/x/tools v0.22.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect

32
go.sum
View file

@ -46,8 +46,8 @@ codeberg.org/gruf/go-fastcopy v1.1.3 h1:Jo9VTQjI6KYimlw25PPc7YLA3Xm+XMQhaHwKnM7x
codeberg.org/gruf/go-fastcopy v1.1.3/go.mod h1:GDDYR0Cnb3U/AIfGM3983V/L+GN+vuwVMvrmVABo21s= codeberg.org/gruf/go-fastcopy v1.1.3/go.mod h1:GDDYR0Cnb3U/AIfGM3983V/L+GN+vuwVMvrmVABo21s=
codeberg.org/gruf/go-fastpath/v2 v2.0.0 h1:iAS9GZahFhyWEH0KLhFEJR+txx1ZhMXxYzu2q5Qo9c0= codeberg.org/gruf/go-fastpath/v2 v2.0.0 h1:iAS9GZahFhyWEH0KLhFEJR+txx1ZhMXxYzu2q5Qo9c0=
codeberg.org/gruf/go-fastpath/v2 v2.0.0/go.mod h1:3pPqu5nZjpbRrOqvLyAK7puS1OfEtQvjd6342Cwz56Q= codeberg.org/gruf/go-fastpath/v2 v2.0.0/go.mod h1:3pPqu5nZjpbRrOqvLyAK7puS1OfEtQvjd6342Cwz56Q=
codeberg.org/gruf/go-ffmpreg v0.3.1 h1:5qE6sHQbLCbQ4RO7ZL4OKZBN4ViAYfDm9ExT8N0ZE7s= codeberg.org/gruf/go-ffmpreg v0.2.6 h1:OHlTOF+62/b+VeM3Svg7praweU/NECRIsuhilZLFaO4=
codeberg.org/gruf/go-ffmpreg v0.3.1/go.mod h1:Ar5nbt3tB2Wr0uoaqV3wDBNwAx+H+AB/mV7Kw7NlZTI= codeberg.org/gruf/go-ffmpreg v0.2.6/go.mod h1:sViRI0BYK2B8PJw4BrOg7DquPD71mZjDfffRAFcDtvk=
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf h1:84s/ii8N6lYlskZjHH+DG6jyia8w2mXMZlRwFn8Gs3A= codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf h1:84s/ii8N6lYlskZjHH+DG6jyia8w2mXMZlRwFn8Gs3A=
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf/go.mod h1:zZAICsp5rY7+hxnws2V0ePrWxE0Z2Z/KXcN3p/RQCfk= codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf/go.mod h1:zZAICsp5rY7+hxnws2V0ePrWxE0Z2Z/KXcN3p/RQCfk=
codeberg.org/gruf/go-kv v1.6.5 h1:ttPf0NA8F79pDqBttSudPTVCZmGncumeNIxmeM9ztz0= codeberg.org/gruf/go-kv v1.6.5 h1:ttPf0NA8F79pDqBttSudPTVCZmGncumeNIxmeM9ztz0=
@ -548,8 +548,8 @@ github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8= github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
github.com/technologize/otel-go-contrib v1.1.1 h1:wZH9aSPNWZWIkEh3vfaKfMb15AJ80jJ1aVj/4GZdqIw= github.com/technologize/otel-go-contrib v1.1.1 h1:wZH9aSPNWZWIkEh3vfaKfMb15AJ80jJ1aVj/4GZdqIw=
github.com/technologize/otel-go-contrib v1.1.1/go.mod h1:dCN/wj2WyUO8aFZFdIN+6tfJHImjTML/8r2YVYAy3So= github.com/technologize/otel-go-contrib v1.1.1/go.mod h1:dCN/wj2WyUO8aFZFdIN+6tfJHImjTML/8r2YVYAy3So=
github.com/tetratelabs/wazero v1.8.1 h1:NrcgVbWfkWvVc4UtT4LRLDf91PsOzDzefMdwhLfA550= github.com/tetratelabs/wazero v1.8.0 h1:iEKu0d4c2Pd+QSRieYbnQC9yiFlMS9D+Jr0LsRmcF4g=
github.com/tetratelabs/wazero v1.8.1/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= github.com/tetratelabs/wazero v1.8.0/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs=
github.com/tidwall/btree v0.0.0-20191029221954-400434d76274 h1:G6Z6HvJuPjG6XfNGi/feOATzeJrfgTNJY+rGrHbA04E= github.com/tidwall/btree v0.0.0-20191029221954-400434d76274 h1:G6Z6HvJuPjG6XfNGi/feOATzeJrfgTNJY+rGrHbA04E=
github.com/tidwall/btree v0.0.0-20191029221954-400434d76274/go.mod h1:huei1BkDWJ3/sLXmO+bsCNELL+Bp2Kks9OLyQFkzvA8= github.com/tidwall/btree v0.0.0-20191029221954-400434d76274/go.mod h1:huei1BkDWJ3/sLXmO+bsCNELL+Bp2Kks9OLyQFkzvA8=
github.com/tidwall/buntdb v1.1.2 h1:noCrqQXL9EKMtcdwJcmuVKSEjqu1ua99RHHgbLTEHRo= github.com/tidwall/buntdb v1.1.2 h1:noCrqQXL9EKMtcdwJcmuVKSEjqu1ua99RHHgbLTEHRo=
@ -668,8 +668,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -684,8 +684,8 @@ golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUF
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s= golang.org/x/image v0.20.0 h1:7cVCUjQwfL18gyBJOmYvptfSHS8Fb3YUDtfLIZ7Nbpw=
golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78= golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -739,8 +739,8 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -800,13 +800,13 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -814,8 +814,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

View file

@ -20,7 +20,6 @@
import ( import (
"context" "context"
"codeberg.org/gruf/go-ffmpreg/wasm"
"github.com/tetratelabs/wazero" "github.com/tetratelabs/wazero"
) )
@ -66,6 +65,6 @@ func (r *runner) Run(ctx context.Context, cmod wazero.CompiledModule, args Args)
// Release slot back to pool on end. // Release slot back to pool on end.
defer func() { r.pool <- struct{}{} }() defer func() { r.pool <- struct{}{} }()
// Pass to main module runner function. // Pass to main module runner.
return wasm.Run(ctx, runtime, cmod, args) return run(ctx, cmod, args)
} }

View file

@ -19,18 +19,20 @@
import ( import (
"context" "context"
"io"
"os" "os"
ffmpeglib "codeberg.org/gruf/go-ffmpreg/embed/ffmpeg" ffmpeglib "codeberg.org/gruf/go-ffmpreg/embed/ffmpeg"
ffprobelib "codeberg.org/gruf/go-ffmpreg/embed/ffprobe" ffprobelib "codeberg.org/gruf/go-ffmpreg/embed/ffprobe"
"codeberg.org/gruf/go-ffmpreg/wasm"
"github.com/tetratelabs/wazero" "github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1" "github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
"github.com/tetratelabs/wazero/sys"
) )
// Use all core features required by ffmpeg / ffprobe // Use all core features required by ffmpeg / ffprobe
// (these should be the same but we OR just in case). // (these should be the same but we OR just in case).
const corefeatures = wasm.CoreFeatures const corefeatures = ffprobelib.CoreFeatures |
ffmpeglib.CoreFeatures
var ( var (
// shared WASM runtime instance. // shared WASM runtime instance.
@ -45,7 +47,65 @@
// configuration options to run an instance // configuration options to run an instance
// of a compiled WebAssembly module that is // of a compiled WebAssembly module that is
// run in a typical CLI manner. // run in a typical CLI manner.
type Args = wasm.Args type Args struct {
// Optional further module configuration function.
// (e.g. to mount filesystem dir, set env vars, etc).
Config func(wazero.ModuleConfig) wazero.ModuleConfig
// Standard FDs.
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
// CLI args.
Args []string
}
// run will run the given compiled
// WebAssembly module using given args,
// using the global wazero runtime.
func run(
ctx context.Context,
cmod wazero.CompiledModule,
args Args,
) (
uint32, // exit code
error,
) {
// Prefix module name as argv0 to args.
cargs := make([]string, len(args.Args)+1)
copy(cargs[1:], args.Args)
cargs[0] = cmod.Name()
// Create base module config.
modcfg := wazero.NewModuleConfig()
modcfg = modcfg.WithArgs(cargs...)
modcfg = modcfg.WithStdin(args.Stdin)
modcfg = modcfg.WithStdout(args.Stdout)
modcfg = modcfg.WithStderr(args.Stderr)
if args.Config != nil {
// Pass through config fn.
modcfg = args.Config(modcfg)
}
// Instantiate the module from precompiled wasm module data.
mod, err := runtime.InstantiateModule(ctx, cmod, modcfg)
if mod != nil {
// Ensure closed.
_ = mod.Close(ctx)
}
// Try extract exit code.
switch err := err.(type) {
case *sys.ExitError:
return err.ExitCode(), nil
default:
return 0, err
}
}
// compileFfmpeg ensures the ffmpeg WebAssembly has been // compileFfmpeg ensures the ffmpeg WebAssembly has been
// pre-compiled into memory. If already compiled is a no-op. // pre-compiled into memory. If already compiled is a no-op.

Binary file not shown.

View file

@ -3,6 +3,8 @@
import ( import (
_ "embed" _ "embed"
"os" "os"
"github.com/tetratelabs/wazero/api"
) )
func init() { func init() {
@ -21,5 +23,14 @@ func init() {
} }
} }
// CoreFeatures is the WebAssembly Core specification
// features this embedded binary was compiled with.
const CoreFeatures = api.CoreFeatureSIMD |
api.CoreFeatureBulkMemoryOperations |
api.CoreFeatureNonTrappingFloatToIntConversion |
api.CoreFeatureMutableGlobal |
api.CoreFeatureReferenceTypes |
api.CoreFeatureSignExtensionOps
//go:embed ffmpeg.wasm //go:embed ffmpeg.wasm
var B []byte var B []byte

Binary file not shown.

View file

@ -3,6 +3,8 @@
import ( import (
_ "embed" _ "embed"
"os" "os"
"github.com/tetratelabs/wazero/api"
) )
func init() { func init() {
@ -21,5 +23,14 @@ func init() {
} }
} }
// CoreFeatures is the WebAssembly Core specification
// features this embedded binary was compiled with.
const CoreFeatures = api.CoreFeatureSIMD |
api.CoreFeatureBulkMemoryOperations |
api.CoreFeatureNonTrappingFloatToIntConversion |
api.CoreFeatureMutableGlobal |
api.CoreFeatureReferenceTypes |
api.CoreFeatureSignExtensionOps
//go:embed ffprobe.wasm //go:embed ffprobe.wasm
var B []byte var B []byte

View file

@ -1,89 +0,0 @@
package wasm
import (
"context"
"io"
"unsafe"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/sys"
)
// CoreFeatures are the WebAssembly Core specification
// features our embedded binaries are compiled with.
const CoreFeatures = api.CoreFeatureSIMD |
api.CoreFeatureBulkMemoryOperations |
api.CoreFeatureNonTrappingFloatToIntConversion |
api.CoreFeatureMutableGlobal |
api.CoreFeatureReferenceTypes |
api.CoreFeatureSignExtensionOps
// Args encompasses a common set of
// configuration options often passed to
// wazero.Runtime on module instantiation.
type Args struct {
// Optional further module configuration function.
// (e.g. to mount filesystem dir, set env vars, etc).
Config func(wazero.ModuleConfig) wazero.ModuleConfig
// Standard FDs.
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
// CLI args.
Args []string
}
// Run will run given compiled WebAssembly module
// within the given runtime, with given arguments.
// Returns the exit code, or error.
func Run(
ctx context.Context,
runtime wazero.Runtime,
module wazero.CompiledModule,
args Args,
) (rc uint32, err error) {
// Prefix arguments with module name.
cargs := make([]string, len(args.Args)+1)
cargs[0] = module.Name()
copy(cargs[1:], args.Args)
// Prepare new module configuration.
modcfg := wazero.NewModuleConfig()
modcfg = modcfg.WithArgs(cargs...)
modcfg = modcfg.WithStdin(args.Stdin)
modcfg = modcfg.WithStdout(args.Stdout)
modcfg = modcfg.WithStderr(args.Stderr)
if args.Config != nil {
// Pass through config fn.
modcfg = args.Config(modcfg)
}
// Instantiate the module from precompiled wasm module data.
mod, err := runtime.InstantiateModule(ctx, module, modcfg)
if !isNil(mod) {
// Ensure closed.
_ = mod.Close(ctx)
}
// Try extract exit code.
switch err := err.(type) {
case *sys.ExitError:
return err.ExitCode(), nil
default:
return 0, err
}
}
// isNil will safely check if 'v' is nil without
// dealing with weird Go interface nil bullshit.
func isNil(i interface{}) bool {
type eface struct{ Type, Data unsafe.Pointer }
return (*(*eface)(unsafe.Pointer(&i))).Data == nil
}

View file

@ -35,8 +35,6 @@ type LinearMemory interface {
// Notes: // Notes:
// - To back a shared memory, Reallocate can't change the address of the // - To back a shared memory, Reallocate can't change the address of the
// backing []byte (only its length/capacity may change). // backing []byte (only its length/capacity may change).
// - Reallocate may return nil if fails to grow the LinearMemory. This
// condition may or may not be handled gracefully by the Wasm module.
Reallocate(size uint64) []byte Reallocate(size uint64) []byte
// Free the backing memory buffer. // Free the backing memory buffer.
Free() Free()

View file

@ -1,9 +1,6 @@
package descriptor package descriptor
import ( import "math/bits"
"math/bits"
"slices"
)
// Table is a data structure mapping 32 bit descriptor to items. // Table is a data structure mapping 32 bit descriptor to items.
// //
@ -40,13 +37,23 @@ func (t *Table[Key, Item]) Len() (n int) {
return n return n
} }
// grow grows the table by n * 64 items. // grow ensures that t has enough room for n items, potentially reallocating the
// internal buffers if their capacity was too small to hold this many items.
func (t *Table[Key, Item]) grow(n int) { func (t *Table[Key, Item]) grow(n int) {
total := len(t.masks) + n // Round up to a multiple of 64 since this is the smallest increment due to
t.masks = slices.Grow(t.masks, n)[:total] // using 64 bits masks.
n = (n*64 + 63) / 64
total = len(t.items) + n*64 if n > len(t.masks) {
t.items = slices.Grow(t.items, n*64)[:total] masks := make([]uint64, n)
copy(masks, t.masks)
items := make([]Item, n*64)
copy(items, t.items)
t.masks = masks
t.items = items
}
} }
// Insert inserts the given item to the table, returning the key that it is // Insert inserts the given item to the table, returning the key that it is
@ -71,9 +78,13 @@ func (t *Table[Key, Item]) Insert(item Item) (key Key, ok bool) {
} }
} }
// No free slot found, grow the table and retry.
offset = len(t.masks) offset = len(t.masks)
t.grow(1) n := 2 * len(t.masks)
if n == 0 {
n = 1
}
t.grow(n)
goto insert goto insert
} }
@ -98,10 +109,10 @@ func (t *Table[Key, Item]) InsertAt(item Item, key Key) bool {
if key < 0 { if key < 0 {
return false return false
} }
index := uint(key) / 64 if diff := int(key) - t.Len(); diff > 0 {
if diff := int(index) - len(t.masks) + 1; diff > 0 {
t.grow(diff) t.grow(diff)
} }
index := uint(key) / 64
shift := uint(key) % 64 shift := uint(key) % 64
t.masks[index] |= 1 << shift t.masks[index] |= 1 << shift
t.items[key] = item t.items[key] = item
@ -113,8 +124,7 @@ func (t *Table[Key, Item]) Delete(key Key) {
if key < 0 { // invalid key if key < 0 { // invalid key
return return
} }
if index := uint(key) / 64; int(index) < len(t.masks) { if index, shift := key/64, key%64; int(index) < len(t.masks) {
shift := uint(key) % 64
mask := t.masks[index] mask := t.masks[index]
if (mask & (1 << shift)) != 0 { if (mask & (1 << shift)) != 0 {
var zero Item var zero Item

View file

@ -487,7 +487,7 @@ func (e *engine) setLabelAddress(op *uint64, label label, labelAddressResolution
} }
// ResolveImportedFunction implements wasm.ModuleEngine. // ResolveImportedFunction implements wasm.ModuleEngine.
func (e *moduleEngine) ResolveImportedFunction(index, descFunc, indexInImportedModule wasm.Index, importedModuleEngine wasm.ModuleEngine) { func (e *moduleEngine) ResolveImportedFunction(index, indexInImportedModule wasm.Index, importedModuleEngine wasm.ModuleEngine) {
imported := importedModuleEngine.(*moduleEngine) imported := importedModuleEngine.(*moduleEngine)
e.functions[index] = imported.functions[indexInImportedModule] e.functions[index] = imported.functions[indexInImportedModule]
} }

View file

@ -237,7 +237,7 @@ func (m *moduleEngine) putLocalMemory() {
} }
// ResolveImportedFunction implements wasm.ModuleEngine. // ResolveImportedFunction implements wasm.ModuleEngine.
func (m *moduleEngine) ResolveImportedFunction(index, descFunc, indexInImportedModule wasm.Index, importedModuleEngine wasm.ModuleEngine) { func (m *moduleEngine) ResolveImportedFunction(index, indexInImportedModule wasm.Index, importedModuleEngine wasm.ModuleEngine) {
executableOffset, moduleCtxOffset, typeIDOffset := m.parent.offsets.ImportedFunctionOffset(index) executableOffset, moduleCtxOffset, typeIDOffset := m.parent.offsets.ImportedFunctionOffset(index)
importedME := importedModuleEngine.(*moduleEngine) importedME := importedModuleEngine.(*moduleEngine)
@ -245,12 +245,12 @@ func (m *moduleEngine) ResolveImportedFunction(index, descFunc, indexInImportedM
indexInImportedModule -= wasm.Index(len(importedME.importedFunctions)) indexInImportedModule -= wasm.Index(len(importedME.importedFunctions))
} else { } else {
imported := &importedME.importedFunctions[indexInImportedModule] imported := &importedME.importedFunctions[indexInImportedModule]
m.ResolveImportedFunction(index, descFunc, imported.indexInModule, imported.me) m.ResolveImportedFunction(index, imported.indexInModule, imported.me)
return // Recursively resolve the imported function. return // Recursively resolve the imported function.
} }
offset := importedME.parent.functionOffsets[indexInImportedModule] offset := importedME.parent.functionOffsets[indexInImportedModule]
typeID := m.module.TypeIDs[descFunc] typeID := getTypeIDOf(indexInImportedModule, importedME.module)
executable := &importedME.parent.executable[offset] executable := &importedME.parent.executable[offset]
// Write functionInstance. // Write functionInstance.
binary.LittleEndian.PutUint64(m.opaque[executableOffset:], uint64(uintptr(unsafe.Pointer(executable)))) binary.LittleEndian.PutUint64(m.opaque[executableOffset:], uint64(uintptr(unsafe.Pointer(executable))))
@ -261,6 +261,28 @@ func (m *moduleEngine) ResolveImportedFunction(index, descFunc, indexInImportedM
m.importedFunctions[index] = importedFunction{me: importedME, indexInModule: indexInImportedModule} m.importedFunctions[index] = importedFunction{me: importedME, indexInModule: indexInImportedModule}
} }
func getTypeIDOf(funcIndex wasm.Index, m *wasm.ModuleInstance) wasm.FunctionTypeID {
source := m.Source
var typeIndex wasm.Index
if funcIndex >= source.ImportFunctionCount {
funcIndex -= source.ImportFunctionCount
typeIndex = source.FunctionSection[funcIndex]
} else {
var cnt wasm.Index
for i := range source.ImportSection {
if source.ImportSection[i].Type == wasm.ExternTypeFunc {
if cnt == funcIndex {
typeIndex = source.ImportSection[i].DescFunc
break
}
cnt++
}
}
}
return m.TypeIDs[typeIndex]
}
// ResolveImportedMemory implements wasm.ModuleEngine. // ResolveImportedMemory implements wasm.ModuleEngine.
func (m *moduleEngine) ResolveImportedMemory(importedModuleEngine wasm.ModuleEngine) { func (m *moduleEngine) ResolveImportedMemory(importedModuleEngine wasm.ModuleEngine) {
importedME := importedModuleEngine.(*moduleEngine) importedME := importedModuleEngine.(*moduleEngine)

View file

@ -5,7 +5,6 @@
import ( import (
"io/fs" "io/fs"
"os" "os"
"path"
experimentalsys "github.com/tetratelabs/wazero/experimental/sys" experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
) )
@ -35,11 +34,6 @@ func (d *dirFS) Chmod(path string, perm fs.FileMode) experimentalsys.Errno {
// Symlink implements the same method as documented on sys.FS // Symlink implements the same method as documented on sys.FS
func (d *dirFS) Symlink(oldName, link string) experimentalsys.Errno { func (d *dirFS) Symlink(oldName, link string) experimentalsys.Errno {
// Creating a symlink with an absolute path string fails with a "not permitted" error.
// https://github.com/WebAssembly/wasi-filesystem/blob/v0.2.0/path-resolution.md#symlinks
if path.IsAbs(oldName) {
return experimentalsys.EPERM
}
// Note: do not resolve `oldName` relative to this dirFS. The link result is always resolved // Note: do not resolve `oldName` relative to this dirFS. The link result is always resolved
// when dereference the `link` on its usage (e.g. readlink, read, etc). // when dereference the `link` on its usage (e.g. readlink, read, etc).
// https://github.com/bytecodealliance/cap-std/blob/v1.0.4/cap-std/src/fs/dir.rs#L404-L409 // https://github.com/bytecodealliance/cap-std/blob/v1.0.4/cap-std/src/fs/dir.rs#L404-L409

View file

@ -269,7 +269,7 @@ func (f *fsFile) Readdir(n int) (dirents []experimentalsys.Dirent, errno experim
if f.reopenDir { // re-open the directory if needed. if f.reopenDir { // re-open the directory if needed.
f.reopenDir = false f.reopenDir = false
if errno = adjustReaddirErr(f, f.closed, f.rewindDir()); errno != 0 { if errno = adjustReaddirErr(f, f.closed, f.reopen()); errno != 0 {
return return
} }
} }
@ -418,25 +418,19 @@ func seek(s io.Seeker, offset int64, whence int) (int64, experimentalsys.Errno)
return newOffset, experimentalsys.UnwrapOSError(err) return newOffset, experimentalsys.UnwrapOSError(err)
} }
func (f *fsFile) rewindDir() experimentalsys.Errno { // reopenFile allows re-opening a file for reasons such as applying flags or
// Reopen the directory to rewind it. // directory iteration.
file, err := f.fs.Open(f.name) type reopenFile func() experimentalsys.Errno
if err != nil {
return experimentalsys.UnwrapOSError(err) // compile-time check to ensure fsFile.reopen implements reopenFile.
} var _ reopenFile = (*fsFile)(nil).reopen
fi, err := file.Stat()
if err != nil { // reopen implements the same method as documented on reopenFile.
return experimentalsys.UnwrapOSError(err) func (f *fsFile) reopen() experimentalsys.Errno {
} _ = f.close()
// Can't check if it's still the same file, var err error
// but is it still a directory, at least? f.file, err = f.fs.Open(f.name)
if !fi.IsDir() { return experimentalsys.UnwrapOSError(err)
return experimentalsys.ENOTDIR
}
// Only update f on success.
_ = f.file.Close()
f.file = file
return 0
} }
// readdirFile allows masking the `Readdir` function on os.File. // readdirFile allows masking the `Readdir` function on os.File.

View file

@ -83,12 +83,21 @@ func (f *osFile) SetAppend(enable bool) (errno experimentalsys.Errno) {
f.flag &= ^experimentalsys.O_APPEND f.flag &= ^experimentalsys.O_APPEND
} }
// appendMode cannot be changed later, so we have to re-open the file // Clear any create or trunc flag, as we are re-opening, not re-creating.
// https://github.com/golang/go/blob/go1.23/src/os/file_unix.go#L60 f.flag &= ^(experimentalsys.O_CREAT | experimentalsys.O_TRUNC)
// appendMode (bool) cannot be changed later, so we have to re-open the
// file. https://github.com/golang/go/blob/go1.20/src/os/file_unix.go#L60
return fileError(f, f.closed, f.reopen()) return fileError(f, f.closed, f.reopen())
} }
// compile-time check to ensure osFile.reopen implements reopenFile.
var _ reopenFile = (*osFile)(nil).reopen
func (f *osFile) reopen() (errno experimentalsys.Errno) { func (f *osFile) reopen() (errno experimentalsys.Errno) {
// Clear any create flag, as we are re-opening, not re-creating.
f.flag &= ^experimentalsys.O_CREAT
var ( var (
isDir bool isDir bool
offset int64 offset int64
@ -107,47 +116,22 @@ func (f *osFile) reopen() (errno experimentalsys.Errno) {
} }
} }
// Clear any create or trunc flag, as we are re-opening, not re-creating. _ = f.close()
flag := f.flag &^ (experimentalsys.O_CREAT | experimentalsys.O_TRUNC) f.file, errno = OpenFile(f.path, f.flag, f.perm)
file, errno := OpenFile(f.path, flag, f.perm)
if errno != 0 {
return errno
}
errno = f.checkSameFile(file)
if errno != 0 { if errno != 0 {
return errno return errno
} }
if !isDir { if !isDir {
_, err = file.Seek(offset, io.SeekStart) _, err = f.file.Seek(offset, io.SeekStart)
if err != nil { if err != nil {
_ = file.Close()
return experimentalsys.UnwrapOSError(err) return experimentalsys.UnwrapOSError(err)
} }
} }
// Only update f on success.
_ = f.file.Close()
f.file = file
f.fd = file.Fd()
return 0 return 0
} }
func (f *osFile) checkSameFile(osf *os.File) experimentalsys.Errno {
fi1, err := f.file.Stat()
if err != nil {
return experimentalsys.UnwrapOSError(err)
}
fi2, err := osf.Stat()
if err != nil {
return experimentalsys.UnwrapOSError(err)
}
if os.SameFile(fi1, fi2) {
return 0
}
return experimentalsys.ENOENT
}
// IsNonblock implements the same method as documented on fsapi.File // IsNonblock implements the same method as documented on fsapi.File
func (f *osFile) IsNonblock() bool { func (f *osFile) IsNonblock() bool {
return isNonblock(f) return isNonblock(f)

View file

@ -44,10 +44,9 @@ type ModuleEngine interface {
// ResolveImportedFunction is used to add imported functions needed to make this ModuleEngine fully functional. // ResolveImportedFunction is used to add imported functions needed to make this ModuleEngine fully functional.
// - `index` is the function Index of this imported function. // - `index` is the function Index of this imported function.
// - `descFunc` is the type Index in Module.TypeSection of this imported function. It corresponds to Import.DescFunc.
// - `indexInImportedModule` is the function Index of the imported function in the imported module. // - `indexInImportedModule` is the function Index of the imported function in the imported module.
// - `importedModuleEngine` is the ModuleEngine for the imported ModuleInstance. // - `importedModuleEngine` is the ModuleEngine for the imported ModuleInstance.
ResolveImportedFunction(index, descFunc, indexInImportedModule Index, importedModuleEngine ModuleEngine) ResolveImportedFunction(index, indexInImportedModule Index, importedModuleEngine ModuleEngine)
// ResolveImportedMemory is called when this module imports a memory from another module. // ResolveImportedMemory is called when this module imports a memory from another module.
ResolveImportedMemory(importedModuleEngine ModuleEngine) ResolveImportedMemory(importedModuleEngine ModuleEngine)

View file

@ -77,7 +77,6 @@ func NewMemoryInstance(memSec *Memory, allocator experimental.MemoryAllocator, m
if allocator != nil { if allocator != nil {
expBuffer = allocator.Allocate(capBytes, maxBytes) expBuffer = allocator.Allocate(capBytes, maxBytes)
buffer = expBuffer.Reallocate(minBytes) buffer = expBuffer.Reallocate(minBytes)
_ = buffer[:minBytes] // Bounds check that the minimum was allocated.
} else if memSec.IsShared { } else if memSec.IsShared {
// Shared memory needs a fixed buffer, so allocate with the maximum size. // Shared memory needs a fixed buffer, so allocate with the maximum size.
// //
@ -239,15 +238,12 @@ func (m *MemoryInstance) Grow(delta uint32) (result uint32, ok bool) {
return currentPages, true return currentPages, true
} }
// If exceeds the max of memory size, we push -1 according to the spec.
newPages := currentPages + delta newPages := currentPages + delta
if newPages > m.Max || int32(delta) < 0 { if newPages > m.Max || int32(delta) < 0 {
return 0, false return 0, false
} else if m.expBuffer != nil { } else if m.expBuffer != nil {
buffer := m.expBuffer.Reallocate(MemoryPagesToBytesNum(newPages)) buffer := m.expBuffer.Reallocate(MemoryPagesToBytesNum(newPages))
if buffer == nil {
// Allocator failed to grow.
return 0, false
}
if m.Shared { if m.Shared {
if unsafe.SliceData(buffer) != unsafe.SliceData(m.Buffer) { if unsafe.SliceData(buffer) != unsafe.SliceData(m.Buffer) {
panic("shared memory cannot move, this is a bug in the memory allocator") panic("shared memory cannot move, this is a bug in the memory allocator")

View file

@ -446,7 +446,7 @@ func (m *ModuleInstance) resolveImports(ctx context.Context, module *Module) (er
return return
} }
m.Engine.ResolveImportedFunction(i.IndexPerType, i.DescFunc, imported.Index, importedModule.Engine) m.Engine.ResolveImportedFunction(i.IndexPerType, imported.Index, importedModule.Engine)
case ExternTypeTable: case ExternTypeTable:
expected := i.DescTable expected := i.DescTable
importedTable := importedModule.Tables[imported.Index] importedTable := importedModule.Tables[imported.Index]

View file

@ -29,7 +29,9 @@
// # Notes // # Notes
// //
// - This is used for WebAssembly ABI emulating the POSIX `stat` system call. // - This is used for WebAssembly ABI emulating the POSIX `stat` system call.
// See https://pubs.opengroup.org/onlinepubs/9699919799/functions/stat.html // Fields included are required for WebAssembly ABI including wasip1
// (a.k.a. wasix) and wasi-filesystem (a.k.a. wasip2). See
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/stat.html
// - Fields here are required for WebAssembly ABI including wasip1 // - Fields here are required for WebAssembly ABI including wasip1
// (a.k.a. wasix) and wasi-filesystem (a.k.a. wasip2). // (a.k.a. wasix) and wasi-filesystem (a.k.a. wasip2).
// - This isn't the same as syscall.Stat_t because wazero supports Windows, // - This isn't the same as syscall.Stat_t because wazero supports Windows,

View file

@ -85,9 +85,9 @@ func newCShake(N, S []byte, rate, outputLen int, dsbyte byte) ShakeHash {
// leftEncode returns max 9 bytes // leftEncode returns max 9 bytes
c.initBlock = make([]byte, 0, 9*2+len(N)+len(S)) c.initBlock = make([]byte, 0, 9*2+len(N)+len(S))
c.initBlock = append(c.initBlock, leftEncode(uint64(len(N))*8)...) c.initBlock = append(c.initBlock, leftEncode(uint64(len(N)*8))...)
c.initBlock = append(c.initBlock, N...) c.initBlock = append(c.initBlock, N...)
c.initBlock = append(c.initBlock, leftEncode(uint64(len(S))*8)...) c.initBlock = append(c.initBlock, leftEncode(uint64(len(S)*8))...)
c.initBlock = append(c.initBlock, S...) c.initBlock = append(c.initBlock, S...)
c.Write(bytepad(c.initBlock, c.rate)) c.Write(bytepad(c.initBlock, c.rate))
return &c return &c

View file

@ -510,8 +510,8 @@ func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, err
if err := s.transport.writePacket(Marshal(discMsg)); err != nil { if err := s.transport.writePacket(Marshal(discMsg)); err != nil {
return nil, err return nil, err
} }
authErrs = append(authErrs, discMsg)
return nil, &ServerAuthError{Errors: authErrs} return nil, discMsg
} }
var userAuthReq userAuthRequestMsg var userAuthReq userAuthRequestMsg

View file

@ -1,122 +0,0 @@
// Copyright 2024 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 http2
import (
"math"
"net/http"
"time"
)
// http2Config is a package-internal version of net/http.HTTP2Config.
//
// http.HTTP2Config was added in Go 1.24.
// When running with a version of net/http that includes HTTP2Config,
// we merge the configuration with the fields in Transport or Server
// to produce an http2Config.
//
// Zero valued fields in http2Config are interpreted as in the
// net/http.HTTPConfig documentation.
//
// Precedence order for reconciling configurations is:
//
// - Use the net/http.{Server,Transport}.HTTP2Config value, when non-zero.
// - Otherwise use the http2.{Server.Transport} value.
// - If the resulting value is zero or out of range, use a default.
type http2Config struct {
MaxConcurrentStreams uint32
MaxDecoderHeaderTableSize uint32
MaxEncoderHeaderTableSize uint32
MaxReadFrameSize uint32
MaxUploadBufferPerConnection int32
MaxUploadBufferPerStream int32
SendPingTimeout time.Duration
PingTimeout time.Duration
WriteByteTimeout time.Duration
PermitProhibitedCipherSuites bool
CountError func(errType string)
}
// configFromServer merges configuration settings from
// net/http.Server.HTTP2Config and http2.Server.
func configFromServer(h1 *http.Server, h2 *Server) http2Config {
conf := http2Config{
MaxConcurrentStreams: h2.MaxConcurrentStreams,
MaxEncoderHeaderTableSize: h2.MaxEncoderHeaderTableSize,
MaxDecoderHeaderTableSize: h2.MaxDecoderHeaderTableSize,
MaxReadFrameSize: h2.MaxReadFrameSize,
MaxUploadBufferPerConnection: h2.MaxUploadBufferPerConnection,
MaxUploadBufferPerStream: h2.MaxUploadBufferPerStream,
SendPingTimeout: h2.ReadIdleTimeout,
PingTimeout: h2.PingTimeout,
WriteByteTimeout: h2.WriteByteTimeout,
PermitProhibitedCipherSuites: h2.PermitProhibitedCipherSuites,
CountError: h2.CountError,
}
fillNetHTTPServerConfig(&conf, h1)
setConfigDefaults(&conf, true)
return conf
}
// configFromServer merges configuration settings from h2 and h2.t1.HTTP2
// (the net/http Transport).
func configFromTransport(h2 *Transport) http2Config {
conf := http2Config{
MaxEncoderHeaderTableSize: h2.MaxEncoderHeaderTableSize,
MaxDecoderHeaderTableSize: h2.MaxDecoderHeaderTableSize,
MaxReadFrameSize: h2.MaxReadFrameSize,
SendPingTimeout: h2.ReadIdleTimeout,
PingTimeout: h2.PingTimeout,
WriteByteTimeout: h2.WriteByteTimeout,
}
// Unlike most config fields, where out-of-range values revert to the default,
// Transport.MaxReadFrameSize clips.
if conf.MaxReadFrameSize < minMaxFrameSize {
conf.MaxReadFrameSize = minMaxFrameSize
} else if conf.MaxReadFrameSize > maxFrameSize {
conf.MaxReadFrameSize = maxFrameSize
}
if h2.t1 != nil {
fillNetHTTPTransportConfig(&conf, h2.t1)
}
setConfigDefaults(&conf, false)
return conf
}
func setDefault[T ~int | ~int32 | ~uint32 | ~int64](v *T, minval, maxval, defval T) {
if *v < minval || *v > maxval {
*v = defval
}
}
func setConfigDefaults(conf *http2Config, server bool) {
setDefault(&conf.MaxConcurrentStreams, 1, math.MaxUint32, defaultMaxStreams)
setDefault(&conf.MaxEncoderHeaderTableSize, 1, math.MaxUint32, initialHeaderTableSize)
setDefault(&conf.MaxDecoderHeaderTableSize, 1, math.MaxUint32, initialHeaderTableSize)
if server {
setDefault(&conf.MaxUploadBufferPerConnection, initialWindowSize, math.MaxInt32, 1<<20)
} else {
setDefault(&conf.MaxUploadBufferPerConnection, initialWindowSize, math.MaxInt32, transportDefaultConnFlow)
}
if server {
setDefault(&conf.MaxUploadBufferPerStream, 1, math.MaxInt32, 1<<20)
} else {
setDefault(&conf.MaxUploadBufferPerStream, 1, math.MaxInt32, transportDefaultStreamFlow)
}
setDefault(&conf.MaxReadFrameSize, minMaxFrameSize, maxFrameSize, defaultMaxReadFrameSize)
setDefault(&conf.PingTimeout, 1, math.MaxInt64, 15*time.Second)
}
// adjustHTTP1MaxHeaderSize converts a limit in bytes on the size of an HTTP/1 header
// to an HTTP/2 MAX_HEADER_LIST_SIZE value.
func adjustHTTP1MaxHeaderSize(n int64) int64 {
// http2's count is in a slightly different unit and includes 32 bytes per pair.
// So, take the net/http.Server value and pad it up a bit, assuming 10 headers.
const perFieldOverhead = 32 // per http2 spec
const typicalHeaders = 10 // conservative
return n + typicalHeaders*perFieldOverhead
}

View file

@ -1,61 +0,0 @@
// Copyright 2024 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.
//go:build go1.24
package http2
import "net/http"
// fillNetHTTPServerConfig sets fields in conf from srv.HTTP2.
func fillNetHTTPServerConfig(conf *http2Config, srv *http.Server) {
fillNetHTTPConfig(conf, srv.HTTP2)
}
// fillNetHTTPServerConfig sets fields in conf from tr.HTTP2.
func fillNetHTTPTransportConfig(conf *http2Config, tr *http.Transport) {
fillNetHTTPConfig(conf, tr.HTTP2)
}
func fillNetHTTPConfig(conf *http2Config, h2 *http.HTTP2Config) {
if h2 == nil {
return
}
if h2.MaxConcurrentStreams != 0 {
conf.MaxConcurrentStreams = uint32(h2.MaxConcurrentStreams)
}
if h2.MaxEncoderHeaderTableSize != 0 {
conf.MaxEncoderHeaderTableSize = uint32(h2.MaxEncoderHeaderTableSize)
}
if h2.MaxDecoderHeaderTableSize != 0 {
conf.MaxDecoderHeaderTableSize = uint32(h2.MaxDecoderHeaderTableSize)
}
if h2.MaxConcurrentStreams != 0 {
conf.MaxConcurrentStreams = uint32(h2.MaxConcurrentStreams)
}
if h2.MaxReadFrameSize != 0 {
conf.MaxReadFrameSize = uint32(h2.MaxReadFrameSize)
}
if h2.MaxReceiveBufferPerConnection != 0 {
conf.MaxUploadBufferPerConnection = int32(h2.MaxReceiveBufferPerConnection)
}
if h2.MaxReceiveBufferPerStream != 0 {
conf.MaxUploadBufferPerStream = int32(h2.MaxReceiveBufferPerStream)
}
if h2.SendPingTimeout != 0 {
conf.SendPingTimeout = h2.SendPingTimeout
}
if h2.PingTimeout != 0 {
conf.PingTimeout = h2.PingTimeout
}
if h2.WriteByteTimeout != 0 {
conf.WriteByteTimeout = h2.WriteByteTimeout
}
if h2.PermitProhibitedCipherSuites {
conf.PermitProhibitedCipherSuites = true
}
if h2.CountError != nil {
conf.CountError = h2.CountError
}
}

View file

@ -1,16 +0,0 @@
// Copyright 2024 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.
//go:build !go1.24
package http2
import "net/http"
// Pre-Go 1.24 fallback.
// The Server.HTTP2 and Transport.HTTP2 config fields were added in Go 1.24.
func fillNetHTTPServerConfig(conf *http2Config, srv *http.Server) {}
func fillNetHTTPTransportConfig(conf *http2Config, tr *http.Transport) {}

View file

@ -19,9 +19,8 @@
"bufio" "bufio"
"context" "context"
"crypto/tls" "crypto/tls"
"errors"
"fmt" "fmt"
"net" "io"
"net/http" "net/http"
"os" "os"
"sort" "sort"
@ -238,19 +237,13 @@ func (cw closeWaiter) Wait() {
// Its buffered writer is lazily allocated as needed, to minimize // Its buffered writer is lazily allocated as needed, to minimize
// idle memory usage with many connections. // idle memory usage with many connections.
type bufferedWriter struct { type bufferedWriter struct {
_ incomparable _ incomparable
group synctestGroupInterface // immutable w io.Writer // immutable
conn net.Conn // immutable bw *bufio.Writer // non-nil when data is buffered
bw *bufio.Writer // non-nil when data is buffered
byteTimeout time.Duration // immutable, WriteByteTimeout
} }
func newBufferedWriter(group synctestGroupInterface, conn net.Conn, timeout time.Duration) *bufferedWriter { func newBufferedWriter(w io.Writer) *bufferedWriter {
return &bufferedWriter{ return &bufferedWriter{w: w}
group: group,
conn: conn,
byteTimeout: timeout,
}
} }
// bufWriterPoolBufferSize is the size of bufio.Writer's // bufWriterPoolBufferSize is the size of bufio.Writer's
@ -277,7 +270,7 @@ func (w *bufferedWriter) Available() int {
func (w *bufferedWriter) Write(p []byte) (n int, err error) { func (w *bufferedWriter) Write(p []byte) (n int, err error) {
if w.bw == nil { if w.bw == nil {
bw := bufWriterPool.Get().(*bufio.Writer) bw := bufWriterPool.Get().(*bufio.Writer)
bw.Reset((*bufferedWriterTimeoutWriter)(w)) bw.Reset(w.w)
w.bw = bw w.bw = bw
} }
return w.bw.Write(p) return w.bw.Write(p)
@ -295,38 +288,6 @@ func (w *bufferedWriter) Flush() error {
return err return err
} }
type bufferedWriterTimeoutWriter bufferedWriter
func (w *bufferedWriterTimeoutWriter) Write(p []byte) (n int, err error) {
return writeWithByteTimeout(w.group, w.conn, w.byteTimeout, p)
}
// writeWithByteTimeout writes to conn.
// If more than timeout passes without any bytes being written to the connection,
// the write fails.
func writeWithByteTimeout(group synctestGroupInterface, conn net.Conn, timeout time.Duration, p []byte) (n int, err error) {
if timeout <= 0 {
return conn.Write(p)
}
for {
var now time.Time
if group == nil {
now = time.Now()
} else {
now = group.Now()
}
conn.SetWriteDeadline(now.Add(timeout))
nn, err := conn.Write(p[n:])
n += nn
if n == len(p) || nn == 0 || !errors.Is(err, os.ErrDeadlineExceeded) {
// Either we finished the write, made no progress, or hit the deadline.
// Whichever it is, we're done now.
conn.SetWriteDeadline(time.Time{})
return n, err
}
}
}
func mustUint31(v int32) uint32 { func mustUint31(v int32) uint32 {
if v < 0 || v > 2147483647 { if v < 0 || v > 2147483647 {
panic("out of range") panic("out of range")

View file

@ -29,7 +29,6 @@
"bufio" "bufio"
"bytes" "bytes"
"context" "context"
"crypto/rand"
"crypto/tls" "crypto/tls"
"errors" "errors"
"fmt" "fmt"
@ -53,14 +52,10 @@
) )
const ( const (
prefaceTimeout = 10 * time.Second prefaceTimeout = 10 * time.Second
firstSettingsTimeout = 2 * time.Second // should be in-flight with preface anyway firstSettingsTimeout = 2 * time.Second // should be in-flight with preface anyway
handlerChunkWriteSize = 4 << 10 handlerChunkWriteSize = 4 << 10
defaultMaxStreams = 250 // TODO: make this 100 as the GFE seems to? defaultMaxStreams = 250 // TODO: make this 100 as the GFE seems to?
// maxQueuedControlFrames is the maximum number of control frames like
// SETTINGS, PING and RST_STREAM that will be queued for writing before
// the connection is closed to prevent memory exhaustion attacks.
maxQueuedControlFrames = 10000 maxQueuedControlFrames = 10000
) )
@ -132,22 +127,6 @@ type Server struct {
// If zero or negative, there is no timeout. // If zero or negative, there is no timeout.
IdleTimeout time.Duration IdleTimeout time.Duration
// ReadIdleTimeout is the timeout after which a health check using a ping
// frame will be carried out if no frame is received on the connection.
// If zero, no health check is performed.
ReadIdleTimeout time.Duration
// PingTimeout is the timeout after which the connection will be closed
// if a response to a ping is not received.
// If zero, a default of 15 seconds is used.
PingTimeout time.Duration
// WriteByteTimeout is the timeout after which a connection will be
// closed if no data can be written to it. The timeout begins when data is
// available to write, and is extended whenever any bytes are written.
// If zero or negative, there is no timeout.
WriteByteTimeout time.Duration
// MaxUploadBufferPerConnection is the size of the initial flow // MaxUploadBufferPerConnection is the size of the initial flow
// control window for each connections. The HTTP/2 spec does not // control window for each connections. The HTTP/2 spec does not
// allow this to be smaller than 65535 or larger than 2^32-1. // allow this to be smaller than 65535 or larger than 2^32-1.
@ -210,6 +189,57 @@ func (s *Server) afterFunc(d time.Duration, f func()) timer {
return timeTimer{time.AfterFunc(d, f)} return timeTimer{time.AfterFunc(d, f)}
} }
func (s *Server) initialConnRecvWindowSize() int32 {
if s.MaxUploadBufferPerConnection >= initialWindowSize {
return s.MaxUploadBufferPerConnection
}
return 1 << 20
}
func (s *Server) initialStreamRecvWindowSize() int32 {
if s.MaxUploadBufferPerStream > 0 {
return s.MaxUploadBufferPerStream
}
return 1 << 20
}
func (s *Server) maxReadFrameSize() uint32 {
if v := s.MaxReadFrameSize; v >= minMaxFrameSize && v <= maxFrameSize {
return v
}
return defaultMaxReadFrameSize
}
func (s *Server) maxConcurrentStreams() uint32 {
if v := s.MaxConcurrentStreams; v > 0 {
return v
}
return defaultMaxStreams
}
func (s *Server) maxDecoderHeaderTableSize() uint32 {
if v := s.MaxDecoderHeaderTableSize; v > 0 {
return v
}
return initialHeaderTableSize
}
func (s *Server) maxEncoderHeaderTableSize() uint32 {
if v := s.MaxEncoderHeaderTableSize; v > 0 {
return v
}
return initialHeaderTableSize
}
// maxQueuedControlFrames is the maximum number of control frames like
// SETTINGS, PING and RST_STREAM that will be queued for writing before
// the connection is closed to prevent memory exhaustion attacks.
func (s *Server) maxQueuedControlFrames() int {
// TODO: if anybody asks, add a Server field, and remember to define the
// behavior of negative values.
return maxQueuedControlFrames
}
type serverInternalState struct { type serverInternalState struct {
mu sync.Mutex mu sync.Mutex
activeConns map[*serverConn]struct{} activeConns map[*serverConn]struct{}
@ -410,15 +440,13 @@ func (s *Server) serveConn(c net.Conn, opts *ServeConnOpts, newf func(*serverCon
baseCtx, cancel := serverConnBaseContext(c, opts) baseCtx, cancel := serverConnBaseContext(c, opts)
defer cancel() defer cancel()
http1srv := opts.baseConfig()
conf := configFromServer(http1srv, s)
sc := &serverConn{ sc := &serverConn{
srv: s, srv: s,
hs: http1srv, hs: opts.baseConfig(),
conn: c, conn: c,
baseCtx: baseCtx, baseCtx: baseCtx,
remoteAddrStr: c.RemoteAddr().String(), remoteAddrStr: c.RemoteAddr().String(),
bw: newBufferedWriter(s.group, c, conf.WriteByteTimeout), bw: newBufferedWriter(c),
handler: opts.handler(), handler: opts.handler(),
streams: make(map[uint32]*stream), streams: make(map[uint32]*stream),
readFrameCh: make(chan readFrameResult), readFrameCh: make(chan readFrameResult),
@ -428,12 +456,9 @@ func (s *Server) serveConn(c net.Conn, opts *ServeConnOpts, newf func(*serverCon
bodyReadCh: make(chan bodyReadMsg), // buffering doesn't matter either way bodyReadCh: make(chan bodyReadMsg), // buffering doesn't matter either way
doneServing: make(chan struct{}), doneServing: make(chan struct{}),
clientMaxStreams: math.MaxUint32, // Section 6.5.2: "Initially, there is no limit to this value" clientMaxStreams: math.MaxUint32, // Section 6.5.2: "Initially, there is no limit to this value"
advMaxStreams: conf.MaxConcurrentStreams, advMaxStreams: s.maxConcurrentStreams(),
initialStreamSendWindowSize: initialWindowSize, initialStreamSendWindowSize: initialWindowSize,
initialStreamRecvWindowSize: conf.MaxUploadBufferPerStream,
maxFrameSize: initialMaxFrameSize, maxFrameSize: initialMaxFrameSize,
pingTimeout: conf.PingTimeout,
countErrorFunc: conf.CountError,
serveG: newGoroutineLock(), serveG: newGoroutineLock(),
pushEnabled: true, pushEnabled: true,
sawClientPreface: opts.SawClientPreface, sawClientPreface: opts.SawClientPreface,
@ -466,15 +491,15 @@ func (s *Server) serveConn(c net.Conn, opts *ServeConnOpts, newf func(*serverCon
sc.flow.add(initialWindowSize) sc.flow.add(initialWindowSize)
sc.inflow.init(initialWindowSize) sc.inflow.init(initialWindowSize)
sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf) sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
sc.hpackEncoder.SetMaxDynamicTableSizeLimit(conf.MaxEncoderHeaderTableSize) sc.hpackEncoder.SetMaxDynamicTableSizeLimit(s.maxEncoderHeaderTableSize())
fr := NewFramer(sc.bw, c) fr := NewFramer(sc.bw, c)
if conf.CountError != nil { if s.CountError != nil {
fr.countError = conf.CountError fr.countError = s.CountError
} }
fr.ReadMetaHeaders = hpack.NewDecoder(conf.MaxDecoderHeaderTableSize, nil) fr.ReadMetaHeaders = hpack.NewDecoder(s.maxDecoderHeaderTableSize(), nil)
fr.MaxHeaderListSize = sc.maxHeaderListSize() fr.MaxHeaderListSize = sc.maxHeaderListSize()
fr.SetMaxReadFrameSize(conf.MaxReadFrameSize) fr.SetMaxReadFrameSize(s.maxReadFrameSize())
sc.framer = fr sc.framer = fr
if tc, ok := c.(connectionStater); ok { if tc, ok := c.(connectionStater); ok {
@ -507,7 +532,7 @@ func (s *Server) serveConn(c net.Conn, opts *ServeConnOpts, newf func(*serverCon
// So for now, do nothing here again. // So for now, do nothing here again.
} }
if !conf.PermitProhibitedCipherSuites && isBadCipher(sc.tlsState.CipherSuite) { if !s.PermitProhibitedCipherSuites && isBadCipher(sc.tlsState.CipherSuite) {
// "Endpoints MAY choose to generate a connection error // "Endpoints MAY choose to generate a connection error
// (Section 5.4.1) of type INADEQUATE_SECURITY if one of // (Section 5.4.1) of type INADEQUATE_SECURITY if one of
// the prohibited cipher suites are negotiated." // the prohibited cipher suites are negotiated."
@ -544,7 +569,7 @@ func (s *Server) serveConn(c net.Conn, opts *ServeConnOpts, newf func(*serverCon
opts.UpgradeRequest = nil opts.UpgradeRequest = nil
} }
sc.serve(conf) sc.serve()
} }
func serverConnBaseContext(c net.Conn, opts *ServeConnOpts) (ctx context.Context, cancel func()) { func serverConnBaseContext(c net.Conn, opts *ServeConnOpts) (ctx context.Context, cancel func()) {
@ -584,7 +609,6 @@ type serverConn struct {
tlsState *tls.ConnectionState // shared by all handlers, like net/http tlsState *tls.ConnectionState // shared by all handlers, like net/http
remoteAddrStr string remoteAddrStr string
writeSched WriteScheduler writeSched WriteScheduler
countErrorFunc func(errType string)
// Everything following is owned by the serve loop; use serveG.check(): // Everything following is owned by the serve loop; use serveG.check():
serveG goroutineLock // used to verify funcs are on serve() serveG goroutineLock // used to verify funcs are on serve()
@ -604,7 +628,6 @@ type serverConn struct {
streams map[uint32]*stream streams map[uint32]*stream
unstartedHandlers []unstartedHandler unstartedHandlers []unstartedHandler
initialStreamSendWindowSize int32 initialStreamSendWindowSize int32
initialStreamRecvWindowSize int32
maxFrameSize int32 maxFrameSize int32
peerMaxHeaderListSize uint32 // zero means unknown (default) peerMaxHeaderListSize uint32 // zero means unknown (default)
canonHeader map[string]string // http2-lower-case -> Go-Canonical-Case canonHeader map[string]string // http2-lower-case -> Go-Canonical-Case
@ -615,14 +638,9 @@ type serverConn struct {
inGoAway bool // we've started to or sent GOAWAY inGoAway bool // we've started to or sent GOAWAY
inFrameScheduleLoop bool // whether we're in the scheduleFrameWrite loop inFrameScheduleLoop bool // whether we're in the scheduleFrameWrite loop
needToSendGoAway bool // we need to schedule a GOAWAY frame write needToSendGoAway bool // we need to schedule a GOAWAY frame write
pingSent bool
sentPingData [8]byte
goAwayCode ErrCode goAwayCode ErrCode
shutdownTimer timer // nil until used shutdownTimer timer // nil until used
idleTimer timer // nil if unused idleTimer timer // nil if unused
readIdleTimeout time.Duration
pingTimeout time.Duration
readIdleTimer timer // nil if unused
// Owned by the writeFrameAsync goroutine: // Owned by the writeFrameAsync goroutine:
headerWriteBuf bytes.Buffer headerWriteBuf bytes.Buffer
@ -637,7 +655,11 @@ func (sc *serverConn) maxHeaderListSize() uint32 {
if n <= 0 { if n <= 0 {
n = http.DefaultMaxHeaderBytes n = http.DefaultMaxHeaderBytes
} }
return uint32(adjustHTTP1MaxHeaderSize(int64(n))) // http2's count is in a slightly different unit and includes 32 bytes per pair.
// So, take the net/http.Server value and pad it up a bit, assuming 10 headers.
const perFieldOverhead = 32 // per http2 spec
const typicalHeaders = 10 // conservative
return uint32(n + typicalHeaders*perFieldOverhead)
} }
func (sc *serverConn) curOpenStreams() uint32 { func (sc *serverConn) curOpenStreams() uint32 {
@ -901,7 +923,7 @@ func (sc *serverConn) notePanic() {
} }
} }
func (sc *serverConn) serve(conf http2Config) { func (sc *serverConn) serve() {
sc.serveG.check() sc.serveG.check()
defer sc.notePanic() defer sc.notePanic()
defer sc.conn.Close() defer sc.conn.Close()
@ -915,18 +937,18 @@ func (sc *serverConn) serve(conf http2Config) {
sc.writeFrame(FrameWriteRequest{ sc.writeFrame(FrameWriteRequest{
write: writeSettings{ write: writeSettings{
{SettingMaxFrameSize, conf.MaxReadFrameSize}, {SettingMaxFrameSize, sc.srv.maxReadFrameSize()},
{SettingMaxConcurrentStreams, sc.advMaxStreams}, {SettingMaxConcurrentStreams, sc.advMaxStreams},
{SettingMaxHeaderListSize, sc.maxHeaderListSize()}, {SettingMaxHeaderListSize, sc.maxHeaderListSize()},
{SettingHeaderTableSize, conf.MaxDecoderHeaderTableSize}, {SettingHeaderTableSize, sc.srv.maxDecoderHeaderTableSize()},
{SettingInitialWindowSize, uint32(sc.initialStreamRecvWindowSize)}, {SettingInitialWindowSize, uint32(sc.srv.initialStreamRecvWindowSize())},
}, },
}) })
sc.unackedSettings++ sc.unackedSettings++
// Each connection starts with initialWindowSize inflow tokens. // Each connection starts with initialWindowSize inflow tokens.
// If a higher value is configured, we add more tokens. // If a higher value is configured, we add more tokens.
if diff := conf.MaxUploadBufferPerConnection - initialWindowSize; diff > 0 { if diff := sc.srv.initialConnRecvWindowSize() - initialWindowSize; diff > 0 {
sc.sendWindowUpdate(nil, int(diff)) sc.sendWindowUpdate(nil, int(diff))
} }
@ -946,18 +968,11 @@ func (sc *serverConn) serve(conf http2Config) {
defer sc.idleTimer.Stop() defer sc.idleTimer.Stop()
} }
if conf.SendPingTimeout > 0 {
sc.readIdleTimeout = conf.SendPingTimeout
sc.readIdleTimer = sc.srv.afterFunc(conf.SendPingTimeout, sc.onReadIdleTimer)
defer sc.readIdleTimer.Stop()
}
go sc.readFrames() // closed by defer sc.conn.Close above go sc.readFrames() // closed by defer sc.conn.Close above
settingsTimer := sc.srv.afterFunc(firstSettingsTimeout, sc.onSettingsTimer) settingsTimer := sc.srv.afterFunc(firstSettingsTimeout, sc.onSettingsTimer)
defer settingsTimer.Stop() defer settingsTimer.Stop()
lastFrameTime := sc.srv.now()
loopNum := 0 loopNum := 0
for { for {
loopNum++ loopNum++
@ -971,7 +986,6 @@ func (sc *serverConn) serve(conf http2Config) {
case res := <-sc.wroteFrameCh: case res := <-sc.wroteFrameCh:
sc.wroteFrame(res) sc.wroteFrame(res)
case res := <-sc.readFrameCh: case res := <-sc.readFrameCh:
lastFrameTime = sc.srv.now()
// Process any written frames before reading new frames from the client since a // Process any written frames before reading new frames from the client since a
// written frame could have triggered a new stream to be started. // written frame could have triggered a new stream to be started.
if sc.writingFrameAsync { if sc.writingFrameAsync {
@ -1003,8 +1017,6 @@ func (sc *serverConn) serve(conf http2Config) {
case idleTimerMsg: case idleTimerMsg:
sc.vlogf("connection is idle") sc.vlogf("connection is idle")
sc.goAway(ErrCodeNo) sc.goAway(ErrCodeNo)
case readIdleTimerMsg:
sc.handlePingTimer(lastFrameTime)
case shutdownTimerMsg: case shutdownTimerMsg:
sc.vlogf("GOAWAY close timer fired; closing conn from %v", sc.conn.RemoteAddr()) sc.vlogf("GOAWAY close timer fired; closing conn from %v", sc.conn.RemoteAddr())
return return
@ -1027,7 +1039,7 @@ func (sc *serverConn) serve(conf http2Config) {
// If the peer is causing us to generate a lot of control frames, // If the peer is causing us to generate a lot of control frames,
// but not reading them from us, assume they are trying to make us // but not reading them from us, assume they are trying to make us
// run out of memory. // run out of memory.
if sc.queuedControlFrames > maxQueuedControlFrames { if sc.queuedControlFrames > sc.srv.maxQueuedControlFrames() {
sc.vlogf("http2: too many control frames in send queue, closing connection") sc.vlogf("http2: too many control frames in send queue, closing connection")
return return
} }
@ -1043,39 +1055,12 @@ func (sc *serverConn) serve(conf http2Config) {
} }
} }
func (sc *serverConn) handlePingTimer(lastFrameReadTime time.Time) {
if sc.pingSent {
sc.vlogf("timeout waiting for PING response")
sc.conn.Close()
return
}
pingAt := lastFrameReadTime.Add(sc.readIdleTimeout)
now := sc.srv.now()
if pingAt.After(now) {
// We received frames since arming the ping timer.
// Reset it for the next possible timeout.
sc.readIdleTimer.Reset(pingAt.Sub(now))
return
}
sc.pingSent = true
// Ignore crypto/rand.Read errors: It generally can't fail, and worse case if it does
// is we send a PING frame containing 0s.
_, _ = rand.Read(sc.sentPingData[:])
sc.writeFrame(FrameWriteRequest{
write: &writePing{data: sc.sentPingData},
})
sc.readIdleTimer.Reset(sc.pingTimeout)
}
type serverMessage int type serverMessage int
// Message values sent to serveMsgCh. // Message values sent to serveMsgCh.
var ( var (
settingsTimerMsg = new(serverMessage) settingsTimerMsg = new(serverMessage)
idleTimerMsg = new(serverMessage) idleTimerMsg = new(serverMessage)
readIdleTimerMsg = new(serverMessage)
shutdownTimerMsg = new(serverMessage) shutdownTimerMsg = new(serverMessage)
gracefulShutdownMsg = new(serverMessage) gracefulShutdownMsg = new(serverMessage)
handlerDoneMsg = new(serverMessage) handlerDoneMsg = new(serverMessage)
@ -1083,7 +1068,6 @@ func (sc *serverConn) handlePingTimer(lastFrameReadTime time.Time) {
func (sc *serverConn) onSettingsTimer() { sc.sendServeMsg(settingsTimerMsg) } func (sc *serverConn) onSettingsTimer() { sc.sendServeMsg(settingsTimerMsg) }
func (sc *serverConn) onIdleTimer() { sc.sendServeMsg(idleTimerMsg) } func (sc *serverConn) onIdleTimer() { sc.sendServeMsg(idleTimerMsg) }
func (sc *serverConn) onReadIdleTimer() { sc.sendServeMsg(readIdleTimerMsg) }
func (sc *serverConn) onShutdownTimer() { sc.sendServeMsg(shutdownTimerMsg) } func (sc *serverConn) onShutdownTimer() { sc.sendServeMsg(shutdownTimerMsg) }
func (sc *serverConn) sendServeMsg(msg interface{}) { func (sc *serverConn) sendServeMsg(msg interface{}) {
@ -1336,10 +1320,6 @@ func (sc *serverConn) wroteFrame(res frameWriteResult) {
sc.writingFrame = false sc.writingFrame = false
sc.writingFrameAsync = false sc.writingFrameAsync = false
if res.err != nil {
sc.conn.Close()
}
wr := res.wr wr := res.wr
if writeEndsStream(wr.write) { if writeEndsStream(wr.write) {
@ -1614,11 +1594,6 @@ func (sc *serverConn) processFrame(f Frame) error {
func (sc *serverConn) processPing(f *PingFrame) error { func (sc *serverConn) processPing(f *PingFrame) error {
sc.serveG.check() sc.serveG.check()
if f.IsAck() { if f.IsAck() {
if sc.pingSent && sc.sentPingData == f.Data {
// This is a response to a PING we sent.
sc.pingSent = false
sc.readIdleTimer.Reset(sc.readIdleTimeout)
}
// 6.7 PING: " An endpoint MUST NOT respond to PING frames // 6.7 PING: " An endpoint MUST NOT respond to PING frames
// containing this flag." // containing this flag."
return nil return nil
@ -2185,7 +2160,7 @@ func (sc *serverConn) newStream(id, pusherID uint32, state streamState) *stream
st.cw.Init() st.cw.Init()
st.flow.conn = &sc.flow // link to conn-level counter st.flow.conn = &sc.flow // link to conn-level counter
st.flow.add(sc.initialStreamSendWindowSize) st.flow.add(sc.initialStreamSendWindowSize)
st.inflow.init(sc.initialStreamRecvWindowSize) st.inflow.init(sc.srv.initialStreamRecvWindowSize())
if sc.hs.WriteTimeout > 0 { if sc.hs.WriteTimeout > 0 {
st.writeDeadline = sc.srv.afterFunc(sc.hs.WriteTimeout, st.onWriteTimeout) st.writeDeadline = sc.srv.afterFunc(sc.hs.WriteTimeout, st.onWriteTimeout)
} }
@ -3326,7 +3301,7 @@ func (sc *serverConn) countError(name string, err error) error {
if sc == nil || sc.srv == nil { if sc == nil || sc.srv == nil {
return err return err
} }
f := sc.countErrorFunc f := sc.srv.CountError
if f == nil { if f == nil {
return err return err
} }

View file

@ -25,6 +25,7 @@
"net/http" "net/http"
"net/http/httptrace" "net/http/httptrace"
"net/textproto" "net/textproto"
"os"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@ -226,26 +227,40 @@ func (t *Transport) contextWithTimeout(ctx context.Context, d time.Duration) (co
} }
func (t *Transport) maxHeaderListSize() uint32 { func (t *Transport) maxHeaderListSize() uint32 {
n := int64(t.MaxHeaderListSize) if t.MaxHeaderListSize == 0 {
if t.t1 != nil && t.t1.MaxResponseHeaderBytes != 0 {
n = t.t1.MaxResponseHeaderBytes
if n > 0 {
n = adjustHTTP1MaxHeaderSize(n)
}
}
if n <= 0 {
return 10 << 20 return 10 << 20
} }
if n >= 0xffffffff { if t.MaxHeaderListSize == 0xffffffff {
return 0 return 0
} }
return uint32(n) return t.MaxHeaderListSize
}
func (t *Transport) maxFrameReadSize() uint32 {
if t.MaxReadFrameSize == 0 {
return 0 // use the default provided by the peer
}
if t.MaxReadFrameSize < minMaxFrameSize {
return minMaxFrameSize
}
if t.MaxReadFrameSize > maxFrameSize {
return maxFrameSize
}
return t.MaxReadFrameSize
} }
func (t *Transport) disableCompression() bool { func (t *Transport) disableCompression() bool {
return t.DisableCompression || (t.t1 != nil && t.t1.DisableCompression) return t.DisableCompression || (t.t1 != nil && t.t1.DisableCompression)
} }
func (t *Transport) pingTimeout() time.Duration {
if t.PingTimeout == 0 {
return 15 * time.Second
}
return t.PingTimeout
}
// ConfigureTransport configures a net/http HTTP/1 Transport to use HTTP/2. // ConfigureTransport configures a net/http HTTP/1 Transport to use HTTP/2.
// It returns an error if t1 has already been HTTP/2-enabled. // It returns an error if t1 has already been HTTP/2-enabled.
// //
@ -355,14 +370,11 @@ type ClientConn struct {
lastActive time.Time lastActive time.Time
lastIdle time.Time // time last idle lastIdle time.Time // time last idle
// Settings from peer: (also guarded by wmu) // Settings from peer: (also guarded by wmu)
maxFrameSize uint32 maxFrameSize uint32
maxConcurrentStreams uint32 maxConcurrentStreams uint32
peerMaxHeaderListSize uint64 peerMaxHeaderListSize uint64
peerMaxHeaderTableSize uint32 peerMaxHeaderTableSize uint32
initialWindowSize uint32 initialWindowSize uint32
initialStreamRecvWindowSize int32
readIdleTimeout time.Duration
pingTimeout time.Duration
// reqHeaderMu is a 1-element semaphore channel controlling access to sending new requests. // reqHeaderMu is a 1-element semaphore channel controlling access to sending new requests.
// Write to reqHeaderMu to lock it, read from it to unlock. // Write to reqHeaderMu to lock it, read from it to unlock.
@ -487,7 +499,6 @@ func (cs *clientStream) closeReqBodyLocked() {
} }
type stickyErrWriter struct { type stickyErrWriter struct {
group synctestGroupInterface
conn net.Conn conn net.Conn
timeout time.Duration timeout time.Duration
err *error err *error
@ -497,9 +508,22 @@ func (sew stickyErrWriter) Write(p []byte) (n int, err error) {
if *sew.err != nil { if *sew.err != nil {
return 0, *sew.err return 0, *sew.err
} }
n, err = writeWithByteTimeout(sew.group, sew.conn, sew.timeout, p) for {
*sew.err = err if sew.timeout != 0 {
return n, err sew.conn.SetWriteDeadline(time.Now().Add(sew.timeout))
}
nn, err := sew.conn.Write(p[n:])
n += nn
if n < len(p) && nn > 0 && errors.Is(err, os.ErrDeadlineExceeded) {
// Keep extending the deadline so long as we're making progress.
continue
}
if sew.timeout != 0 {
sew.conn.SetWriteDeadline(time.Time{})
}
*sew.err = err
return n, err
}
} }
// noCachedConnError is the concrete type of ErrNoCachedConn, which // noCachedConnError is the concrete type of ErrNoCachedConn, which
@ -734,36 +758,44 @@ func (t *Transport) expectContinueTimeout() time.Duration {
return t.t1.ExpectContinueTimeout return t.t1.ExpectContinueTimeout
} }
func (t *Transport) maxDecoderHeaderTableSize() uint32 {
if v := t.MaxDecoderHeaderTableSize; v > 0 {
return v
}
return initialHeaderTableSize
}
func (t *Transport) maxEncoderHeaderTableSize() uint32 {
if v := t.MaxEncoderHeaderTableSize; v > 0 {
return v
}
return initialHeaderTableSize
}
func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) { func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
return t.newClientConn(c, t.disableKeepAlives()) return t.newClientConn(c, t.disableKeepAlives())
} }
func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, error) { func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, error) {
conf := configFromTransport(t)
cc := &ClientConn{ cc := &ClientConn{
t: t, t: t,
tconn: c, tconn: c,
readerDone: make(chan struct{}), readerDone: make(chan struct{}),
nextStreamID: 1, nextStreamID: 1,
maxFrameSize: 16 << 10, // spec default maxFrameSize: 16 << 10, // spec default
initialWindowSize: 65535, // spec default initialWindowSize: 65535, // spec default
initialStreamRecvWindowSize: conf.MaxUploadBufferPerStream, maxConcurrentStreams: initialMaxConcurrentStreams, // "infinite", per spec. Use a smaller value until we have received server settings.
maxConcurrentStreams: initialMaxConcurrentStreams, // "infinite", per spec. Use a smaller value until we have received server settings. peerMaxHeaderListSize: 0xffffffffffffffff, // "infinite", per spec. Use 2^64-1 instead.
peerMaxHeaderListSize: 0xffffffffffffffff, // "infinite", per spec. Use 2^64-1 instead. streams: make(map[uint32]*clientStream),
streams: make(map[uint32]*clientStream), singleUse: singleUse,
singleUse: singleUse, wantSettingsAck: true,
wantSettingsAck: true, pings: make(map[[8]byte]chan struct{}),
readIdleTimeout: conf.SendPingTimeout, reqHeaderMu: make(chan struct{}, 1),
pingTimeout: conf.PingTimeout,
pings: make(map[[8]byte]chan struct{}),
reqHeaderMu: make(chan struct{}, 1),
} }
var group synctestGroupInterface
if t.transportTestHooks != nil { if t.transportTestHooks != nil {
t.markNewGoroutine() t.markNewGoroutine()
t.transportTestHooks.newclientconn(cc) t.transportTestHooks.newclientconn(cc)
c = cc.tconn c = cc.tconn
group = t.group
} }
if VerboseLogs { if VerboseLogs {
t.vlogf("http2: Transport creating client conn %p to %v", cc, c.RemoteAddr()) t.vlogf("http2: Transport creating client conn %p to %v", cc, c.RemoteAddr())
@ -775,23 +807,24 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro
// TODO: adjust this writer size to account for frame size + // TODO: adjust this writer size to account for frame size +
// MTU + crypto/tls record padding. // MTU + crypto/tls record padding.
cc.bw = bufio.NewWriter(stickyErrWriter{ cc.bw = bufio.NewWriter(stickyErrWriter{
group: group,
conn: c, conn: c,
timeout: conf.WriteByteTimeout, timeout: t.WriteByteTimeout,
err: &cc.werr, err: &cc.werr,
}) })
cc.br = bufio.NewReader(c) cc.br = bufio.NewReader(c)
cc.fr = NewFramer(cc.bw, cc.br) cc.fr = NewFramer(cc.bw, cc.br)
cc.fr.SetMaxReadFrameSize(conf.MaxReadFrameSize) if t.maxFrameReadSize() != 0 {
cc.fr.SetMaxReadFrameSize(t.maxFrameReadSize())
}
if t.CountError != nil { if t.CountError != nil {
cc.fr.countError = t.CountError cc.fr.countError = t.CountError
} }
maxHeaderTableSize := conf.MaxDecoderHeaderTableSize maxHeaderTableSize := t.maxDecoderHeaderTableSize()
cc.fr.ReadMetaHeaders = hpack.NewDecoder(maxHeaderTableSize, nil) cc.fr.ReadMetaHeaders = hpack.NewDecoder(maxHeaderTableSize, nil)
cc.fr.MaxHeaderListSize = t.maxHeaderListSize() cc.fr.MaxHeaderListSize = t.maxHeaderListSize()
cc.henc = hpack.NewEncoder(&cc.hbuf) cc.henc = hpack.NewEncoder(&cc.hbuf)
cc.henc.SetMaxDynamicTableSizeLimit(conf.MaxEncoderHeaderTableSize) cc.henc.SetMaxDynamicTableSizeLimit(t.maxEncoderHeaderTableSize())
cc.peerMaxHeaderTableSize = initialHeaderTableSize cc.peerMaxHeaderTableSize = initialHeaderTableSize
if cs, ok := c.(connectionStater); ok { if cs, ok := c.(connectionStater); ok {
@ -801,9 +834,11 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro
initialSettings := []Setting{ initialSettings := []Setting{
{ID: SettingEnablePush, Val: 0}, {ID: SettingEnablePush, Val: 0},
{ID: SettingInitialWindowSize, Val: uint32(cc.initialStreamRecvWindowSize)}, {ID: SettingInitialWindowSize, Val: transportDefaultStreamFlow},
}
if max := t.maxFrameReadSize(); max != 0 {
initialSettings = append(initialSettings, Setting{ID: SettingMaxFrameSize, Val: max})
} }
initialSettings = append(initialSettings, Setting{ID: SettingMaxFrameSize, Val: conf.MaxReadFrameSize})
if max := t.maxHeaderListSize(); max != 0 { if max := t.maxHeaderListSize(); max != 0 {
initialSettings = append(initialSettings, Setting{ID: SettingMaxHeaderListSize, Val: max}) initialSettings = append(initialSettings, Setting{ID: SettingMaxHeaderListSize, Val: max})
} }
@ -813,8 +848,8 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro
cc.bw.Write(clientPreface) cc.bw.Write(clientPreface)
cc.fr.WriteSettings(initialSettings...) cc.fr.WriteSettings(initialSettings...)
cc.fr.WriteWindowUpdate(0, uint32(conf.MaxUploadBufferPerConnection)) cc.fr.WriteWindowUpdate(0, transportDefaultConnFlow)
cc.inflow.init(conf.MaxUploadBufferPerConnection + initialWindowSize) cc.inflow.init(transportDefaultConnFlow + initialWindowSize)
cc.bw.Flush() cc.bw.Flush()
if cc.werr != nil { if cc.werr != nil {
cc.Close() cc.Close()
@ -832,7 +867,7 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro
} }
func (cc *ClientConn) healthCheck() { func (cc *ClientConn) healthCheck() {
pingTimeout := cc.pingTimeout pingTimeout := cc.t.pingTimeout()
// We don't need to periodically ping in the health check, because the readLoop of ClientConn will // We don't need to periodically ping in the health check, because the readLoop of ClientConn will
// trigger the healthCheck again if there is no frame received. // trigger the healthCheck again if there is no frame received.
ctx, cancel := cc.t.contextWithTimeout(context.Background(), pingTimeout) ctx, cancel := cc.t.contextWithTimeout(context.Background(), pingTimeout)
@ -2164,7 +2199,7 @@ type resAndError struct {
func (cc *ClientConn) addStreamLocked(cs *clientStream) { func (cc *ClientConn) addStreamLocked(cs *clientStream) {
cs.flow.add(int32(cc.initialWindowSize)) cs.flow.add(int32(cc.initialWindowSize))
cs.flow.setConnFlow(&cc.flow) cs.flow.setConnFlow(&cc.flow)
cs.inflow.init(cc.initialStreamRecvWindowSize) cs.inflow.init(transportDefaultStreamFlow)
cs.ID = cc.nextStreamID cs.ID = cc.nextStreamID
cc.nextStreamID += 2 cc.nextStreamID += 2
cc.streams[cs.ID] = cs cc.streams[cs.ID] = cs
@ -2310,7 +2345,7 @@ func (cc *ClientConn) countReadFrameError(err error) {
func (rl *clientConnReadLoop) run() error { func (rl *clientConnReadLoop) run() error {
cc := rl.cc cc := rl.cc
gotSettings := false gotSettings := false
readIdleTimeout := cc.readIdleTimeout readIdleTimeout := cc.t.ReadIdleTimeout
var t timer var t timer
if readIdleTimeout != 0 { if readIdleTimeout != 0 {
t = cc.t.afterFunc(readIdleTimeout, cc.healthCheck) t = cc.t.afterFunc(readIdleTimeout, cc.healthCheck)

View file

@ -131,16 +131,6 @@ func (se StreamError) writeFrame(ctx writeContext) error {
func (se StreamError) staysWithinBuffer(max int) bool { return frameHeaderLen+4 <= max } func (se StreamError) staysWithinBuffer(max int) bool { return frameHeaderLen+4 <= max }
type writePing struct {
data [8]byte
}
func (w writePing) writeFrame(ctx writeContext) error {
return ctx.Framer().WritePing(false, w.data)
}
func (w writePing) staysWithinBuffer(max int) bool { return frameHeaderLen+len(w.data) <= max }
type writePingAck struct{ pf *PingFrame } type writePingAck struct{ pf *PingFrame }
func (w writePingAck) writeFrame(ctx writeContext) error { func (w writePingAck) writeFrame(ctx writeContext) error {

View file

@ -156,7 +156,7 @@ from the generated architecture-specific files listed below, and merge these
into a common file for each OS. into a common file for each OS.
The merge is performed in the following steps: The merge is performed in the following steps:
1. Construct the set of common code that is identical in all architecture-specific files. 1. Construct the set of common code that is idential in all architecture-specific files.
2. Write this common code to the merged file. 2. Write this common code to the merged file.
3. Remove the common code from all architecture-specific files. 3. Remove the common code from all architecture-specific files.

View file

@ -656,7 +656,7 @@ errors=$(
signals=$( signals=$(
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags | echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' | awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
grep -E -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT|SIGMAX64)' | grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT\|SIGMAX64' |
sort sort
) )
@ -666,7 +666,7 @@ echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
sort >_error.grep sort >_error.grep
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags | echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' | awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
grep -E -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT|SIGMAX64)' | grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT\|SIGMAX64' |
sort >_signal.grep sort >_signal.grep
echo '// mkerrors.sh' "$@" echo '// mkerrors.sh' "$@"

View file

@ -360,7 +360,7 @@ func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int,
var status _C_int var status _C_int
var r Pid_t var r Pid_t
err = ERESTART err = ERESTART
// AIX wait4 may return with ERESTART errno, while the process is still // AIX wait4 may return with ERESTART errno, while the processus is still
// active. // active.
for err == ERESTART { for err == ERESTART {
r, err = wait4(Pid_t(pid), &status, options, rusage) r, err = wait4(Pid_t(pid), &status, options, rusage)

View file

@ -1295,48 +1295,6 @@ func GetsockoptTCPInfo(fd, level, opt int) (*TCPInfo, error) {
return &value, err return &value, err
} }
// GetsockoptTCPCCVegasInfo returns algorithm specific congestion control information for a socket using the "vegas"
// algorithm.
//
// The socket's congestion control algorighm can be retrieved via [GetsockoptString] with the [TCP_CONGESTION] option:
//
// algo, err := unix.GetsockoptString(fd, unix.IPPROTO_TCP, unix.TCP_CONGESTION)
func GetsockoptTCPCCVegasInfo(fd, level, opt int) (*TCPVegasInfo, error) {
var value [SizeofTCPCCInfo / 4]uint32 // ensure proper alignment
vallen := _Socklen(SizeofTCPCCInfo)
err := getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)
out := (*TCPVegasInfo)(unsafe.Pointer(&value[0]))
return out, err
}
// GetsockoptTCPCCDCTCPInfo returns algorithm specific congestion control information for a socket using the "dctp"
// algorithm.
//
// The socket's congestion control algorighm can be retrieved via [GetsockoptString] with the [TCP_CONGESTION] option:
//
// algo, err := unix.GetsockoptString(fd, unix.IPPROTO_TCP, unix.TCP_CONGESTION)
func GetsockoptTCPCCDCTCPInfo(fd, level, opt int) (*TCPDCTCPInfo, error) {
var value [SizeofTCPCCInfo / 4]uint32 // ensure proper alignment
vallen := _Socklen(SizeofTCPCCInfo)
err := getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)
out := (*TCPDCTCPInfo)(unsafe.Pointer(&value[0]))
return out, err
}
// GetsockoptTCPCCBBRInfo returns algorithm specific congestion control information for a socket using the "bbr"
// algorithm.
//
// The socket's congestion control algorighm can be retrieved via [GetsockoptString] with the [TCP_CONGESTION] option:
//
// algo, err := unix.GetsockoptString(fd, unix.IPPROTO_TCP, unix.TCP_CONGESTION)
func GetsockoptTCPCCBBRInfo(fd, level, opt int) (*TCPBBRInfo, error) {
var value [SizeofTCPCCInfo / 4]uint32 // ensure proper alignment
vallen := _Socklen(SizeofTCPCCInfo)
err := getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)
out := (*TCPBBRInfo)(unsafe.Pointer(&value[0]))
return out, err
}
// GetsockoptString returns the string value of the socket option opt for the // GetsockoptString returns the string value of the socket option opt for the
// socket associated with fd at the given socket level. // socket associated with fd at the given socket level.
func GetsockoptString(fd, level, opt int) (string, error) { func GetsockoptString(fd, level, opt int) (string, error) {
@ -2001,26 +1959,7 @@ func Getpgrp() (pid int) {
//sysnb Getpid() (pid int) //sysnb Getpid() (pid int)
//sysnb Getppid() (ppid int) //sysnb Getppid() (ppid int)
//sys Getpriority(which int, who int) (prio int, err error) //sys Getpriority(which int, who int) (prio int, err error)
//sys Getrandom(buf []byte, flags int) (n int, err error)
func Getrandom(buf []byte, flags int) (n int, err error) {
vdsoRet, supported := vgetrandom(buf, uint32(flags))
if supported {
if vdsoRet < 0 {
return 0, errnoErr(syscall.Errno(-vdsoRet))
}
return vdsoRet, nil
}
var p *byte
if len(buf) > 0 {
p = &buf[0]
}
r, _, e := Syscall(SYS_GETRANDOM, uintptr(unsafe.Pointer(p)), uintptr(len(buf)), uintptr(flags))
if e != 0 {
return 0, errnoErr(e)
}
return int(r), nil
}
//sysnb Getrusage(who int, rusage *Rusage) (err error) //sysnb Getrusage(who int, rusage *Rusage) (err error)
//sysnb Getsid(pid int) (sid int, err error) //sysnb Getsid(pid int) (sid int, err error)
//sysnb Gettid() (tid int) //sysnb Gettid() (tid int)

View file

@ -182,5 +182,3 @@ func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error
} }
return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags) return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags)
} }
const SYS_FSTATAT = SYS_NEWFSTATAT

View file

@ -214,5 +214,3 @@ func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error
} }
return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags) return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags)
} }
const SYS_FSTATAT = SYS_NEWFSTATAT

View file

@ -187,5 +187,3 @@ func RISCVHWProbe(pairs []RISCVHWProbePairs, set *CPUSet, flags uint) (err error
} }
return riscvHWProbe(pairs, setSize, set, flags) return riscvHWProbe(pairs, setSize, set, flags)
} }
const SYS_FSTATAT = SYS_NEWFSTATAT

View file

@ -1,13 +0,0 @@
// Copyright 2024 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.
//go:build linux && go1.24
package unix
import _ "unsafe"
//go:linkname vgetrandom runtime.vgetrandom
//go:noescape
func vgetrandom(p []byte, flags uint32) (ret int, supported bool)

View file

@ -1,11 +0,0 @@
// Copyright 2024 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.
//go:build !linux || !go1.24
package unix
func vgetrandom(p []byte, flags uint32) (ret int, supported bool) {
return -1, false
}

View file

@ -495,7 +495,6 @@
BPF_F_TEST_REG_INVARIANTS = 0x80 BPF_F_TEST_REG_INVARIANTS = 0x80
BPF_F_TEST_RND_HI32 = 0x4 BPF_F_TEST_RND_HI32 = 0x4
BPF_F_TEST_RUN_ON_CPU = 0x1 BPF_F_TEST_RUN_ON_CPU = 0x1
BPF_F_TEST_SKB_CHECKSUM_COMPLETE = 0x4
BPF_F_TEST_STATE_FREQ = 0x8 BPF_F_TEST_STATE_FREQ = 0x8
BPF_F_TEST_XDP_LIVE_FRAMES = 0x2 BPF_F_TEST_XDP_LIVE_FRAMES = 0x2
BPF_F_XDP_DEV_BOUND_ONLY = 0x40 BPF_F_XDP_DEV_BOUND_ONLY = 0x40
@ -1923,7 +1922,6 @@
MNT_EXPIRE = 0x4 MNT_EXPIRE = 0x4
MNT_FORCE = 0x1 MNT_FORCE = 0x1
MNT_ID_REQ_SIZE_VER0 = 0x18 MNT_ID_REQ_SIZE_VER0 = 0x18
MNT_ID_REQ_SIZE_VER1 = 0x20
MODULE_INIT_COMPRESSED_FILE = 0x4 MODULE_INIT_COMPRESSED_FILE = 0x4
MODULE_INIT_IGNORE_MODVERSIONS = 0x1 MODULE_INIT_IGNORE_MODVERSIONS = 0x1
MODULE_INIT_IGNORE_VERMAGIC = 0x2 MODULE_INIT_IGNORE_VERMAGIC = 0x2
@ -2189,7 +2187,7 @@
NFT_REG_SIZE = 0x10 NFT_REG_SIZE = 0x10
NFT_REJECT_ICMPX_MAX = 0x3 NFT_REJECT_ICMPX_MAX = 0x3
NFT_RT_MAX = 0x4 NFT_RT_MAX = 0x4
NFT_SECMARK_CTX_MAXLEN = 0x1000 NFT_SECMARK_CTX_MAXLEN = 0x100
NFT_SET_MAXNAMELEN = 0x100 NFT_SET_MAXNAMELEN = 0x100
NFT_SOCKET_MAX = 0x3 NFT_SOCKET_MAX = 0x3
NFT_TABLE_F_MASK = 0x7 NFT_TABLE_F_MASK = 0x7
@ -2358,11 +2356,9 @@
PERF_MEM_LVLNUM_IO = 0xa PERF_MEM_LVLNUM_IO = 0xa
PERF_MEM_LVLNUM_L1 = 0x1 PERF_MEM_LVLNUM_L1 = 0x1
PERF_MEM_LVLNUM_L2 = 0x2 PERF_MEM_LVLNUM_L2 = 0x2
PERF_MEM_LVLNUM_L2_MHB = 0x5
PERF_MEM_LVLNUM_L3 = 0x3 PERF_MEM_LVLNUM_L3 = 0x3
PERF_MEM_LVLNUM_L4 = 0x4 PERF_MEM_LVLNUM_L4 = 0x4
PERF_MEM_LVLNUM_LFB = 0xc PERF_MEM_LVLNUM_LFB = 0xc
PERF_MEM_LVLNUM_MSC = 0x6
PERF_MEM_LVLNUM_NA = 0xf PERF_MEM_LVLNUM_NA = 0xf
PERF_MEM_LVLNUM_PMEM = 0xe PERF_MEM_LVLNUM_PMEM = 0xe
PERF_MEM_LVLNUM_RAM = 0xd PERF_MEM_LVLNUM_RAM = 0xd
@ -2435,7 +2431,6 @@
PRIO_PGRP = 0x1 PRIO_PGRP = 0x1
PRIO_PROCESS = 0x0 PRIO_PROCESS = 0x0
PRIO_USER = 0x2 PRIO_USER = 0x2
PROCFS_IOCTL_MAGIC = 'f'
PROC_SUPER_MAGIC = 0x9fa0 PROC_SUPER_MAGIC = 0x9fa0
PROT_EXEC = 0x4 PROT_EXEC = 0x4
PROT_GROWSDOWN = 0x1000000 PROT_GROWSDOWN = 0x1000000
@ -2938,12 +2933,11 @@
RUSAGE_SELF = 0x0 RUSAGE_SELF = 0x0
RUSAGE_THREAD = 0x1 RUSAGE_THREAD = 0x1
RWF_APPEND = 0x10 RWF_APPEND = 0x10
RWF_ATOMIC = 0x40
RWF_DSYNC = 0x2 RWF_DSYNC = 0x2
RWF_HIPRI = 0x1 RWF_HIPRI = 0x1
RWF_NOAPPEND = 0x20 RWF_NOAPPEND = 0x20
RWF_NOWAIT = 0x8 RWF_NOWAIT = 0x8
RWF_SUPPORTED = 0x7f RWF_SUPPORTED = 0x3f
RWF_SYNC = 0x4 RWF_SYNC = 0x4
RWF_WRITE_LIFE_NOT_SET = 0x0 RWF_WRITE_LIFE_NOT_SET = 0x0
SCHED_BATCH = 0x3 SCHED_BATCH = 0x3
@ -3216,7 +3210,6 @@
STATX_ATTR_MOUNT_ROOT = 0x2000 STATX_ATTR_MOUNT_ROOT = 0x2000
STATX_ATTR_NODUMP = 0x40 STATX_ATTR_NODUMP = 0x40
STATX_ATTR_VERITY = 0x100000 STATX_ATTR_VERITY = 0x100000
STATX_ATTR_WRITE_ATOMIC = 0x400000
STATX_BASIC_STATS = 0x7ff STATX_BASIC_STATS = 0x7ff
STATX_BLOCKS = 0x400 STATX_BLOCKS = 0x400
STATX_BTIME = 0x800 STATX_BTIME = 0x800
@ -3233,7 +3226,6 @@
STATX_SUBVOL = 0x8000 STATX_SUBVOL = 0x8000
STATX_TYPE = 0x1 STATX_TYPE = 0x1
STATX_UID = 0x8 STATX_UID = 0x8
STATX_WRITE_ATOMIC = 0x10000
STATX__RESERVED = 0x80000000 STATX__RESERVED = 0x80000000
SYNC_FILE_RANGE_WAIT_AFTER = 0x4 SYNC_FILE_RANGE_WAIT_AFTER = 0x4
SYNC_FILE_RANGE_WAIT_BEFORE = 0x1 SYNC_FILE_RANGE_WAIT_BEFORE = 0x1
@ -3632,7 +3624,6 @@
XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000 XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000
XDP_UMEM_PGOFF_FILL_RING = 0x100000000 XDP_UMEM_PGOFF_FILL_RING = 0x100000000
XDP_UMEM_REG = 0x4 XDP_UMEM_REG = 0x4
XDP_UMEM_TX_METADATA_LEN = 0x4
XDP_UMEM_TX_SW_CSUM = 0x2 XDP_UMEM_TX_SW_CSUM = 0x2
XDP_UMEM_UNALIGNED_CHUNK_FLAG = 0x1 XDP_UMEM_UNALIGNED_CHUNK_FLAG = 0x1
XDP_USE_NEED_WAKEUP = 0x8 XDP_USE_NEED_WAKEUP = 0x8

View file

@ -153,14 +153,9 @@
NFDBITS = 0x20 NFDBITS = 0x20
NLDLY = 0x100 NLDLY = 0x100
NOFLSH = 0x80 NOFLSH = 0x80
NS_GET_MNTNS_ID = 0x8008b705
NS_GET_NSTYPE = 0xb703 NS_GET_NSTYPE = 0xb703
NS_GET_OWNER_UID = 0xb704 NS_GET_OWNER_UID = 0xb704
NS_GET_PARENT = 0xb702 NS_GET_PARENT = 0xb702
NS_GET_PID_FROM_PIDNS = 0x8004b706
NS_GET_PID_IN_PIDNS = 0x8004b708
NS_GET_TGID_FROM_PIDNS = 0x8004b707
NS_GET_TGID_IN_PIDNS = 0x8004b709
NS_GET_USERNS = 0xb701 NS_GET_USERNS = 0xb701
OLCUC = 0x2 OLCUC = 0x2
ONLCR = 0x4 ONLCR = 0x4

View file

@ -153,14 +153,9 @@
NFDBITS = 0x40 NFDBITS = 0x40
NLDLY = 0x100 NLDLY = 0x100
NOFLSH = 0x80 NOFLSH = 0x80
NS_GET_MNTNS_ID = 0x8008b705
NS_GET_NSTYPE = 0xb703 NS_GET_NSTYPE = 0xb703
NS_GET_OWNER_UID = 0xb704 NS_GET_OWNER_UID = 0xb704
NS_GET_PARENT = 0xb702 NS_GET_PARENT = 0xb702
NS_GET_PID_FROM_PIDNS = 0x8004b706
NS_GET_PID_IN_PIDNS = 0x8004b708
NS_GET_TGID_FROM_PIDNS = 0x8004b707
NS_GET_TGID_IN_PIDNS = 0x8004b709
NS_GET_USERNS = 0xb701 NS_GET_USERNS = 0xb701
OLCUC = 0x2 OLCUC = 0x2
ONLCR = 0x4 ONLCR = 0x4

View file

@ -150,14 +150,9 @@
NFDBITS = 0x20 NFDBITS = 0x20
NLDLY = 0x100 NLDLY = 0x100
NOFLSH = 0x80 NOFLSH = 0x80
NS_GET_MNTNS_ID = 0x8008b705
NS_GET_NSTYPE = 0xb703 NS_GET_NSTYPE = 0xb703
NS_GET_OWNER_UID = 0xb704 NS_GET_OWNER_UID = 0xb704
NS_GET_PARENT = 0xb702 NS_GET_PARENT = 0xb702
NS_GET_PID_FROM_PIDNS = 0x8004b706
NS_GET_PID_IN_PIDNS = 0x8004b708
NS_GET_TGID_FROM_PIDNS = 0x8004b707
NS_GET_TGID_IN_PIDNS = 0x8004b709
NS_GET_USERNS = 0xb701 NS_GET_USERNS = 0xb701
OLCUC = 0x2 OLCUC = 0x2
ONLCR = 0x4 ONLCR = 0x4

View file

@ -154,14 +154,9 @@
NFDBITS = 0x40 NFDBITS = 0x40
NLDLY = 0x100 NLDLY = 0x100
NOFLSH = 0x80 NOFLSH = 0x80
NS_GET_MNTNS_ID = 0x8008b705
NS_GET_NSTYPE = 0xb703 NS_GET_NSTYPE = 0xb703
NS_GET_OWNER_UID = 0xb704 NS_GET_OWNER_UID = 0xb704
NS_GET_PARENT = 0xb702 NS_GET_PARENT = 0xb702
NS_GET_PID_FROM_PIDNS = 0x8004b706
NS_GET_PID_IN_PIDNS = 0x8004b708
NS_GET_TGID_FROM_PIDNS = 0x8004b707
NS_GET_TGID_IN_PIDNS = 0x8004b709
NS_GET_USERNS = 0xb701 NS_GET_USERNS = 0xb701
OLCUC = 0x2 OLCUC = 0x2
ONLCR = 0x4 ONLCR = 0x4

View file

@ -154,14 +154,9 @@
NFDBITS = 0x40 NFDBITS = 0x40
NLDLY = 0x100 NLDLY = 0x100
NOFLSH = 0x80 NOFLSH = 0x80
NS_GET_MNTNS_ID = 0x8008b705
NS_GET_NSTYPE = 0xb703 NS_GET_NSTYPE = 0xb703
NS_GET_OWNER_UID = 0xb704 NS_GET_OWNER_UID = 0xb704
NS_GET_PARENT = 0xb702 NS_GET_PARENT = 0xb702
NS_GET_PID_FROM_PIDNS = 0x8004b706
NS_GET_PID_IN_PIDNS = 0x8004b708
NS_GET_TGID_FROM_PIDNS = 0x8004b707
NS_GET_TGID_IN_PIDNS = 0x8004b709
NS_GET_USERNS = 0xb701 NS_GET_USERNS = 0xb701
OLCUC = 0x2 OLCUC = 0x2
ONLCR = 0x4 ONLCR = 0x4

View file

@ -150,14 +150,9 @@
NFDBITS = 0x20 NFDBITS = 0x20
NLDLY = 0x100 NLDLY = 0x100
NOFLSH = 0x80 NOFLSH = 0x80
NS_GET_MNTNS_ID = 0x4008b705
NS_GET_NSTYPE = 0x2000b703 NS_GET_NSTYPE = 0x2000b703
NS_GET_OWNER_UID = 0x2000b704 NS_GET_OWNER_UID = 0x2000b704
NS_GET_PARENT = 0x2000b702 NS_GET_PARENT = 0x2000b702
NS_GET_PID_FROM_PIDNS = 0x4004b706
NS_GET_PID_IN_PIDNS = 0x4004b708
NS_GET_TGID_FROM_PIDNS = 0x4004b707
NS_GET_TGID_IN_PIDNS = 0x4004b709
NS_GET_USERNS = 0x2000b701 NS_GET_USERNS = 0x2000b701
OLCUC = 0x2 OLCUC = 0x2
ONLCR = 0x4 ONLCR = 0x4

View file

@ -150,14 +150,9 @@
NFDBITS = 0x40 NFDBITS = 0x40
NLDLY = 0x100 NLDLY = 0x100
NOFLSH = 0x80 NOFLSH = 0x80
NS_GET_MNTNS_ID = 0x4008b705
NS_GET_NSTYPE = 0x2000b703 NS_GET_NSTYPE = 0x2000b703
NS_GET_OWNER_UID = 0x2000b704 NS_GET_OWNER_UID = 0x2000b704
NS_GET_PARENT = 0x2000b702 NS_GET_PARENT = 0x2000b702
NS_GET_PID_FROM_PIDNS = 0x4004b706
NS_GET_PID_IN_PIDNS = 0x4004b708
NS_GET_TGID_FROM_PIDNS = 0x4004b707
NS_GET_TGID_IN_PIDNS = 0x4004b709
NS_GET_USERNS = 0x2000b701 NS_GET_USERNS = 0x2000b701
OLCUC = 0x2 OLCUC = 0x2
ONLCR = 0x4 ONLCR = 0x4

View file

@ -150,14 +150,9 @@
NFDBITS = 0x40 NFDBITS = 0x40
NLDLY = 0x100 NLDLY = 0x100
NOFLSH = 0x80 NOFLSH = 0x80
NS_GET_MNTNS_ID = 0x4008b705
NS_GET_NSTYPE = 0x2000b703 NS_GET_NSTYPE = 0x2000b703
NS_GET_OWNER_UID = 0x2000b704 NS_GET_OWNER_UID = 0x2000b704
NS_GET_PARENT = 0x2000b702 NS_GET_PARENT = 0x2000b702
NS_GET_PID_FROM_PIDNS = 0x4004b706
NS_GET_PID_IN_PIDNS = 0x4004b708
NS_GET_TGID_FROM_PIDNS = 0x4004b707
NS_GET_TGID_IN_PIDNS = 0x4004b709
NS_GET_USERNS = 0x2000b701 NS_GET_USERNS = 0x2000b701
OLCUC = 0x2 OLCUC = 0x2
ONLCR = 0x4 ONLCR = 0x4

View file

@ -150,14 +150,9 @@
NFDBITS = 0x20 NFDBITS = 0x20
NLDLY = 0x100 NLDLY = 0x100
NOFLSH = 0x80 NOFLSH = 0x80
NS_GET_MNTNS_ID = 0x4008b705
NS_GET_NSTYPE = 0x2000b703 NS_GET_NSTYPE = 0x2000b703
NS_GET_OWNER_UID = 0x2000b704 NS_GET_OWNER_UID = 0x2000b704
NS_GET_PARENT = 0x2000b702 NS_GET_PARENT = 0x2000b702
NS_GET_PID_FROM_PIDNS = 0x4004b706
NS_GET_PID_IN_PIDNS = 0x4004b708
NS_GET_TGID_FROM_PIDNS = 0x4004b707
NS_GET_TGID_IN_PIDNS = 0x4004b709
NS_GET_USERNS = 0x2000b701 NS_GET_USERNS = 0x2000b701
OLCUC = 0x2 OLCUC = 0x2
ONLCR = 0x4 ONLCR = 0x4

View file

@ -152,14 +152,9 @@
NL3 = 0x300 NL3 = 0x300
NLDLY = 0x300 NLDLY = 0x300
NOFLSH = 0x80000000 NOFLSH = 0x80000000
NS_GET_MNTNS_ID = 0x4008b705
NS_GET_NSTYPE = 0x2000b703 NS_GET_NSTYPE = 0x2000b703
NS_GET_OWNER_UID = 0x2000b704 NS_GET_OWNER_UID = 0x2000b704
NS_GET_PARENT = 0x2000b702 NS_GET_PARENT = 0x2000b702
NS_GET_PID_FROM_PIDNS = 0x4004b706
NS_GET_PID_IN_PIDNS = 0x4004b708
NS_GET_TGID_FROM_PIDNS = 0x4004b707
NS_GET_TGID_IN_PIDNS = 0x4004b709
NS_GET_USERNS = 0x2000b701 NS_GET_USERNS = 0x2000b701
OLCUC = 0x4 OLCUC = 0x4
ONLCR = 0x2 ONLCR = 0x2

View file

@ -152,14 +152,9 @@
NL3 = 0x300 NL3 = 0x300
NLDLY = 0x300 NLDLY = 0x300
NOFLSH = 0x80000000 NOFLSH = 0x80000000
NS_GET_MNTNS_ID = 0x4008b705
NS_GET_NSTYPE = 0x2000b703 NS_GET_NSTYPE = 0x2000b703
NS_GET_OWNER_UID = 0x2000b704 NS_GET_OWNER_UID = 0x2000b704
NS_GET_PARENT = 0x2000b702 NS_GET_PARENT = 0x2000b702
NS_GET_PID_FROM_PIDNS = 0x4004b706
NS_GET_PID_IN_PIDNS = 0x4004b708
NS_GET_TGID_FROM_PIDNS = 0x4004b707
NS_GET_TGID_IN_PIDNS = 0x4004b709
NS_GET_USERNS = 0x2000b701 NS_GET_USERNS = 0x2000b701
OLCUC = 0x4 OLCUC = 0x4
ONLCR = 0x2 ONLCR = 0x2

View file

@ -152,14 +152,9 @@
NL3 = 0x300 NL3 = 0x300
NLDLY = 0x300 NLDLY = 0x300
NOFLSH = 0x80000000 NOFLSH = 0x80000000
NS_GET_MNTNS_ID = 0x4008b705
NS_GET_NSTYPE = 0x2000b703 NS_GET_NSTYPE = 0x2000b703
NS_GET_OWNER_UID = 0x2000b704 NS_GET_OWNER_UID = 0x2000b704
NS_GET_PARENT = 0x2000b702 NS_GET_PARENT = 0x2000b702
NS_GET_PID_FROM_PIDNS = 0x4004b706
NS_GET_PID_IN_PIDNS = 0x4004b708
NS_GET_TGID_FROM_PIDNS = 0x4004b707
NS_GET_TGID_IN_PIDNS = 0x4004b709
NS_GET_USERNS = 0x2000b701 NS_GET_USERNS = 0x2000b701
OLCUC = 0x4 OLCUC = 0x4
ONLCR = 0x2 ONLCR = 0x2

View file

@ -150,14 +150,9 @@
NFDBITS = 0x40 NFDBITS = 0x40
NLDLY = 0x100 NLDLY = 0x100
NOFLSH = 0x80 NOFLSH = 0x80
NS_GET_MNTNS_ID = 0x8008b705
NS_GET_NSTYPE = 0xb703 NS_GET_NSTYPE = 0xb703
NS_GET_OWNER_UID = 0xb704 NS_GET_OWNER_UID = 0xb704
NS_GET_PARENT = 0xb702 NS_GET_PARENT = 0xb702
NS_GET_PID_FROM_PIDNS = 0x8004b706
NS_GET_PID_IN_PIDNS = 0x8004b708
NS_GET_TGID_FROM_PIDNS = 0x8004b707
NS_GET_TGID_IN_PIDNS = 0x8004b709
NS_GET_USERNS = 0xb701 NS_GET_USERNS = 0xb701
OLCUC = 0x2 OLCUC = 0x2
ONLCR = 0x4 ONLCR = 0x4

View file

@ -150,14 +150,9 @@
NFDBITS = 0x40 NFDBITS = 0x40
NLDLY = 0x100 NLDLY = 0x100
NOFLSH = 0x80 NOFLSH = 0x80
NS_GET_MNTNS_ID = 0x8008b705
NS_GET_NSTYPE = 0xb703 NS_GET_NSTYPE = 0xb703
NS_GET_OWNER_UID = 0xb704 NS_GET_OWNER_UID = 0xb704
NS_GET_PARENT = 0xb702 NS_GET_PARENT = 0xb702
NS_GET_PID_FROM_PIDNS = 0x8004b706
NS_GET_PID_IN_PIDNS = 0x8004b708
NS_GET_TGID_FROM_PIDNS = 0x8004b707
NS_GET_TGID_IN_PIDNS = 0x8004b709
NS_GET_USERNS = 0xb701 NS_GET_USERNS = 0xb701
OLCUC = 0x2 OLCUC = 0x2
ONLCR = 0x4 ONLCR = 0x4

View file

@ -155,14 +155,9 @@
NFDBITS = 0x40 NFDBITS = 0x40
NLDLY = 0x100 NLDLY = 0x100
NOFLSH = 0x80 NOFLSH = 0x80
NS_GET_MNTNS_ID = 0x4008b705
NS_GET_NSTYPE = 0x2000b703 NS_GET_NSTYPE = 0x2000b703
NS_GET_OWNER_UID = 0x2000b704 NS_GET_OWNER_UID = 0x2000b704
NS_GET_PARENT = 0x2000b702 NS_GET_PARENT = 0x2000b702
NS_GET_PID_FROM_PIDNS = 0x4004b706
NS_GET_PID_IN_PIDNS = 0x4004b708
NS_GET_TGID_FROM_PIDNS = 0x4004b707
NS_GET_TGID_IN_PIDNS = 0x4004b709
NS_GET_USERNS = 0x2000b701 NS_GET_USERNS = 0x2000b701
OLCUC = 0x2 OLCUC = 0x2
ONLCR = 0x4 ONLCR = 0x4

View file

@ -971,6 +971,23 @@ func Getpriority(which int, who int) (prio int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getrandom(buf []byte, flags int) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_GETRANDOM, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getrusage(who int, rusage *Rusage) (err error) { func Getrusage(who int, rusage *Rusage) (err error) {
_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
if e1 != 0 { if e1 != 0 {

View file

@ -341,7 +341,6 @@
SYS_STATX = 332 SYS_STATX = 332
SYS_IO_PGETEVENTS = 333 SYS_IO_PGETEVENTS = 333
SYS_RSEQ = 334 SYS_RSEQ = 334
SYS_URETPROBE = 335
SYS_PIDFD_SEND_SIGNAL = 424 SYS_PIDFD_SEND_SIGNAL = 424
SYS_IO_URING_SETUP = 425 SYS_IO_URING_SETUP = 425
SYS_IO_URING_ENTER = 426 SYS_IO_URING_ENTER = 426

View file

@ -85,7 +85,7 @@
SYS_SPLICE = 76 SYS_SPLICE = 76
SYS_TEE = 77 SYS_TEE = 77
SYS_READLINKAT = 78 SYS_READLINKAT = 78
SYS_NEWFSTATAT = 79 SYS_FSTATAT = 79
SYS_FSTAT = 80 SYS_FSTAT = 80
SYS_SYNC = 81 SYS_SYNC = 81
SYS_FSYNC = 82 SYS_FSYNC = 82

View file

@ -84,8 +84,6 @@
SYS_SPLICE = 76 SYS_SPLICE = 76
SYS_TEE = 77 SYS_TEE = 77
SYS_READLINKAT = 78 SYS_READLINKAT = 78
SYS_NEWFSTATAT = 79
SYS_FSTAT = 80
SYS_SYNC = 81 SYS_SYNC = 81
SYS_FSYNC = 82 SYS_FSYNC = 82
SYS_FDATASYNC = 83 SYS_FDATASYNC = 83

View file

@ -84,7 +84,7 @@
SYS_SPLICE = 76 SYS_SPLICE = 76
SYS_TEE = 77 SYS_TEE = 77
SYS_READLINKAT = 78 SYS_READLINKAT = 78
SYS_NEWFSTATAT = 79 SYS_FSTATAT = 79
SYS_FSTAT = 80 SYS_FSTAT = 80
SYS_SYNC = 81 SYS_SYNC = 81
SYS_FSYNC = 82 SYS_FSYNC = 82

View file

@ -87,35 +87,31 @@ type StatxTimestamp struct {
} }
type Statx_t struct { type Statx_t struct {
Mask uint32 Mask uint32
Blksize uint32 Blksize uint32
Attributes uint64 Attributes uint64
Nlink uint32 Nlink uint32
Uid uint32 Uid uint32
Gid uint32 Gid uint32
Mode uint16 Mode uint16
_ [1]uint16 _ [1]uint16
Ino uint64 Ino uint64
Size uint64 Size uint64
Blocks uint64 Blocks uint64
Attributes_mask uint64 Attributes_mask uint64
Atime StatxTimestamp Atime StatxTimestamp
Btime StatxTimestamp Btime StatxTimestamp
Ctime StatxTimestamp Ctime StatxTimestamp
Mtime StatxTimestamp Mtime StatxTimestamp
Rdev_major uint32 Rdev_major uint32
Rdev_minor uint32 Rdev_minor uint32
Dev_major uint32 Dev_major uint32
Dev_minor uint32 Dev_minor uint32
Mnt_id uint64 Mnt_id uint64
Dio_mem_align uint32 Dio_mem_align uint32
Dio_offset_align uint32 Dio_offset_align uint32
Subvol uint64 Subvol uint64
Atomic_write_unit_min uint32 _ [11]uint64
Atomic_write_unit_max uint32
Atomic_write_segments_max uint32
_ [1]uint32
_ [9]uint64
} }
type Fsid struct { type Fsid struct {
@ -520,29 +516,6 @@ type TCPInfo struct {
Total_rto_time uint32 Total_rto_time uint32
} }
type TCPVegasInfo struct {
Enabled uint32
Rttcnt uint32
Rtt uint32
Minrtt uint32
}
type TCPDCTCPInfo struct {
Enabled uint16
Ce_state uint16
Alpha uint32
Ab_ecn uint32
Ab_tot uint32
}
type TCPBBRInfo struct {
Bw_lo uint32
Bw_hi uint32
Min_rtt uint32
Pacing_gain uint32
Cwnd_gain uint32
}
type CanFilter struct { type CanFilter struct {
Id uint32 Id uint32
Mask uint32 Mask uint32
@ -584,7 +557,6 @@ type TCPRepairOpt struct {
SizeofICMPv6Filter = 0x20 SizeofICMPv6Filter = 0x20
SizeofUcred = 0xc SizeofUcred = 0xc
SizeofTCPInfo = 0xf8 SizeofTCPInfo = 0xf8
SizeofTCPCCInfo = 0x14
SizeofCanFilter = 0x8 SizeofCanFilter = 0x8
SizeofTCPRepairOpt = 0x8 SizeofTCPRepairOpt = 0x8
) )
@ -3794,7 +3766,7 @@ type PPSKTime struct {
ETHTOOL_MSG_PSE_GET = 0x24 ETHTOOL_MSG_PSE_GET = 0x24
ETHTOOL_MSG_PSE_SET = 0x25 ETHTOOL_MSG_PSE_SET = 0x25
ETHTOOL_MSG_RSS_GET = 0x26 ETHTOOL_MSG_RSS_GET = 0x26
ETHTOOL_MSG_USER_MAX = 0x2c ETHTOOL_MSG_USER_MAX = 0x2b
ETHTOOL_MSG_KERNEL_NONE = 0x0 ETHTOOL_MSG_KERNEL_NONE = 0x0
ETHTOOL_MSG_STRSET_GET_REPLY = 0x1 ETHTOOL_MSG_STRSET_GET_REPLY = 0x1
ETHTOOL_MSG_LINKINFO_GET_REPLY = 0x2 ETHTOOL_MSG_LINKINFO_GET_REPLY = 0x2
@ -3834,7 +3806,7 @@ type PPSKTime struct {
ETHTOOL_MSG_MODULE_NTF = 0x24 ETHTOOL_MSG_MODULE_NTF = 0x24
ETHTOOL_MSG_PSE_GET_REPLY = 0x25 ETHTOOL_MSG_PSE_GET_REPLY = 0x25
ETHTOOL_MSG_RSS_GET_REPLY = 0x26 ETHTOOL_MSG_RSS_GET_REPLY = 0x26
ETHTOOL_MSG_KERNEL_MAX = 0x2c ETHTOOL_MSG_KERNEL_MAX = 0x2b
ETHTOOL_FLAG_COMPACT_BITSETS = 0x1 ETHTOOL_FLAG_COMPACT_BITSETS = 0x1
ETHTOOL_FLAG_OMIT_REPLY = 0x2 ETHTOOL_FLAG_OMIT_REPLY = 0x2
ETHTOOL_FLAG_STATS = 0x4 ETHTOOL_FLAG_STATS = 0x4
@ -3979,7 +3951,7 @@ type PPSKTime struct {
ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL = 0x17 ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL = 0x17
ETHTOOL_A_COALESCE_USE_CQE_MODE_TX = 0x18 ETHTOOL_A_COALESCE_USE_CQE_MODE_TX = 0x18
ETHTOOL_A_COALESCE_USE_CQE_MODE_RX = 0x19 ETHTOOL_A_COALESCE_USE_CQE_MODE_RX = 0x19
ETHTOOL_A_COALESCE_MAX = 0x1e ETHTOOL_A_COALESCE_MAX = 0x1c
ETHTOOL_A_PAUSE_UNSPEC = 0x0 ETHTOOL_A_PAUSE_UNSPEC = 0x0
ETHTOOL_A_PAUSE_HEADER = 0x1 ETHTOOL_A_PAUSE_HEADER = 0x1
ETHTOOL_A_PAUSE_AUTONEG = 0x2 ETHTOOL_A_PAUSE_AUTONEG = 0x2
@ -4637,7 +4609,7 @@ type KCMClone struct {
NL80211_ATTR_MAC_HINT = 0xc8 NL80211_ATTR_MAC_HINT = 0xc8
NL80211_ATTR_MAC_MASK = 0xd7 NL80211_ATTR_MAC_MASK = 0xd7
NL80211_ATTR_MAX_AP_ASSOC_STA = 0xca NL80211_ATTR_MAX_AP_ASSOC_STA = 0xca
NL80211_ATTR_MAX = 0x14c NL80211_ATTR_MAX = 0x14a
NL80211_ATTR_MAX_CRIT_PROT_DURATION = 0xb4 NL80211_ATTR_MAX_CRIT_PROT_DURATION = 0xb4
NL80211_ATTR_MAX_CSA_COUNTERS = 0xce NL80211_ATTR_MAX_CSA_COUNTERS = 0xce
NL80211_ATTR_MAX_MATCH_SETS = 0x85 NL80211_ATTR_MAX_MATCH_SETS = 0x85
@ -5241,7 +5213,7 @@ type KCMClone struct {
NL80211_FREQUENCY_ATTR_GO_CONCURRENT = 0xf NL80211_FREQUENCY_ATTR_GO_CONCURRENT = 0xf
NL80211_FREQUENCY_ATTR_INDOOR_ONLY = 0xe NL80211_FREQUENCY_ATTR_INDOOR_ONLY = 0xe
NL80211_FREQUENCY_ATTR_IR_CONCURRENT = 0xf NL80211_FREQUENCY_ATTR_IR_CONCURRENT = 0xf
NL80211_FREQUENCY_ATTR_MAX = 0x21 NL80211_FREQUENCY_ATTR_MAX = 0x20
NL80211_FREQUENCY_ATTR_MAX_TX_POWER = 0x6 NL80211_FREQUENCY_ATTR_MAX_TX_POWER = 0x6
NL80211_FREQUENCY_ATTR_NO_10MHZ = 0x11 NL80211_FREQUENCY_ATTR_NO_10MHZ = 0x11
NL80211_FREQUENCY_ATTR_NO_160MHZ = 0xc NL80211_FREQUENCY_ATTR_NO_160MHZ = 0xc

View file

@ -65,7 +65,7 @@ func LoadDLL(name string) (dll *DLL, err error) {
return d, nil return d, nil
} }
// MustLoadDLL is like LoadDLL but panics if load operation fails. // MustLoadDLL is like LoadDLL but panics if load operation failes.
func MustLoadDLL(name string) *DLL { func MustLoadDLL(name string) *DLL {
d, e := LoadDLL(name) d, e := LoadDLL(name)
if e != nil { if e != nil {

15
vendor/modules.txt vendored
View file

@ -24,11 +24,10 @@ codeberg.org/gruf/go-fastcopy
# codeberg.org/gruf/go-fastpath/v2 v2.0.0 # codeberg.org/gruf/go-fastpath/v2 v2.0.0
## explicit; go 1.14 ## explicit; go 1.14
codeberg.org/gruf/go-fastpath/v2 codeberg.org/gruf/go-fastpath/v2
# codeberg.org/gruf/go-ffmpreg v0.3.1 # codeberg.org/gruf/go-ffmpreg v0.2.6
## explicit; go 1.22.0 ## explicit; go 1.22.0
codeberg.org/gruf/go-ffmpreg/embed/ffmpeg codeberg.org/gruf/go-ffmpreg/embed/ffmpeg
codeberg.org/gruf/go-ffmpreg/embed/ffprobe codeberg.org/gruf/go-ffmpreg/embed/ffprobe
codeberg.org/gruf/go-ffmpreg/wasm
# codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf # codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf
## explicit; go 1.21 ## explicit; go 1.21
codeberg.org/gruf/go-iotools codeberg.org/gruf/go-iotools
@ -845,7 +844,7 @@ github.com/tdewolff/parse/v2/strconv
# github.com/technologize/otel-go-contrib v1.1.1 # github.com/technologize/otel-go-contrib v1.1.1
## explicit; go 1.17 ## explicit; go 1.17
github.com/technologize/otel-go-contrib/otelginmetrics github.com/technologize/otel-go-contrib/otelginmetrics
# github.com/tetratelabs/wazero v1.8.1 # github.com/tetratelabs/wazero v1.8.0
## explicit; go 1.21 ## explicit; go 1.21
github.com/tetratelabs/wazero github.com/tetratelabs/wazero
github.com/tetratelabs/wazero/api github.com/tetratelabs/wazero/api
@ -1058,7 +1057,7 @@ go.uber.org/multierr
# golang.org/x/arch v0.8.0 # golang.org/x/arch v0.8.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/arch/x86/x86asm golang.org/x/arch/x86/x86asm
# golang.org/x/crypto v0.28.0 # golang.org/x/crypto v0.27.0
## explicit; go 1.20 ## explicit; go 1.20
golang.org/x/crypto/acme golang.org/x/crypto/acme
golang.org/x/crypto/acme/autocert golang.org/x/crypto/acme/autocert
@ -1085,7 +1084,7 @@ golang.org/x/exp/slices
golang.org/x/exp/slog golang.org/x/exp/slog
golang.org/x/exp/slog/internal golang.org/x/exp/slog/internal
golang.org/x/exp/slog/internal/buffer golang.org/x/exp/slog/internal/buffer
# golang.org/x/image v0.21.0 # golang.org/x/image v0.20.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/image/riff golang.org/x/image/riff
golang.org/x/image/vp8 golang.org/x/image/vp8
@ -1096,7 +1095,7 @@ golang.org/x/image/webp
golang.org/x/mod/internal/lazyregexp golang.org/x/mod/internal/lazyregexp
golang.org/x/mod/module golang.org/x/mod/module
golang.org/x/mod/semver golang.org/x/mod/semver
# golang.org/x/net v0.30.0 # golang.org/x/net v0.29.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/net/bpf golang.org/x/net/bpf
golang.org/x/net/context golang.org/x/net/context
@ -1124,13 +1123,13 @@ golang.org/x/oauth2/internal
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/sync/errgroup golang.org/x/sync/errgroup
golang.org/x/sync/semaphore golang.org/x/sync/semaphore
# golang.org/x/sys v0.26.0 # golang.org/x/sys v0.25.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/sys/cpu golang.org/x/sys/cpu
golang.org/x/sys/unix golang.org/x/sys/unix
golang.org/x/sys/windows golang.org/x/sys/windows
golang.org/x/sys/windows/registry golang.org/x/sys/windows/registry
# golang.org/x/text v0.19.0 # golang.org/x/text v0.18.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/text/cases golang.org/x/text/cases
golang.org/x/text/encoding golang.org/x/text/encoding