Update go-pkgz, system modules

This brings stricter check for auth provider names, slog support.
This commit is contained in:
Dmitry Verkhoturov
2025-04-29 08:24:53 +01:00
parent 61dbf6b1f2
commit fd0799384f
92 changed files with 2364 additions and 1077 deletions
+6 -6
View File
@@ -6,7 +6,7 @@ toolchain go1.24.1
require (
github.com/go-pkgz/jrpc v0.3.1
github.com/go-pkgz/lgr v0.11.1
github.com/go-pkgz/lgr v0.12.0
github.com/jessevdk/go-flags v1.6.1
github.com/stretchr/testify v1.10.0
github.com/umputun/remark42/backend v1.1000.0
@@ -25,7 +25,7 @@ require (
github.com/go-chi/chi/v5 v5.2.1 // indirect
github.com/go-chi/render v1.0.3 // indirect
github.com/go-pkgz/expirable-cache/v3 v3.0.0 // indirect
github.com/go-pkgz/rest v1.20.2 // indirect
github.com/go-pkgz/rest v1.20.3 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
@@ -36,10 +36,10 @@ require (
github.com/rs/xid v1.6.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
go.etcd.io/bbolt v1.4.0 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/image v0.25.0 // indirect
golang.org/x/net v0.37.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/image v0.26.0 // indirect
golang.org/x/net v0.39.0 // indirect
golang.org/x/sys v0.32.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
+14 -14
View File
@@ -29,10 +29,10 @@ github.com/go-pkgz/expirable-cache/v3 v3.0.0 h1:u3/gcu3sabLYiTCevoRKv+WzjIn5oo7P
github.com/go-pkgz/expirable-cache/v3 v3.0.0/go.mod h1:2OQiDyEGQalYecLWmXprm3maPXeVb5/6/X7yRPYTzec=
github.com/go-pkgz/jrpc v0.3.1 h1:jRxnO5ppOookkL9PuOWw/IloevmzqbsKaGImTR3iALQ=
github.com/go-pkgz/jrpc v0.3.1/go.mod h1:DJg1RfhwvJpVT3YXtk8LxowB7DN5jUoZ3U4MbHnm76M=
github.com/go-pkgz/lgr v0.11.1 h1:hXFhZcznehI6imLhEa379oMOKFz7TQUmisAqb3oLOSM=
github.com/go-pkgz/lgr v0.11.1/go.mod h1:tgDF4RXQnBfIgJqjgkv0yOeTQ3F1yewWIZkpUhHnAkU=
github.com/go-pkgz/rest v1.20.2 h1:6wYWo85H7xFU09FadVKKc5LKIfIpCStBXJj9F/P4COc=
github.com/go-pkgz/rest v1.20.2/go.mod h1:NC2xNN/y1rIs0PY13FowKoH8rk9RhJNJ0tTbkBg8Yks=
github.com/go-pkgz/lgr v0.12.0 h1:uoSCLdiMocZDa+L66DavHG5UIkOJvWKOVqt6sNQllw0=
github.com/go-pkgz/lgr v0.12.0/go.mod h1:A4AxjOthFVFK6jRnVYMeusno5SeDAxcLVHd0kI/lN/Y=
github.com/go-pkgz/rest v1.20.3 h1:oGGfM8XTnvwek29q1OAhcI1nkKKOpurRFApBiYH44Fk=
github.com/go-pkgz/rest v1.20.3/go.mod h1:NC2xNN/y1rIs0PY13FowKoH8rk9RhJNJ0tTbkBg8Yks=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
@@ -72,10 +72,10 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY=
golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
@@ -90,8 +90,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -99,8 +99,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -112,8 +112,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
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=
+17 -16
View File
@@ -1,7 +1,8 @@
module github.com/umputun/remark42/backend
go 1.23
toolchain go1.24.1
go 1.23.0
toolchain go1.24.2
require (
github.com/Depado/bfchroma/v2 v2.0.0
@@ -12,13 +13,13 @@ require (
github.com/go-chi/chi/v5 v5.2.1
github.com/go-chi/cors v1.2.1
github.com/go-chi/render v1.0.3
github.com/go-pkgz/auth/v2 v2.0.0-20241221172452-ba01339372ba
github.com/go-pkgz/auth/v2 v2.0.1-0.20250415030422-4f9f2c5e3b0d
github.com/go-pkgz/jrpc v0.3.1
github.com/go-pkgz/lcw/v2 v2.0.0
github.com/go-pkgz/lgr v0.11.1
github.com/go-pkgz/lgr v0.12.0
github.com/go-pkgz/notify v1.2.0
github.com/go-pkgz/repeater v1.2.0
github.com/go-pkgz/rest v1.20.2
github.com/go-pkgz/rest v1.20.3
github.com/go-pkgz/syncs v1.3.2
github.com/golang-jwt/jwt/v5 v5.2.2
github.com/google/uuid v1.6.0
@@ -33,9 +34,9 @@ require (
github.com/stretchr/testify v1.10.0
go.etcd.io/bbolt v1.4.0
go.uber.org/goleak v1.3.0
golang.org/x/crypto v0.36.0
golang.org/x/image v0.25.0
golang.org/x/net v0.37.0
golang.org/x/crypto v0.37.0
golang.org/x/image v0.26.0
golang.org/x/net v0.39.0
)
require (
@@ -49,15 +50,15 @@ require (
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/didip/tollbooth/v8 v8.0.1 // indirect
github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/go-oauth2/oauth2/v4 v4.5.2 // indirect
github.com/go-oauth2/oauth2/v4 v4.5.3 // indirect
github.com/go-pkgz/email v0.5.0 // indirect
github.com/go-pkgz/expirable-cache/v3 v3.0.0 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/golang/snappy v1.0.0 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/montanaflynn/stats v0.7.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/redis/go-redis/v9 v9.7.3 // indirect
@@ -67,10 +68,10 @@ require (
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.mongodb.org/mongo-driver v1.17.1 // indirect
golang.org/x/oauth2 v0.24.0 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect
go.mongodb.org/mongo-driver v1.17.3 // indirect
golang.org/x/oauth2 v0.29.0 // indirect
golang.org/x/sync v0.13.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/text v0.24.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
+39 -32
View File
@@ -27,6 +27,7 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bytedance/gopkg v0.0.0-20221122125632-68358b8ecec6/go.mod h1:5FoAH5xUHHCMDvQPy1rnj8moqLkLHFaDVBjHhcFwEi0=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -58,10 +59,10 @@ github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
github.com/go-oauth2/oauth2/v4 v4.5.2 h1:CuZhD3lhGuI6aNLyUbRHXsgG2RwGRBOuCBfd4WQKqBQ=
github.com/go-oauth2/oauth2/v4 v4.5.2/go.mod h1:wk/2uLImWIa9VVQDgxz99H2GDbhmfi/9/Xr+GvkSUSQ=
github.com/go-pkgz/auth/v2 v2.0.0-20241221172452-ba01339372ba h1:TqoOfThmmcoiSAs/J+y0/3hwS/YRhzR2XepO147jR+I=
github.com/go-pkgz/auth/v2 v2.0.0-20241221172452-ba01339372ba/go.mod h1:VkvKMNbRJz36sdTL1F75khRqpl4yux4u2CujFzCZOeY=
github.com/go-oauth2/oauth2/v4 v4.5.3 h1:lQt7O9KOnu/v4awe166FH7+p8tFUXQyR+no6nctAKU0=
github.com/go-oauth2/oauth2/v4 v4.5.3/go.mod h1:ryzb7zr8fdQBlciD0+tcnEWeOok5B0J8V/DniwYqQ2k=
github.com/go-pkgz/auth/v2 v2.0.1-0.20250415030422-4f9f2c5e3b0d h1:xyTp7JRaHy3/ttpcNiJO/YzxENZcvxcZL8iE3QfssnY=
github.com/go-pkgz/auth/v2 v2.0.1-0.20250415030422-4f9f2c5e3b0d/go.mod h1:YTCEC2cBE2ugyRf0ePew4NZIJE5ozglI06/IokmtiwU=
github.com/go-pkgz/email v0.5.0 h1:fdtMDGJ8NwyBACLR0LYHaCIK/OeUwZHMhH7Q0+oty9U=
github.com/go-pkgz/email v0.5.0/go.mod h1:BdxglsQnymzhfdbnncEE72a6DrucZHy6I+42LK2jLEc=
github.com/go-pkgz/expirable-cache v0.1.0/go.mod h1:GTrEl0X+q0mPNqN6dtcQXksACnzCBQ5k/k1SwXJsZKs=
@@ -71,21 +72,19 @@ github.com/go-pkgz/jrpc v0.3.1 h1:jRxnO5ppOookkL9PuOWw/IloevmzqbsKaGImTR3iALQ=
github.com/go-pkgz/jrpc v0.3.1/go.mod h1:DJg1RfhwvJpVT3YXtk8LxowB7DN5jUoZ3U4MbHnm76M=
github.com/go-pkgz/lcw/v2 v2.0.0 h1:gTwXpiJBhQeA1rXuqkRuLcV79uATFna8CckH8ZBBrH0=
github.com/go-pkgz/lcw/v2 v2.0.0/go.mod h1:yxJHOn+IbQBQHxUqkCtMrbGjIfdYcsBAZcVCBaL1Va8=
github.com/go-pkgz/lgr v0.11.1 h1:hXFhZcznehI6imLhEa379oMOKFz7TQUmisAqb3oLOSM=
github.com/go-pkgz/lgr v0.11.1/go.mod h1:tgDF4RXQnBfIgJqjgkv0yOeTQ3F1yewWIZkpUhHnAkU=
github.com/go-pkgz/lgr v0.12.0 h1:uoSCLdiMocZDa+L66DavHG5UIkOJvWKOVqt6sNQllw0=
github.com/go-pkgz/lgr v0.12.0/go.mod h1:A4AxjOthFVFK6jRnVYMeusno5SeDAxcLVHd0kI/lN/Y=
github.com/go-pkgz/notify v1.2.0 h1:jqbsbWkodCDB9ffyI9fCG1bTSgidWJRS5UWD/twjU44=
github.com/go-pkgz/notify v1.2.0/go.mod h1:BTHj9ly7xZpaxg91lBdxCxSmkpVQ9R6q5QviX/upeYo=
github.com/go-pkgz/repeater v1.2.0 h1:oJFvjyKdTDd5RCzpzxlzYIZFFj6Zfl17rE1aUfu6UjQ=
github.com/go-pkgz/repeater v1.2.0/go.mod h1:vypP6xamA53MFmafnGUucqOmALKk36xgKu2hSG73LHM=
github.com/go-pkgz/rest v1.20.2 h1:6wYWo85H7xFU09FadVKKc5LKIfIpCStBXJj9F/P4COc=
github.com/go-pkgz/rest v1.20.2/go.mod h1:NC2xNN/y1rIs0PY13FowKoH8rk9RhJNJ0tTbkBg8Yks=
github.com/go-pkgz/rest v1.20.3 h1:oGGfM8XTnvwek29q1OAhcI1nkKKOpurRFApBiYH44Fk=
github.com/go-pkgz/rest v1.20.3/go.mod h1:NC2xNN/y1rIs0PY13FowKoH8rk9RhJNJ0tTbkBg8Yks=
github.com/go-pkgz/syncs v1.3.2 h1:gmioASlJNy3gNosPlgvWOM2QP0Hdjzn2u+/sUShgd8E=
github.com/go-pkgz/syncs v1.3.2/go.mod h1:qjgzpp7OpuhDf7BWsW/FHCu9DLjE32NPy6/vXAXT/Cw=
github.com/go-session/session v3.1.2+incompatible/go.mod h1:8B3iivBQjrz/JtC68Np2T1yBBLxTan3mn/3OM0CyRt0=
github.com/go-session/session/v3 v3.2.1/go.mod h1:RftEBbyuzqkNCAxIrCLJe+rfBqB/4G11qxq9KYKrx4M=
github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
@@ -97,8 +96,8 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -111,6 +110,8 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0=
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
github.com/gorilla/feeds v1.2.0 h1:O6pBiXJ5JHhPvqy53NsjKOThq+dNFm8+DFrxBEdzSCc=
@@ -132,11 +133,12 @@ github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4=
github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -180,12 +182,15 @@ github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDq
github.com/slack-go/slack v0.15.0 h1:LE2lj2y9vqqiOf+qIIy0GvEoxgF1N5yLGZffmEZykt0=
github.com/slack-go/slack v0.15.0/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0=
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
@@ -246,8 +251,8 @@ github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
go.mongodb.org/mongo-driver v1.17.1 h1:Wic5cJIwJgSpBhe3lx3+/RybR5PiYRMpVFgO7cOHyIM=
go.mongodb.org/mongo-driver v1.17.1/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4=
go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ=
go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -257,10 +262,10 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY=
golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
@@ -283,22 +288,23 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -315,14 +321,15 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
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=
@@ -344,8 +351,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-2
View File
@@ -1,2 +0,0 @@
[*.go]
end_of_line = crlf
+4
View File
@@ -68,6 +68,10 @@ func main() {
srv.SetAllowGetAccessRequest(true)
srv.SetClientInfoHandler(server.ClientFormHandler)
srv.UserAuthorizationHandler = func(w http.ResponseWriter, r *http.Request) (userID string, err error) {
return "000000", nil
}
srv.SetInternalErrorHandler(func(err error) (re *errors.Response) {
log.Println("Internal Error:", err.Error())
return
+7
View File
@@ -1,6 +1,7 @@
package oauth2
import (
"net/url"
"time"
)
@@ -57,4 +58,10 @@ type (
GetRefreshExpiresIn() time.Duration
SetRefreshExpiresIn(time.Duration)
}
ExtendableTokenInfo interface {
TokenInfo
GetExtension() url.Values
SetExtension(url.Values)
}
)
+49 -1
View File
@@ -3,6 +3,7 @@ package server
import (
"context"
"net/http"
"strings"
"time"
"github.com/go-oauth2/oauth2/v4"
@@ -49,8 +50,14 @@ type (
// ExtensionFieldsHandler in response to the access token with the extension of the field
ExtensionFieldsHandler func(ti oauth2.TokenInfo) (fieldsValue map[string]interface{})
// ResponseTokenHandler response token handing
// ResponseTokenHandler response token handling
ResponseTokenHandler func(w http.ResponseWriter, data map[string]interface{}, header http.Header, statusCode ...int) error
// Handler to fetch the refresh token from the request
RefreshTokenResolveHandler func(r *http.Request) (string, error)
// Handler to fetch the access token from the request
AccessTokenResolveHandler func(r *http.Request) (string, bool)
)
// ClientFormHandler get client data from form
@@ -71,3 +78,44 @@ func ClientBasicHandler(r *http.Request) (string, string, error) {
}
return username, password, nil
}
func RefreshTokenFormResolveHandler(r *http.Request) (string, error) {
rt := r.FormValue("refresh_token")
if rt == "" {
return "", errors.ErrInvalidRequest
}
return rt, nil
}
func RefreshTokenCookieResolveHandler(r *http.Request) (string, error) {
c, err := r.Cookie("refresh_token")
if err != nil {
return "", errors.ErrInvalidRequest
}
return c.Value, nil
}
func AccessTokenDefaultResolveHandler(r *http.Request) (string, bool) {
token := ""
auth := r.Header.Get("Authorization")
prefix := "Bearer "
if auth != "" && strings.HasPrefix(auth, prefix) {
token = auth[len(prefix):]
} else {
token = r.FormValue("access_token")
}
return token, token != ""
}
func AccessTokenCookieResolveHandler(r *http.Request) (string, bool) {
c, err := r.Cookie("access_token")
if err != nil {
return "", false
}
return c.Value, true
}
+9 -21
View File
@@ -6,7 +6,6 @@ import (
"fmt"
"net/http"
"net/url"
"strings"
"time"
"github.com/go-oauth2/oauth2/v4"
@@ -25,8 +24,10 @@ func NewServer(cfg *Config, manager oauth2.Manager) *Server {
Manager: manager,
}
// default handler
// default handlers
srv.ClientInfoHandler = ClientBasicHandler
srv.RefreshTokenResolveHandler = RefreshTokenFormResolveHandler
srv.AccessTokenResolveHandler = AccessTokenDefaultResolveHandler
srv.UserAuthorizationHandler = func(w http.ResponseWriter, r *http.Request) (string, error) {
return "", errors.ErrAccessDenied
@@ -56,6 +57,8 @@ type Server struct {
AccessTokenExpHandler AccessTokenExpHandler
AuthorizeScopeHandler AuthorizeScopeHandler
ResponseTokenHandler ResponseTokenHandler
RefreshTokenResolveHandler RefreshTokenResolveHandler
AccessTokenResolveHandler AccessTokenResolveHandler
}
func (s *Server) handleError(w http.ResponseWriter, req *AuthorizeRequest, err error) error {
@@ -367,10 +370,10 @@ func (s *Server) ValidationTokenRequest(r *http.Request) (oauth2.GrantType, *oau
case oauth2.ClientCredentials:
tgr.Scope = r.FormValue("scope")
case oauth2.Refreshing:
tgr.Refresh = r.FormValue("refresh_token")
tgr.Refresh, err = s.RefreshTokenResolveHandler(r)
tgr.Scope = r.FormValue("scope")
if tgr.Refresh == "" {
return "", nil, errors.ErrInvalidRequest
if err != nil {
return "", nil, err
}
}
return gt, tgr, nil
@@ -569,27 +572,12 @@ func (s *Server) GetErrorData(err error) (map[string]interface{}, int, http.Head
return data, statusCode, re.Header
}
// BearerAuth parse bearer token
func (s *Server) BearerAuth(r *http.Request) (string, bool) {
auth := r.Header.Get("Authorization")
prefix := "Bearer "
token := ""
if auth != "" && strings.HasPrefix(auth, prefix) {
token = auth[len(prefix):]
} else {
token = r.FormValue("access_token")
}
return token, token != ""
}
// ValidationBearerToken validation the bearer tokens
// https://tools.ietf.org/html/rfc6750
func (s *Server) ValidationBearerToken(r *http.Request) (oauth2.TokenInfo, error) {
ctx := r.Context()
accessToken, ok := s.BearerAuth(r)
accessToken, ok := s.AccessTokenResolveHandler(r)
if !ok {
return nil, errors.ErrInvalidAccessToken
}
+10
View File
@@ -93,3 +93,13 @@ func (s *Server) SetAuthorizeScopeHandler(handler AuthorizeScopeHandler) {
func (s *Server) SetResponseTokenHandler(handler ResponseTokenHandler) {
s.ResponseTokenHandler = handler
}
// SetRefreshTokenResolveHandler refresh token resolver
func (s *Server) SetRefreshTokenResolveHandler(handler RefreshTokenResolveHandler) {
s.RefreshTokenResolveHandler = handler
}
// SetAccessTokenResolveHandler access token resolver
func (s *Server) SetAccessTokenResolveHandler(handler AccessTokenResolveHandler) {
s.AccessTokenResolveHandler = handler
}
+34
View File
@@ -4,6 +4,8 @@ package auth
import (
"fmt"
"net/http"
"net/url"
"regexp"
"strings"
"time"
@@ -270,10 +272,42 @@ func (s *Service) addProviderByName(name string, p provider.Params) {
}
func (s *Service) addProvider(prov provider.Provider) {
if !s.isValidProviderName(prov.Name()) {
return
}
s.providers = append(s.providers, provider.NewService(prov))
s.authMiddleware.Providers = s.providers
}
func (s *Service) isValidProviderName(name string) bool {
if strings.TrimSpace(name) == "" {
s.logger.Logf("[ERROR] provider has been ignored because its name is empty")
return false
}
formatForbidden := func(name string) string {
return fmt.Sprintf("provider has been ignored because its name contains forbidden characters: '%s'", name)
}
path, err := url.PathUnescape(name)
if err != nil || path != name {
s.logger.Logf("[ERROR] %s", formatForbidden(name))
return false
}
if name != url.PathEscape(name) {
s.logger.Logf("[ERROR] %s", formatForbidden(name))
return false
}
// net/url package does not escape everything (https://github.com/golang/go/issues/5684)
// It is better to reject all reserved characters from https://datatracker.ietf.org/doc/html/rfc3986#section-2.2
if regexp.MustCompile(`[:/?#\[\]@!$&'\(\)*+,;=]`).MatchString(name) {
s.logger.Logf("[ERROR] %s", formatForbidden(name))
return false
}
return true
}
// AddProvider adds provider for given name
func (s *Service) AddProvider(name, cid, csecret string) {
p := provider.Params{
+17 -6
View File
@@ -129,7 +129,7 @@ func (a *Authenticator) auth(reqAuth bool) func(http.Handler) http.Handler {
}
// check if user provider is allowed
if !a.isProviderAllowed(claims.User.ID) {
if !a.isProviderAllowed(&claims) {
onError(h, w, r, fmt.Errorf("user %s/%s provider is not allowed", claims.User.Name, claims.User.ID))
a.JWTService.Reset(w)
return
@@ -153,13 +153,24 @@ func (a *Authenticator) auth(reqAuth bool) func(http.Handler) http.Handler {
return f
}
// isProviderAllowed checks if user provider is allowed, user id looks like "provider_1234567890"
// this check is needed to reject users from providers what are used to be allowed but not anymore.
// isProviderAllowed checks if user provider is allowed.
// If provider name is explicitly set in the token claims, then that provider is checked.
//
// If user id looks like "provider_1234567890",
// then there is an attempt to extract provider name from that user ID.
// Note that such read can fail if user id has multiple "_" separator symbols.
//
// This check is needed to reject users from providers what are used to be allowed but not anymore.
// Such users made token before the provider was disabled and should not be allowed to login anymore.
func (a *Authenticator) isProviderAllowed(userID string) bool {
userProvider := strings.Split(userID, "_")[0]
func (a *Authenticator) isProviderAllowed(claims *token.Claims) bool {
// TODO: remove this read when old tokens expire and all new tokens have a provider name in them
userIDProvider := strings.Split(claims.User.ID, "_")[0]
for _, p := range a.Providers {
if p.Name() == userProvider {
name := p.Name()
if claims.AuthProvider != nil && claims.AuthProvider.Name == name {
return true
}
if name == userIDProvider {
return true
}
}
+10 -4
View File
@@ -267,6 +267,9 @@ func (ah *AppleHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
ExpiresAt: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)),
NotBefore: jwt.NewNumericDate(time.Now().Add(-1 * time.Minute)),
},
AuthProvider: &token.AuthProvider{
Name: ah.name,
},
}
if _, err = ah.JwtService.Set(w, claims); err != nil {
@@ -337,7 +340,7 @@ func (ah AppleHandler) AuthHandler(w http.ResponseWriter, r *http.Request) {
// trying to fetch Apple public key (JWK) for verify token signature, it need for verify IDToken received from Apple
keySet, err := fetchAppleJWK(r.Context(), ah.conf.jwkURL)
if err != nil {
ah.L.Logf("[ERROR] failed to fetch JWK from Apple key service: " + err.Error())
ah.Logf("[ERROR] failed to fetch JWK from Apple key service: " + err.Error())
rest.SendErrorJSON(w, r, ah.L, http.StatusInternalServerError, nil, fmt.Sprintf("failed to fetch JWK from Apple key service: %s", resp.Error))
return
}
@@ -346,7 +349,7 @@ func (ah AppleHandler) AuthHandler(w http.ResponseWriter, r *http.Request) {
tokenClaims := jwt.MapClaims{}
_, err = jwt.ParseWithClaims(resp.IDToken, tokenClaims, keySet.keyFunc)
if err != nil {
ah.L.Logf("[ERROR] failed to get claims: " + err.Error())
ah.Logf("[ERROR] failed to get claims: " + err.Error())
rest.SendErrorJSON(w, r, ah.L, http.StatusInternalServerError, nil, fmt.Sprintf("failed to token validation, key is invalid: %s", resp.Error))
return
}
@@ -376,6 +379,9 @@ func (ah AppleHandler) AuthHandler(w http.ResponseWriter, r *http.Request) {
Audience: oauthClaims.Audience,
},
SessionOnly: false,
AuthProvider: &token.AuthProvider{
Name: ah.name,
},
}
if _, err = ah.JwtService.Set(w, claims); err != nil {
@@ -445,7 +451,7 @@ func (ah *AppleHandler) exchange(ctx context.Context, code, redirectURI string,
defer func() {
if err = res.Body.Close(); err != nil {
ah.L.Logf("[ERROR] close request body failed when get access token: %v", err)
ah.Logf("[ERROR] close request body failed when get access token: %v", err)
}
}()
@@ -498,7 +504,7 @@ func (ah *AppleHandler) parseUserData(user *token.User, jUser string) {
// Catch error for log only. No need break flow if user name doesn't exist
if err := json.Unmarshal([]byte(jUser), &userData); err != nil {
ah.L.Logf("[DEBUG] failed to parse user data %s: %v", user, err)
ah.Logf("[DEBUG] failed to parse user data %s: %v", user, err)
user.Name = "noname_" + user.ID[6:12] // paste noname if user name failed to parse
return
}
+3
View File
@@ -126,6 +126,9 @@ func (p DirectHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
Audience: []string{creds.Audience},
},
SessionOnly: sessOnly,
AuthProvider: &token.AuthProvider{
Name: p.ProviderName,
},
}
if _, err = p.TokenService.Set(w, claims); err != nil {
+6
View File
@@ -61,6 +61,9 @@ func (h Oauth1Handler) LoginHandler(w http.ResponseWriter, r *http.Request) {
ExpiresAt: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)),
NotBefore: jwt.NewNumericDate(time.Now().Add(-1 * time.Minute)),
},
AuthProvider: &token.AuthProvider{
Name: h.name,
},
}
if _, err = h.JwtService.Set(w, claims); err != nil {
@@ -146,6 +149,9 @@ func (h Oauth1Handler) AuthHandler(w http.ResponseWriter, r *http.Request) {
Audience: oauthClaims.Audience,
},
SessionOnly: oauthClaims.SessionOnly,
AuthProvider: &token.AuthProvider{
Name: h.name,
},
}
if _, err = h.JwtService.Set(w, claims); err != nil {
+6
View File
@@ -118,6 +118,9 @@ func (p Oauth2Handler) LoginHandler(w http.ResponseWriter, r *http.Request) {
NotBefore: jwt.NewNumericDate(time.Now().Add(-1 * time.Minute)),
},
NoAva: r.URL.Query().Get("noava") == "1",
AuthProvider: &token.AuthProvider{
Name: p.name,
},
}
if _, err := p.JwtService.Set(w, claims); err != nil {
@@ -215,6 +218,9 @@ func (p Oauth2Handler) AuthHandler(w http.ResponseWriter, r *http.Request) {
},
SessionOnly: oauthClaims.SessionOnly,
NoAva: oauthClaims.NoAva,
AuthProvider: &token.AuthProvider{
Name: p.name,
},
}
if _, err = p.JwtService.Set(w, claims); err != nil {
+3
View File
@@ -310,6 +310,9 @@ func (th *TelegramHandler) LoginHandler(w http.ResponseWriter, r *http.Request)
NotBefore: jwt.NewNumericDate(time.Now().Add(-1 * time.Minute)),
},
SessionOnly: false, // TODO review?
AuthProvider: &authtoken.AuthProvider{
Name: th.ProviderName,
},
}
if _, err := th.TokenService.Set(w, claims); err != nil {
+6
View File
@@ -117,6 +117,9 @@ func (e VerifyHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
Audience: confClaims.Audience,
},
SessionOnly: sessOnly,
AuthProvider: &token.AuthProvider{
Name: e.ProviderName,
},
}
if _, err = e.TokenService.Set(w, claims); err != nil {
@@ -152,6 +155,9 @@ func (e VerifyHandler) sendConfirmation(w http.ResponseWriter, r *http.Request)
NotBefore: jwt.NewNumericDate(time.Now().Add(-1 * time.Minute)),
Issuer: e.Issuer,
},
AuthProvider: &token.AuthProvider{
Name: e.ProviderName,
},
}
tkn, err := e.TokenService.Token(claims)
+11 -5
View File
@@ -23,10 +23,11 @@ type Service struct {
// Claims stores user info for token and state & from from login
type Claims struct {
jwt.RegisteredClaims
User *User `json:"user,omitempty"` // user info
SessionOnly bool `json:"sess_only,omitempty"`
Handshake *Handshake `json:"handshake,omitempty"` // used for oauth handshake
NoAva bool `json:"no-ava,omitempty"` // disable avatar, always use identicon
User *User `json:"user,omitempty"` // user info
SessionOnly bool `json:"sess_only,omitempty"`
Handshake *Handshake `json:"handshake,omitempty"` // used for oauth handshake
NoAva bool `json:"no-ava,omitempty"` // disable avatar, always use identicon
AuthProvider *AuthProvider `json:"auth_provider,omitempty"` // auth provider info
}
// Handshake used for oauth handshake
@@ -36,6 +37,11 @@ type Handshake struct {
ID string `json:"id,omitempty"`
}
// AuthProvider stores attributes of provider which has created a JWT token
type AuthProvider struct {
Name string `json:"name,omitempty"`
}
const (
// default names for cookies and headers
defaultJWTCookieName = "JWT"
@@ -241,7 +247,7 @@ func (j *Service) validate(claims *Claims) error {
func (j *Service) Set(w http.ResponseWriter, claims Claims) (Claims, error) {
nowUnix := time.Now().Unix()
if claims.ExpiresAt == nil || claims.ExpiresAt.Time.Unix() == 0 {
if claims.ExpiresAt == nil || claims.ExpiresAt.Unix() == 0 {
claims.ExpiresAt = jwt.NewNumericDate(time.Unix(nowUnix, 0).Add(j.TokenDuration))
}
+50 -14
View File
@@ -1,8 +1,8 @@
linters-settings:
govet:
check-shadowing: true
shadow: true
golint:
min-confidence: 0
min-confidence: 0.6
gocyclo:
min-complexity: 15
maligned:
@@ -24,44 +24,80 @@ linters-settings:
disabled-checks:
- wrapperFunc
- hugeParam
- rangeValCopy
linters:
disable-all: true
enable:
- megacheck
- revive
- govet
- unconvert
- megacheck
- gas
- gocyclo
- dupl
- misspell
- gosec
- unparam
- unused
- typecheck
- ineffassign
- stylecheck
- gochecknoinits
- exportloopref
- gocritic
- nakedret
- gosimple
- prealloc
fast: false
disable-all: true
run:
output:
format: tab
skip-dirs:
- vendor
concurrency: 4
issues:
exclude-dirs:
- vendor
exclude-rules:
- text: "should have a package comment, unless it's in another file for this package"
linters:
- golint
- text: "exitAfterDefer:"
linters:
- gocritic
- text: "whyNoLint: include an explanation for nolint directive"
linters:
- gocritic
- text: "go.mongodb.org/mongo-driver/bson/primitive.E"
linters:
- govet
- text: "weak cryptographic primitive"
linters:
- gosec
- text: "integer overflow conversion"
linters:
- gosec
- text: "should have a package comment"
linters:
- revive
- text: "at least one file in a package should have a package comment"
linters:
- stylecheck
- text: "commentedOutCode: may want to remove commented-out code"
linters:
- gocritic
- text: "unnamedResult: consider giving a name to these results"
linters:
- gocritic
- text: "var-naming: don't use an underscore in package name"
linters:
- revive
- text: "should not use underscores in package names"
linters:
- stylecheck
- text: "struct literal uses unkeyed fields"
linters:
- govet
- linters:
- unparam
- unused
- revive
path: _test\.go$
text: "unused-parameter"
exclude-use-default: false
+5
View File
@@ -0,0 +1,5 @@
# These owners will be the default owners for everything in the repo.
# Unless a later match takes precedence, @umputun will be requested for
# review when someone opens a pull request.
* @umputun
+77 -4
View File
@@ -37,15 +37,16 @@ _Without `lgr.Caller*` it will drop `{caller}` part_
- `lgr.Trace` - turn trace mode on to allow messages with "TRACE" abd "DEBUG" levels both (filtered otherwise)
- `lgr.Out(io.Writer)` - sets the output writer, default `os.Stdout`
- `lgr.Err(io.Writer)` - sets the error writer, default `os.Stderr`
- `lgr.CallerFile` - adds the caller file info
- `lgr.CallerFunc` - adds the caller function info
- `lgr.CallerPkg` - adds the caller package
- `lgr.CallerFile` - adds the caller file info (only affects lgr's native text format, not slog output)
- `lgr.CallerFunc` - adds the caller function info (only affects lgr's native text format, not slog output)
- `lgr.CallerPkg` - adds the caller package (only affects lgr's native text format, not slog output)
- `lgr.LevelBraces` - wraps levels with "[" and "]"
- `lgr.Msec` - adds milliseconds to timestamp
- `lgr.Format` - sets a custom template, overwrite all other formatting modifiers.
- `lgr.Secret(secret ...)` - sets list of the secrets to hide from the logging outputs.
- `lgr.Map(mapper)` - sets mapper functions to change elements of the logging output based on levels.
- `lgr.StackTraceOnError` - turns on stack trace for ERROR level.
- `lgr.SlogHandler(h slog.Handler)` - delegates logging to the provided slog handler.
example: `l := lgr.New(lgr.Debug, lgr.Msec)`
@@ -106,15 +107,87 @@ example with [fatih/color](https://github.com/fatih/color):
```
### adaptors
`lgr` logger can be converted to `io.Writer` or `*log.Logger`
`lgr` logger can be converted to `io.Writer`, `*log.Logger`, or `slog.Handler`
- `lgr.ToWriter(l lgr.L, level string) io.Writer` - makes io.Writer forwarding write ops to underlying `lgr.L`
- `lgr.ToStdLogger(l lgr.L, level string) *log.Logger` - makes standard logger on top of `lgr.L`
- `lgr.ToSlogHandler(l lgr.L) slog.Handler` - converts lgr.L to a slog.Handler for use with slog
_`level` parameter is optional, if defined (non-empty) will enforce the level._
- `lgr.SetupStdLogger(opts ...Option)` initializes std global logger (`log.std`) with lgr logger and given options.
All standard methods like `log.Print`, `log.Println`, `log.Fatal` and so on will be forwarder to lgr.
- `lgr.SetupWithSlog(logger *slog.Logger)` sets up the global logger with a slog logger.
### slog integration
In addition to the standard logger interface, lgr provides seamless integration with Go's `log/slog` package:
#### Using lgr with slog
```go
// Create lgr logger
lgrLogger := lgr.New(lgr.Debug, lgr.Msec)
// Convert to slog handler and create slog logger
handler := lgr.ToSlogHandler(lgrLogger)
logger := slog.New(handler)
// Use standard slog API with lgr formatting
logger.Info("message", "key1", "value1")
// Output: 2023/09/15 10:34:56.789 INFO message key1="value1"
```
#### Using slog with lgr interface
```go
// Create slog handler
jsonHandler := slog.NewJSONHandler(os.Stdout, nil)
// Wrap it with lgr interface
logger := lgr.FromSlogHandler(jsonHandler)
// Use lgr API with slog backend
logger.Logf("INFO message with %s", "structured data")
// Output: {"time":"2023-09-15T10:34:56.789Z","level":"INFO","msg":"message with structured data"}
```
#### Using slog directly in lgr
```go
// Create a logger that uses slog directly
jsonHandler := slog.NewJSONHandler(os.Stdout, nil)
logger := lgr.New(lgr.SlogHandler(jsonHandler))
// Use lgr API with slog backend
logger.Logf("INFO message")
// Output: {"time":"2023-09-15T10:34:56.789Z","level":"INFO","msg":"message"}
```
#### JSON output with caller information
To get caller information in JSON output when using slog handlers, create the handler with `AddSource: true`:
```go
// Create JSON handler with source information (caller info)
jsonHandler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
AddSource: true, // This enables caller information in JSON output
})
// Use handler with lgr
logger := lgr.New(lgr.SlogHandler(jsonHandler))
logger.Logf("INFO message with caller info")
// Output will include source file, line and function in JSON
```
Note: The lgr caller options (`lgr.CallerFile`, `lgr.CallerFunc`, `lgr.CallerPkg`) only work with lgr's native text format
and don't affect JSON output from slog handlers. To include caller information in JSON logs:
1. For slog JSON handlers: Create the handler with `AddSource: true` as shown above
2. For text-based logs: Use lgr's native caller options without slog integration
This behavior is designed to respect each logging system's conventions for representing caller information.
### global logger
+2 -2
View File
@@ -18,7 +18,7 @@ type Func func(format string, args ...interface{})
func (f Func) Logf(format string, args ...interface{}) { f(format, args...) }
// NoOp logger
var NoOp = Func(func(format string, args ...interface{}) {})
var NoOp = Func(func(format string, args ...interface{}) {}) //nolint:revive
// Std logger sends to std default logger directly
var Std = Func(func(format string, args ...interface{}) { stdlog.Printf(format, args...) })
@@ -30,7 +30,7 @@ func Printf(format string, args ...interface{}) {
// Print simplifies replacement of std logger
func Print(line string) {
def.logf(line)
def.logf(line) //nolint:govet
}
// Fatalf simplifies replacement of std logger
+34 -12
View File
@@ -11,8 +11,10 @@ package lgr
import (
"bytes"
"context"
"fmt"
"io"
"log/slog"
"os"
"path"
"regexp"
@@ -51,18 +53,19 @@ var (
// Logger provided simple logger with basic support of levels. Thread safe
type Logger struct {
// set with Option calls
stdout, stderr io.Writer // destination writes for out and err
sameStream bool // stdout and stderr are the same stream
dbg bool // allows reporting for DEBUG level
trace bool // allows reporting for TRACE and DEBUG levels
callerFile bool // reports caller file with line number, i.e. foo/bar.go:89
callerFunc bool // reports caller function name, i.e. bar.myFunc
callerPkg bool // reports caller package name
levelBraces bool // encloses level with [], i.e. [INFO]
callerDepth int // how many stack frames to skip, relative to the real (reported) frame
format string // layout template
secrets [][]byte // sub-strings to secrets by matching
mapper Mapper // map (alter) output based on levels
stdout, stderr io.Writer // destination writes for out and err
sameStream bool // stdout and stderr are the same stream
dbg bool // allows reporting for DEBUG level
trace bool // allows reporting for TRACE and DEBUG levels
callerFile bool // reports caller file with line number, i.e. foo/bar.go:89
callerFunc bool // reports caller function name, i.e. bar.myFunc
callerPkg bool // reports caller package name
levelBraces bool // encloses level with [], i.e. [INFO]
callerDepth int // how many stack frames to skip, relative to the real (reported) frame
format string // layout template
secrets [][]byte // sub-strings to secrets by matching
mapper Mapper // map (alter) output based on levels
slogHandler slog.Handler // optional slog handler to delegate logging
// internal use
now nowFn
@@ -161,6 +164,25 @@ func (l *Logger) logf(format string, args ...interface{}) {
return
}
// if slog handler is set, use it
if l.slogHandler != nil {
// use NewRecord for consistency with adapter setup
// skip=0 because we don't need caller information from this context
record := slog.NewRecord(l.now(), stringToLevel(lv), msg, 0)
_ = l.slogHandler.Handle(context.Background(), record)
// handle FATAL and PANIC levels as they have special behavior
if lv == "FATAL" || lv == "PANIC" {
if lv == "PANIC" {
// print panic stack trace
stack := getDump()
_, _ = l.stderr.Write([]byte(fmt.Sprintf("\n*** PANIC: %s\n\n%s", msg, stack)))
}
l.fatal()
}
return
}
var ci callerInfo
if l.callerOn { // optimization to avoid expensive caller evaluation if caller info not in the template
ci = l.reportCaller(l.callerDepth)
+35
View File
@@ -2,6 +2,7 @@ package lgr
import (
"io"
"log/slog"
"strings"
)
@@ -48,11 +49,13 @@ func Format(f string) Option {
}
// CallerFunc adds caller info with function name. Ignored if Format option used.
// Note: This option only affects lgr's native text format and is ignored when using SlogHandler.
func CallerFunc(l *Logger) {
l.callerFunc = true
}
// CallerPkg adds caller's package name. Ignored if Format option used.
// Note: This option only affects lgr's native text format and is ignored when using SlogHandler.
func CallerPkg(l *Logger) {
l.callerPkg = true
}
@@ -63,6 +66,7 @@ func LevelBraces(l *Logger) {
}
// CallerFile adds caller info with file, and line number. Ignored if Format option used.
// Note: This option only affects lgr's native text format and is ignored when using SlogHandler.
func CallerFile(l *Logger) {
l.callerFile = true
}
@@ -96,3 +100,34 @@ func Map(m Mapper) Option {
func StackTraceOnError(l *Logger) {
l.errorDump = true
}
// SlogHandler sets slog.Handler to delegate logging to. When using this option,
// the output format will be controlled by the slog.Handler provided, not by lgr's
// format options.
//
// IMPORTANT: When using lgr.SlogHandler:
//
// 1. To get caller information in JSON output, you must create the handler with
// slog.HandlerOptions{AddSource: true}.
//
// 2. The lgr caller info options (lgr.CallerFile, lgr.CallerFunc) do NOT affect
// JSON output from slog handlers. They only work with lgr's native text format.
//
// Example of correct setup for JSON with caller info:
//
// // create handler with AddSource enabled
// jsonHandler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
// AddSource: true, // This enables caller information in JSON output
// })
//
// // use handler with lgr
// logger := lgr.New(lgr.SlogHandler(jsonHandler))
//
// For text format with caller info, use lgr's native caller options:
//
// logger := lgr.New(lgr.CallerFile, lgr.CallerFunc)
func SlogHandler(h slog.Handler) Option {
return func(l *Logger) {
l.slogHandler = h
}
}
+220
View File
@@ -0,0 +1,220 @@
package lgr
import (
"context"
"fmt"
"log/slog"
"os"
"runtime"
"strings"
"time"
)
// ToSlogHandler converts lgr.L to slog.Handler
func ToSlogHandler(l L) slog.Handler {
return &lgrSlogHandler{lgr: l}
}
// FromSlogHandler creates lgr.L wrapper around slog.Handler
func FromSlogHandler(h slog.Handler) L {
return &slogLgrAdapter{handler: h}
}
// SetupWithSlog sets up the global logger with a slog logger
func SetupWithSlog(logger *slog.Logger) {
Setup(SlogHandler(logger.Handler()))
}
// lgrSlogHandler implements slog.Handler using lgr.L
type lgrSlogHandler struct {
lgr L
attrs []slog.Attr
groups []string
}
// Enabled implements slog.Handler
func (h *lgrSlogHandler) Enabled(_ context.Context, level slog.Level) bool {
switch {
case level < slog.LevelInfo: // debug, Trace
// check if underlying lgr logger is configured to show debug
// since we can't directly query lgr's debug status, we assume enabled
return true
default:
return true
}
}
// Handle implements slog.Handler
func (h *lgrSlogHandler) Handle(_ context.Context, record slog.Record) error {
level := levelToString(record.Level)
// build message with attributes
msg := record.Message
// add time if record has it, otherwise current time is used by lgr
var timeStr string
if !record.Time.IsZero() {
timeStr = record.Time.Format("2006/01/02 15:04:05.000 ")
}
// format attributes as key=value pairs
var attrs strings.Builder
if len(h.attrs) > 0 || record.NumAttrs() > 0 {
attrs.WriteString(" ")
}
// add pre-defined attributes
for _, attr := range h.attrs {
attrs.WriteString(formatAttr(attr, h.groups))
}
// add record attributes
record.Attrs(func(attr slog.Attr) bool {
attrs.WriteString(formatAttr(attr, h.groups))
return true
})
// combine everything into final message
logMsg := fmt.Sprintf("%s%s %s%s", timeStr, level, msg, attrs.String())
h.lgr.Logf(logMsg)
return nil
}
// WithAttrs implements slog.Handler
func (h *lgrSlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
newHandler := &lgrSlogHandler{
lgr: h.lgr,
attrs: append(h.attrs, attrs...),
groups: h.groups,
}
return newHandler
}
// WithGroup implements slog.Handler
func (h *lgrSlogHandler) WithGroup(name string) slog.Handler {
newHandler := &lgrSlogHandler{
lgr: h.lgr,
attrs: h.attrs,
groups: append(h.groups, name),
}
return newHandler
}
// slogLgrAdapter implements lgr.L using slog.Handler
type slogLgrAdapter struct {
handler slog.Handler
}
// Logf implements lgr.L interface
func (a *slogLgrAdapter) Logf(format string, args ...interface{}) {
// parse log level from the beginning of the message
msg := fmt.Sprintf(format, args...)
level, msg := extractLevel(msg)
// create a record with caller information
// skip level is critical:
// - 0 = this line
// - 1 = this function (Logf)
// - 2 = caller of Logf (user code)
//
// note: We use PC=0 to ensure slog.Record.PC() returns 0,
// which causes slog to skip obtaining the caller info itself
record := slog.NewRecord(time.Now(), stringToLevel(level), msg, 2)
// we need to manually add the source information ourselves, since
// slog.Handler might have AddSource=true but won't get the caller
// right due to how we're adapting lgr → slog
pc, file, line, ok := runtime.Caller(2) // skip to caller of Logf
if ok {
// only add source info if we can find it
funcName := runtime.FuncForPC(pc).Name()
record.AddAttrs(
slog.Group("source",
slog.String("function", funcName),
slog.String("file", file),
slog.Int("line", line),
),
)
}
// handle the record
if err := a.handler.Handle(context.Background(), record); err != nil {
// if handling fails, fallback to stderr
fmt.Fprintf(os.Stderr, "slog handler error: %v\n", err)
}
}
// Helper functions
// levelToString converts slog.Level to string representation used by lgr
func levelToString(level slog.Level) string {
switch {
case level < slog.LevelInfo:
if level <= slog.LevelDebug-4 {
return "TRACE"
}
return "DEBUG"
case level < slog.LevelWarn:
return "INFO"
case level < slog.LevelError:
return "WARN"
default:
return "ERROR"
}
}
// stringToLevel converts lgr level string to slog.Level
func stringToLevel(level string) slog.Level {
switch level {
case "TRACE":
return slog.LevelDebug - 4
case "DEBUG":
return slog.LevelDebug
case "INFO":
return slog.LevelInfo
case "WARN":
return slog.LevelWarn
case "ERROR", "PANIC", "FATAL":
return slog.LevelError
default:
return slog.LevelInfo
}
}
// extractLevel parses lgr-style log message to extract level prefix
func extractLevel(msg string) (level, message string) {
for _, lvl := range levels {
prefix := lvl + " "
bracketPrefix := "[" + lvl + "] "
if strings.HasPrefix(msg, prefix) {
return lvl, strings.TrimPrefix(msg, prefix)
}
if strings.HasPrefix(msg, bracketPrefix) {
return lvl, strings.TrimPrefix(msg, bracketPrefix)
}
}
return "INFO", msg
}
// formatAttr converts slog.Attr to string representation
func formatAttr(attr slog.Attr, groups []string) string {
if attr.Equal(slog.Attr{}) {
return ""
}
key := attr.Key
if len(groups) > 0 {
key = strings.Join(groups, ".") + "." + key
}
val := attr.Value.String()
// handle string values specially by quoting them
if attr.Value.Kind() == slog.KindString {
val = fmt.Sprintf("%q", attr.Value.String())
}
return fmt.Sprintf("%s=%s ", key, val)
}
+20 -11
View File
@@ -45,7 +45,8 @@ func Get(r *http.Request) (string, error) {
if firstIP == "" && realIP != nil {
firstIP = ip
}
if !realIP.IsGlobalUnicast() || isPrivateSubnet(realIP) {
// Guard against nil realIP
if realIP == nil || !realIP.IsGlobalUnicast() || isPrivateSubnet(realIP) {
continue
}
return ip, nil
@@ -56,22 +57,30 @@ func Get(r *http.Request) (string, error) {
return firstIP, nil
}
ip, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
return "", fmt.Errorf("can't parse ip %q: %w", r.RemoteAddr, err)
}
if netIP := net.ParseIP(ip); netIP == nil {
return "", fmt.Errorf("no valid ip found")
// handle RemoteAddr which may be just an IP or IP:port
remoteIP := r.RemoteAddr
// try to extract host from host:port format
host, _, err := net.SplitHostPort(remoteIP)
if err == nil {
remoteIP = host
}
return ip, nil
// at this point remoteIP could be either:
// 1. the host part extracted from host:port
// 2. yhe original RemoteAddr if it doesn't contain a port
// try to parse it as a valid IP address
if netIP := net.ParseIP(remoteIP); netIP == nil {
return "", fmt.Errorf("no valid ip found in %q", r.RemoteAddr)
}
return remoteIP, nil
}
// isPrivateSubnet - check to see if this ip is in a private subnet
func isPrivateSubnet(ipAddress net.IP) bool {
// inRange - check to see if a given ip address is within a range given
inRange := func(r ipRange, ipAddress net.IP) bool {
inRange := func(r ipRange, ipAddress net.IP) bool { // check to see if a given ip address is within a range given
// ensure the IPs are in the same format for comparison
ipAddress = ipAddress.To16()
r.start = r.start.To16()
+6 -1
View File
@@ -1,8 +1,13 @@
The Snappy compression format in the Go programming language.
To download and install from source:
To use as a library:
$ go get github.com/golang/snappy
To use as a binary:
$ go install github.com/golang/snappy/cmd/snappytool@latest
$ cat decoded | ~/go/bin/snappytool -e > encoded
$ cat encoded | ~/go/bin/snappytool -d > decoded
Unless otherwise noted, the Snappy-Go source files are distributed
under the BSD-style license found in the LICENSE file.
+2 -2
View File
@@ -27,7 +27,7 @@
// The unusual register allocation of local variables, such as R10 for the
// source pointer, matches the allocation used at the call site in encodeBlock,
// which makes it easier to manually inline this function.
TEXT ·emitLiteral(SB), NOSPLIT, $32-56
TEXT ·emitLiteral(SB), NOSPLIT, $40-56
MOVD dst_base+0(FP), R8
MOVD lit_base+24(FP), R10
MOVD lit_len+32(FP), R3
@@ -261,7 +261,7 @@ extendMatchEnd:
// "var table [maxTableSize]uint16" takes up 32768 bytes of stack space. An
// extra 64 bytes, to call other functions, and an extra 64 bytes, to spill
// local variables (registers) during calls gives 32768 + 64 + 64 = 32896.
TEXT ·encodeBlock(SB), 0, $32896-56
TEXT ·encodeBlock(SB), 0, $32904-56
MOVD dst_base+0(FP), R8
MOVD src_base+24(FP), R7
MOVD src_len+32(FP), R14
+45 -95
View File
@@ -14,8 +14,34 @@ This package provides various compression algorithms.
[![Go](https://github.com/klauspost/compress/actions/workflows/go.yml/badge.svg)](https://github.com/klauspost/compress/actions/workflows/go.yml)
[![Sourcegraph Badge](https://sourcegraph.com/github.com/klauspost/compress/-/badge.svg)](https://sourcegraph.com/github.com/klauspost/compress?badge)
# package usage
Use `go get github.com/klauspost/compress@latest` to add it to your project.
This package will support the current Go version and 2 versions back.
* Use the `nounsafe` tag to disable all use of the "unsafe" package.
* Use the `noasm` tag to disable all assembly across packages.
Use the links above for more information on each.
# changelog
* Feb 19th, 2025 - [1.18.0](https://github.com/klauspost/compress/releases/tag/v1.18.0)
* Add unsafe little endian loaders https://github.com/klauspost/compress/pull/1036
* fix: check `r.err != nil` but return a nil value error `err` by @alingse in https://github.com/klauspost/compress/pull/1028
* flate: Simplify L4-6 loading https://github.com/klauspost/compress/pull/1043
* flate: Simplify matchlen (remove asm) https://github.com/klauspost/compress/pull/1045
* s2: Improve small block compression speed w/o asm https://github.com/klauspost/compress/pull/1048
* flate: Fix matchlen L5+L6 https://github.com/klauspost/compress/pull/1049
* flate: Cleanup & reduce casts https://github.com/klauspost/compress/pull/1050
* Oct 11th, 2024 - [1.17.11](https://github.com/klauspost/compress/releases/tag/v1.17.11)
* zstd: Fix extra CRC written with multiple Close calls https://github.com/klauspost/compress/pull/1017
* s2: Don't use stack for index tables https://github.com/klauspost/compress/pull/1014
* gzhttp: No content-type on no body response code by @juliens in https://github.com/klauspost/compress/pull/1011
* gzhttp: Do not set the content-type when response has no body by @kevinpollet in https://github.com/klauspost/compress/pull/1013
* Sep 23rd, 2024 - [1.17.10](https://github.com/klauspost/compress/releases/tag/v1.17.10)
* gzhttp: Add TransportAlwaysDecompress option. https://github.com/klauspost/compress/pull/978
* gzhttp: Add supported decompress request body by @mirecl in https://github.com/klauspost/compress/pull/1002
@@ -65,9 +91,9 @@ https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/comp
* zstd: Fix rare *CORRUPTION* output in "best" mode. See https://github.com/klauspost/compress/pull/876
* Oct 14th, 2023 - [v1.17.1](https://github.com/klauspost/compress/releases/tag/v1.17.1)
* s2: Fix S2 "best" dictionary wrong encoding by @klauspost in https://github.com/klauspost/compress/pull/871
* s2: Fix S2 "best" dictionary wrong encoding https://github.com/klauspost/compress/pull/871
* flate: Reduce allocations in decompressor and minor code improvements by @fakefloordiv in https://github.com/klauspost/compress/pull/869
* s2: Fix EstimateBlockSize on 6&7 length input by @klauspost in https://github.com/klauspost/compress/pull/867
* s2: Fix EstimateBlockSize on 6&7 length input https://github.com/klauspost/compress/pull/867
* Sept 19th, 2023 - [v1.17.0](https://github.com/klauspost/compress/releases/tag/v1.17.0)
* Add experimental dictionary builder https://github.com/klauspost/compress/pull/853
@@ -124,7 +150,7 @@ https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/comp
<summary>See changes to v1.15.x</summary>
* Jan 21st, 2023 (v1.15.15)
* deflate: Improve level 7-9 by @klauspost in https://github.com/klauspost/compress/pull/739
* deflate: Improve level 7-9 https://github.com/klauspost/compress/pull/739
* zstd: Add delta encoding support by @greatroar in https://github.com/klauspost/compress/pull/728
* zstd: Various speed improvements by @greatroar https://github.com/klauspost/compress/pull/741 https://github.com/klauspost/compress/pull/734 https://github.com/klauspost/compress/pull/736 https://github.com/klauspost/compress/pull/744 https://github.com/klauspost/compress/pull/743 https://github.com/klauspost/compress/pull/745
* gzhttp: Add SuffixETag() and DropETag() options to prevent ETag collisions on compressed responses by @willbicks in https://github.com/klauspost/compress/pull/740
@@ -167,7 +193,7 @@ https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/comp
* zstd: Fix decoder crash on amd64 (no BMI) on invalid input https://github.com/klauspost/compress/pull/645
* zstd: Disable decoder extended memory copies (amd64) due to possible crashes https://github.com/klauspost/compress/pull/644
* zstd: Allow single segments up to "max decoded size" by @klauspost in https://github.com/klauspost/compress/pull/643
* zstd: Allow single segments up to "max decoded size" https://github.com/klauspost/compress/pull/643
* July 13, 2022 (v1.15.8)
@@ -209,7 +235,7 @@ https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/comp
* zstd: Speed up when WithDecoderLowmem(false) https://github.com/klauspost/compress/pull/599
* zstd: faster next state update in BMI2 version of decode by @WojciechMula in https://github.com/klauspost/compress/pull/593
* huff0: Do not check max size when reading table. https://github.com/klauspost/compress/pull/586
* flate: Inplace hashing for level 7-9 by @klauspost in https://github.com/klauspost/compress/pull/590
* flate: Inplace hashing for level 7-9 https://github.com/klauspost/compress/pull/590
* May 11, 2022 (v1.15.4)
@@ -236,12 +262,12 @@ https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/comp
* zstd: Add stricter block size checks in [#523](https://github.com/klauspost/compress/pull/523)
* Mar 3, 2022 (v1.15.0)
* zstd: Refactor decoder by @klauspost in [#498](https://github.com/klauspost/compress/pull/498)
* zstd: Add stream encoding without goroutines by @klauspost in [#505](https://github.com/klauspost/compress/pull/505)
* zstd: Refactor decoder [#498](https://github.com/klauspost/compress/pull/498)
* zstd: Add stream encoding without goroutines [#505](https://github.com/klauspost/compress/pull/505)
* huff0: Prevent single blocks exceeding 16 bits by @klauspost in[#507](https://github.com/klauspost/compress/pull/507)
* flate: Inline literal emission by @klauspost in [#509](https://github.com/klauspost/compress/pull/509)
* gzhttp: Add zstd to transport by @klauspost in [#400](https://github.com/klauspost/compress/pull/400)
* gzhttp: Make content-type optional by @klauspost in [#510](https://github.com/klauspost/compress/pull/510)
* flate: Inline literal emission [#509](https://github.com/klauspost/compress/pull/509)
* gzhttp: Add zstd to transport [#400](https://github.com/klauspost/compress/pull/400)
* gzhttp: Make content-type optional [#510](https://github.com/klauspost/compress/pull/510)
Both compression and decompression now supports "synchronous" stream operations. This means that whenever "concurrency" is set to 1, they will operate without spawning goroutines.
@@ -258,7 +284,7 @@ While the release has been extensively tested, it is recommended to testing when
* flate: Fix rare huffman only (-2) corruption. [#503](https://github.com/klauspost/compress/pull/503)
* zip: Update deprecated CreateHeaderRaw to correctly call CreateRaw by @saracen in [#502](https://github.com/klauspost/compress/pull/502)
* zip: don't read data descriptor early by @saracen in [#501](https://github.com/klauspost/compress/pull/501) #501
* huff0: Use static decompression buffer up to 30% faster by @klauspost in [#499](https://github.com/klauspost/compress/pull/499) [#500](https://github.com/klauspost/compress/pull/500)
* huff0: Use static decompression buffer up to 30% faster [#499](https://github.com/klauspost/compress/pull/499) [#500](https://github.com/klauspost/compress/pull/500)
* Feb 17, 2022 (v1.14.3)
* flate: Improve fastest levels compression speed ~10% more throughput. [#482](https://github.com/klauspost/compress/pull/482) [#489](https://github.com/klauspost/compress/pull/489) [#490](https://github.com/klauspost/compress/pull/490) [#491](https://github.com/klauspost/compress/pull/491) [#494](https://github.com/klauspost/compress/pull/494) [#478](https://github.com/klauspost/compress/pull/478)
@@ -565,12 +591,14 @@ While the release has been extensively tested, it is recommended to testing when
The packages are drop-in replacements for standard libraries. Simply replace the import path to use them:
| old import | new import | Documentation
|--------------------|-----------------------------------------|--------------------|
| `compress/gzip` | `github.com/klauspost/compress/gzip` | [gzip](https://pkg.go.dev/github.com/klauspost/compress/gzip?tab=doc)
| `compress/zlib` | `github.com/klauspost/compress/zlib` | [zlib](https://pkg.go.dev/github.com/klauspost/compress/zlib?tab=doc)
| `archive/zip` | `github.com/klauspost/compress/zip` | [zip](https://pkg.go.dev/github.com/klauspost/compress/zip?tab=doc)
| `compress/flate` | `github.com/klauspost/compress/flate` | [flate](https://pkg.go.dev/github.com/klauspost/compress/flate?tab=doc)
Typical speed is about 2x of the standard library packages.
| old import | new import | Documentation |
|------------------|---------------------------------------|-------------------------------------------------------------------------|
| `compress/gzip` | `github.com/klauspost/compress/gzip` | [gzip](https://pkg.go.dev/github.com/klauspost/compress/gzip?tab=doc) |
| `compress/zlib` | `github.com/klauspost/compress/zlib` | [zlib](https://pkg.go.dev/github.com/klauspost/compress/zlib?tab=doc) |
| `archive/zip` | `github.com/klauspost/compress/zip` | [zip](https://pkg.go.dev/github.com/klauspost/compress/zip?tab=doc) |
| `compress/flate` | `github.com/klauspost/compress/flate` | [flate](https://pkg.go.dev/github.com/klauspost/compress/flate?tab=doc) |
* Optimized [deflate](https://godoc.org/github.com/klauspost/compress/flate) packages which can be used as a dropin replacement for [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip) and [zlib](https://godoc.org/github.com/klauspost/compress/zlib).
@@ -625,84 +653,6 @@ This will only use up to 4KB in memory when the writer is idle.
Compression is almost always worse than the fastest compression level
and each write will allocate (a little) memory.
# Performance Update 2018
It has been a while since we have been looking at the speed of this package compared to the standard library, so I thought I would re-do my tests and give some overall recommendations based on the current state. All benchmarks have been performed with Go 1.10 on my Desktop Intel(R) Core(TM) i7-2600 CPU @3.40GHz. Since I last ran the tests, I have gotten more RAM, which means tests with big files are no longer limited by my SSD.
The raw results are in my [updated spreadsheet](https://docs.google.com/spreadsheets/d/1nuNE2nPfuINCZJRMt6wFWhKpToF95I47XjSsc-1rbPQ/edit?usp=sharing). Due to cgo changes and upstream updates i could not get the cgo version of gzip to compile. Instead I included the [zstd](https://github.com/datadog/zstd) cgo implementation. If I get cgo gzip to work again, I might replace the results in the sheet.
The columns to take note of are: *MB/s* - the throughput. *Reduction* - the data size reduction in percent of the original. *Rel Speed* relative speed compared to the standard library at the same level. *Smaller* - how many percent smaller is the compressed output compared to stdlib. Negative means the output was bigger. *Loss* means the loss (or gain) in compression as a percentage difference of the input.
The `gzstd` (standard library gzip) and `gzkp` (this package gzip) only uses one CPU core. [`pgzip`](https://github.com/klauspost/pgzip), [`bgzf`](https://github.com/biogo/hts/tree/master/bgzf) uses all 4 cores. [`zstd`](https://github.com/DataDog/zstd) uses one core, and is a beast (but not Go, yet).
## Overall differences.
There appears to be a roughly 5-10% speed advantage over the standard library when comparing at similar compression levels.
The biggest difference you will see is the result of [re-balancing](https://blog.klauspost.com/rebalancing-deflate-compression-levels/) the compression levels. I wanted by library to give a smoother transition between the compression levels than the standard library.
This package attempts to provide a more smooth transition, where "1" is taking a lot of shortcuts, "5" is the reasonable trade-off and "9" is the "give me the best compression", and the values in between gives something reasonable in between. The standard library has big differences in levels 1-4, but levels 5-9 having no significant gains - often spending a lot more time than can be justified by the achieved compression.
There are links to all the test data in the [spreadsheet](https://docs.google.com/spreadsheets/d/1nuNE2nPfuINCZJRMt6wFWhKpToF95I47XjSsc-1rbPQ/edit?usp=sharing) in the top left field on each tab.
## Web Content
This test set aims to emulate typical use in a web server. The test-set is 4GB data in 53k files, and is a mixture of (mostly) HTML, JS, CSS.
Since level 1 and 9 are close to being the same code, they are quite close. But looking at the levels in-between the differences are quite big.
Looking at level 6, this package is 88% faster, but will output about 6% more data. For a web server, this means you can serve 88% more data, but have to pay for 6% more bandwidth. You can draw your own conclusions on what would be the most expensive for your case.
## Object files
This test is for typical data files stored on a server. In this case it is a collection of Go precompiled objects. They are very compressible.
The picture is similar to the web content, but with small differences since this is very compressible. Levels 2-3 offer good speed, but is sacrificing quite a bit of compression.
The standard library seems suboptimal on level 3 and 4 - offering both worse compression and speed than level 6 & 7 of this package respectively.
## Highly Compressible File
This is a JSON file with very high redundancy. The reduction starts at 95% on level 1, so in real life terms we are dealing with something like a highly redundant stream of data, etc.
It is definitely visible that we are dealing with specialized content here, so the results are very scattered. This package does not do very well at levels 1-4, but picks up significantly at level 5 and levels 7 and 8 offering great speed for the achieved compression.
So if you know you content is extremely compressible you might want to go slightly higher than the defaults. The standard library has a huge gap between levels 3 and 4 in terms of speed (2.75x slowdown), so it offers little "middle ground".
## Medium-High Compressible
This is a pretty common test corpus: [enwik9](http://mattmahoney.net/dc/textdata.html). It contains the first 10^9 bytes of the English Wikipedia dump on Mar. 3, 2006. This is a very good test of typical text based compression and more data heavy streams.
We see a similar picture here as in "Web Content". On equal levels some compression is sacrificed for more speed. Level 5 seems to be the best trade-off between speed and size, beating stdlib level 3 in both.
## Medium Compressible
I will combine two test sets, one [10GB file set](http://mattmahoney.net/dc/10gb.html) and a VM disk image (~8GB). Both contain different data types and represent a typical backup scenario.
The most notable thing is how quickly the standard library drops to very low compression speeds around level 5-6 without any big gains in compression. Since this type of data is fairly common, this does not seem like good behavior.
## Un-compressible Content
This is mainly a test of how good the algorithms are at detecting un-compressible input. The standard library only offers this feature with very conservative settings at level 1. Obviously there is no reason for the algorithms to try to compress input that cannot be compressed. The only downside is that it might skip some compressible data on false detections.
## Huffman only compression
This compression library adds a special compression level, named `HuffmanOnly`, which allows near linear time compression. This is done by completely disabling matching of previous data, and only reduce the number of bits to represent each character.
This means that often used characters, like 'e' and ' ' (space) in text use the fewest bits to represent, and rare characters like '¤' takes more bits to represent. For more information see [wikipedia](https://en.wikipedia.org/wiki/Huffman_coding) or this nice [video](https://youtu.be/ZdooBTdW5bM).
Since this type of compression has much less variance, the compression speed is mostly unaffected by the input data, and is usually more than *180MB/s* for a single core.
The downside is that the compression ratio is usually considerably worse than even the fastest conventional compression. The compression ratio can never be better than 8:1 (12.5%).
The linear time compression can be used as a "better than nothing" mode, where you cannot risk the encoder to slow down on some content. For comparison, the size of the "Twain" text is *233460 bytes* (+29% vs. level 1) and encode speed is 144MB/s (4.5x level 1). So in this case you trade a 30% size increase for a 4 times speedup.
For more information see my blog post on [Fast Linear Time Compression](http://blog.klauspost.com/constant-time-gzipzip-compression/).
This is implemented on Go 1.7 as "Huffman Only" mode, though not exposed for gzip.
# Other packages
+10 -15
View File
@@ -6,10 +6,11 @@
package huff0
import (
"encoding/binary"
"errors"
"fmt"
"io"
"github.com/klauspost/compress/internal/le"
)
// bitReader reads a bitstream in reverse.
@@ -46,7 +47,7 @@ func (b *bitReaderBytes) init(in []byte) error {
return nil
}
// peekBitsFast requires that at least one bit is requested every time.
// peekByteFast requires that at least one byte is requested every time.
// There are no checks if the buffer is filled.
func (b *bitReaderBytes) peekByteFast() uint8 {
got := uint8(b.value >> 56)
@@ -66,8 +67,7 @@ func (b *bitReaderBytes) fillFast() {
}
// 2 bounds checks.
v := b.in[b.off-4 : b.off]
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
low := le.Load32(b.in, b.off-4)
b.value |= uint64(low) << (b.bitsRead - 32)
b.bitsRead -= 32
b.off -= 4
@@ -76,7 +76,7 @@ func (b *bitReaderBytes) fillFast() {
// fillFastStart() assumes the bitReaderBytes is empty and there is at least 8 bytes to read.
func (b *bitReaderBytes) fillFastStart() {
// Do single re-slice to avoid bounds checks.
b.value = binary.LittleEndian.Uint64(b.in[b.off-8:])
b.value = le.Load64(b.in, b.off-8)
b.bitsRead = 0
b.off -= 8
}
@@ -86,9 +86,8 @@ func (b *bitReaderBytes) fill() {
if b.bitsRead < 32 {
return
}
if b.off > 4 {
v := b.in[b.off-4 : b.off]
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
if b.off >= 4 {
low := le.Load32(b.in, b.off-4)
b.value |= uint64(low) << (b.bitsRead - 32)
b.bitsRead -= 32
b.off -= 4
@@ -175,9 +174,7 @@ func (b *bitReaderShifted) fillFast() {
return
}
// 2 bounds checks.
v := b.in[b.off-4 : b.off]
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
low := le.Load32(b.in, b.off-4)
b.value |= uint64(low) << ((b.bitsRead - 32) & 63)
b.bitsRead -= 32
b.off -= 4
@@ -185,8 +182,7 @@ func (b *bitReaderShifted) fillFast() {
// fillFastStart() assumes the bitReaderShifted is empty and there is at least 8 bytes to read.
func (b *bitReaderShifted) fillFastStart() {
// Do single re-slice to avoid bounds checks.
b.value = binary.LittleEndian.Uint64(b.in[b.off-8:])
b.value = le.Load64(b.in, b.off-8)
b.bitsRead = 0
b.off -= 8
}
@@ -197,8 +193,7 @@ func (b *bitReaderShifted) fill() {
return
}
if b.off > 4 {
v := b.in[b.off-4 : b.off]
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
low := le.Load32(b.in, b.off-4)
b.value |= uint64(low) << ((b.bitsRead - 32) & 63)
b.bitsRead -= 32
b.off -= 4
+5
View File
@@ -0,0 +1,5 @@
package le
type Indexer interface {
int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64
}
@@ -0,0 +1,42 @@
//go:build !(amd64 || arm64 || ppc64le || riscv64) || nounsafe || purego || appengine
package le
import (
"encoding/binary"
)
// Load8 will load from b at index i.
func Load8[I Indexer](b []byte, i I) byte {
return b[i]
}
// Load16 will load from b at index i.
func Load16[I Indexer](b []byte, i I) uint16 {
return binary.LittleEndian.Uint16(b[i:])
}
// Load32 will load from b at index i.
func Load32[I Indexer](b []byte, i I) uint32 {
return binary.LittleEndian.Uint32(b[i:])
}
// Load64 will load from b at index i.
func Load64[I Indexer](b []byte, i I) uint64 {
return binary.LittleEndian.Uint64(b[i:])
}
// Store16 will store v at b.
func Store16(b []byte, v uint16) {
binary.LittleEndian.PutUint16(b, v)
}
// Store32 will store v at b.
func Store32(b []byte, v uint32) {
binary.LittleEndian.PutUint32(b, v)
}
// Store64 will store v at b.
func Store64(b []byte, v uint64) {
binary.LittleEndian.PutUint64(b, v)
}
@@ -0,0 +1,55 @@
// We enable 64 bit LE platforms:
//go:build (amd64 || arm64 || ppc64le || riscv64) && !nounsafe && !purego && !appengine
package le
import (
"unsafe"
)
// Load8 will load from b at index i.
func Load8[I Indexer](b []byte, i I) byte {
//return binary.LittleEndian.Uint16(b[i:])
//return *(*uint16)(unsafe.Pointer(&b[i]))
return *(*byte)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i))
}
// Load16 will load from b at index i.
func Load16[I Indexer](b []byte, i I) uint16 {
//return binary.LittleEndian.Uint16(b[i:])
//return *(*uint16)(unsafe.Pointer(&b[i]))
return *(*uint16)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i))
}
// Load32 will load from b at index i.
func Load32[I Indexer](b []byte, i I) uint32 {
//return binary.LittleEndian.Uint32(b[i:])
//return *(*uint32)(unsafe.Pointer(&b[i]))
return *(*uint32)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i))
}
// Load64 will load from b at index i.
func Load64[I Indexer](b []byte, i I) uint64 {
//return binary.LittleEndian.Uint64(b[i:])
//return *(*uint64)(unsafe.Pointer(&b[i]))
return *(*uint64)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i))
}
// Store16 will store v at b.
func Store16(b []byte, v uint16) {
//binary.LittleEndian.PutUint16(b, v)
*(*uint16)(unsafe.Pointer(unsafe.SliceData(b))) = v
}
// Store32 will store v at b.
func Store32(b []byte, v uint32) {
//binary.LittleEndian.PutUint32(b, v)
*(*uint32)(unsafe.Pointer(unsafe.SliceData(b))) = v
}
// Store64 will store v at b.
func Store64(b []byte, v uint64) {
//binary.LittleEndian.PutUint64(b, v)
*(*uint64)(unsafe.Pointer(unsafe.SliceData(b))) = v
}
+1 -2
View File
@@ -1,4 +1,3 @@
module github.com/klauspost/compress
go 1.19
go 1.22
+1 -1
View File
@@ -6,7 +6,7 @@ A high performance compression algorithm is implemented. For now focused on spee
This package provides [compression](#Compressor) to and [decompression](#Decompressor) of Zstandard content.
This package is pure Go and without use of "unsafe".
This package is pure Go. Use `noasm` and `nounsafe` to disable relevant features.
The `zstd` package is provided as open source software using a Go standard license.
+18 -19
View File
@@ -5,11 +5,12 @@
package zstd
import (
"encoding/binary"
"errors"
"fmt"
"io"
"math/bits"
"github.com/klauspost/compress/internal/le"
)
// bitReader reads a bitstream in reverse.
@@ -18,6 +19,7 @@ import (
type bitReader struct {
in []byte
value uint64 // Maybe use [16]byte, but shifting is awkward.
cursor int // offset where next read should end
bitsRead uint8
}
@@ -32,6 +34,7 @@ func (b *bitReader) init(in []byte) error {
if v == 0 {
return errors.New("corrupt stream, did not find end of stream")
}
b.cursor = len(in)
b.bitsRead = 64
b.value = 0
if len(in) >= 8 {
@@ -67,18 +70,15 @@ func (b *bitReader) fillFast() {
if b.bitsRead < 32 {
return
}
v := b.in[len(b.in)-4:]
b.in = b.in[:len(b.in)-4]
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
b.value = (b.value << 32) | uint64(low)
b.cursor -= 4
b.value = (b.value << 32) | uint64(le.Load32(b.in, b.cursor))
b.bitsRead -= 32
}
// fillFastStart() assumes the bitreader is empty and there is at least 8 bytes to read.
func (b *bitReader) fillFastStart() {
v := b.in[len(b.in)-8:]
b.in = b.in[:len(b.in)-8]
b.value = binary.LittleEndian.Uint64(v)
b.cursor -= 8
b.value = le.Load64(b.in, b.cursor)
b.bitsRead = 0
}
@@ -87,25 +87,23 @@ func (b *bitReader) fill() {
if b.bitsRead < 32 {
return
}
if len(b.in) >= 4 {
v := b.in[len(b.in)-4:]
b.in = b.in[:len(b.in)-4]
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
b.value = (b.value << 32) | uint64(low)
if b.cursor >= 4 {
b.cursor -= 4
b.value = (b.value << 32) | uint64(le.Load32(b.in, b.cursor))
b.bitsRead -= 32
return
}
b.bitsRead -= uint8(8 * len(b.in))
for len(b.in) > 0 {
b.value = (b.value << 8) | uint64(b.in[len(b.in)-1])
b.in = b.in[:len(b.in)-1]
b.bitsRead -= uint8(8 * b.cursor)
for b.cursor > 0 {
b.cursor -= 1
b.value = (b.value << 8) | uint64(b.in[b.cursor])
}
}
// finished returns true if all bits have been read from the bit stream.
func (b *bitReader) finished() bool {
return len(b.in) == 0 && b.bitsRead >= 64
return b.cursor == 0 && b.bitsRead >= 64
}
// overread returns true if more bits have been requested than is on the stream.
@@ -115,13 +113,14 @@ func (b *bitReader) overread() bool {
// remain returns the number of bits remaining.
func (b *bitReader) remain() uint {
return 8*uint(len(b.in)) + 64 - uint(b.bitsRead)
return 8*uint(b.cursor) + 64 - uint(b.bitsRead)
}
// close the bitstream and returns an error if out-of-buffer reads occurred.
func (b *bitReader) close() error {
// Release reference.
b.in = nil
b.cursor = 0
if !b.finished() {
return fmt.Errorf("%d extra bits on block, should be 0", b.remain())
}
-19
View File
@@ -5,14 +5,10 @@
package zstd
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"hash/crc32"
"io"
"os"
"path/filepath"
"sync"
"github.com/klauspost/compress/huff0"
@@ -648,21 +644,6 @@ func (b *blockDec) prepareSequences(in []byte, hist *history) (err error) {
println("initializing sequences:", err)
return err
}
// Extract blocks...
if false && hist.dict == nil {
fatalErr := func(err error) {
if err != nil {
panic(err)
}
}
fn := fmt.Sprintf("n-%d-lits-%d-prev-%d-%d-%d-win-%d.blk", hist.decoders.nSeqs, len(hist.decoders.literals), hist.recentOffsets[0], hist.recentOffsets[1], hist.recentOffsets[2], hist.windowSize)
var buf bytes.Buffer
fatalErr(binary.Write(&buf, binary.LittleEndian, hist.decoders.litLengths.fse))
fatalErr(binary.Write(&buf, binary.LittleEndian, hist.decoders.matchLengths.fse))
fatalErr(binary.Write(&buf, binary.LittleEndian, hist.decoders.offsets.fse))
buf.Write(in)
os.WriteFile(filepath.Join("testdata", "seqs", fn), buf.Bytes(), os.ModePerm)
}
return nil
}
+5 -22
View File
@@ -9,6 +9,7 @@ import (
"fmt"
"math"
"math/bits"
"slices"
"github.com/klauspost/compress/huff0"
)
@@ -457,16 +458,7 @@ func fuzzFseEncoder(data []byte) int {
// All 0
return 0
}
maxCount := func(a []uint32) int {
var max uint32
for _, v := range a {
if v > max {
max = v
}
}
return int(max)
}
cnt := maxCount(hist[:maxSym])
cnt := int(slices.Max(hist[:maxSym]))
if cnt == len(data) {
// RLE
return 0
@@ -884,15 +876,6 @@ func (b *blockEnc) genCodes() {
}
}
}
maxCount := func(a []uint32) int {
var max uint32
for _, v := range a {
if v > max {
max = v
}
}
return int(max)
}
if debugAsserts && mlMax > maxMatchLengthSymbol {
panic(fmt.Errorf("mlMax > maxMatchLengthSymbol (%d)", mlMax))
}
@@ -903,7 +886,7 @@ func (b *blockEnc) genCodes() {
panic(fmt.Errorf("llMax > maxLiteralLengthSymbol (%d)", llMax))
}
b.coders.mlEnc.HistogramFinished(mlMax, maxCount(mlH[:mlMax+1]))
b.coders.ofEnc.HistogramFinished(ofMax, maxCount(ofH[:ofMax+1]))
b.coders.llEnc.HistogramFinished(llMax, maxCount(llH[:llMax+1]))
b.coders.mlEnc.HistogramFinished(mlMax, int(slices.Max(mlH[:mlMax+1])))
b.coders.ofEnc.HistogramFinished(ofMax, int(slices.Max(ofH[:ofMax+1])))
b.coders.llEnc.HistogramFinished(llMax, int(slices.Max(llH[:llMax+1])))
}
+2 -1
View File
@@ -123,7 +123,7 @@ func NewReader(r io.Reader, opts ...DOption) (*Decoder, error) {
}
// Read bytes from the decompressed stream into p.
// Returns the number of bytes written and any error that occurred.
// Returns the number of bytes read and any error that occurred.
// When the stream is done, io.EOF will be returned.
func (d *Decoder) Read(p []byte) (int, error) {
var n int
@@ -323,6 +323,7 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) {
frame.bBuf = nil
if frame.history.decoders.br != nil {
frame.history.decoders.br.in = nil
frame.history.decoders.br.cursor = 0
}
d.decoders <- block
}()
+1 -1
View File
@@ -116,7 +116,7 @@ func (e *fastBase) matchlen(s, t int32, src []byte) int32 {
panic(err)
}
if t < 0 {
err := fmt.Sprintf("s (%d) < 0", s)
err := fmt.Sprintf("t (%d) < 0", t)
panic(err)
}
if s-t > e.maxMatchOff {
+8 -3
View File
@@ -7,20 +7,25 @@
package zstd
import (
"encoding/binary"
"math/bits"
"github.com/klauspost/compress/internal/le"
)
// matchLen returns the maximum common prefix length of a and b.
// a must be the shortest of the two.
func matchLen(a, b []byte) (n int) {
for ; len(a) >= 8 && len(b) >= 8; a, b = a[8:], b[8:] {
diff := binary.LittleEndian.Uint64(a) ^ binary.LittleEndian.Uint64(b)
left := len(a)
for left >= 8 {
diff := le.Load64(a, n) ^ le.Load64(b, n)
if diff != 0 {
return n + bits.TrailingZeros64(diff)>>3
}
n += 8
left -= 8
}
a = a[n:]
b = b[n:]
for i := range a {
if a[i] != b[i] {
+1 -1
View File
@@ -245,7 +245,7 @@ func (s *sequenceDecs) decodeSync(hist []byte) error {
return io.ErrUnexpectedEOF
}
var ll, mo, ml int
if len(br.in) > 4+((maxOffsetBits+16+16)>>3) {
if br.cursor > 4+((maxOffsetBits+16+16)>>3) {
// inlined function:
// ll, mo, ml = s.nextFast(br, llState, mlState, ofState)
+32 -32
View File
@@ -7,9 +7,9 @@
TEXT ·sequenceDecs_decode_amd64(SB), $8-32
MOVQ br+8(FP), CX
MOVQ 24(CX), DX
MOVBQZX 32(CX), BX
MOVBQZX 40(CX), BX
MOVQ (CX), AX
MOVQ 8(CX), SI
MOVQ 32(CX), SI
ADDQ SI, AX
MOVQ AX, (SP)
MOVQ ctx+16(FP), AX
@@ -299,8 +299,8 @@ sequenceDecs_decode_amd64_match_len_ofs_ok:
MOVQ R13, 160(AX)
MOVQ br+8(FP), AX
MOVQ DX, 24(AX)
MOVB BL, 32(AX)
MOVQ SI, 8(AX)
MOVB BL, 40(AX)
MOVQ SI, 32(AX)
// Return success
MOVQ $0x00000000, ret+24(FP)
@@ -335,9 +335,9 @@ error_overread:
TEXT ·sequenceDecs_decode_56_amd64(SB), $8-32
MOVQ br+8(FP), CX
MOVQ 24(CX), DX
MOVBQZX 32(CX), BX
MOVBQZX 40(CX), BX
MOVQ (CX), AX
MOVQ 8(CX), SI
MOVQ 32(CX), SI
ADDQ SI, AX
MOVQ AX, (SP)
MOVQ ctx+16(FP), AX
@@ -598,8 +598,8 @@ sequenceDecs_decode_56_amd64_match_len_ofs_ok:
MOVQ R13, 160(AX)
MOVQ br+8(FP), AX
MOVQ DX, 24(AX)
MOVB BL, 32(AX)
MOVQ SI, 8(AX)
MOVB BL, 40(AX)
MOVQ SI, 32(AX)
// Return success
MOVQ $0x00000000, ret+24(FP)
@@ -634,9 +634,9 @@ error_overread:
TEXT ·sequenceDecs_decode_bmi2(SB), $8-32
MOVQ br+8(FP), BX
MOVQ 24(BX), AX
MOVBQZX 32(BX), DX
MOVBQZX 40(BX), DX
MOVQ (BX), CX
MOVQ 8(BX), BX
MOVQ 32(BX), BX
ADDQ BX, CX
MOVQ CX, (SP)
MOVQ ctx+16(FP), CX
@@ -884,8 +884,8 @@ sequenceDecs_decode_bmi2_match_len_ofs_ok:
MOVQ R12, 160(CX)
MOVQ br+8(FP), CX
MOVQ AX, 24(CX)
MOVB DL, 32(CX)
MOVQ BX, 8(CX)
MOVB DL, 40(CX)
MOVQ BX, 32(CX)
// Return success
MOVQ $0x00000000, ret+24(FP)
@@ -920,9 +920,9 @@ error_overread:
TEXT ·sequenceDecs_decode_56_bmi2(SB), $8-32
MOVQ br+8(FP), BX
MOVQ 24(BX), AX
MOVBQZX 32(BX), DX
MOVBQZX 40(BX), DX
MOVQ (BX), CX
MOVQ 8(BX), BX
MOVQ 32(BX), BX
ADDQ BX, CX
MOVQ CX, (SP)
MOVQ ctx+16(FP), CX
@@ -1141,8 +1141,8 @@ sequenceDecs_decode_56_bmi2_match_len_ofs_ok:
MOVQ R12, 160(CX)
MOVQ br+8(FP), CX
MOVQ AX, 24(CX)
MOVB DL, 32(CX)
MOVQ BX, 8(CX)
MOVB DL, 40(CX)
MOVQ BX, 32(CX)
// Return success
MOVQ $0x00000000, ret+24(FP)
@@ -1787,9 +1787,9 @@ empty_seqs:
TEXT ·sequenceDecs_decodeSync_amd64(SB), $64-32
MOVQ br+8(FP), CX
MOVQ 24(CX), DX
MOVBQZX 32(CX), BX
MOVBQZX 40(CX), BX
MOVQ (CX), AX
MOVQ 8(CX), SI
MOVQ 32(CX), SI
ADDQ SI, AX
MOVQ AX, (SP)
MOVQ ctx+16(FP), AX
@@ -2281,8 +2281,8 @@ handle_loop:
loop_finished:
MOVQ br+8(FP), AX
MOVQ DX, 24(AX)
MOVB BL, 32(AX)
MOVQ SI, 8(AX)
MOVB BL, 40(AX)
MOVQ SI, 32(AX)
// Update the context
MOVQ ctx+16(FP), AX
@@ -2349,9 +2349,9 @@ error_not_enough_space:
TEXT ·sequenceDecs_decodeSync_bmi2(SB), $64-32
MOVQ br+8(FP), BX
MOVQ 24(BX), AX
MOVBQZX 32(BX), DX
MOVBQZX 40(BX), DX
MOVQ (BX), CX
MOVQ 8(BX), BX
MOVQ 32(BX), BX
ADDQ BX, CX
MOVQ CX, (SP)
MOVQ ctx+16(FP), CX
@@ -2801,8 +2801,8 @@ handle_loop:
loop_finished:
MOVQ br+8(FP), CX
MOVQ AX, 24(CX)
MOVB DL, 32(CX)
MOVQ BX, 8(CX)
MOVB DL, 40(CX)
MOVQ BX, 32(CX)
// Update the context
MOVQ ctx+16(FP), AX
@@ -2869,9 +2869,9 @@ error_not_enough_space:
TEXT ·sequenceDecs_decodeSync_safe_amd64(SB), $64-32
MOVQ br+8(FP), CX
MOVQ 24(CX), DX
MOVBQZX 32(CX), BX
MOVBQZX 40(CX), BX
MOVQ (CX), AX
MOVQ 8(CX), SI
MOVQ 32(CX), SI
ADDQ SI, AX
MOVQ AX, (SP)
MOVQ ctx+16(FP), AX
@@ -3465,8 +3465,8 @@ handle_loop:
loop_finished:
MOVQ br+8(FP), AX
MOVQ DX, 24(AX)
MOVB BL, 32(AX)
MOVQ SI, 8(AX)
MOVB BL, 40(AX)
MOVQ SI, 32(AX)
// Update the context
MOVQ ctx+16(FP), AX
@@ -3533,9 +3533,9 @@ error_not_enough_space:
TEXT ·sequenceDecs_decodeSync_safe_bmi2(SB), $64-32
MOVQ br+8(FP), BX
MOVQ 24(BX), AX
MOVBQZX 32(BX), DX
MOVBQZX 40(BX), DX
MOVQ (BX), CX
MOVQ 8(BX), BX
MOVQ 32(BX), BX
ADDQ BX, CX
MOVQ CX, (SP)
MOVQ ctx+16(FP), CX
@@ -4087,8 +4087,8 @@ handle_loop:
loop_finished:
MOVQ br+8(FP), CX
MOVQ AX, 24(CX)
MOVB DL, 32(CX)
MOVQ BX, 8(CX)
MOVB DL, 40(CX)
MOVQ BX, 32(CX)
// Update the context
MOVQ ctx+16(FP), AX
+1 -1
View File
@@ -29,7 +29,7 @@ func (s *sequenceDecs) decode(seqs []seqVals) error {
}
for i := range seqs {
var ll, mo, ml int
if len(br.in) > 4+((maxOffsetBits+16+16)>>3) {
if br.cursor > 4+((maxOffsetBits+16+16)>>3) {
// inlined function:
// ll, mo, ml = s.nextFast(br, llState, mlState, ofState)
-2
View File
@@ -69,7 +69,6 @@ var llBitsTable = [maxLLCode + 1]byte{
func llCode(litLength uint32) uint8 {
const llDeltaCode = 19
if litLength <= 63 {
// Compiler insists on bounds check (Go 1.12)
return llCodeTable[litLength&63]
}
return uint8(highBit(litLength)) + llDeltaCode
@@ -102,7 +101,6 @@ var mlBitsTable = [maxMLCode + 1]byte{
func mlCode(mlBase uint32) uint8 {
const mlDeltaCode = 36
if mlBase <= 127 {
// Compiler insists on bounds check (Go 1.12)
return mlCodeTable[mlBase&127]
}
return uint8(highBit(mlBase)) + mlDeltaCode
+2 -2
View File
@@ -197,7 +197,7 @@ func (r *SnappyConverter) Convert(in io.Reader, w io.Writer) (int64, error) {
n, r.err = w.Write(r.block.output)
if r.err != nil {
return written, err
return written, r.err
}
written += int64(n)
continue
@@ -239,7 +239,7 @@ func (r *SnappyConverter) Convert(in io.Reader, w io.Writer) (int64, error) {
}
n, r.err = w.Write(r.block.output)
if r.err != nil {
return written, err
return written, r.err
}
written += int64(n)
continue
+4 -3
View File
@@ -5,10 +5,11 @@ package zstd
import (
"bytes"
"encoding/binary"
"errors"
"log"
"math"
"github.com/klauspost/compress/internal/le"
)
// enable debug printing
@@ -110,11 +111,11 @@ func printf(format string, a ...interface{}) {
}
func load3232(b []byte, i int32) uint32 {
return binary.LittleEndian.Uint32(b[:len(b):len(b)][i:])
return le.Load32(b, i)
}
func load6432(b []byte, i int32) uint64 {
return binary.LittleEndian.Uint64(b[:len(b):len(b)][i:])
return le.Load64(b, i)
}
type byter interface {
@@ -1521,6 +1521,18 @@ func (dvd DefaultValueDecoders) ValueUnmarshalerDecodeValue(_ DecodeContext, vr
return ValueDecoderError{Name: "ValueUnmarshalerDecodeValue", Types: []reflect.Type{tValueUnmarshaler}, Received: val}
}
// If BSON value is null and the go value is a pointer, then don't call
// UnmarshalBSONValue. Even if the Go pointer is already initialized (i.e.,
// non-nil), encountering null in BSON will result in the pointer being
// directly set to nil here. Since the pointer is being replaced with nil,
// there is no opportunity (or reason) for the custom UnmarshalBSONValue logic
// to be called.
if vr.Type() == bsontype.Null && val.Kind() == reflect.Ptr {
val.Set(reflect.Zero(val.Type()))
return vr.ReadNull()
}
if val.Kind() == reflect.Ptr && val.IsNil() {
if !val.CanSet() {
return ValueDecoderError{Name: "ValueUnmarshalerDecodeValue", Types: []reflect.Type{tValueUnmarshaler}, Received: val}
+3
View File
@@ -41,6 +41,9 @@ type ValueUnmarshaler interface {
// Unmarshal parses the BSON-encoded data and stores the result in the value
// pointed to by val. If val is nil or not a pointer, Unmarshal returns
// InvalidUnmarshalError.
//
// When unmarshaling BSON, if the BSON value is null and the Go value is a
// pointer, the pointer is set to nil without calling UnmarshalBSONValue.
func Unmarshal(data []byte, val interface{}) error {
return UnmarshalWithRegistry(DefaultRegistry, data, val)
}
+9
View File
@@ -39,6 +39,7 @@ type bulkWrite struct {
writeConcern *writeconcern.WriteConcern
result BulkWriteResult
let interface{}
bypassEmptyTsReplacement *bool
}
func (bw *bulkWrite) execute(ctx context.Context) error {
@@ -207,6 +208,10 @@ func (bw *bulkWrite) runInsert(ctx context.Context, batch bulkWriteBatch) (opera
}
op = op.Retry(retry)
if bw.bypassEmptyTsReplacement != nil {
op.BypassEmptyTsReplacement(*bw.bypassEmptyTsReplacement)
}
err := op.Execute(ctx)
return op.Result(), err
@@ -415,6 +420,10 @@ func (bw *bulkWrite) runUpdate(ctx context.Context, batch bulkWriteBatch) (opera
}
op = op.Retry(retry)
if bw.bypassEmptyTsReplacement != nil {
op.BypassEmptyTsReplacement(*bw.bypassEmptyTsReplacement)
}
err := op.Execute(ctx)
return op.Result(), err
+1 -1
View File
@@ -861,7 +861,7 @@ func newLogger(opts *options.LoggerOptions) (*logger.Logger, error) {
// If there are no component-level options and the environment does not
// contain component variables, then do nothing.
if (opts.ComponentLevels == nil || len(opts.ComponentLevels) == 0) &&
if (len(opts.ComponentLevels) == 0) &&
!logger.EnvHasComponentVariables() {
return nil, nil
+17
View File
@@ -234,6 +234,7 @@ func (coll *Collection) BulkWrite(ctx context.Context, models []WriteModel,
selector: selector,
writeConcern: wc,
let: bwo.Let,
bypassEmptyTsReplacement: bwo.BypassEmptyTsReplacement,
}
err = op.execute(ctx)
@@ -307,6 +308,9 @@ func (coll *Collection) insert(ctx context.Context, documents []interface{},
if imo.Ordered != nil {
op = op.Ordered(*imo.Ordered)
}
if imo.BypassEmptyTsReplacement != nil {
op = op.BypassEmptyTsReplacement(*imo.BypassEmptyTsReplacement)
}
retry := driver.RetryNone
if coll.client.retryWrites {
retry = driver.RetryOncePerCommand
@@ -355,6 +359,9 @@ func (coll *Collection) InsertOne(ctx context.Context, document interface{},
if ioOpts.Comment != nil {
imOpts.SetComment(ioOpts.Comment)
}
if ioOpts.BypassEmptyTsReplacement != nil {
imOpts.BypassEmptyTsReplacement = ioOpts.BypassEmptyTsReplacement
}
res, err := coll.insert(ctx, []interface{}{document}, imOpts)
rr, err := processWriteError(err)
@@ -609,6 +616,9 @@ func (coll *Collection) updateOrReplace(ctx context.Context, filter bsoncore.Doc
}
op = op.Comment(comment)
}
if uo.BypassEmptyTsReplacement != nil {
op.BypassEmptyTsReplacement(*uo.BypassEmptyTsReplacement)
}
retry := driver.RetryNone
// retryable writes are only enabled updateOne/replaceOne operations
if !multi && coll.client.retryWrites {
@@ -760,6 +770,7 @@ func (coll *Collection) ReplaceOne(ctx context.Context, filter interface{},
uOpts.Hint = opt.Hint
uOpts.Let = opt.Let
uOpts.Comment = opt.Comment
uOpts.BypassEmptyTsReplacement = opt.BypassEmptyTsReplacement
updateOptions = append(updateOptions, uOpts)
}
@@ -1659,6 +1670,9 @@ func (coll *Collection) FindOneAndReplace(ctx context.Context, filter interface{
}
op = op.Let(let)
}
if fo.BypassEmptyTsReplacement != nil {
op = op.BypassEmptyTsReplacement(*fo.BypassEmptyTsReplacement)
}
return coll.findAndModify(ctx, op)
}
@@ -1765,6 +1779,9 @@ func (coll *Collection) FindOneAndUpdate(ctx context.Context, filter interface{}
}
op = op.Let(let)
}
if fo.BypassEmptyTsReplacement != nil {
op = op.BypassEmptyTsReplacement(*fo.BypassEmptyTsReplacement)
}
return coll.findAndModify(ctx, op)
}
@@ -29,6 +29,12 @@ type BulkWriteOptions struct {
// parameter names to values. Values must be constant or closed expressions that do not reference document fields.
// Parameters can then be accessed as variables in an aggregate expression context (e.g. "$$var").
Let interface{}
// If true, the server accepts empty Timestamp as a literal rather than replacing it with the current time.
//
// Deprecated: This option is for internal use only and should not be set. It may be changed or removed in any
// release.
BypassEmptyTsReplacement *bool
}
// BulkWrite creates a new *BulkWriteOptions instance.
@@ -88,6 +94,9 @@ func MergeBulkWriteOptions(opts ...*BulkWriteOptions) *BulkWriteOptions {
if opt.Let != nil {
b.Let = opt.Let
}
if opt.BypassEmptyTsReplacement != nil {
b.BypassEmptyTsReplacement = opt.BypassEmptyTsReplacement
}
}
return b
@@ -675,6 +675,12 @@ type FindOneAndReplaceOptions struct {
// Values must be constant or closed expressions that do not reference document fields. Parameters can then be
// accessed as variables in an aggregate expression context (e.g. "$$var").
Let interface{}
// If true, the server accepts empty Timestamp as a literal rather than replacing it with the current time.
//
// Deprecated: This option is for internal use only and should not be set. It may be changed or removed in any
// release.
BypassEmptyTsReplacement *bool
}
// FindOneAndReplace creates a new FindOneAndReplaceOptions instance.
@@ -787,6 +793,9 @@ func MergeFindOneAndReplaceOptions(opts ...*FindOneAndReplaceOptions) *FindOneAn
if opt.Let != nil {
fo.Let = opt.Let
}
if opt.BypassEmptyTsReplacement != nil {
fo.BypassEmptyTsReplacement = opt.BypassEmptyTsReplacement
}
}
return fo
@@ -852,6 +861,12 @@ type FindOneAndUpdateOptions struct {
// Values must be constant or closed expressions that do not reference document fields. Parameters can then be
// accessed as variables in an aggregate expression context (e.g. "$$var").
Let interface{}
// If true, the server accepts empty Timestamp as a literal rather than replacing it with the current time.
//
// Deprecated: This option is for internal use only and should not be set. It may be changed or removed in any
// release.
BypassEmptyTsReplacement *bool
}
// FindOneAndUpdate creates a new FindOneAndUpdateOptions instance.
@@ -973,6 +988,9 @@ func MergeFindOneAndUpdateOptions(opts ...*FindOneAndUpdateOptions) *FindOneAndU
if opt.Let != nil {
fo.Let = opt.Let
}
if opt.BypassEmptyTsReplacement != nil {
fo.BypassEmptyTsReplacement = opt.BypassEmptyTsReplacement
}
}
return fo
@@ -17,6 +17,12 @@ type InsertOneOptions struct {
// A string or document that will be included in server logs, profiling logs, and currentOp queries to help trace
// the operation. The default value is nil, which means that no comment will be included in the logs.
Comment interface{}
// If true, the server accepts empty Timestamp as a literal rather than replacing it with the current time.
//
// Deprecated: This option is for internal use only and should not be set. It may be changed or removed in any
// release.
BypassEmptyTsReplacement *bool
}
// InsertOne creates a new InsertOneOptions instance.
@@ -53,6 +59,9 @@ func MergeInsertOneOptions(opts ...*InsertOneOptions) *InsertOneOptions {
if ioo.Comment != nil {
ioOpts.Comment = ioo.Comment
}
if ioo.BypassEmptyTsReplacement != nil {
ioOpts.BypassEmptyTsReplacement = ioo.BypassEmptyTsReplacement
}
}
return ioOpts
@@ -72,6 +81,12 @@ type InsertManyOptions struct {
// If true, no writes will be executed after one fails. The default value is true.
Ordered *bool
// If true, the server accepts empty Timestamp as a literal rather than replacing it with the current time.
//
// Deprecated: This option is for internal use only and should not be set. It may be changed or removed in any
// release.
BypassEmptyTsReplacement *bool
}
// InsertMany creates a new InsertManyOptions instance.
@@ -119,6 +134,9 @@ func MergeInsertManyOptions(opts ...*InsertManyOptions) *InsertManyOptions {
if imo.Ordered != nil {
imOpts.Ordered = imo.Ordered
}
if imo.BypassEmptyTsReplacement != nil {
imOpts.BypassEmptyTsReplacement = imo.BypassEmptyTsReplacement
}
}
return imOpts
@@ -40,6 +40,12 @@ type ReplaceOptions struct {
// Values must be constant or closed expressions that do not reference document fields. Parameters can then be
// accessed as variables in an aggregate expression context (e.g. "$$var").
Let interface{}
// If true, the server accepts empty Timestamp as a literal rather than replacing it with the current time.
//
// Deprecated: This option is for internal use only and should not be set. It may be changed or removed in any
// release.
BypassEmptyTsReplacement *bool
}
// Replace creates a new ReplaceOptions instance.
@@ -112,6 +118,9 @@ func MergeReplaceOptions(opts ...*ReplaceOptions) *ReplaceOptions {
if ro.Let != nil {
rOpts.Let = ro.Let
}
if ro.BypassEmptyTsReplacement != nil {
rOpts.BypassEmptyTsReplacement = ro.BypassEmptyTsReplacement
}
}
return rOpts
@@ -45,6 +45,12 @@ type UpdateOptions struct {
// Values must be constant or closed expressions that do not reference document fields. Parameters can then be
// accessed as variables in an aggregate expression context (e.g. "$$var").
Let interface{}
// If true, the server accepts empty Timestamp as a literal rather than replacing it with the current time.
//
// Deprecated: This option is for internal use only and should not be set. It may be changed or removed in any
// release.
BypassEmptyTsReplacement *bool
}
// Update creates a new UpdateOptions instance.
@@ -125,6 +131,9 @@ func MergeUpdateOptions(opts ...*UpdateOptions) *UpdateOptions {
if uo.Let != nil {
uOpts.Let = uo.Let
}
if uo.BypassEmptyTsReplacement != nil {
uOpts.BypassEmptyTsReplacement = uo.BypassEmptyTsReplacement
}
}
return uOpts
+5 -2
View File
@@ -4,8 +4,11 @@
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// DO NOT EDIT. Code generated by Github action
// "mongodb-labs/drivers-github-tools/golang/pre-publish".
// Package version defines the Go Driver version.
package version // import "go.mongodb.org/mongo-driver/version"
package version
// Driver is the current version of the driver.
var Driver = "1.17.1"
var Driver = "1.17.3"
@@ -52,6 +52,7 @@ type FindAndModify struct {
serverAPI *driver.ServerAPIOptions
let bsoncore.Document
timeout *time.Duration
bypassEmptyTsReplacement *bool
result FindAndModifyResult
}
@@ -214,6 +215,9 @@ func (fam *FindAndModify) command(dst []byte, desc description.SelectedServer) (
if fam.let != nil {
dst = bsoncore.AppendDocumentElement(dst, "let", fam.let)
}
if fam.bypassEmptyTsReplacement != nil {
dst = bsoncore.AppendBooleanElement(dst, "bypassEmptyTsReplacement", *fam.bypassEmptyTsReplacement)
}
return dst, nil
}
@@ -489,3 +493,13 @@ func (fam *FindAndModify) Authenticator(authenticator driver.Authenticator) *Fin
fam.authenticator = authenticator
return fam
}
// BypassEmptyTsReplacement sets the bypassEmptyTsReplacement to use for this operation.
func (fam *FindAndModify) BypassEmptyTsReplacement(bypassEmptyTsReplacement bool) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.bypassEmptyTsReplacement = &bypassEmptyTsReplacement
return fam
}
@@ -43,6 +43,7 @@ type Insert struct {
result InsertResult
serverAPI *driver.ServerAPIOptions
timeout *time.Duration
bypassEmptyTsReplacement *bool
logger *logger.Logger
}
@@ -131,6 +132,9 @@ func (i *Insert) command(dst []byte, desc description.SelectedServer) ([]byte, e
if i.ordered != nil {
dst = bsoncore.AppendBooleanElement(dst, "ordered", *i.ordered)
}
if i.bypassEmptyTsReplacement != nil {
dst = bsoncore.AppendBooleanElement(dst, "bypassEmptyTsReplacement", *i.bypassEmptyTsReplacement)
}
return dst, nil
}
@@ -317,3 +321,13 @@ func (i *Insert) Authenticator(authenticator driver.Authenticator) *Insert {
i.authenticator = authenticator
return i
}
// BypassEmptyTsReplacement sets the bypassEmptyTsReplacement to use for this operation.
func (i *Insert) BypassEmptyTsReplacement(bypassEmptyTsReplacement bool) *Insert {
if i == nil {
i = new(Insert)
}
i.bypassEmptyTsReplacement = &bypassEmptyTsReplacement
return i
}
@@ -47,6 +47,7 @@ type Update struct {
serverAPI *driver.ServerAPIOptions
let bsoncore.Document
timeout *time.Duration
bypassEmptyTsReplacement *bool
logger *logger.Logger
}
@@ -204,6 +205,9 @@ func (u *Update) command(dst []byte, desc description.SelectedServer) ([]byte, e
if u.let != nil {
dst = bsoncore.AppendDocumentElement(dst, "let", u.let)
}
if u.bypassEmptyTsReplacement != nil {
dst = bsoncore.AppendBooleanElement(dst, "bypassEmptyTsReplacement", *u.bypassEmptyTsReplacement)
}
return dst, nil
}
@@ -426,3 +430,13 @@ func (u *Update) Authenticator(authenticator driver.Authenticator) *Update {
u.authenticator = authenticator
return u
}
// BypassEmptyTsReplacement sets the bypassEmptyTsReplacement to use for this operation.
func (u *Update) BypassEmptyTsReplacement(bypassEmptyTsReplacement bool) *Update {
if u == nil {
u = new(Update)
}
u.bypassEmptyTsReplacement = &bypassEmptyTsReplacement
return u
}
@@ -539,6 +539,17 @@ func ReadCompressedCompressorID(src []byte) (id CompressorID, rem []byte, ok boo
return CompressorID(src[0]), src[1:], true
}
// ReadCompressedCompressedMessage reads the compressed wiremessage to dst.
//
// Deprecated: This function is not required by the Go Driver and will be
// removed in the 2.0 release.
func ReadCompressedCompressedMessage(src []byte, length int32) (msg []byte, rem []byte, ok bool) {
if len(src) < int(length) || length < 0 {
return nil, src, false
}
return src[:length], src[length:], true
}
// ReadKillCursorsZero reads the zero field from src.
func ReadKillCursorsZero(src []byte) (zero int32, rem []byte, ok bool) {
return readi32(src)
+1 -1
View File
@@ -92,7 +92,7 @@ func jwsEncodeJSON(claimset interface{}, key crypto.Signer, kid KeyID, nonce, ur
if err != nil {
return nil, err
}
phead := base64.RawURLEncoding.EncodeToString([]byte(phJSON))
phead := base64.RawURLEncoding.EncodeToString(phJSON)
var payload string
if val, ok := claimset.(string); ok {
payload = val
+629 -627
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -924,7 +924,7 @@ func inBodyIM(p *parser) bool {
p.addElement()
p.im = inFramesetIM
return true
case a.Address, a.Article, a.Aside, a.Blockquote, a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Main, a.Menu, a.Nav, a.Ol, a.P, a.Section, a.Summary, a.Ul:
case a.Address, a.Article, a.Aside, a.Blockquote, a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Main, a.Menu, a.Nav, a.Ol, a.P, a.Search, a.Section, a.Summary, a.Ul:
p.popUntil(buttonScope, a.P)
p.addElement()
case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
@@ -1136,7 +1136,7 @@ func inBodyIM(p *parser) bool {
return false
}
return true
case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Main, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul:
case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Main, a.Menu, a.Nav, a.Ol, a.Pre, a.Search, a.Section, a.Summary, a.Ul:
p.popUntil(defaultScope, p.tok.DataAtom)
case a.Form:
if p.oe.contains(a.Template) {
+16 -2
View File
@@ -839,8 +839,22 @@ func (z *Tokenizer) readStartTag() TokenType {
if raw {
z.rawTag = strings.ToLower(string(z.buf[z.data.start:z.data.end]))
}
// Look for a self-closing token like "<br/>".
if z.err == nil && z.buf[z.raw.end-2] == '/' {
// Look for a self-closing token (e.g. <br/>).
//
// Originally, we did this by just checking that the last character of the
// tag (ignoring the closing bracket) was a solidus (/) character, but this
// is not always accurate.
//
// We need to be careful that we don't misinterpret a non-self-closing tag
// as self-closing, as can happen if the tag contains unquoted attribute
// values (i.e. <p a=/>).
//
// To avoid this, we check that the last non-bracket character of the tag
// (z.raw.end-2) isn't the same character as the last non-quote character of
// the last attribute of the tag (z.pendingAttr[1].end-1), if the tag has
// attributes.
nAttrs := len(z.attr)
if z.err == nil && z.buf[z.raw.end-2] == '/' && (nAttrs == 0 || z.raw.end-2 != z.attr[nAttrs-1][1].end-1) {
return SelfClosingTagToken
}
return StartTagToken
+12
View File
@@ -35,6 +35,12 @@ var Cern = oauth2.Endpoint{
TokenURL: "https://oauth.web.cern.ch/OAuth/Token",
}
// Discord is the endpoint for Discord.
var Discord = oauth2.Endpoint{
AuthURL: "https://discord.com/oauth2/authorize",
TokenURL: "https://discord.com/api/oauth2/token",
}
// Facebook is the endpoint for Facebook.
var Facebook = oauth2.Endpoint{
AuthURL: "https://www.facebook.com/v3.2/dialog/oauth",
@@ -146,6 +152,12 @@ var Odnoklassniki = oauth2.Endpoint{
TokenURL: "https://api.odnoklassniki.ru/oauth/token.do",
}
// Patreon is the endpoint for Patreon.
var Patreon = oauth2.Endpoint{
AuthURL: "https://www.patreon.com/oauth2/authorize",
TokenURL: "https://www.patreon.com/api/oauth2/token",
}
// PayPal is the endpoint for PayPal.
var PayPal = oauth2.Endpoint{
AuthURL: "https://www.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize",
+12
View File
@@ -251,6 +251,12 @@ func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials
// a Google Developers service account key file, a gcloud user credentials file (a.k.a. refresh
// token JSON), or the JSON configuration file for workload identity federation in non-Google cloud
// platforms (see https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation).
//
// Important: If you accept a credential configuration (credential JSON/File/Stream) from an
// external source for authentication to Google Cloud Platform, you must validate it before
// providing it to any Google API or library. Providing an unvalidated credential configuration to
// Google APIs can compromise the security of your systems and data. For more information, refer to
// [Validate credential configurations from external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
func CredentialsFromJSONWithParams(ctx context.Context, jsonData []byte, params CredentialsParams) (*Credentials, error) {
// Make defensive copy of the slices in params.
params = params.deepCopy()
@@ -294,6 +300,12 @@ func CredentialsFromJSONWithParams(ctx context.Context, jsonData []byte, params
}
// CredentialsFromJSON invokes CredentialsFromJSONWithParams with the specified scopes.
//
// Important: If you accept a credential configuration (credential JSON/File/Stream) from an
// external source for authentication to Google Cloud Platform, you must validate it before
// providing it to any Google API or library. Providing an unvalidated credential configuration to
// Google APIs can compromise the security of your systems and data. For more information, refer to
// [Validate credential configurations from external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*Credentials, error) {
var params CredentialsParams
params.Scopes = scopes
+1 -1
View File
@@ -28,7 +28,7 @@ import (
// AwsSecurityCredentials models AWS security credentials.
type AwsSecurityCredentials struct {
// AccessKeyId is the AWS Access Key ID - Required.
// AccessKeyID is the AWS Access Key ID - Required.
AccessKeyID string `json:"AccessKeyID"`
// SecretAccessKey is the AWS Secret Access Key - Required.
SecretAccessKey string `json:"SecretAccessKey"`
@@ -263,7 +263,7 @@ const (
fileTypeJSON = "json"
)
// Format contains information needed to retireve a subject token for URL or File sourced credentials.
// Format contains information needed to retrieve a subject token for URL or File sourced credentials.
type Format struct {
// Type should be either "text" or "json". This determines whether the file or URL sourced credentials
// expect a simple text subject token or if the subject token will be contained in a JSON object.
@@ -278,20 +278,52 @@ type Format struct {
type CredentialSource struct {
// File is the location for file sourced credentials.
// One field amongst File, URL, Executable, or EnvironmentID should be provided, depending on the kind of credential in question.
//
// Important: If you accept a credential configuration (credential
// JSON/File/Stream) from an external source for authentication to Google
// Cloud Platform, you must validate it before providing it to any Google
// API or library. Providing an unvalidated credential configuration to
// Google APIs can compromise the security of your systems and data. For
// more information, refer to [Validate credential configurations from
// external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
File string `json:"file"`
// Url is the URL to call for URL sourced credentials.
// One field amongst File, URL, Executable, or EnvironmentID should be provided, depending on the kind of credential in question.
//
// Important: If you accept a credential configuration (credential
// JSON/File/Stream) from an external source for authentication to Google
// Cloud Platform, you must validate it before providing it to any Google
// API or library. Providing an unvalidated credential configuration to
// Google APIs can compromise the security of your systems and data. For
// more information, refer to [Validate credential configurations from
// external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
URL string `json:"url"`
// Headers are the headers to attach to the request for URL sourced credentials.
Headers map[string]string `json:"headers"`
// Executable is the configuration object for executable sourced credentials.
// One field amongst File, URL, Executable, or EnvironmentID should be provided, depending on the kind of credential in question.
//
// Important: If you accept a credential configuration (credential
// JSON/File/Stream) from an external source for authentication to Google
// Cloud Platform, you must validate it before providing it to any Google
// API or library. Providing an unvalidated credential configuration to
// Google APIs can compromise the security of your systems and data. For
// more information, refer to [Validate credential configurations from
// external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
Executable *ExecutableConfig `json:"executable"`
// EnvironmentID is the EnvironmentID used for AWS sourced credentials. This should start with "AWS".
// One field amongst File, URL, Executable, or EnvironmentID should be provided, depending on the kind of credential in question.
//
// Important: If you accept a credential configuration (credential
// JSON/File/Stream) from an external source for authentication to Google
// Cloud Platform, you must validate it before providing it to any Google
// API or library. Providing an unvalidated credential configuration to
// Google APIs can compromise the security of your systems and data. For
// more information, refer to [Validate credential configurations from
// external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
EnvironmentID string `json:"environment_id"`
// RegionURL is the metadata URL to retrieve the region from for EC2 AWS credentials.
RegionURL string `json:"region_url"`
@@ -329,7 +361,7 @@ type SubjectTokenSupplier interface {
type AwsSecurityCredentialsSupplier interface {
// AwsRegion should return the AWS region or an error.
AwsRegion(ctx context.Context, options SupplierOptions) (string, error)
// GetAwsSecurityCredentials should return a valid set of AwsSecurityCredentials or an error.
// AwsSecurityCredentials should return a valid set of AwsSecurityCredentials or an error.
// The external account token source does not cache the returned security credentials, so caching
// logic should be implemented in the supplier to prevent multiple requests for the same security credentials.
AwsSecurityCredentials(ctx context.Context, options SupplierOptions) (*AwsSecurityCredentials, error)
+25 -9
View File
@@ -116,12 +116,12 @@ func (h *Header) encode() (string, error) {
// Decode decodes a claim set from a JWS payload.
func Decode(payload string) (*ClaimSet, error) {
// decode returned id token to get expiry
s := strings.Split(payload, ".")
if len(s) < 2 {
_, claims, _, ok := parseToken(payload)
if !ok {
// TODO(jbd): Provide more context about the error.
return nil, errors.New("jws: invalid token received")
}
decoded, err := base64.RawURLEncoding.DecodeString(s[1])
decoded, err := base64.RawURLEncoding.DecodeString(claims)
if err != nil {
return nil, err
}
@@ -165,18 +165,34 @@ func Encode(header *Header, c *ClaimSet, key *rsa.PrivateKey) (string, error) {
// Verify tests whether the provided JWT token's signature was produced by the private key
// associated with the supplied public key.
func Verify(token string, key *rsa.PublicKey) error {
parts := strings.Split(token, ".")
if len(parts) != 3 {
header, claims, sig, ok := parseToken(token)
if !ok {
return errors.New("jws: invalid token received, token must have 3 parts")
}
signedContent := parts[0] + "." + parts[1]
signatureString, err := base64.RawURLEncoding.DecodeString(parts[2])
signatureString, err := base64.RawURLEncoding.DecodeString(sig)
if err != nil {
return err
}
h := sha256.New()
h.Write([]byte(signedContent))
h.Write([]byte(header + tokenDelim + claims))
return rsa.VerifyPKCS1v15(key, crypto.SHA256, h.Sum(nil), signatureString)
}
func parseToken(s string) (header, claims, sig string, ok bool) {
header, s, ok = strings.Cut(s, tokenDelim)
if !ok { // no period found
return "", "", "", false
}
claims, s, ok = strings.Cut(s, tokenDelim)
if !ok { // only one period found
return "", "", "", false
}
sig, _, ok = strings.Cut(s, tokenDelim)
if ok { // three periods found
return "", "", "", false
}
return header, claims, sig, true
}
const tokenDelim = "."
+7 -3
View File
@@ -56,7 +56,7 @@ type Config struct {
// the OAuth flow, after the resource owner's URLs.
RedirectURL string
// Scope specifies optional requested permissions.
// Scopes specifies optional requested permissions.
Scopes []string
// authStyleCache caches which auth style to use when Endpoint.AuthStyle is
@@ -288,7 +288,7 @@ func (tf *tokenRefresher) Token() (*Token, error) {
if tf.refreshToken != tk.RefreshToken {
tf.refreshToken = tk.RefreshToken
}
return tk, err
return tk, nil
}
// reuseTokenSource is a TokenSource that holds a single token in memory
@@ -356,11 +356,15 @@ func NewClient(ctx context.Context, src TokenSource) *http.Client {
if src == nil {
return internal.ContextClient(ctx)
}
cc := internal.ContextClient(ctx)
return &http.Client{
Transport: &Transport{
Base: internal.ContextClient(ctx).Transport,
Base: cc.Transport,
Source: ReuseTokenSource(nil, src),
},
CheckRedirect: cc.CheckRedirect,
Jar: cc.Jar,
Timeout: cc.Timeout,
}
}
+2 -2
View File
@@ -21,7 +21,7 @@ const (
//
// A fresh verifier should be generated for each authorization.
// S256ChallengeOption(verifier) should then be passed to Config.AuthCodeURL
// (or Config.DeviceAccess) and VerifierOption(verifier) to Config.Exchange
// (or Config.DeviceAuth) and VerifierOption(verifier) to Config.Exchange
// (or Config.DeviceAccessToken).
func GenerateVerifier() string {
// "RECOMMENDED that the output of a suitable random number generator be
@@ -51,7 +51,7 @@ func S256ChallengeFromVerifier(verifier string) string {
}
// S256ChallengeOption derives a PKCE code challenge derived from verifier with
// method S256. It should be passed to Config.AuthCodeURL or Config.DeviceAccess
// method S256. It should be passed to Config.AuthCodeURL or Config.DeviceAuth
// only.
func S256ChallengeOption(verifier string) AuthCodeOption {
return challengeOption{
+1 -1
View File
@@ -169,7 +169,7 @@ func tokenFromInternal(t *internal.Token) *Token {
// retrieveToken takes a *Config and uses that to retrieve an *internal.Token.
// This token is then mapped from *internal.Token into an *oauth2.Token which is returned along
// with an error..
// with an error.
func retrieveToken(ctx context.Context, c *Config, v url.Values) (*Token, error) {
tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.Endpoint.TokenURL, v, internal.AuthStyle(c.Endpoint.AuthStyle), c.authStyleCache.Get())
if err != nil {
+2 -1
View File
@@ -18,7 +18,7 @@ import (
type token struct{}
// A Group is a collection of goroutines working on subtasks that are part of
// the same overall task.
// the same overall task. A Group should not be reused for different tasks.
//
// A zero Group is valid, has no limit on the number of active goroutines,
// and does not cancel on error.
@@ -61,6 +61,7 @@ func (g *Group) Wait() error {
}
// Go calls the given function in a new goroutine.
// The first call to Go must happen before a Wait.
// It blocks until the new goroutine can be added without the number of
// active goroutines in the group exceeding the configured limit.
//
+12
View File
@@ -149,6 +149,18 @@ var ARM struct {
_ CacheLinePad
}
// The booleans in Loong64 contain the correspondingly named cpu feature bit.
// The struct is padded to avoid false sharing.
var Loong64 struct {
_ CacheLinePad
HasLSX bool // support 128-bit vector extension
HasLASX bool // support 256-bit vector extension
HasCRC32 bool // support CRC instruction
HasLAM_BH bool // support AM{SWAP/ADD}[_DB].{B/H} instruction
HasLAMCAS bool // support AMCAS[_DB].{B/H/W/D} instruction
_ CacheLinePad
}
// MIPS64X contains the supported CPU features of the current mips64/mips64le
// platforms. If the current platform is not mips64/mips64le or the current
// operating system is not Linux then all feature flags are false.
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2025 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 cpu
// HWCAP bits. These are exposed by the Linux kernel.
const (
hwcap_LOONGARCH_LSX = 1 << 4
hwcap_LOONGARCH_LASX = 1 << 5
)
func doinit() {
// TODO: Features that require kernel support like LSX and LASX can
// be detected here once needed in std library or by the compiler.
Loong64.HasLSX = hwcIsSet(hwCap, hwcap_LOONGARCH_LSX)
Loong64.HasLASX = hwcIsSet(hwCap, hwcap_LOONGARCH_LASX)
}
func hwcIsSet(hwc uint, val uint) bool {
return hwc&val != 0
}
+1 -1
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x && !riscv64
//go:build linux && !arm && !arm64 && !loong64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x && !riscv64
package cpu
+38
View File
@@ -8,5 +8,43 @@ package cpu
const cacheLineSize = 64
// Bit fields for CPUCFG registers, Related reference documents:
// https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#_cpucfg
const (
// CPUCFG1 bits
cpucfg1_CRC32 = 1 << 25
// CPUCFG2 bits
cpucfg2_LAM_BH = 1 << 27
cpucfg2_LAMCAS = 1 << 28
)
func initOptions() {
options = []option{
{Name: "lsx", Feature: &Loong64.HasLSX},
{Name: "lasx", Feature: &Loong64.HasLASX},
{Name: "crc32", Feature: &Loong64.HasCRC32},
{Name: "lam_bh", Feature: &Loong64.HasLAM_BH},
{Name: "lamcas", Feature: &Loong64.HasLAMCAS},
}
// The CPUCFG data on Loong64 only reflects the hardware capabilities,
// not the kernel support status, so features such as LSX and LASX that
// require kernel support cannot be obtained from the CPUCFG data.
//
// These features only require hardware capability support and do not
// require kernel specific support, so they can be obtained directly
// through CPUCFG
cfg1 := get_cpucfg(1)
cfg2 := get_cpucfg(2)
Loong64.HasCRC32 = cfgIsSet(cfg1, cpucfg1_CRC32)
Loong64.HasLAMCAS = cfgIsSet(cfg2, cpucfg2_LAMCAS)
Loong64.HasLAM_BH = cfgIsSet(cfg2, cpucfg2_LAM_BH)
}
func get_cpucfg(reg uint32) uint32
func cfgIsSet(cfg uint32, val uint32) bool {
return cfg&val != 0
}
+13
View File
@@ -0,0 +1,13 @@
// Copyright 2025 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.
#include "textflag.h"
// func get_cpucfg(reg uint32) uint32
TEXT ·get_cpucfg(SB), NOSPLIT|NOFRAME, $0
MOVW reg+0(FP), R5
// CPUCFG R5, R4 = 0x00006ca4
WORD $0x00006ca4
MOVW R4, ret+8(FP)
RET
+2 -2
View File
@@ -13,7 +13,7 @@ import "strconv"
// https://golang.org/cl/209597.
func parseRelease(rel string) (major, minor, patch int, ok bool) {
// Strip anything after a dash or plus.
for i := 0; i < len(rel); i++ {
for i := range len(rel) {
if rel[i] == '-' || rel[i] == '+' {
rel = rel[:i]
break
@@ -21,7 +21,7 @@ func parseRelease(rel string) (major, minor, patch int, ok bool) {
}
next := func() (int, bool) {
for i := 0; i < len(rel); i++ {
for i := range len(rel) {
if rel[i] == '.' {
ver, err := strconv.Atoi(rel[:i])
rel = rel[i+1:]
+148 -1
View File
@@ -602,7 +602,150 @@ func Connectx(fd int, srcIf uint32, srcAddr, dstAddr Sockaddr, associd SaeAssocI
return
}
//sys connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error)
// sys connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error)
const minIovec = 8
func Readv(fd int, iovs [][]byte) (n int, err error) {
if !darwinKernelVersionMin(11, 0, 0) {
return 0, ENOSYS
}
iovecs := make([]Iovec, 0, minIovec)
iovecs = appendBytes(iovecs, iovs)
n, err = readv(fd, iovecs)
readvRacedetect(iovecs, n, err)
return n, err
}
func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) {
if !darwinKernelVersionMin(11, 0, 0) {
return 0, ENOSYS
}
iovecs := make([]Iovec, 0, minIovec)
iovecs = appendBytes(iovecs, iovs)
n, err = preadv(fd, iovecs, offset)
readvRacedetect(iovecs, n, err)
return n, err
}
func Writev(fd int, iovs [][]byte) (n int, err error) {
if !darwinKernelVersionMin(11, 0, 0) {
return 0, ENOSYS
}
iovecs := make([]Iovec, 0, minIovec)
iovecs = appendBytes(iovecs, iovs)
if raceenabled {
raceReleaseMerge(unsafe.Pointer(&ioSync))
}
n, err = writev(fd, iovecs)
writevRacedetect(iovecs, n)
return n, err
}
func Pwritev(fd int, iovs [][]byte, offset int64) (n int, err error) {
if !darwinKernelVersionMin(11, 0, 0) {
return 0, ENOSYS
}
iovecs := make([]Iovec, 0, minIovec)
iovecs = appendBytes(iovecs, iovs)
if raceenabled {
raceReleaseMerge(unsafe.Pointer(&ioSync))
}
n, err = pwritev(fd, iovecs, offset)
writevRacedetect(iovecs, n)
return n, err
}
func appendBytes(vecs []Iovec, bs [][]byte) []Iovec {
for _, b := range bs {
var v Iovec
v.SetLen(len(b))
if len(b) > 0 {
v.Base = &b[0]
} else {
v.Base = (*byte)(unsafe.Pointer(&_zero))
}
vecs = append(vecs, v)
}
return vecs
}
func writevRacedetect(iovecs []Iovec, n int) {
if !raceenabled {
return
}
for i := 0; n > 0 && i < len(iovecs); i++ {
m := int(iovecs[i].Len)
if m > n {
m = n
}
n -= m
if m > 0 {
raceReadRange(unsafe.Pointer(iovecs[i].Base), m)
}
}
}
func readvRacedetect(iovecs []Iovec, n int, err error) {
if !raceenabled {
return
}
for i := 0; n > 0 && i < len(iovecs); i++ {
m := int(iovecs[i].Len)
if m > n {
m = n
}
n -= m
if m > 0 {
raceWriteRange(unsafe.Pointer(iovecs[i].Base), m)
}
}
if err == nil {
raceAcquire(unsafe.Pointer(&ioSync))
}
}
func darwinMajorMinPatch() (maj, min, patch int, err error) {
var un Utsname
err = Uname(&un)
if err != nil {
return
}
var mmp [3]int
c := 0
Loop:
for _, b := range un.Release[:] {
switch {
case b >= '0' && b <= '9':
mmp[c] = 10*mmp[c] + int(b-'0')
case b == '.':
c++
if c > 2 {
return 0, 0, 0, ENOTSUP
}
case b == 0:
break Loop
default:
return 0, 0, 0, ENOTSUP
}
}
if c != 2 {
return 0, 0, 0, ENOTSUP
}
return mmp[0], mmp[1], mmp[2], nil
}
func darwinKernelVersionMin(maj, min, patch int) bool {
actualMaj, actualMin, actualPatch, err := darwinMajorMinPatch()
if err != nil {
return false
}
return actualMaj > maj || actualMaj == maj && (actualMin > min || actualMin == min && actualPatch >= patch)
}
//sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error)
//sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error)
@@ -705,3 +848,7 @@ func Connectx(fd int, srcIf uint32, srcAddr, dstAddr Sockaddr, associd SaeAssocI
//sys write(fd int, p []byte) (n int, err error)
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
//sys munmap(addr uintptr, length uintptr) (err error)
//sys readv(fd int, iovecs []Iovec) (n int, err error)
//sys preadv(fd int, iovecs []Iovec, offset int64) (n int, err error)
//sys writev(fd int, iovecs []Iovec) (n int, err error)
//sys pwritev(fd int, iovecs []Iovec, offset int64) (n int, err error)
+16 -26
View File
@@ -13,6 +13,7 @@ package unix
import (
"encoding/binary"
"slices"
"strconv"
"syscall"
"time"
@@ -417,7 +418,7 @@ func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
return nil, 0, EINVAL
}
sa.raw.Family = AF_UNIX
for i := 0; i < n; i++ {
for i := range n {
sa.raw.Path[i] = int8(name[i])
}
// length is family (uint16), name, NUL.
@@ -507,7 +508,7 @@ func (sa *SockaddrL2) sockaddr() (unsafe.Pointer, _Socklen, error) {
psm := (*[2]byte)(unsafe.Pointer(&sa.raw.Psm))
psm[0] = byte(sa.PSM)
psm[1] = byte(sa.PSM >> 8)
for i := 0; i < len(sa.Addr); i++ {
for i := range len(sa.Addr) {
sa.raw.Bdaddr[i] = sa.Addr[len(sa.Addr)-1-i]
}
cid := (*[2]byte)(unsafe.Pointer(&sa.raw.Cid))
@@ -589,11 +590,11 @@ func (sa *SockaddrCAN) sockaddr() (unsafe.Pointer, _Socklen, error) {
sa.raw.Family = AF_CAN
sa.raw.Ifindex = int32(sa.Ifindex)
rx := (*[4]byte)(unsafe.Pointer(&sa.RxID))
for i := 0; i < 4; i++ {
for i := range 4 {
sa.raw.Addr[i] = rx[i]
}
tx := (*[4]byte)(unsafe.Pointer(&sa.TxID))
for i := 0; i < 4; i++ {
for i := range 4 {
sa.raw.Addr[i+4] = tx[i]
}
return unsafe.Pointer(&sa.raw), SizeofSockaddrCAN, nil
@@ -618,11 +619,11 @@ func (sa *SockaddrCANJ1939) sockaddr() (unsafe.Pointer, _Socklen, error) {
sa.raw.Family = AF_CAN
sa.raw.Ifindex = int32(sa.Ifindex)
n := (*[8]byte)(unsafe.Pointer(&sa.Name))
for i := 0; i < 8; i++ {
for i := range 8 {
sa.raw.Addr[i] = n[i]
}
p := (*[4]byte)(unsafe.Pointer(&sa.PGN))
for i := 0; i < 4; i++ {
for i := range 4 {
sa.raw.Addr[i+8] = p[i]
}
sa.raw.Addr[12] = sa.Addr
@@ -911,7 +912,7 @@ func (sa *SockaddrIUCV) sockaddr() (unsafe.Pointer, _Socklen, error) {
// These are EBCDIC encoded by the kernel, but we still need to pad them
// with blanks. Initializing with blanks allows the caller to feed in either
// a padded or an unpadded string.
for i := 0; i < 8; i++ {
for i := range 8 {
sa.raw.Nodeid[i] = ' '
sa.raw.User_id[i] = ' '
sa.raw.Name[i] = ' '
@@ -1148,7 +1149,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
var user [8]byte
var name [8]byte
for i := 0; i < 8; i++ {
for i := range 8 {
user[i] = byte(pp.User_id[i])
name[i] = byte(pp.Name[i])
}
@@ -1173,11 +1174,11 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
Ifindex: int(pp.Ifindex),
}
name := (*[8]byte)(unsafe.Pointer(&sa.Name))
for i := 0; i < 8; i++ {
for i := range 8 {
name[i] = pp.Addr[i]
}
pgn := (*[4]byte)(unsafe.Pointer(&sa.PGN))
for i := 0; i < 4; i++ {
for i := range 4 {
pgn[i] = pp.Addr[i+8]
}
addr := (*[1]byte)(unsafe.Pointer(&sa.Addr))
@@ -1188,11 +1189,11 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
Ifindex: int(pp.Ifindex),
}
rx := (*[4]byte)(unsafe.Pointer(&sa.RxID))
for i := 0; i < 4; i++ {
for i := range 4 {
rx[i] = pp.Addr[i]
}
tx := (*[4]byte)(unsafe.Pointer(&sa.TxID))
for i := 0; i < 4; i++ {
for i := range 4 {
tx[i] = pp.Addr[i+4]
}
return sa, nil
@@ -2216,10 +2217,7 @@ func readvRacedetect(iovecs []Iovec, n int, err error) {
return
}
for i := 0; n > 0 && i < len(iovecs); i++ {
m := int(iovecs[i].Len)
if m > n {
m = n
}
m := min(int(iovecs[i].Len), n)
n -= m
if m > 0 {
raceWriteRange(unsafe.Pointer(iovecs[i].Base), m)
@@ -2270,10 +2268,7 @@ func writevRacedetect(iovecs []Iovec, n int) {
return
}
for i := 0; n > 0 && i < len(iovecs); i++ {
m := int(iovecs[i].Len)
if m > n {
m = n
}
m := min(int(iovecs[i].Len), n)
n -= m
if m > 0 {
raceReadRange(unsafe.Pointer(iovecs[i].Base), m)
@@ -2320,12 +2315,7 @@ func isGroupMember(gid int) bool {
return false
}
for _, g := range groups {
if g == gid {
return true
}
}
return false
return slices.Contains(groups, gid)
}
func isCapDacOverrideSet() bool {
+84
View File
@@ -2512,6 +2512,90 @@ var libc_munmap_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func readv(fd int, iovecs []Iovec) (n int, err error) {
var _p0 unsafe.Pointer
if len(iovecs) > 0 {
_p0 = unsafe.Pointer(&iovecs[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall_syscall(libc_readv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)))
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_readv_trampoline_addr uintptr
//go:cgo_import_dynamic libc_readv readv "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func preadv(fd int, iovecs []Iovec, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(iovecs) > 0 {
_p0 = unsafe.Pointer(&iovecs[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall_syscall6(libc_preadv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0)
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_preadv_trampoline_addr uintptr
//go:cgo_import_dynamic libc_preadv preadv "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func writev(fd int, iovecs []Iovec) (n int, err error) {
var _p0 unsafe.Pointer
if len(iovecs) > 0 {
_p0 = unsafe.Pointer(&iovecs[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall_syscall(libc_writev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)))
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_writev_trampoline_addr uintptr
//go:cgo_import_dynamic libc_writev writev "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func pwritev(fd int, iovecs []Iovec, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(iovecs) > 0 {
_p0 = unsafe.Pointer(&iovecs[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall_syscall6(libc_pwritev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0)
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_pwritev_trampoline_addr uintptr
//go:cgo_import_dynamic libc_pwritev pwritev "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fstat(fd int, stat *Stat_t) (err error) {
_, _, e1 := syscall_syscall(libc_fstat64_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
if e1 != 0 {
+20
View File
@@ -738,6 +738,26 @@ TEXT libc_munmap_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_munmap_trampoline_addr(SB), RODATA, $8
DATA ·libc_munmap_trampoline_addr(SB)/8, $libc_munmap_trampoline<>(SB)
TEXT libc_readv_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_readv(SB)
GLOBL ·libc_readv_trampoline_addr(SB), RODATA, $8
DATA ·libc_readv_trampoline_addr(SB)/8, $libc_readv_trampoline<>(SB)
TEXT libc_preadv_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_preadv(SB)
GLOBL ·libc_preadv_trampoline_addr(SB), RODATA, $8
DATA ·libc_preadv_trampoline_addr(SB)/8, $libc_preadv_trampoline<>(SB)
TEXT libc_writev_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_writev(SB)
GLOBL ·libc_writev_trampoline_addr(SB), RODATA, $8
DATA ·libc_writev_trampoline_addr(SB)/8, $libc_writev_trampoline<>(SB)
TEXT libc_pwritev_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_pwritev(SB)
GLOBL ·libc_pwritev_trampoline_addr(SB), RODATA, $8
DATA ·libc_pwritev_trampoline_addr(SB)/8, $libc_pwritev_trampoline<>(SB)
TEXT libc_fstat64_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_fstat64(SB)
GLOBL ·libc_fstat64_trampoline_addr(SB), RODATA, $8
+84
View File
@@ -2512,6 +2512,90 @@ var libc_munmap_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func readv(fd int, iovecs []Iovec) (n int, err error) {
var _p0 unsafe.Pointer
if len(iovecs) > 0 {
_p0 = unsafe.Pointer(&iovecs[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall_syscall(libc_readv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)))
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_readv_trampoline_addr uintptr
//go:cgo_import_dynamic libc_readv readv "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func preadv(fd int, iovecs []Iovec, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(iovecs) > 0 {
_p0 = unsafe.Pointer(&iovecs[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall_syscall6(libc_preadv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0)
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_preadv_trampoline_addr uintptr
//go:cgo_import_dynamic libc_preadv preadv "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func writev(fd int, iovecs []Iovec) (n int, err error) {
var _p0 unsafe.Pointer
if len(iovecs) > 0 {
_p0 = unsafe.Pointer(&iovecs[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall_syscall(libc_writev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)))
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_writev_trampoline_addr uintptr
//go:cgo_import_dynamic libc_writev writev "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func pwritev(fd int, iovecs []Iovec, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(iovecs) > 0 {
_p0 = unsafe.Pointer(&iovecs[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall_syscall6(libc_pwritev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0)
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_pwritev_trampoline_addr uintptr
//go:cgo_import_dynamic libc_pwritev pwritev "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fstat(fd int, stat *Stat_t) (err error) {
_, _, e1 := syscall_syscall(libc_fstat_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
if e1 != 0 {
+20
View File
@@ -738,6 +738,26 @@ TEXT libc_munmap_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_munmap_trampoline_addr(SB), RODATA, $8
DATA ·libc_munmap_trampoline_addr(SB)/8, $libc_munmap_trampoline<>(SB)
TEXT libc_readv_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_readv(SB)
GLOBL ·libc_readv_trampoline_addr(SB), RODATA, $8
DATA ·libc_readv_trampoline_addr(SB)/8, $libc_readv_trampoline<>(SB)
TEXT libc_preadv_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_preadv(SB)
GLOBL ·libc_preadv_trampoline_addr(SB), RODATA, $8
DATA ·libc_preadv_trampoline_addr(SB)/8, $libc_preadv_trampoline<>(SB)
TEXT libc_writev_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_writev(SB)
GLOBL ·libc_writev_trampoline_addr(SB), RODATA, $8
DATA ·libc_writev_trampoline_addr(SB)/8, $libc_writev_trampoline<>(SB)
TEXT libc_pwritev_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_pwritev(SB)
GLOBL ·libc_pwritev_trampoline_addr(SB), RODATA, $8
DATA ·libc_pwritev_trampoline_addr(SB)/8, $libc_pwritev_trampoline<>(SB)
TEXT libc_fstat_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_fstat(SB)
GLOBL ·libc_fstat_trampoline_addr(SB), RODATA, $8
+11 -2
View File
@@ -164,7 +164,12 @@ loopItems:
func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool, err error) {
var h syscall.Handle
var d uint32
err = regCreateKeyEx(syscall.Handle(k), syscall.StringToUTF16Ptr(path),
var pathPointer *uint16
pathPointer, err = syscall.UTF16PtrFromString(path)
if err != nil {
return 0, false, err
}
err = regCreateKeyEx(syscall.Handle(k), pathPointer,
0, nil, _REG_OPTION_NON_VOLATILE, access, nil, &h, &d)
if err != nil {
return 0, false, err
@@ -174,7 +179,11 @@ func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool
// DeleteKey deletes the subkey path of key k and its values.
func DeleteKey(k Key, path string) error {
return regDeleteKey(syscall.Handle(k), syscall.StringToUTF16Ptr(path))
pathPointer, err := syscall.UTF16PtrFromString(path)
if err != nil {
return err
}
return regDeleteKey(syscall.Handle(k), pathPointer)
}
// A KeyInfo describes the statistics of a key. It is returned by Stat.
+5 -1
View File
@@ -340,7 +340,11 @@ func (k Key) SetBinaryValue(name string, value []byte) error {
// DeleteValue removes a named value from the key k.
func (k Key) DeleteValue(name string) error {
return regDeleteValue(syscall.Handle(k), syscall.StringToUTF16Ptr(name))
namePointer, err := syscall.UTF16PtrFromString(name)
if err != nil {
return err
}
return regDeleteValue(syscall.Handle(k), namePointer)
}
// ReadValueNames returns the value names of key k.
+27
View File
@@ -1074,6 +1074,7 @@ const (
IP_ADD_MEMBERSHIP = 0xc
IP_DROP_MEMBERSHIP = 0xd
IP_PKTINFO = 0x13
IP_MTU_DISCOVER = 0x47
IPV6_V6ONLY = 0x1b
IPV6_UNICAST_HOPS = 0x4
@@ -1083,6 +1084,7 @@ const (
IPV6_JOIN_GROUP = 0xc
IPV6_LEAVE_GROUP = 0xd
IPV6_PKTINFO = 0x13
IPV6_MTU_DISCOVER = 0x47
MSG_OOB = 0x1
MSG_PEEK = 0x2
@@ -1132,6 +1134,15 @@ const (
WSASYS_STATUS_LEN = 128
)
// enum PMTUD_STATE from ws2ipdef.h
const (
IP_PMTUDISC_NOT_SET = 0
IP_PMTUDISC_DO = 1
IP_PMTUDISC_DONT = 2
IP_PMTUDISC_PROBE = 3
IP_PMTUDISC_MAX = 4
)
type WSABuf struct {
Len uint32
Buf *byte
@@ -1146,6 +1157,22 @@ type WSAMsg struct {
Flags uint32
}
type WSACMSGHDR struct {
Len uintptr
Level int32
Type int32
}
type IN_PKTINFO struct {
Addr [4]byte
Ifindex uint32
}
type IN6_PKTINFO struct {
Addr [16]byte
Ifindex uint32
}
// Flags for WSASocket
const (
WSA_FLAG_OVERLAPPED = 0x01
+19 -18
View File
@@ -67,13 +67,13 @@ github.com/go-chi/cors
# github.com/go-chi/render v1.0.3
## explicit; go 1.16
github.com/go-chi/render
# github.com/go-oauth2/oauth2/v4 v4.5.2
# github.com/go-oauth2/oauth2/v4 v4.5.3
## explicit; go 1.13
github.com/go-oauth2/oauth2/v4
github.com/go-oauth2/oauth2/v4/errors
github.com/go-oauth2/oauth2/v4/server
# github.com/go-pkgz/auth/v2 v2.0.0-20241221172452-ba01339372ba
## explicit; go 1.21
# github.com/go-pkgz/auth/v2 v2.0.1-0.20250415030422-4f9f2c5e3b0d
## explicit; go 1.23.0
github.com/go-pkgz/auth/v2
github.com/go-pkgz/auth/v2/avatar
github.com/go-pkgz/auth/v2/logger
@@ -94,8 +94,8 @@ github.com/go-pkgz/jrpc
## explicit; go 1.21
github.com/go-pkgz/lcw/v2
github.com/go-pkgz/lcw/v2/eventbus
# github.com/go-pkgz/lgr v0.11.1
## explicit; go 1.20
# github.com/go-pkgz/lgr v0.12.0
## explicit; go 1.21
github.com/go-pkgz/lgr
# github.com/go-pkgz/notify v1.2.0
## explicit; go 1.21
@@ -104,7 +104,7 @@ github.com/go-pkgz/notify
## explicit; go 1.20
github.com/go-pkgz/repeater
github.com/go-pkgz/repeater/strategy
# github.com/go-pkgz/rest v1.20.2
# github.com/go-pkgz/rest v1.20.3
## explicit; go 1.21
github.com/go-pkgz/rest
github.com/go-pkgz/rest/logger
@@ -115,7 +115,7 @@ github.com/go-pkgz/syncs
# github.com/golang-jwt/jwt/v5 v5.2.2
## explicit; go 1.18
github.com/golang-jwt/jwt/v5
# github.com/golang/snappy v0.0.4
# github.com/golang/snappy v1.0.0
## explicit
github.com/golang/snappy
# github.com/google/uuid v1.6.0
@@ -145,12 +145,13 @@ github.com/hashicorp/golang-lru/v2/simplelru
# github.com/jessevdk/go-flags v1.6.1
## explicit; go 1.20
github.com/jessevdk/go-flags
# github.com/klauspost/compress v1.17.11
## explicit; go 1.21
# github.com/klauspost/compress v1.18.0
## explicit; go 1.22
github.com/klauspost/compress
github.com/klauspost/compress/fse
github.com/klauspost/compress/huff0
github.com/klauspost/compress/internal/cpuinfo
github.com/klauspost/compress/internal/le
github.com/klauspost/compress/internal/snapref
github.com/klauspost/compress/zstd
github.com/klauspost/compress/zstd/internal/xxhash
@@ -221,7 +222,7 @@ go.etcd.io/bbolt
go.etcd.io/bbolt/errors
go.etcd.io/bbolt/internal/common
go.etcd.io/bbolt/internal/freelist
# go.mongodb.org/mongo-driver v1.17.1
# go.mongodb.org/mongo-driver v1.17.3
## explicit; go 1.18
go.mongodb.org/mongo-driver/bson
go.mongodb.org/mongo-driver/bson/bsoncodec
@@ -275,7 +276,7 @@ go.mongodb.org/mongo-driver/x/mongo/driver/wiremessage
## explicit; go 1.20
go.uber.org/goleak
go.uber.org/goleak/internal/stack
# golang.org/x/crypto v0.36.0
# golang.org/x/crypto v0.37.0
## explicit; go 1.23.0
golang.org/x/crypto/acme
golang.org/x/crypto/acme/autocert
@@ -286,17 +287,17 @@ golang.org/x/crypto/blowfish
golang.org/x/crypto/ocsp
golang.org/x/crypto/pbkdf2
golang.org/x/crypto/scrypt
# golang.org/x/image v0.25.0
# golang.org/x/image v0.26.0
## explicit; go 1.23.0
golang.org/x/image/draw
golang.org/x/image/math/f64
# golang.org/x/net v0.37.0
# golang.org/x/net v0.39.0
## explicit; go 1.23.0
golang.org/x/net/html
golang.org/x/net/html/atom
golang.org/x/net/idna
# golang.org/x/oauth2 v0.24.0
## explicit; go 1.18
# golang.org/x/oauth2 v0.29.0
## explicit; go 1.23.0
golang.org/x/oauth2
golang.org/x/oauth2/authhandler
golang.org/x/oauth2/endpoints
@@ -312,17 +313,17 @@ golang.org/x/oauth2/jws
golang.org/x/oauth2/jwt
golang.org/x/oauth2/microsoft
golang.org/x/oauth2/yandex
# golang.org/x/sync v0.12.0
# golang.org/x/sync v0.13.0
## explicit; go 1.23.0
golang.org/x/sync/errgroup
golang.org/x/sync/singleflight
# golang.org/x/sys v0.31.0
# golang.org/x/sys v0.32.0
## explicit; go 1.23.0
golang.org/x/sys/cpu
golang.org/x/sys/unix
golang.org/x/sys/windows
golang.org/x/sys/windows/registry
# golang.org/x/text v0.23.0
# golang.org/x/text v0.24.0
## explicit; go 1.23.0
golang.org/x/text/secure/bidirule
golang.org/x/text/transform