chore: bump packages, consolidated dependabot (#12240)

* chore(deps): bump @testing-library/jest-dom in /services/idp

Bumps [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) from 6.6.4 to 6.9.1.
- [Release notes](https://github.com/testing-library/jest-dom/releases)
- [Changelog](https://github.com/testing-library/jest-dom/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/jest-dom/compare/v6.6.4...v6.9.1)

---
updated-dependencies:
- dependency-name: "@testing-library/jest-dom"
  dependency-version: 6.9.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(deps): bump filippo.io/edwards25519 from 1.1.0 to 1.1.1

Bumps [filippo.io/edwards25519](https://github.com/FiloSottile/edwards25519) from 1.1.0 to 1.1.1.
- [Commits](https://github.com/FiloSottile/edwards25519/compare/v1.1.0...v1.1.1)

---
updated-dependencies:
- dependency-name: filippo.io/edwards25519
  dependency-version: 1.1.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Merge branch 'master' into dependabot/go_modules/github.com/russellhaering/goxmldsig-1.6.0

* build(deps): bump alpine from 3.23.3 to 3.23.4

Bumps alpine from 3.23.3 to 3.23.4.

---
updated-dependencies:
- dependency-name: alpine
  dependency-version: 3.23.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): bump arm64v8/alpine from 3.23.3 to 3.23.4 in /ocis/docker

Bumps arm64v8/alpine from 3.23.3 to 3.23.4.

---
updated-dependencies:
- dependency-name: arm64v8/alpine
  dependency-version: 3.23.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): bump actions/cache from 5.0.4 to 5.0.5

Bumps [actions/cache](https://github.com/actions/cache) from 5.0.4 to 5.0.5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](668228422a...27d5ce7f10)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 5.0.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): bump github.com/go-acme/lego/v4 from 4.25.2 to 4.34.0

Bumps [github.com/go-acme/lego/v4](https://github.com/go-acme/lego) from 4.25.2 to 4.34.0.
- [Release notes](https://github.com/go-acme/lego/releases)
- [Changelog](https://github.com/go-acme/lego/blob/master/CHANGELOG.md)
- [Commits](https://github.com/go-acme/lego/compare/v4.25.2...v4.34.0)

---
updated-dependencies:
- dependency-name: github.com/go-acme/lego/v4
  dependency-version: 4.34.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): bump github.com/go-git/go-git/v5 from 5.17.1 to 5.18.0

Bumps [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) from 5.17.1 to 5.18.0.
- [Release notes](https://github.com/go-git/go-git/releases)
- [Commits](https://github.com/go-git/go-git/compare/v5.17.1...v5.18.0)

---
updated-dependencies:
- dependency-name: github.com/go-git/go-git/v5
  dependency-version: 5.18.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore: regenerate pnpm-lock.yaml

* fix(ci): replace nc-based fakeoffice with Python HTTP server

BusyBox nc -k restarts between connections leaving a gap where the
collaboration service gets ECONNRESET at startup, so healthz never
binds and the 300s wait times out. Python HTTPServer is gap-free.

---------

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
Michal Klos
2026-04-21 17:59:21 +02:00
committed by GitHub
parent 0b76ae28a0
commit eaaf8533f4
128 changed files with 2723 additions and 2721 deletions

View File

@@ -166,7 +166,7 @@ jobs:
- name: Cache libcurl 8.12.0
id: cache-libcurl
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: /opt/libcurl
key: libcurl-8.12.0-${{ runner.os }}
@@ -282,7 +282,7 @@ jobs:
- name: Cache libcurl 8.12.0
id: cache-libcurl
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: /opt/libcurl
key: libcurl-8.12.0-${{ runner.os }}
@@ -372,7 +372,7 @@ jobs:
CHROMEDRIVER_SKIP_DOWNLOAD: "true"
- name: Cache Playwright Chromium
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.cache/ms-playwright
key: playwright-chromium-${{ hashFiles('.drone.env') }}

View File

@@ -39,8 +39,8 @@
* [Changelog for 3.0.0](#changelog-for-300-2023-06-06)
* [Changelog for 2.0.0](#changelog-for-200-2022-11-30)
* [Changelog for 1.20.0](#changelog-for-1200-2022-04-13)
* [Changelog for 1.19.0](#changelog-for-1190-2022-03-29)
* [Changelog for 1.19.1](#changelog-for-1191-2022-03-29)
* [Changelog for 1.19.0](#changelog-for-1190-2022-03-29)
* [Changelog for 1.18.0](#changelog-for-1180-2022-03-03)
* [Changelog for 1.17.0](#changelog-for-1170-2022-02-16)
* [Changelog for 1.16.0](#changelog-for-1160-2021-12-10)
@@ -12755,7 +12755,7 @@ The following sections list the changes for 2.0.0.
The following sections list the changes for 1.20.0.
[1.20.0]: https://github.com/owncloud/ocis/compare/v1.19.0...v1.20.0
[1.20.0]: https://github.com/owncloud/ocis/compare/v1.19.1...v1.20.0
## Summary
@@ -12929,11 +12929,29 @@ The following sections list the changes for 1.20.0.
https://github.com/owncloud/ocis/pull/3509
https://github.com/owncloud/web/releases/tag/v5.4.0
# Changelog for [1.19.1] (2022-03-29)
The following sections list the changes for 1.19.1.
[1.19.1]: https://github.com/owncloud/ocis/compare/v1.19.0...v1.19.1
## Summary
* Bugfix - Return correct special item urls: [#3419](https://github.com/owncloud/ocis/pull/3419)
## Details
* Bugfix - Return correct special item urls: [#3419](https://github.com/owncloud/ocis/pull/3419)
URLs for Special items (space image, readme) were broken.
https://github.com/owncloud/ocis/pull/3419
# Changelog for [1.19.0] (2022-03-29)
The following sections list the changes for 1.19.0.
[1.19.0]: https://github.com/owncloud/ocis/compare/v1.19.1...v1.19.0
[1.19.0]: https://github.com/owncloud/ocis/compare/v1.18.0...v1.19.0
## Summary
@@ -13107,24 +13125,6 @@ The following sections list the changes for 1.19.0.
https://github.com/owncloud/ocis/pull/3375
https://github.com/owncloud/web/releases/tag/v5.3.0
# Changelog for [1.19.1] (2022-03-29)
The following sections list the changes for 1.19.1.
[1.19.1]: https://github.com/owncloud/ocis/compare/v1.18.0...v1.19.1
## Summary
* Bugfix - Return correct special item urls: [#3419](https://github.com/owncloud/ocis/pull/3419)
## Details
* Bugfix - Return correct special item urls: [#3419](https://github.com/owncloud/ocis/pull/3419)
URLs for Special items (space image, readme) were broken.
https://github.com/owncloud/ocis/pull/3419
# Changelog for [1.18.0] (2022-03-03)
The following sections list the changes for 1.18.0.

View File

@@ -28,7 +28,7 @@ COPY --from=generate /ocis /ocis
WORKDIR /ocis/ocis
RUN make ci-go-generate build ENABLE_VIPS=true
FROM alpine:3.23.3
FROM alpine:3.23.4
RUN apk add --no-cache attr ca-certificates curl mailcap tree vips && \
echo 'hosts: files dns' >| /etc/nsswitch.conf

50
go.mod
View File

@@ -19,7 +19,7 @@ require (
github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
github.com/egirna/icap-client v0.1.1
github.com/gabriel-vasile/mimetype v1.4.12
github.com/gabriel-vasile/mimetype v1.4.13
github.com/ggwhite/go-masker v1.1.0
github.com/go-chi/chi/v5 v5.2.5
github.com/go-chi/render v1.0.3
@@ -87,23 +87,23 @@ require (
go-micro.dev/v4 v4.11.0
go.etcd.io/bbolt v1.4.3
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0
go.opentelemetry.io/contrib/zpages v0.64.0
go.opentelemetry.io/otel v1.43.0
go.opentelemetry.io/otel/exporters/jaeger v1.17.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0
go.opentelemetry.io/otel/sdk v1.43.0
go.opentelemetry.io/otel/trace v1.43.0
golang.org/x/crypto v0.49.0
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b
golang.org/x/crypto v0.50.0
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f
golang.org/x/image v0.38.0
golang.org/x/net v0.51.0
golang.org/x/oauth2 v0.35.0
golang.org/x/net v0.53.0
golang.org/x/oauth2 v0.36.0
golang.org/x/sync v0.20.0
golang.org/x/term v0.41.0
golang.org/x/text v0.35.0
google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409
google.golang.org/grpc v1.79.3
golang.org/x/term v0.42.0
golang.org/x/text v0.36.0
google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7
google.golang.org/grpc v1.80.0
google.golang.org/protobuf v1.36.11
gopkg.in/yaml.v2 v2.4.0
gotest.tools/v3 v3.5.2
@@ -112,7 +112,7 @@ require (
require (
contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
filippo.io/edwards25519 v1.1.1 // indirect
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/BurntSushi/toml v1.6.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
@@ -180,11 +180,11 @@ require (
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/gdexlab/go-render v1.0.1 // indirect
github.com/go-acme/lego/v4 v4.25.2 // indirect
github.com/go-acme/lego/v4 v4.34.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.8.0 // indirect
github.com/go-git/go-git/v5 v5.17.1 // indirect
github.com/go-git/go-git/v5 v5.18.0 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.5 // indirect
github.com/go-jose/go-jose/v4 v4.1.4 // indirect
@@ -198,25 +198,25 @@ require (
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-redis/redis/v8 v8.11.5 // indirect
github.com/go-resty/resty/v2 v2.16.5 // indirect
github.com/go-resty/resty/v2 v2.17.2 // indirect
github.com/go-sql-driver/mysql v1.9.3 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/go-test/deep v1.1.0 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.2.1 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/goccy/go-yaml v1.18.0 // indirect
github.com/goccy/go-yaml v1.19.2 // indirect
github.com/gofrs/flock v0.13.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gomodule/redigo v1.9.3 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/go-querystring v1.2.0 // indirect
github.com/google/go-tpm v0.9.8 // indirect
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect
github.com/google/renameio/v2 v2.0.1 // indirect
@@ -234,7 +234,7 @@ require (
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jonboulle/clockwork v0.5.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 // indirect
github.com/juliangruber/go-intersect v1.1.0 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.18.4 // indirect
@@ -256,12 +256,12 @@ require (
github.com/longsleep/rndm v1.2.0 // indirect
github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-isatty v0.0.21 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mattn/go-sqlite3 v1.14.34 // indirect
github.com/maxymania/go-system v0.0.0-20170110133659-647cc364bf0b // indirect
github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103 // indirect
github.com/miekg/dns v1.1.68 // indirect
github.com/miekg/dns v1.1.72 // indirect
github.com/mileusna/useragent v1.3.5 // indirect
github.com/minio/crc64nvme v1.1.1 // indirect
github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76 // indirect
@@ -312,7 +312,7 @@ require (
github.com/skeema/knownhosts v1.3.1 // indirect
github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/stretchr/objx v0.5.3 // indirect
github.com/studio-b12/gowebdav v0.9.0 // indirect
github.com/tchap/go-patricia/v2 v2.3.3 // indirect
github.com/tidwall/match v1.1.1 // indirect
@@ -340,12 +340,12 @@ require (
go.uber.org/zap v1.27.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/mod v0.33.0 // indirect
golang.org/x/sys v0.42.0 // indirect
golang.org/x/mod v0.35.0 // indirect
golang.org/x/sys v0.43.0 // indirect
golang.org/x/time v0.15.0 // indirect
golang.org/x/tools v0.42.0 // indirect
golang.org/x/tools v0.44.0 // indirect
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect

104
go.sum
View File

@@ -37,8 +37,8 @@ contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
filippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw=
filippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/Acconut/go-httptest-recorder v1.0.0 h1:TAv2dfnqp/l+SUvIaMAUK4GeN4+wqb6KZsFFFTGhoJg=
github.com/Acconut/go-httptest-recorder v1.0.0/go.mod h1:CwQyhTH1kq/gLyWiRieo7c0uokpu3PXeyF/nZjUNtmM=
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
@@ -266,8 +266,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw=
github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gdexlab/go-render v1.0.1 h1:rxqB3vo5s4n1kF0ySmoNeSPRYkEsyHgln4jFIQY7v0U=
github.com/gdexlab/go-render v1.0.1/go.mod h1:wRi5nW2qfjiGj4mPukH4UV0IknS1cHD4VgFTmJX5JzM=
github.com/ggwhite/go-masker v1.1.0 h1:kN/KIvktu2U+hd3KWrSlLj7xBGD1iBfc9/xdbVgFbRc=
@@ -280,8 +280,8 @@ github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01
github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc=
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
github.com/go-acme/lego/v4 v4.25.2 h1:+D1Q+VnZrD+WJdlkgUEGHFFTcDrwGlE7q24IFtMmHDI=
github.com/go-acme/lego/v4 v4.25.2/go.mod h1:OORYyVNZPaNdIdVYCGSBNRNZDIjhQbPuFxwGDgWj/yM=
github.com/go-acme/lego/v4 v4.34.0 h1:oRsIuPJ4ORX7ufviXvelUpBSez2XxeKGwo5pNG9BVeY=
github.com/go-acme/lego/v4 v4.34.0/go.mod h1:gsmdlx/ZS6OUeXbOj0U+VnCLLfEFj4WCYRkcGpZw+pc=
github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-asn1-ber/asn1-ber v1.4.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
@@ -296,8 +296,8 @@ github.com/go-git/go-billy/v5 v5.8.0 h1:I8hjc3LbBlXTtVuFNJuwYuMiHvQJDq1AT6u4DwDz
github.com/go-git/go-billy/v5 v5.8.0/go.mod h1:RpvI/rw4Vr5QA+Z60c6d6LXH0rYJo0uD5SqfmrrheCY=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
github.com/go-git/go-git/v5 v5.17.1 h1:WnljyxIzSj9BRRUlnmAU35ohDsjRK0EKmL0evDqi5Jk=
github.com/go-git/go-git/v5 v5.17.1/go.mod h1:pW/VmeqkanRFqR6AljLcs7EA7FbZaN5MQqO7oZADXpo=
github.com/go-git/go-git/v5 v5.18.0 h1:O831KI+0PR51hM2kep6T8k+w0/LIAD490gvqMCvL5hM=
github.com/go-git/go-git/v5 v5.18.0/go.mod h1:pW/VmeqkanRFqR6AljLcs7EA7FbZaN5MQqO7oZADXpo=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -363,8 +363,8 @@ github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy0
github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
github.com/go-resty/resty/v2 v2.17.2 h1:FQW5oHYcIlkCNrMD2lloGScxcHJ0gkjshV3qcQAyHQk=
github.com/go-resty/resty/v2 v2.17.2/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA=
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@@ -375,8 +375,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
@@ -387,8 +387,8 @@ github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk=
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw=
github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0=
@@ -453,7 +453,6 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -462,8 +461,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfhIxNtP0=
github.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU=
github.com/google/go-tika v0.3.1 h1:l+jr10hDhZjcgxFRfcQChRLo1bPXQeLFluMyvDhXTTA=
github.com/google/go-tika v0.3.1/go.mod h1:DJh5N8qxXIl85QkqmXknd+PeeRkUOTbvwyYf7ieDz6c=
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
@@ -561,8 +560,9 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 h1:9Nu54bhS/H/Kgo2/7xNSUuC5G28VR8ljfrLKU2G4IjU=
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12/go.mod h1:TBzl5BIHNXfS9+C35ZyJaklL7mLDbgUkcgXzSLa8Tk0=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/juliangruber/go-intersect v1.1.0 h1:sc+y5dCjMMx0pAdYk/N6KBm00tD/f3tq+Iox7dYDUrY=
@@ -652,8 +652,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.21 h1:xYae+lCNBP7QuW4PUnNG61ffM4hVIfm+zUzDuSzYLGs=
github.com/mattn/go-isatty v0.0.21/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.34 h1:3NtcvcUnFBPsuRcno8pUtupspG/GM+9nZ88zgJcp6Zk=
@@ -665,8 +665,8 @@ github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103 h1:Z/i1e+gTZrmcGeZy
github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103/go.mod h1:o9YPB5aGP8ob35Vy6+vyq3P3bWe7NQWzf+JLiXCiMaE=
github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE=
github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A=
github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=
github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI=
github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
github.com/mileusna/useragent v1.3.5 h1:SJM5NzBmh/hO+4LGeATKpaEX9+b4vcGg2qXGLiNGDws=
github.com/mileusna/useragent v1.3.5/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc=
github.com/minio/crc64nvme v1.1.1 h1:8dwx/Pz49suywbO+auHCBpCtlW1OfpcLN7wYgVR6wAI=
@@ -874,8 +874,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
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=
@@ -971,8 +971,8 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0 h1:XmiuHzgJt067+a6kwyAzkhXooYVv3/TOw9cM2VfJgUM=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0/go.mod h1:KDgtbWKTQs4bM+VPUr6WlL9m/WXcmkCcBlIzqxPGzmI=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg=
go.opentelemetry.io/contrib/zpages v0.64.0 h1:iMybqKVR8AHHxFX4DuEWJ9dY75+9E7+IPwUK3Ll7NxM=
go.opentelemetry.io/contrib/zpages v0.64.0/go.mod h1:DnkiyoQ7Yx/NmmKn10b6M2YBXreUqq0qhFa/kYgSZME=
go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
@@ -1022,8 +1022,8 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1034,8 +1034,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM=
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
@@ -1065,8 +1065,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1112,8 +1112,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.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1121,8 +1121,8 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1207,8 +1207,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.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.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
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=
@@ -1219,8 +1219,8 @@ golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1234,8 +1234,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.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1290,16 +1290,16 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
golang.org/x/tools/godoc v0.1.0-deprecated h1:o+aZ1BOj6Hsx/GBdJO/s815sqftjSnrZZwyYTHODvtk=
golang.org/x/tools/godoc v0.1.0-deprecated/go.mod h1:qM63CriJ961IHWmnWa9CjZnBndniPt4a3CK0PVB9bIg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -1354,10 +1354,10 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb h1:ITgPrl429bc6+2ZraNSzMDk3I95nmQln2fuPstKwFDE=
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE=
google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 h1:merA0rdPeUV3YIIfHHcH4qBkiQAc1nfCKSI7lB4cV2M=
google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409/go.mod h1:fl8J1IvUjCilwZzQowmw2b7HQB2eAuYBabMXzWurF+I=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 h1:H86B94AW+VfJWDqFeEbBPhEtHzJwJfTbgE2lZa54ZAQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7 h1:41r6JMbpzBMen0R/4TZeeAmGXSJC7DftGINUodzTkPI=
google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:EIQZ5bFCfRQDV4MhRle7+OgjNtZ6P1PiZBgAKuxXu/Y=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -1371,8 +1371,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
google.golang.org/grpc/examples v0.0.0-20211102180624-670c133e568e h1:m7aQHHqd0q89mRwhwS9Bx2rjyl/hsFAeta+uGrHsQaU=
google.golang.org/grpc/examples v0.0.0-20211102180624-670c133e568e/go.mod h1:gID3PKrg7pWKntu9Ss6zTLJ0ttC0X9IHgREOCZwbCVU=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=

View File

@@ -1,4 +1,4 @@
FROM arm64v8/alpine:3.23.3
FROM arm64v8/alpine:3.23.4
ARG VERSION=""
ARG REVISION=""

View File

@@ -74,7 +74,7 @@
"@fontsource/roboto": "^5.2.6",
"@mui/icons-material": "^5.18.0",
"@mui/material": "^5.18.0",
"@testing-library/jest-dom": "^6.6.4",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^12.1.5",
"@testing-library/user-event": "^14.6.1",
"@types/jest": "^30.0.0",

View File

@@ -32,8 +32,8 @@ importers:
specifier: ^5.18.0
version: 5.18.0(@types/react@17.0.87)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
'@testing-library/jest-dom':
specifier: ^6.6.4
version: 6.6.4
specifier: ^6.9.1
version: 6.9.1
'@testing-library/react':
specifier: ^12.1.5
version: 12.1.5(@types/react@17.0.87)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
@@ -60,7 +60,7 @@ importers:
version: 3.0.13
axios:
specifier: ^1.15.0
version: 1.15.0
version: 1.15.1
classnames:
specifier: ^2.5.1
version: 2.5.1
@@ -302,8 +302,8 @@ importers:
packages:
'@adobe/css-tools@4.4.0':
resolution: {integrity: sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==}
'@adobe/css-tools@4.4.4':
resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==}
'@apideck/better-ajv-errors@0.3.6':
resolution: {integrity: sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==}
@@ -319,10 +319,6 @@ packages:
resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==}
engines: {node: '>=6.9.0'}
'@babel/code-frame@7.29.0':
resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
engines: {node: '>=6.9.0'}
'@babel/compat-data@7.28.0':
resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==}
engines: {node: '>=6.9.0'}
@@ -1107,10 +1103,6 @@ packages:
resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==}
engines: {node: '>=6.9.0'}
'@babel/runtime@7.29.2':
resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==}
engines: {node: '>=6.9.0'}
'@babel/template@7.28.6':
resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
engines: {node: '>=6.9.0'}
@@ -2045,8 +2037,8 @@ packages:
resolution: {integrity: sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==}
engines: {node: '>=12'}
'@testing-library/jest-dom@6.6.4':
resolution: {integrity: sha512-xDXgLjVunjHqczScfkCJ9iyjdNOVHvvCdqHSSxwM9L0l/wHkTRum67SDc020uAlCoqktJplgO2AAQeLP1wgqDQ==}
'@testing-library/jest-dom@6.9.1':
resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==}
engines: {node: '>=14', npm: '>=6', yarn: '>=1'}
'@testing-library/react@12.1.5':
@@ -2506,7 +2498,6 @@ packages:
'@xmldom/xmldom@0.8.10':
resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==}
engines: {node: '>=10.0.0'}
deprecated: this version has critical issues, please update to the latest version
'@xtuc/ieee754@1.2.0':
resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==}
@@ -2533,6 +2524,11 @@ packages:
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
acorn@8.14.0:
resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==}
engines: {node: '>=0.4.0'}
hasBin: true
acorn@8.15.0:
resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
engines: {node: '>=0.4.0'}
@@ -2698,8 +2694,8 @@ packages:
resolution: {integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==}
engines: {node: '>=4'}
axios@1.15.0:
resolution: {integrity: sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==}
axios@1.15.1:
resolution: {integrity: sha512-WOG+Jj8ZOvR0a3rAn+Tuf1UQJRxw5venr6DgdbJzngJE3qG7X0kL83CZGpdHMxEm+ZK3seAbvFsw4FfOfP9vxg==}
axobject-query@4.1.0:
resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
@@ -2785,6 +2781,9 @@ packages:
babel-preset-react-app@10.1.0:
resolution: {integrity: sha512-f9B1xMdnkCIqe+2dHrJsoQFRz7reChaAHE/65SdaykPklQqhme2WaC08oD3is77x9ff98/9EazAKFDZv5rFEQg==}
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
balanced-match@4.0.4:
resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
engines: {node: 18 || 20 || >=22}
@@ -2812,8 +2811,11 @@ packages:
boolbase@1.0.0:
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
brace-expansion@5.0.3:
resolution: {integrity: sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==}
brace-expansion@2.0.2:
resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
brace-expansion@5.0.5:
resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==}
engines: {node: 18 || 20 || >=22}
braces@3.0.3:
@@ -2894,6 +2896,12 @@ packages:
caniuse-api@3.0.0:
resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==}
caniuse-lite@1.0.30001715:
resolution: {integrity: sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==}
caniuse-lite@1.0.30001727:
resolution: {integrity: sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==}
caniuse-lite@1.0.30001765:
resolution: {integrity: sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ==}
@@ -3067,8 +3075,8 @@ packages:
resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
engines: {node: '>=10'}
cosmiconfig@9.0.1:
resolution: {integrity: sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==}
cosmiconfig@9.0.0:
resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==}
engines: {node: '>=14'}
peerDependencies:
typescript: '>=4.9.5'
@@ -3407,6 +3415,12 @@ packages:
engines: {node: '>=0.10.0'}
hasBin: true
electron-to-chromium@1.4.829:
resolution: {integrity: sha512-5qp1N2POAfW0u1qGAxXEtz6P7bO1m6gpZr5hdf5ve6lxpLM7MpiM4jIPz7xcrNlClQMafbyUDDWjlIQZ1Mw0Rw==}
electron-to-chromium@1.5.191:
resolution: {integrity: sha512-xcwe9ELcuxYLUFqZZxL19Z6HVKcvNkIwhbHUz7L3us6u12yR+7uY89dSl570f/IqNthx8dAw3tojG7i4Ni4tDA==}
electron-to-chromium@1.5.267:
resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==}
@@ -3430,8 +3444,8 @@ packages:
encoding@0.1.13:
resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==}
enhanced-resolve@5.19.0:
resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==}
enhanced-resolve@5.20.1:
resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==}
engines: {node: '>=10.13.0'}
ensure-posix-path@1.1.1:
@@ -3948,7 +3962,6 @@ packages:
glob@10.5.0:
resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==}
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
hasBin: true
global-modules@2.0.0:
@@ -4096,7 +4109,6 @@ packages:
i18next-parser@9.3.0:
resolution: {integrity: sha512-VaQqk/6nLzTFx1MDiCZFtzZXKKyBV6Dv0cJMFM/hOt4/BWHWRgYafzYfVQRUzotwUwjqeNCprWnutzD/YAGczg==}
engines: {node: ^18.0.0 || ^20.0.0 || ^22.0.0, npm: '>=6', yarn: '>=1'}
deprecated: Project is deprecated, use i18next-cli instead
hasBin: true
i18next-resources-to-backend@1.2.1:
@@ -4781,11 +4793,11 @@ packages:
peerDependencies:
webpack: ^5.0.0
minimatch@3.1.5:
resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==}
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
minimatch@5.1.9:
resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==}
minimatch@5.1.6:
resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
engines: {node: '>=10'}
minimatch@9.0.7:
@@ -4860,6 +4872,12 @@ packages:
node-int64@0.4.0:
resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
node-releases@2.0.17:
resolution: {integrity: sha512-Ww6ZlOiEQfPfXM45v17oabk77Z7mg5bOt7AjDyzy7RjK9OrLrLC8dyZQoAPEOtFX9SaNf1Tdvr5gRJWdTJj7GA==}
node-releases@2.0.19:
resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
node-releases@2.0.27:
resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==}
@@ -5944,8 +5962,8 @@ packages:
engines: {node: '>=10'}
hasBin: true
semver@7.7.4:
resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
semver@7.7.3:
resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==}
engines: {node: '>=10'}
hasBin: true
@@ -6248,8 +6266,8 @@ packages:
resolution: {integrity: sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==}
engines: {node: '>=10'}
terser-webpack-plugin@5.3.16:
resolution: {integrity: sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==}
terser-webpack-plugin@5.4.0:
resolution: {integrity: sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==}
engines: {node: '>= 10.13.0'}
peerDependencies:
'@swc/core': '*'
@@ -6456,6 +6474,18 @@ packages:
resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==}
engines: {node: '>=4'}
update-browserslist-db@1.1.0:
resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==}
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'
update-browserslist-db@1.1.3:
resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'
update-browserslist-db@1.2.3:
resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
hasBin: true
@@ -6729,7 +6759,7 @@ packages:
snapshots:
'@adobe/css-tools@4.4.0': {}
'@adobe/css-tools@4.4.4': {}
'@apideck/better-ajv-errors@0.3.6(ajv@8.18.0)':
dependencies:
@@ -6749,12 +6779,6 @@ snapshots:
js-tokens: 4.0.0
picocolors: 1.1.1
'@babel/code-frame@7.29.0':
dependencies:
'@babel/helper-validator-identifier': 7.28.5
js-tokens: 4.0.0
picocolors: 1.1.1
'@babel/compat-data@7.28.0': {}
'@babel/compat-data@7.28.6': {}
@@ -7744,8 +7768,6 @@ snapshots:
'@babel/runtime@7.28.6': {}
'@babel/runtime@7.29.2': {}
'@babel/template@7.28.6':
dependencies:
'@babel/code-frame': 7.28.6
@@ -8220,7 +8242,7 @@ snapshots:
ignore: 5.3.2
import-fresh: 3.3.1
js-yaml: 4.1.1
minimatch: 3.1.5
minimatch: 3.1.2
strip-json-comments: 3.1.1
transitivePeerDependencies:
- supports-color
@@ -8285,7 +8307,7 @@ snapshots:
dependencies:
'@humanwhocodes/object-schema': 2.0.3
debug: 4.4.3
minimatch: 3.1.5
minimatch: 3.1.2
transitivePeerDependencies:
- supports-color
@@ -8530,7 +8552,7 @@ snapshots:
'@material-ui/core@4.12.4(@types/react@17.0.87)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
'@babel/runtime': 7.29.2
'@babel/runtime': 7.28.6
'@material-ui/styles': 4.11.5(@types/react@17.0.87)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
'@material-ui/system': 4.12.2(@types/react@17.0.87)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
'@material-ui/types': 5.1.0(@types/react@17.0.87)
@@ -8549,7 +8571,7 @@ snapshots:
'@material-ui/styles@4.11.5(@types/react@17.0.87)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
'@babel/runtime': 7.29.2
'@babel/runtime': 7.28.6
'@emotion/hash': 0.8.0
'@material-ui/types': 5.1.0(@types/react@17.0.87)
'@material-ui/utils': 4.11.3(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
@@ -8572,7 +8594,7 @@ snapshots:
'@material-ui/system@4.12.2(@types/react@17.0.87)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
'@babel/runtime': 7.29.2
'@babel/runtime': 7.28.6
'@material-ui/utils': 4.11.3(react-dom@17.0.2(react@17.0.2))(react@17.0.2)
csstype: 2.6.21
prop-types: 15.8.1
@@ -8587,7 +8609,7 @@ snapshots:
'@material-ui/utils@4.11.3(react-dom@17.0.2(react@17.0.2))(react@17.0.2)':
dependencies:
'@babel/runtime': 7.29.2
'@babel/runtime': 7.28.6
prop-types: 15.8.1
react: 17.0.2
react-dom: 17.0.2(react@17.0.2)
@@ -8695,7 +8717,7 @@ snapshots:
'@npmcli/fs@3.1.1':
dependencies:
semver: 7.7.4
semver: 7.7.3
'@pkgjs/parseargs@0.11.0':
optional: true
@@ -8781,8 +8803,8 @@ snapshots:
'@testing-library/dom@10.3.2':
dependencies:
'@babel/code-frame': 7.29.0
'@babel/runtime': 7.29.2
'@babel/code-frame': 7.28.6
'@babel/runtime': 7.28.6
'@types/aria-query': 5.0.4
aria-query: 5.3.0
chalk: 4.1.2
@@ -8801,13 +8823,12 @@ snapshots:
lz-string: 1.5.0
pretty-format: 27.5.1
'@testing-library/jest-dom@6.6.4':
'@testing-library/jest-dom@6.9.1':
dependencies:
'@adobe/css-tools': 4.4.0
aria-query: 5.3.0
'@adobe/css-tools': 4.4.4
aria-query: 5.3.2
css.escape: 1.5.1
dom-accessibility-api: 0.6.3
lodash: 4.18.1
picocolors: 1.1.1
redent: 3.0.0
@@ -8860,7 +8881,7 @@ snapshots:
'@types/eslint@8.56.12':
dependencies:
'@types/estree': 1.0.8
'@types/estree': 1.0.6
'@types/json-schema': 7.0.15
'@types/estree@0.0.39': {}
@@ -8964,7 +8985,7 @@ snapshots:
graphemer: 1.4.0
ignore: 5.3.2
natural-compare-lite: 1.4.0
semver: 7.7.4
semver: 7.7.3
tsutils: 3.21.0(typescript@5.9.3)
optionalDependencies:
typescript: 5.9.3
@@ -9096,7 +9117,7 @@ snapshots:
debug: 4.4.3
globby: 11.1.0
is-glob: 4.0.3
semver: 7.7.4
semver: 7.7.3
tsutils: 3.21.0(typescript@5.9.3)
optionalDependencies:
typescript: 5.9.3
@@ -9111,7 +9132,7 @@ snapshots:
globby: 11.1.0
is-glob: 4.0.3
minimatch: 9.0.7
semver: 7.7.4
semver: 7.7.3
ts-api-utils: 1.4.3(typescript@5.9.3)
optionalDependencies:
typescript: 5.9.3
@@ -9126,7 +9147,7 @@ snapshots:
globby: 11.1.0
is-glob: 4.0.3
minimatch: 9.0.7
semver: 7.7.4
semver: 7.7.3
ts-api-utils: 1.4.3(typescript@5.9.3)
optionalDependencies:
typescript: 5.9.3
@@ -9143,7 +9164,7 @@ snapshots:
fast-glob: 3.3.3
is-glob: 4.0.3
minimatch: 9.0.7
semver: 7.7.4
semver: 7.7.3
ts-api-utils: 2.1.0(typescript@5.9.3)
typescript: 5.9.3
transitivePeerDependencies:
@@ -9159,7 +9180,7 @@ snapshots:
'@typescript-eslint/typescript-estree': 5.62.0(typescript@5.9.3)
eslint: 8.57.1
eslint-scope: 5.1.1
semver: 7.7.4
semver: 7.7.3
transitivePeerDependencies:
- supports-color
- typescript
@@ -9173,7 +9194,7 @@ snapshots:
'@typescript-eslint/types': 7.0.0
'@typescript-eslint/typescript-estree': 7.0.0(typescript@5.9.3)
eslint: 8.57.1
semver: 7.7.4
semver: 7.7.3
transitivePeerDependencies:
- supports-color
- typescript
@@ -9362,9 +9383,11 @@ snapshots:
dependencies:
acorn: 8.15.0
acorn-jsx@5.3.2(acorn@8.15.0):
acorn-jsx@5.3.2(acorn@8.14.0):
dependencies:
acorn: 8.15.0
acorn: 8.14.0
acorn@8.14.0: {}
acorn@8.15.0: {}
@@ -9536,7 +9559,7 @@ snapshots:
autoprefixer@10.4.21(postcss@8.5.6):
dependencies:
browserslist: 4.28.1
caniuse-lite: 1.0.30001765
caniuse-lite: 1.0.30001727
fraction.js: 4.3.7
normalize-range: 0.1.2
picocolors: 1.1.1
@@ -9549,7 +9572,7 @@ snapshots:
axe-core@4.10.3: {}
axios@1.15.0:
axios@1.15.1:
dependencies:
follow-redirects: 1.15.11
form-data: 4.0.5
@@ -9702,6 +9725,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
balanced-match@1.0.2: {}
balanced-match@4.0.4: {}
bare-events@2.4.2:
@@ -9723,7 +9748,11 @@ snapshots:
boolbase@1.0.0: {}
brace-expansion@5.0.3:
brace-expansion@2.0.2:
dependencies:
balanced-match: 1.0.2
brace-expansion@5.0.5:
dependencies:
balanced-match: 4.0.4
@@ -9757,17 +9786,17 @@ snapshots:
browserslist@4.23.2:
dependencies:
caniuse-lite: 1.0.30001765
electron-to-chromium: 1.5.267
node-releases: 2.0.27
update-browserslist-db: 1.2.3(browserslist@4.23.2)
caniuse-lite: 1.0.30001715
electron-to-chromium: 1.4.829
node-releases: 2.0.17
update-browserslist-db: 1.1.0(browserslist@4.23.2)
browserslist@4.25.1:
dependencies:
caniuse-lite: 1.0.30001765
electron-to-chromium: 1.5.267
node-releases: 2.0.27
update-browserslist-db: 1.2.3(browserslist@4.25.1)
caniuse-lite: 1.0.30001727
electron-to-chromium: 1.5.191
node-releases: 2.0.19
update-browserslist-db: 1.1.3(browserslist@4.25.1)
browserslist@4.28.1:
dependencies:
@@ -9825,6 +9854,10 @@ snapshots:
lodash.memoize: 4.1.2
lodash.uniq: 4.5.0
caniuse-lite@1.0.30001715: {}
caniuse-lite@1.0.30001727: {}
caniuse-lite@1.0.30001765: {}
case-sensitive-paths-webpack-plugin@2.4.0: {}
@@ -10001,7 +10034,7 @@ snapshots:
path-type: 4.0.0
yaml: 1.10.2
cosmiconfig@9.0.1(typescript@5.9.3):
cosmiconfig@9.0.0(typescript@5.9.3):
dependencies:
env-paths: 2.2.1
import-fresh: 3.3.1
@@ -10109,7 +10142,7 @@ snapshots:
css-vendor@2.0.8:
dependencies:
'@babel/runtime': 7.29.2
'@babel/runtime': 7.28.6
is-in-browser: 1.1.3
css-what@6.1.0: {}
@@ -10364,6 +10397,10 @@ snapshots:
dependencies:
jake: 10.9.1
electron-to-chromium@1.4.829: {}
electron-to-chromium@1.5.191: {}
electron-to-chromium@1.5.267: {}
emittery@0.13.1: {}
@@ -10383,7 +10420,7 @@ snapshots:
dependencies:
iconv-lite: 0.6.3
enhanced-resolve@5.19.0:
enhanced-resolve@5.20.1:
dependencies:
graceful-fs: 4.2.11
tapable: 2.3.0
@@ -10702,7 +10739,7 @@ snapshots:
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
minimatch: 3.1.5
minimatch: 3.1.2
object.fromentries: 2.0.8
object.groupby: 1.0.3
object.values: 1.2.1
@@ -10731,7 +10768,7 @@ snapshots:
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
minimatch: 3.1.5
minimatch: 3.1.2
object.fromentries: 2.0.8
object.groupby: 1.0.3
object.values: 1.2.1
@@ -10781,7 +10818,7 @@ snapshots:
hasown: 2.0.2
jsx-ast-utils: 3.3.5
language-tags: 1.0.9
minimatch: 3.1.5
minimatch: 3.1.2
object.fromentries: 2.0.8
safe-regex-test: 1.1.0
string.prototype.includes: 2.0.1
@@ -10802,7 +10839,7 @@ snapshots:
estraverse: 5.3.0
hasown: 2.0.2
jsx-ast-utils: 3.3.5
minimatch: 3.1.5
minimatch: 3.1.2
object.entries: 1.1.9
object.fromentries: 2.0.8
object.values: 1.2.1
@@ -10890,7 +10927,7 @@ snapshots:
json-stable-stringify-without-jsonify: 1.0.1
levn: 0.4.1
lodash.merge: 4.6.2
minimatch: 3.1.5
minimatch: 3.1.2
natural-compare: 1.4.0
optionator: 0.9.4
strip-ansi: 6.0.1
@@ -10900,8 +10937,8 @@ snapshots:
espree@9.6.1:
dependencies:
acorn: 8.15.0
acorn-jsx: 5.3.2(acorn@8.15.0)
acorn: 8.14.0
acorn-jsx: 5.3.2(acorn@8.14.0)
eslint-visitor-keys: 3.4.3
esprima@4.0.1: {}
@@ -10997,7 +11034,7 @@ snapshots:
filelist@1.0.4:
dependencies:
minimatch: 5.1.9
minimatch: 5.1.6
filesize@8.0.7: {}
@@ -11061,9 +11098,9 @@ snapshots:
fs-extra: 9.1.0
glob: 10.5.0
memfs: 3.5.3
minimatch: 3.1.5
minimatch: 3.1.2
schema-utils: 2.7.0
semver: 7.7.4
semver: 7.7.3
tapable: 1.1.3
typescript: 5.9.3
webpack: 5.104.1
@@ -11635,7 +11672,7 @@ snapshots:
'@babel/parser': 7.28.6
'@istanbuljs/schema': 0.1.3
istanbul-lib-coverage: 3.2.2
semver: 7.7.4
semver: 7.7.3
transitivePeerDependencies:
- supports-color
@@ -11678,7 +11715,7 @@ snapshots:
async: 3.2.5
chalk: 4.1.2
filelist: 1.0.4
minimatch: 3.1.5
minimatch: 3.1.2
jest-changed-files@30.2.0:
dependencies:
@@ -11936,7 +11973,7 @@ snapshots:
jest-message-util: 30.2.0
jest-util: 30.2.0
pretty-format: 30.2.0
semver: 7.7.4
semver: 7.7.3
synckit: 0.11.11
transitivePeerDependencies:
- supports-color
@@ -12059,46 +12096,46 @@ snapshots:
jss-plugin-camel-case@10.10.0:
dependencies:
'@babel/runtime': 7.29.2
'@babel/runtime': 7.28.6
hyphenate-style-name: 1.1.0
jss: 10.10.0
jss-plugin-default-unit@10.10.0:
dependencies:
'@babel/runtime': 7.29.2
'@babel/runtime': 7.28.6
jss: 10.10.0
jss-plugin-global@10.10.0:
dependencies:
'@babel/runtime': 7.29.2
'@babel/runtime': 7.28.6
jss: 10.10.0
jss-plugin-nested@10.10.0:
dependencies:
'@babel/runtime': 7.29.2
'@babel/runtime': 7.28.6
jss: 10.10.0
tiny-warning: 1.0.3
jss-plugin-props-sort@10.10.0:
dependencies:
'@babel/runtime': 7.29.2
'@babel/runtime': 7.28.6
jss: 10.10.0
jss-plugin-rule-value-function@10.10.0:
dependencies:
'@babel/runtime': 7.29.2
'@babel/runtime': 7.28.6
jss: 10.10.0
tiny-warning: 1.0.3
jss-plugin-vendor-prefixer@10.10.0:
dependencies:
'@babel/runtime': 7.29.2
'@babel/runtime': 7.28.6
css-vendor: 2.0.8
jss: 10.10.0
jss@10.10.0:
dependencies:
'@babel/runtime': 7.29.2
'@babel/runtime': 7.28.6
csstype: 3.2.3
is-in-browser: 1.1.3
tiny-warning: 1.0.3
@@ -12220,7 +12257,7 @@ snapshots:
make-dir@4.0.0:
dependencies:
semver: 7.7.4
semver: 7.7.3
makeerror@1.0.12:
dependencies:
@@ -12229,7 +12266,7 @@ snapshots:
matcher-collection@2.0.1:
dependencies:
'@types/minimatch': 3.0.5
minimatch: 3.1.5
minimatch: 3.1.2
math-intrinsics@1.1.0: {}
@@ -12271,17 +12308,17 @@ snapshots:
tapable: 2.2.1
webpack: 5.104.1
minimatch@3.1.5:
minimatch@3.1.2:
dependencies:
brace-expansion: 5.0.3
brace-expansion: 2.0.2
minimatch@5.1.9:
minimatch@5.1.6:
dependencies:
brace-expansion: 5.0.3
brace-expansion: 2.0.2
minimatch@9.0.7:
dependencies:
brace-expansion: 5.0.3
brace-expansion: 5.0.5
minimist@1.2.8: {}
@@ -12326,6 +12363,10 @@ snapshots:
node-int64@0.4.0: {}
node-releases@2.0.17: {}
node-releases@2.0.19: {}
node-releases@2.0.27: {}
nopt@7.2.1:
@@ -12336,7 +12377,7 @@ snapshots:
dependencies:
hosted-git-info: 6.1.1
is-core-module: 2.16.1
semver: 7.7.4
semver: 7.7.3
validate-npm-package-license: 3.0.4
normalize-path@3.0.0: {}
@@ -12491,7 +12532,7 @@ snapshots:
parse-json@5.2.0:
dependencies:
'@babel/code-frame': 7.29.0
'@babel/code-frame': 7.28.6
error-ex: 1.3.4
json-parse-even-better-errors: 2.3.1
lines-and-columns: 1.2.4
@@ -12722,10 +12763,10 @@ snapshots:
postcss-loader@8.2.1(postcss@8.5.6)(typescript@5.9.3)(webpack@5.104.1):
dependencies:
cosmiconfig: 9.0.1(typescript@5.9.3)
cosmiconfig: 9.0.0(typescript@5.9.3)
jiti: 2.6.1
postcss: 8.5.6
semver: 7.7.4
semver: 7.7.3
optionalDependencies:
webpack: 5.104.1
transitivePeerDependencies:
@@ -13233,7 +13274,7 @@ snapshots:
'@npmcli/fs': 3.1.1
debug: 4.4.3
read-package-json: 6.0.4
semver: 7.7.4
semver: 7.7.3
slide: 1.1.6
optionalDependencies:
graceful-fs: 4.2.11
@@ -13277,7 +13318,7 @@ snapshots:
recursive-readdir@2.2.3:
dependencies:
minimatch: 3.1.5
minimatch: 3.1.2
redent@3.0.0:
dependencies:
@@ -13516,7 +13557,7 @@ snapshots:
semver@7.7.2: {}
semver@7.7.4: {}
semver@7.7.3: {}
seq@0.3.5:
dependencies:
@@ -13864,12 +13905,11 @@ snapshots:
type-fest: 0.16.0
unique-string: 2.0.0
terser-webpack-plugin@5.3.16(webpack@5.104.1):
terser-webpack-plugin@5.4.0(webpack@5.104.1):
dependencies:
'@jridgewell/trace-mapping': 0.3.31
jest-worker: 27.5.1
schema-utils: 4.3.3
serialize-javascript: 7.0.3
terser: 5.44.0
webpack: 5.104.1
@@ -13884,7 +13924,7 @@ snapshots:
dependencies:
'@istanbuljs/schema': 0.1.3
glob: 10.5.0
minimatch: 3.1.5
minimatch: 3.1.2
text-decoder@1.1.1:
dependencies:
@@ -14078,13 +14118,13 @@ snapshots:
upath@1.2.0: {}
update-browserslist-db@1.2.3(browserslist@4.23.2):
update-browserslist-db@1.1.0(browserslist@4.23.2):
dependencies:
browserslist: 4.23.2
escalade: 3.2.0
escalade: 3.1.2
picocolors: 1.1.1
update-browserslist-db@1.2.3(browserslist@4.25.1):
update-browserslist-db@1.1.3(browserslist@4.25.1):
dependencies:
browserslist: 4.25.1
escalade: 3.2.0
@@ -14178,7 +14218,7 @@ snapshots:
'@types/minimatch': 3.0.5
ensure-posix-path: 1.1.1
matcher-collection: 2.0.1
minimatch: 3.1.5
minimatch: 3.1.2
walker@1.0.8:
dependencies:
@@ -14225,7 +14265,7 @@ snapshots:
acorn-import-phases: 1.0.4(acorn@8.15.0)
browserslist: 4.28.1
chrome-trace-event: 1.0.4
enhanced-resolve: 5.19.0
enhanced-resolve: 5.20.1
es-module-lexer: 2.0.0
eslint-scope: 5.1.1
events: 3.3.0
@@ -14237,7 +14277,7 @@ snapshots:
neo-async: 2.6.2
schema-utils: 4.3.3
tapable: 2.3.0
terser-webpack-plugin: 5.3.16(webpack@5.104.1)
terser-webpack-plugin: 5.4.0(webpack@5.104.1)
watchpack: 2.5.1
webpack-sources: 3.3.4
transitivePeerDependencies:

View File

@@ -507,12 +507,26 @@ def main() -> int:
# Only deviation: container hostnames → localhost
# ---------------------------------------------------------------------------
def fakeOffice():
# drone: OC_CI_ALPINE container running serve-hosting-discovery.sh with repo at /drone/src
# use same image so BusyBox nc (not OpenBSD nc) handles FIN correctly on stdin EOF
# BusyBox nc -k has a race between connections: after each response the
# while-loop restarts nc, leaving a window where connections are refused.
# The collaboration service hits that window at startup → readLoopPeekFailLocked
# → healthz never binds → 300s timeout. Use Python's built-in HTTP server
# instead; it handles concurrent connections without gaps.
run(["docker", "run", "-d", "--name", "fakeoffice", "--network", "host",
"-v", f"{repo_root}:/drone/src:ro",
"owncloudci/alpine:latest",
"sh", "/drone/src/tests/config/drone/serve-hosting-discovery.sh"])
"python:3-alpine",
"python3", "-c",
"import http.server, pathlib\n"
"body = pathlib.Path('/drone/src/tests/config/drone/hosting-discovery.xml').read_bytes()\n"
"class H(http.server.BaseHTTPRequestHandler):\n"
" def do_GET(self):\n"
" self.send_response(200)\n"
" self.send_header('Content-Type', 'text/xml')\n"
" self.end_headers()\n"
" self.wfile.write(body)\n"
" def log_message(self, *a): pass\n"
"http.server.HTTPServer(('', 8080), H).serve_forever()\n"
])
return []
def collaboraService():

View File

@@ -265,6 +265,7 @@ func (v *Point) MultiScalarMult(scalars []*Scalar, points []*Point) *Point {
tmp1 := &projP1xP1{}
tmp2 := &projP2{}
// Lookup-and-add the appropriate multiple of each input point
v.Set(NewIdentityPoint())
for j := range tables {
tables[j].SelectInto(multiple, digits[j][63])
tmp1.Add(v, multiple) // tmp1 = v + x_(j,63)*Q in P1xP1 coords

View File

@@ -63,8 +63,6 @@ type parserState struct {
// mainly because the functionality is not needed.
currPath [][]byte
// firstToken stores the first JSON token encountered in input.
// TODO: performance would be better if we would stop parsing as soon
// as we see that first token is not what we are interested in.
firstToken int
// querySatisfied is true if both path and value of any queries passed to
// consumeAny are satisfied.

View File

@@ -40,9 +40,10 @@ func Voc(raw []byte, _ uint32) bool {
return bytes.HasPrefix(raw, []byte("Creative Voice File"))
}
// M3u matches a Playlist file.
func M3u(raw []byte, _ uint32) bool {
return bytes.HasPrefix(raw, []byte("#EXTM3U"))
// M3U matches a Playlist file.
func M3U(raw []byte, _ uint32) bool {
return bytes.HasPrefix(raw, []byte("#EXTM3U\n")) ||
bytes.HasPrefix(raw, []byte("#EXTM3U\r\n"))
}
// AAC matches an Advanced Audio Coding file.

View File

@@ -3,6 +3,8 @@ package magic
import (
"bytes"
"encoding/binary"
"github.com/gabriel-vasile/mimetype/internal/scan"
)
// Pdf matches a Portable Document Format file.
@@ -98,3 +100,26 @@ func Lotus123(raw []byte, _ uint32) bool {
func CHM(raw []byte, _ uint32) bool {
return bytes.HasPrefix(raw, []byte("ITSF\003\000\000\000\x60\000\000\000"))
}
// Inf matches an OS/2 .inf file.
func Inf(raw []byte, _ uint32) bool {
return bytes.HasPrefix(raw, []byte("HSP\x01\x9b\x00"))
}
// Hlp matches an OS/2 .hlp file.
func Hlp(raw []byte, _ uint32) bool {
return bytes.HasPrefix(raw, []byte("HSP\x10\x9b\x00"))
}
// FrameMaker matches an Adobe FrameMaker file.
func FrameMaker(raw []byte, _ uint32) bool {
b := scan.Bytes(raw)
if !bytes.HasPrefix(b, []byte("<MakerFile")) &&
!bytes.HasPrefix(b, []byte("<MakerDictionary")) &&
b.Match([]byte("<BOOKFILE"), scan.IgnoreCase) == -1 {
return false
}
// To avoid plain text false positives.
return bytes.IndexByte(b[:min(len(b), 512)], 0x00) != -1
}

View File

@@ -2,6 +2,7 @@ package magic
import (
"bytes"
"encoding/binary"
)
// Woff matches a Web Open Font Format file.
@@ -16,7 +17,11 @@ func Woff2(raw []byte, _ uint32) bool {
// Otf matches an OpenType font file.
func Otf(raw []byte, _ uint32) bool {
return bytes.HasPrefix(raw, []byte{0x4F, 0x54, 0x54, 0x4F, 0x00})
// After OTTO an little endian int16 specifies the number of tables.
// Since the number of tables cannot exceed 256, the first byte of the
// int16 is always 0. PUID: fmt/520
return len(raw) > 48 && bytes.HasPrefix(raw, []byte("OTTO\x00")) &&
bytes.Contains(raw[12:48], []byte("CFF "))
}
// Ttf matches a TrueType font file.
@@ -24,7 +29,72 @@ func Ttf(raw []byte, limit uint32) bool {
if !bytes.HasPrefix(raw, []byte{0x00, 0x01, 0x00, 0x00}) {
return false
}
return !MsAccessAce(raw, limit) && !MsAccessMdb(raw, limit)
return hasSFNTTable(raw)
}
func hasSFNTTable(raw []byte) bool {
// 49 possible tables as explained below
if len(raw) < 16 || binary.BigEndian.Uint16(raw[4:]) >= 49 {
return false
}
// libmagic says there are 47 table names in specification, but it seems
// they reached 49 in the meantime.
// https://github.com/file/file/blob/5184ca2471c0e801c156ee120a90e669fe27b31d/magic/Magdir/fonts#L279
// At the same time, the TrueType docs seem misleading:
// 1. https://developer.apple.com/fonts/TrueType-Reference-Manual/index.html
// 2. https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6.html
// Page 1. has 48 tables. Page 2. has 49 tables. The diff is the gcid table.
// Take a permissive approach.
possibleTables := []uint32{
0x61636e74, // "acnt"
0x616e6b72, // "ankr"
0x61766172, // "avar"
0x62646174, // "bdat"
0x62686564, // "bhed"
0x626c6f63, // "bloc"
0x62736c6e, // "bsln"
0x636d6170, // "cmap"
0x63766172, // "cvar"
0x63767420, // "cvt "
0x45425343, // "EBSC"
0x66647363, // "fdsc"
0x66656174, // "feat"
0x666d7478, // "fmtx"
0x666f6e64, // "fond"
0x6670676d, // "fpgm"
0x66766172, // "fvar"
0x67617370, // "gasp"
0x67636964, // "gcid"
0x676c7966, // "glyf"
0x67766172, // "gvar"
0x68646d78, // "hdmx"
0x68656164, // "head"
0x68686561, // "hhea"
0x686d7478, // "hmtx"
0x6876676c, // "hvgl"
0x6876706d, // "hvpm"
0x6a757374, // "just"
0x6b65726e, // "kern"
0x6b657278, // "kerx"
0x6c636172, // "lcar"
0x6c6f6361, // "loca"
0x6c746167, // "ltag"
0x6d617870, // "maxp"
0x6d657461, // "meta"
0x6d6f7274, // "mort"
0x6d6f7278, // "morx"
0x6e616d65, // "name"
0x6f706264, // "opbd"
0x4f532f32, // "OS/2"
}
ourTable := binary.BigEndian.Uint32(raw[12:16])
for _, t := range possibleTables {
if ourTable == t {
return true
}
}
return false
}
// Eot matches an Embedded OpenType font file.

View File

@@ -1,6 +1,10 @@
package magic
import "bytes"
import (
"bytes"
"encoding/binary"
"slices"
)
// Png matches a Portable Network Graphics file.
// https://www.w3.org/TR/PNG/
@@ -42,7 +46,28 @@ func Gif(raw []byte, _ uint32) bool {
// Bmp matches a bitmap image file.
func Bmp(raw []byte, _ uint32) bool {
return bytes.HasPrefix(raw, []byte{0x42, 0x4D})
if len(raw) < 18 {
return false
}
if raw[0] != 'B' || raw[1] != 'M' {
return false
}
bmpFormat := binary.LittleEndian.Uint32(raw[14:])
// sourced from libmagic Magdir/images
possibleFormats := []uint32{
48, // PC bitmap, OS/2 2.x format (DIB header size=48)
24, // PC bitmap, OS/2 2.x format (DIB header size=24)
16, // PC bitmap, OS/2 2.x format (DIB header size=16)
64, // PC bitmap, OS/2 2.x format
52, // PC bitmap, Adobe Photoshop
56, // PC bitmap, Adobe Photoshop with alpha channel mask
40, // PC bitmap, Windows 3.x format
124, // PC bitmap, Windows 98/2000 and newer format
108, // PC bitmap, Windows 95/NT4 and newer format
}
return slices.Contains(possibleFormats, bmpFormat)
}
// Ps matches a PostScript file.

View File

@@ -10,3 +10,11 @@ func GRIB(raw []byte, _ uint32) bool {
bytes.HasPrefix(raw, []byte("GRIB")) &&
(raw[7] == 1 || raw[7] == 2)
}
// BUFR matches meteorological data format for storing point or time series data.
// https://confluence.ecmwf.int/download/attachments/31064617/ecCodes_BUFR_in_a_nutshell.pdf?version=1&modificationDate=1457000352419&api=v2
func BUFR(raw []byte, _ uint32) bool {
return len(raw) > 7 &&
bytes.HasPrefix(raw, []byte("BUFR")) &&
(raw[7] == 0x03 || raw[7] == 0x04)
}

View File

@@ -352,6 +352,9 @@ func GLTF(raw []byte, limit uint32) bool {
return jsonHelper(raw, limit, json.QueryGLTF, json.TokObject)
}
// jsonHelper parses raw and tries to match the q query against it. wantToks
// ensures we're not wasting time parsing an input that would not pass anyway,
// ex: the input is a valid JSON array, but we're looking for a JSON object.
func jsonHelper(raw scan.Bytes, limit uint32, q string, wantToks ...int) bool {
firstNonWS := raw.FirstNonWS()
@@ -376,7 +379,7 @@ func jsonHelper(raw scan.Bytes, limit uint32, q string, wantToks ...int) bool {
// If a section of the file was provided, check if all of it was inspected.
// In other words, check that if there was a problem parsing, that problem
// occurred at the last byte in the input.
// occurred after the last byte in the input.
return inspected == lraw && lraw > 0
}
@@ -387,7 +390,6 @@ func NdJSON(raw []byte, limit uint32) bool {
lCount, objOrArr := 0, 0
s := scan.Bytes(raw)
s.DropLastLine(limit)
var l scan.Bytes
for len(s) != 0 {
l = s.Line()

View File

@@ -1,7 +1,7 @@
package mimetype
import (
"mime"
stdmime "mime"
"slices"
"strings"
@@ -52,8 +52,8 @@ func (m *MIME) Parent() *MIME {
func (m *MIME) Is(expectedMIME string) bool {
// Parsing is needed because some detected MIME types contain parameters
// that need to be stripped for the comparison.
expectedMIME, _, _ = mime.ParseMediaType(expectedMIME)
found, _, _ := mime.ParseMediaType(m.mime)
expectedMIME, _, _ = stdmime.ParseMediaType(expectedMIME)
found, _, _ := stdmime.ParseMediaType(m.mime)
if expectedMIME == found {
return true
@@ -118,7 +118,7 @@ func (m *MIME) match(in []byte, readLimit uint32) *MIME {
// flatten transforms an hierarchy of MIMEs into a slice of MIMEs.
func (m *MIME) flatten() []*MIME {
out := []*MIME{m}
out := []*MIME{m} //nolint:prealloc
for _, c := range m.children {
out = append(out, c.flatten()...)
}
@@ -196,6 +196,7 @@ func (m *MIME) lookup(mime string) *MIME {
// The sub-format will be detected if all the detectors in the parent chain return true.
// The extension should include the leading dot, as in ".html".
func (m *MIME) Extend(detector func(raw []byte, limit uint32) bool, mime, extension string, aliases ...string) {
mime, _, _ = stdmime.ParseMediaType(mime)
c := &MIME{
mime: mime,
extension: extension,

View File

@@ -1,4 +1,4 @@
## 195 Supported MIME types
## 199 Supported MIME types
This file is automatically generated when running tests. Do not edit manually.
Extension | MIME type <br> Aliases | Hierarchy
@@ -99,7 +99,7 @@ Extension | MIME type <br> Aliases | Hierarchy
**.asf** | **video/x-ms-asf** <br> video/asf, video/x-ms-wmv | asf>root
**.aac** | **audio/aac** | aac>root
**.voc** | **audio/x-unknown** | voc>root
**.m3u** | **application/vnd.apple.mpegurl** <br> audio/mpegurl | m3u>root
**.m3u** | **application/vnd.apple.mpegurl** <br> audio/mpegurl, application/x-mpegurl | m3u>root
**.rmvb** | **application/vnd.rn-realmedia-vbr** | rmvb>root
**.gz** | **application/gzip** <br> application/x-gzip, application/x-gunzip, application/gzipped, application/gzip-compressed, application/x-gzip-compressed, gzip/document | gz>root
**.class** | **application/x-java-applet** | class>root
@@ -154,6 +154,10 @@ Extension | MIME type <br> Aliases | Hierarchy
**.dxf** | **image/vnd.dxf** | dxf>root
**.grb** | **application/grib** | grb>root
**n/a** | **application/zlib** | zlib>root
**.inf** | **application/x-os2-inf** | inf>root
**.hlp** | **application/x-os2-hlp** | hlp>root
**.fm** | **application/vnd.framemaker** | fm>root
**.bufr** | **application/bufr** | bufr>root
**.txt** | **text/plain** | txt>root
**.svg** | **image/svg+xml** | svg>txt>root
**.html** | **text/html** | html>txt>root

View File

@@ -24,7 +24,7 @@ var root = newMIME("application/octet-stream", "",
woff2, otf, ttc, eot, wasm, shx, dbf, dcm, rar, djvu, mobi, lit, bpg, cbor,
sqlite3, dwg, nes, lnk, macho, qcp, icns, hdr, mrc, mdb, accdb, zstd, cab,
rpm, xz, lzip, torrent, cpio, tzif, xcf, pat, gbr, glb, cabIS, jxr, parquet,
oneNote, chm, wpd, dxf, grib, zlib,
oneNote, chm, wpd, dxf, grib, zlib, inf, hlp, fm, bufr,
// Keep text last because it is the slowest check.
text,
)
@@ -174,8 +174,8 @@ var (
aMp4 = newMIME("audio/mp4", ".mp4", magic.AMp4).
alias("audio/x-mp4a")
m4a = newMIME("audio/x-m4a", ".m4a", magic.M4a)
m3u = newMIME("application/vnd.apple.mpegurl", ".m3u", magic.M3u).
alias("audio/mpegurl")
m3u = newMIME("application/vnd.apple.mpegurl", ".m3u", magic.M3U).
alias("audio/mpegurl", "application/x-mpegurl")
m4v = newMIME("video/x-m4v", ".m4v", magic.M4v)
mj2 = newMIME("video/mj2", ".mj2", magic.Mj2)
dvb = newMIME("video/vnd.dvb.file", ".dvb", magic.Dvb)
@@ -290,4 +290,8 @@ var (
rfc822 = newMIME("message/rfc822", ".eml", magic.RFC822)
grib = newMIME("application/grib", ".grb", magic.GRIB)
zlib = newMIME("application/zlib", "", magic.Zlib)
inf = newMIME("application/x-os2-inf", ".inf", magic.Inf)
hlp = newMIME("application/x-os2-hlp", ".hlp", magic.Hlp)
fm = newMIME("application/vnd.framemaker", ".fm", magic.FrameMaker)
bufr = newMIME("application/bufr", ".bufr", magic.BUFR)
)

View File

@@ -77,13 +77,14 @@ type Meta struct {
// profiles (optional, object):
// A map of profile names to human-readable descriptions of those profiles.
// https://www.ietf.org/id/draft-aaron-acme-profiles-00.html#section-3
// https://www.ietf.org/id/draft-ietf-acme-profiles-00.html#section-3
Profiles map[string]string `json:"profiles"`
}
// ExtendedAccount an extended Account.
type ExtendedAccount struct {
Account
// Contains the value of the response header `Location`
Location string `json:"-"`
}
@@ -156,7 +157,7 @@ type Order struct {
// profile (string, optional):
// A string uniquely identifying the profile
// which will be used to affect issuance of the certificate requested by this Order.
// https://www.ietf.org/id/draft-aaron-acme-profiles-00.html#section-4
// https://www.ietf.org/id/draft-ietf-acme-profiles-00.html#section-4
Profile string `json:"profile,omitempty"`
// notBefore (optional, string):
@@ -220,11 +221,11 @@ type Authorization struct {
// The timestamp after which the server will consider this authorization invalid,
// encoded in the format specified in RFC 3339 [RFC3339].
// This field is REQUIRED for objects with "valid" in the "status" field.
Expires time.Time `json:"expires,omitempty"`
Expires time.Time `json:"expires,omitzero"`
// identifier (required, object):
// The identifier that the account is authorized to represent
Identifier Identifier `json:"identifier,omitempty"`
Identifier Identifier `json:"identifier"`
// challenges (required, array of objects):
// For pending authorizations, the challenges that the client can fulfill in order to prove possession of the identifier.
@@ -244,6 +245,7 @@ type Authorization struct {
// ExtendedChallenge a extended Challenge.
type ExtendedChallenge struct {
Challenge
// Contains the value of the response header `Retry-After`
RetryAfter string `json:"-"`
// Contains the value of the response header `Link` rel="up"
@@ -270,7 +272,7 @@ type Challenge struct {
// The time at which the server validated this challenge,
// encoded in the format specified in RFC 3339 [RFC3339].
// This field is REQUIRED if the "status" field is "valid".
Validated time.Time `json:"validated,omitempty"`
Validated time.Time `json:"validated,omitzero"`
// error (optional, object):
// Error that occurred while the server was validating the challenge, if any,

View File

@@ -2,6 +2,7 @@ package acme
import (
"fmt"
"strings"
)
// Errors types.
@@ -9,6 +10,7 @@ const (
errNS = "urn:ietf:params:acme:error:"
BadNonceErr = errNS + "badNonce"
AlreadyReplacedErr = errNS + "alreadyReplaced"
RateLimitedErr = errNS + "rateLimited"
)
// ProblemDetails the problem details object.
@@ -27,21 +29,25 @@ type ProblemDetails struct {
}
func (p *ProblemDetails) Error() string {
msg := fmt.Sprintf("acme: error: %d", p.HTTPStatus)
msg := new(strings.Builder)
_, _ = fmt.Fprintf(msg, "acme: error: %d", p.HTTPStatus)
if p.Method != "" || p.URL != "" {
msg += fmt.Sprintf(" :: %s :: %s", p.Method, p.URL)
_, _ = fmt.Fprintf(msg, " :: %s :: %s", p.Method, p.URL)
}
msg += fmt.Sprintf(" :: %s :: %s", p.Type, p.Detail)
_, _ = fmt.Fprintf(msg, " :: %s :: %s", p.Type, p.Detail)
for _, sub := range p.SubProblems {
msg += fmt.Sprintf(", problem: %q :: %s", sub.Type, sub.Detail)
_, _ = fmt.Fprintf(msg, ", problem: %q :: %s", sub.Type, sub.Detail)
}
if p.Instance != "" {
msg += ", url: " + p.Instance
msg.WriteString(", url: " + p.Instance)
}
return msg
return msg.String()
}
// SubProblem a "subproblems".
@@ -49,7 +55,7 @@ func (p *ProblemDetails) Error() string {
type SubProblem struct {
Type string `json:"type,omitempty"`
Detail string `json:"detail,omitempty"`
Identifier Identifier `json:"identifier,omitempty"`
Identifier Identifier `json:"identifier"`
}
// NonceError represents the error which is returned
@@ -58,9 +64,30 @@ type NonceError struct {
*ProblemDetails
}
func (e *NonceError) Unwrap() error {
return e.ProblemDetails
}
// AlreadyReplacedError represents the error which is returned
// If the Server rejects the request because the identified certificate has already been marked as replaced.
// if the Server rejects the request because the identified certificate has already been marked as replaced.
// - https://www.rfc-editor.org/rfc/rfc9773.html#section-5
type AlreadyReplacedError struct {
*ProblemDetails
}
func (e *AlreadyReplacedError) Unwrap() error {
return e.ProblemDetails
}
// RateLimitedError represents the error which is returned
// if the server rejects the request because the client has exceeded the rate limit.
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-6.6
type RateLimitedError struct {
*ProblemDetails
RetryAfter string
}
func (e *RateLimitedError) Unwrap() error {
return e.ProblemDetails
}

View File

@@ -40,5 +40,6 @@ func GetTargetedDomain(authz acme.Authorization) string {
if authz.Wildcard {
return "*." + authz.Identifier.Value
}
return authz.Identifier.Value
}

View File

@@ -7,7 +7,6 @@ import (
"crypto/tls"
"crypto/x509"
"fmt"
"net"
"net/http"
"net/url"
"reflect"
@@ -24,6 +23,33 @@ import (
"github.com/go-git/go-git/v5/utils/ioutil"
)
type contextKey int
const initialRequestKey contextKey = iota
// RedirectPolicy controls how the HTTP transport follows redirects.
//
// The values mirror Git's http.followRedirects config:
// "true" follows redirects for all requests, "false" treats redirects as
// errors, and "initial" follows redirects only for the initial
// /info/refs discovery request. The zero value defaults to "initial".
type RedirectPolicy string
const (
FollowInitialRedirects RedirectPolicy = "initial"
FollowRedirects RedirectPolicy = "true"
NoFollowRedirects RedirectPolicy = "false"
)
func withInitialRequest(ctx context.Context) context.Context {
return context.WithValue(ctx, initialRequestKey, true)
}
func isInitialRequest(req *http.Request) bool {
v, _ := req.Context().Value(initialRequestKey).(bool)
return v
}
// it requires a bytes.Buffer, because we need to know the length
func applyHeadersToRequest(req *http.Request, content *bytes.Buffer, host string, requestType string) {
req.Header.Add("User-Agent", capability.DefaultAgent())
@@ -54,12 +80,15 @@ func advertisedReferences(ctx context.Context, s *session, serviceName string) (
s.ApplyAuthToRequest(req)
applyHeadersToRequest(req, nil, s.endpoint.Host, serviceName)
res, err := s.client.Do(req.WithContext(ctx))
res, err := s.client.Do(req.WithContext(withInitialRequest(ctx)))
if err != nil {
return nil, err
}
s.ModifyEndpointIfRedirect(res)
if err := s.ModifyEndpointIfRedirect(res); err != nil {
_ = res.Body.Close()
return nil, err
}
defer ioutil.CheckClose(res.Body, &err)
if err = NewErr(res); err != nil {
@@ -96,6 +125,7 @@ type client struct {
client *http.Client
transports *lru.Cache
mutex sync.RWMutex
follow RedirectPolicy
}
// ClientOptions holds user configurable options for the client.
@@ -106,6 +136,11 @@ type ClientOptions struct {
// size, will result in the least recently used transport getting deleted
// before the provided transport is added to the cache.
CacheMaxEntries int
// RedirectPolicy controls redirect handling. Supported values are
// "true", "false", and "initial". The zero value defaults to
// "initial", matching Git's http.followRedirects default.
RedirectPolicy RedirectPolicy
}
var (
@@ -150,12 +185,16 @@ func NewClientWithOptions(c *http.Client, opts *ClientOptions) transport.Transpo
}
cl := &client{
client: c,
follow: FollowInitialRedirects,
}
if opts != nil {
if opts.CacheMaxEntries > 0 {
cl.transports = lru.New(opts.CacheMaxEntries)
}
if opts.RedirectPolicy != "" {
cl.follow = opts.RedirectPolicy
}
}
return cl
}
@@ -289,14 +328,9 @@ func newSession(c *client, ep *transport.Endpoint, auth transport.AuthMethod) (*
}
}
httpClient = &http.Client{
Transport: transport,
CheckRedirect: c.client.CheckRedirect,
Jar: c.client.Jar,
Timeout: c.client.Timeout,
}
httpClient = c.cloneHTTPClient(transport)
} else {
httpClient = c.client
httpClient = c.cloneHTTPClient(c.client.Transport)
}
s := &session{
@@ -324,30 +358,122 @@ func (s *session) ApplyAuthToRequest(req *http.Request) {
s.auth.SetAuth(req)
}
func (s *session) ModifyEndpointIfRedirect(res *http.Response) {
func (s *session) ModifyEndpointIfRedirect(res *http.Response) error {
if res.Request == nil {
return
return nil
}
if s.endpoint == nil {
return fmt.Errorf("http redirect: nil endpoint")
}
r := res.Request
if !strings.HasSuffix(r.URL.Path, infoRefsPath) {
return
return fmt.Errorf("http redirect: target %q does not end with %s", r.URL.Path, infoRefsPath)
}
if r.URL.Scheme != "http" && r.URL.Scheme != "https" {
return fmt.Errorf("http redirect: unsupported scheme %q", r.URL.Scheme)
}
if r.URL.Scheme != s.endpoint.Protocol &&
!(s.endpoint.Protocol == "http" && r.URL.Scheme == "https") {
return fmt.Errorf("http redirect: changes scheme from %q to %q", s.endpoint.Protocol, r.URL.Scheme)
}
h, p, err := net.SplitHostPort(r.URL.Host)
host := endpointHost(r.URL.Hostname())
port, err := endpointPort(r.URL.Port())
if err != nil {
h = r.URL.Host
return err
}
if p != "" {
port, err := strconv.Atoi(p)
if err == nil {
s.endpoint.Port = port
}
if host != s.endpoint.Host || effectivePort(r.URL.Scheme, port) != effectivePort(s.endpoint.Protocol, s.endpoint.Port) {
s.endpoint.User = ""
s.endpoint.Password = ""
s.auth = nil
}
s.endpoint.Host = h
s.endpoint.Host = host
s.endpoint.Port = port
s.endpoint.Protocol = r.URL.Scheme
s.endpoint.Path = r.URL.Path[:len(r.URL.Path)-len(infoRefsPath)]
return nil
}
func endpointHost(host string) string {
if strings.Contains(host, ":") {
return "[" + host + "]"
}
return host
}
func endpointPort(port string) (int, error) {
if port == "" {
return 0, nil
}
parsed, err := strconv.Atoi(port)
if err != nil {
return 0, fmt.Errorf("http redirect: invalid port %q", port)
}
return parsed, nil
}
func effectivePort(scheme string, port int) int {
if port != 0 {
return port
}
switch strings.ToLower(scheme) {
case "http":
return 80
case "https":
return 443
default:
return 0
}
}
func (c *client) cloneHTTPClient(transport http.RoundTripper) *http.Client {
return &http.Client{
Transport: transport,
CheckRedirect: wrapCheckRedirect(c.follow, c.client.CheckRedirect),
Jar: c.client.Jar,
Timeout: c.client.Timeout,
}
}
func wrapCheckRedirect(policy RedirectPolicy, next func(*http.Request, []*http.Request) error) func(*http.Request, []*http.Request) error {
return func(req *http.Request, via []*http.Request) error {
if err := checkRedirect(req, via, policy); err != nil {
return err
}
if next != nil {
return next(req, via)
}
return nil
}
}
func checkRedirect(req *http.Request, via []*http.Request, policy RedirectPolicy) error {
switch policy {
case FollowRedirects:
case NoFollowRedirects:
return fmt.Errorf("http redirect: redirects disabled to %s", req.URL)
case "", FollowInitialRedirects:
if !isInitialRequest(req) {
return fmt.Errorf("http redirect: redirect on non-initial request to %s", req.URL)
}
default:
return fmt.Errorf("http redirect: invalid redirect policy %q", policy)
}
if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
return fmt.Errorf("http redirect: unsupported scheme %q", req.URL.Scheme)
}
if len(via) >= 10 {
return fmt.Errorf("http redirect: too many redirects")
}
return nil
}
func (*session) Close() error {

View File

@@ -132,30 +132,64 @@ func (w *PackWriter) clean() error {
func (w *PackWriter) save() error {
base := w.fs.Join(objectsPath, packPath, fmt.Sprintf("pack-%s", w.checksum))
idx, err := w.fs.Create(fmt.Sprintf("%s.idx", base))
// Pack files are content addressable. Each file is checked
// individually — if it already exists on disk, skip creating it.
idxPath := fmt.Sprintf("%s.idx", base)
exists, err := fileExists(w.fs, idxPath)
if err != nil {
return err
}
if !exists {
idx, err := w.fs.Create(idxPath)
if err != nil {
return err
}
if err := w.encodeIdx(idx); err != nil {
_ = idx.Close()
return err
}
if err := w.encodeIdx(idx); err != nil {
_ = idx.Close()
return err
}
if err := idx.Close(); err != nil {
return err
if err := idx.Close(); err != nil {
return err
}
fixPermissions(w.fs, idxPath)
}
fixPermissions(w.fs, fmt.Sprintf("%s.idx", base))
packPath := fmt.Sprintf("%s.pack", base)
if err := w.fs.Rename(w.fw.Name(), packPath); err != nil {
exists, err = fileExists(w.fs, packPath)
if err != nil {
return err
}
fixPermissions(w.fs, packPath)
if !exists {
if err := w.fs.Rename(w.fw.Name(), packPath); err != nil {
return err
}
fixPermissions(w.fs, packPath)
} else {
// Pack already exists, clean up the temp file.
return w.clean()
}
return nil
}
// fileExists checks whether path already exists as a regular file.
// It returns (true, nil) for an existing regular file, (false, nil) when the
// path does not exist, and (false, err) if the path exists but is not a
// regular file (e.g. a directory or symlink).
func fileExists(fs billy.Filesystem, path string) (bool, error) {
fi, err := fs.Lstat(path)
if err != nil {
return false, nil
}
if !fi.Mode().IsRegular() {
return false, fmt.Errorf("unexpected file type for %q: %s", path, fi.Mode().Type())
}
return true, nil
}
func (w *PackWriter) encodeIdx(writer io.Writer) error {
idx, err := w.writer.Index()
if err != nil {
@@ -235,7 +269,6 @@ func (s *syncedReader) sleep() {
atomic.StoreUint32(&s.blocked, 1)
<-s.news
}
}
func (s *syncedReader) Seek(offset int64, whence int) (int64, error) {
@@ -293,7 +326,7 @@ func (w *ObjectWriter) save() error {
// Loose objects are content addressable, if they already exist
// we can safely delete the temporary file and short-circuit the
// operation.
if _, err := w.fs.Stat(file); err == nil || os.IsExist(err) {
if _, err := w.fs.Lstat(file); err == nil || os.IsExist(err) {
return w.fs.Remove(w.f.Name())
}

View File

@@ -4,12 +4,12 @@
<p align="center"><a href="#features">Features</a> section describes in detail about Resty capabilities</p>
</p>
<p align="center">
<p align="center"><a href="https://github.com/go-resty/resty/actions/workflows/ci.yml?query=branch%3Av2"><img src="https://github.com/go-resty/resty/actions/workflows/ci.yml/badge.svg?branch=v2" alt="Build Status"></a> <a href="https://app.codecov.io/gh/go-resty/resty/tree/v2"><img src="https://codecov.io/gh/go-resty/resty/branch/v2/graph/badge.svg" alt="Code Coverage"></a> <a href="https://goreportcard.com/report/go-resty/resty"><img src="https://goreportcard.com/badge/go-resty/resty" alt="Go Report Card"></a> <a href="https://github.com/go-resty/resty/releases/latest"><img src="https://img.shields.io/badge/version-2.16.5-blue.svg" alt="Release Version"></a> <a href="https://pkg.go.dev/github.com/go-resty/resty/v2"><img src="https://pkg.go.dev/badge/github.com/go-resty/resty" alt="GoDoc"></a> <a href="LICENSE"><img src="https://img.shields.io/github/license/go-resty/resty.svg" alt="License"></a> <a href="https://github.com/avelino/awesome-go"><img src="https://awesome.re/mentioned-badge.svg" alt="Mentioned in Awesome Go"></a></p>
<p align="center"><a href="https://github.com/go-resty/resty/actions/workflows/ci.yml?query=branch%3Av2"><img src="https://github.com/go-resty/resty/actions/workflows/ci.yml/badge.svg?branch=v2" alt="Build Status"></a> <a href="https://app.codecov.io/gh/go-resty/resty/tree/v2"><img src="https://codecov.io/gh/go-resty/resty/branch/v2/graph/badge.svg" alt="Code Coverage"></a> <a href="https://goreportcard.com/report/go-resty/resty"><img src="https://goreportcard.com/badge/go-resty/resty" alt="Go Report Card"></a> <a href="https://github.com/go-resty/resty/releases/latest"><img src="https://img.shields.io/badge/version-2.17.2-blue.svg" alt="Release Version"></a> <a href="https://pkg.go.dev/github.com/go-resty/resty/v2"><img src="https://pkg.go.dev/badge/github.com/go-resty/resty" alt="GoDoc"></a> <a href="LICENSE"><img src="https://img.shields.io/github/license/go-resty/resty.svg" alt="License"></a> <a href="https://github.com/avelino/awesome-go"><img src="https://awesome.re/mentioned-badge.svg" alt="Mentioned in Awesome Go"></a></p>
</p>
## News
* v2.16.5 [released](https://github.com/go-resty/resty/releases/tag/v2.16.5) and tagged on Jan 22, 2025.
* v2.17.2 [released](https://github.com/go-resty/resty/releases/tag/v2.17.2) and tagged on Feb 14, 2026.
* v2.0.0 [released](https://github.com/go-resty/resty/releases/tag/v2.0.0) and tagged on Jul 16, 2019.
* v1.12.0 [released](https://github.com/go-resty/resty/releases/tag/v1.12.0) and tagged on Feb 27, 2019.
* v1.0 released and tagged on Sep 25, 2017. - Resty's first version was released on Sep 15, 2015 then it grew gradually as a very handy and helpful library. Its been a two years since first release. I'm very thankful to Resty users and its [contributors](https://github.com/go-resty/resty/graphs/contributors).
@@ -83,7 +83,7 @@
#### Supported Go Versions
Recommended to use `go1.20` and above.
Recommended to use `go1.23` and above.
Initially Resty started supporting `go modules` since `v1.10.0` release.

View File

@@ -57,7 +57,7 @@ func parseRequestURL(c *Client, r *Request) error {
buf := acquireBuffer()
defer releaseBuffer(buf)
// search for the next or first opened curly bracket
for curr := strings.Index(r.URL, "{"); curr == 0 || curr > prev; curr = prev + strings.Index(r.URL[prev:], "{") {
for curr := strings.Index(r.URL, "{"); curr == 0 || curr >= prev; curr = prev + strings.Index(r.URL[prev:], "{") {
// write everything from the previous position up to the current
if curr > prev {
buf.WriteString(r.URL[prev:curr])
@@ -196,6 +196,10 @@ func parseRequestBody(c *Client, r *Request) error {
}
case len(c.FormData) > 0 || len(r.FormData) > 0: // Handling Form Data
handleFormData(c, r)
case r.Body == nil && r.bodyBuf == nil: // Handling Request body when nil body
// Go http library omits Content-Length if body is nil; use http.NoBody to force it if SetContentLength is true
r.Body = http.NoBody
fallthrough
case r.Body != nil: // Handling Request body
handleContentType(c, r)
@@ -240,7 +244,7 @@ func createHTTPRequest(c *Client, r *Request) (err error) {
r.RawRequest.Close = c.closeConnection
// Add headers into http request
r.RawRequest.Header = r.Header
r.RawRequest.Header = r.Header.Clone()
// Add cookies from client instance into http request
for _, cookie := range c.Cookies {
@@ -315,6 +319,7 @@ func createCurlCmd(c *Client, r *Request) (err error) {
}
*r.resultCurlCmd = buildCurlRequest(r.RawRequest, c.httpClient.Jar)
}
return nil
}
@@ -496,6 +501,9 @@ func handleFormData(c *Client, r *Request) {
}
func handleContentType(c *Client, r *Request) {
if r.Body == http.NoBody {
return
}
contentType := r.Header.Get(hdrContentTypeKey)
if IsStringEmpty(contentType) {
contentType = DetectContentType(r.Body)

View File

@@ -897,24 +897,42 @@ func (r *Request) TraceInfo() TraceInfo {
return TraceInfo{}
}
ct.lock.RLock()
defer ct.lock.RUnlock()
ti := TraceInfo{
DNSLookup: ct.dnsDone.Sub(ct.dnsStart),
TLSHandshake: ct.tlsHandshakeDone.Sub(ct.tlsHandshakeStart),
ServerTime: ct.gotFirstResponseByte.Sub(ct.gotConn),
DNSLookup: 0,
TCPConnTime: 0,
ServerTime: 0,
IsConnReused: ct.gotConnInfo.Reused,
IsConnWasIdle: ct.gotConnInfo.WasIdle,
ConnIdleTime: ct.gotConnInfo.IdleTime,
RequestAttempt: r.Attempt,
}
// Calculate the total time accordingly,
// when connection is reused
if ct.gotConnInfo.Reused {
ti.TotalTime = ct.endTime.Sub(ct.getConn)
} else {
ti.TotalTime = ct.endTime.Sub(ct.dnsStart)
if !ct.dnsStart.IsZero() && !ct.dnsDone.IsZero() {
ti.DNSLookup = ct.dnsDone.Sub(ct.dnsStart)
}
if !ct.tlsHandshakeDone.IsZero() && !ct.tlsHandshakeStart.IsZero() {
ti.TLSHandshake = ct.tlsHandshakeDone.Sub(ct.tlsHandshakeStart)
}
if !ct.gotFirstResponseByte.IsZero() && !ct.gotConn.IsZero() {
ti.ServerTime = ct.gotFirstResponseByte.Sub(ct.gotConn)
}
// Calculate the total time accordingly when connection is reused,
// and DNS start and get conn time may be zero if the request is invalid.
// See issue #1016.
requestStartTime := r.Time
if ct.gotConnInfo.Reused && !ct.getConn.IsZero() {
requestStartTime = ct.getConn
} else if !ct.dnsStart.IsZero() {
requestStartTime = ct.dnsStart
}
ti.TotalTime = ct.endTime.Sub(requestStartTime)
// Only calculate on successful connections
if !ct.connectDone.IsZero() {
ti.TCPConnTime = ct.connectDone.Sub(ct.dnsDone)
@@ -1077,7 +1095,8 @@ type SRVRecord struct {
func (r *Request) fmtBodyString(sl int64) (body string) {
body = "***** NO CONTENT *****"
if !isPayloadSupported(r.Method, r.client.AllowGetMethodPayload) {
if !isPayloadSupported(r.Method, r.client.AllowGetMethodPayload) ||
r.Body == http.NoBody {
return
}

View File

@@ -14,7 +14,7 @@ import (
)
// Version # of resty
const Version = "2.16.5"
const Version = "2.17.2"
// New method creates a new Resty client.
func New() *Client {

View File

@@ -9,6 +9,7 @@ import (
"crypto/tls"
"net"
"net/http/httptrace"
"sync"
"time"
)
@@ -70,6 +71,7 @@ type TraceInfo struct {
// with the same naming for easy understanding. Plus additional insights
// [Request].
type clientTrace struct {
lock sync.RWMutex
getConn time.Time
dnsStart time.Time
dnsDone time.Time
@@ -87,37 +89,55 @@ func (t *clientTrace) createContext(ctx context.Context) context.Context {
ctx,
&httptrace.ClientTrace{
DNSStart: func(_ httptrace.DNSStartInfo) {
t.lock.Lock()
t.dnsStart = time.Now()
t.lock.Unlock()
},
DNSDone: func(_ httptrace.DNSDoneInfo) {
t.lock.Lock()
t.dnsDone = time.Now()
t.lock.Unlock()
},
ConnectStart: func(_, _ string) {
t.lock.Lock()
if t.dnsDone.IsZero() {
t.dnsDone = time.Now()
}
if t.dnsStart.IsZero() {
t.dnsStart = t.dnsDone
}
t.lock.Unlock()
},
ConnectDone: func(net, addr string, err error) {
t.lock.Lock()
t.connectDone = time.Now()
t.lock.Unlock()
},
GetConn: func(_ string) {
t.lock.Lock()
t.getConn = time.Now()
t.lock.Unlock()
},
GotConn: func(ci httptrace.GotConnInfo) {
t.lock.Lock()
t.gotConn = time.Now()
t.gotConnInfo = ci
t.lock.Unlock()
},
GotFirstResponseByte: func() {
t.lock.Lock()
t.gotFirstResponseByte = time.Now()
t.lock.Unlock()
},
TLSHandshakeStart: func() {
t.lock.Lock()
t.tlsHandshakeStart = time.Now()
t.lock.Unlock()
},
TLSHandshakeDone: func(_ tls.ConnectionState, _ error) {
t.lock.Lock()
t.tlsHandshakeDone = time.Now()
t.lock.Unlock()
},
},
)

View File

@@ -19,3 +19,6 @@ indent_size = 2
[.golangci.yaml]
indent_size = 2
[devenv.yaml]
indent_size = 2

View File

@@ -1,6 +1,10 @@
/.devenv/
/.direnv/
/.pre-commit-config.yaml
/bin/
/build/
/var/
# Devenv
.devenv*
devenv.local.nix
devenv.local.yaml
.direnv
.pre-commit-config.yaml

103
vendor/github.com/go-viper/mapstructure/v2/devenv.lock generated vendored Normal file
View File

@@ -0,0 +1,103 @@
{
"nodes": {
"devenv": {
"locked": {
"dir": "src/modules",
"lastModified": 1765288076,
"owner": "cachix",
"repo": "devenv",
"rev": "93c055af1e8fcac49251f1b2e1c57f78620ad351",
"type": "github"
},
"original": {
"dir": "src/modules",
"owner": "cachix",
"repo": "devenv",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1765121682,
"owner": "edolstra",
"repo": "flake-compat",
"rev": "65f23138d8d09a92e30f1e5c87611b23ef451bf3",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"git-hooks": {
"inputs": {
"flake-compat": "flake-compat",
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1765016596,
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "548fc44fca28a5e81c5d6b846e555e6b9c2a5a3c",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"git-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1762808025,
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "cb5e3fdca1de58ccbc3ef53de65bd372b48f567c",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1764580874,
"owner": "cachix",
"repo": "devenv-nixpkgs",
"rev": "dcf61356c3ab25f1362b4a4428a6d871e84f1d1d",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "rolling",
"repo": "devenv-nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"devenv": "devenv",
"git-hooks": "git-hooks",
"nixpkgs": "nixpkgs",
"pre-commit-hooks": [
"git-hooks"
]
}
}
},
"root": "root",
"version": 7
}

14
vendor/github.com/go-viper/mapstructure/v2/devenv.nix generated vendored Normal file
View File

@@ -0,0 +1,14 @@
{
pkgs,
...
}:
{
languages = {
go.enable = true;
};
packages = with pkgs; [
golangci-lint
];
}

View File

@@ -0,0 +1,4 @@
# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json
inputs:
nixpkgs:
url: github:cachix/devenv-nixpkgs/rolling

View File

@@ -1,294 +0,0 @@
{
"nodes": {
"cachix": {
"inputs": {
"devenv": [
"devenv"
],
"flake-compat": [
"devenv"
],
"git-hooks": [
"devenv"
],
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1742042642,
"narHash": "sha256-D0gP8srrX0qj+wNYNPdtVJsQuFzIng3q43thnHXQ/es=",
"owner": "cachix",
"repo": "cachix",
"rev": "a624d3eaf4b1d225f918de8543ed739f2f574203",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "latest",
"repo": "cachix",
"type": "github"
}
},
"devenv": {
"inputs": {
"cachix": "cachix",
"flake-compat": "flake-compat",
"git-hooks": "git-hooks",
"nix": "nix",
"nixpkgs": "nixpkgs_3"
},
"locked": {
"lastModified": 1744876578,
"narHash": "sha256-8MTBj2REB8t29sIBLpxbR0+AEGJ7f+RkzZPAGsFd40c=",
"owner": "cachix",
"repo": "devenv",
"rev": "7ff7c351bba20d0615be25ecdcbcf79b57b85fe1",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "devenv",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1733328505,
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": [
"devenv",
"nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1712014858,
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_2": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1743550720,
"narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "c621e8422220273271f52058f618c94e405bb0f5",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"git-hooks": {
"inputs": {
"flake-compat": [
"devenv"
],
"gitignore": "gitignore",
"nixpkgs": [
"devenv",
"nixpkgs"
]
},
"locked": {
"lastModified": 1742649964,
"narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"devenv",
"git-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"libgit2": {
"flake": false,
"locked": {
"lastModified": 1697646580,
"narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
"owner": "libgit2",
"repo": "libgit2",
"rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
"type": "github"
},
"original": {
"owner": "libgit2",
"repo": "libgit2",
"type": "github"
}
},
"nix": {
"inputs": {
"flake-compat": [
"devenv"
],
"flake-parts": "flake-parts",
"libgit2": "libgit2",
"nixpkgs": "nixpkgs_2",
"nixpkgs-23-11": [
"devenv"
],
"nixpkgs-regression": [
"devenv"
],
"pre-commit-hooks": [
"devenv"
]
},
"locked": {
"lastModified": 1741798497,
"narHash": "sha256-E3j+3MoY8Y96mG1dUIiLFm2tZmNbRvSiyN7CrSKuAVg=",
"owner": "domenkozar",
"repo": "nix",
"rev": "f3f44b2baaf6c4c6e179de8cbb1cc6db031083cd",
"type": "github"
},
"original": {
"owner": "domenkozar",
"ref": "devenv-2.24",
"repo": "nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1733212471,
"narHash": "sha256-M1+uCoV5igihRfcUKrr1riygbe73/dzNnzPsmaLCmpo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "55d15ad12a74eb7d4646254e13638ad0c4128776",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-lib": {
"locked": {
"lastModified": 1743296961,
"narHash": "sha256-b1EdN3cULCqtorQ4QeWgLMrd5ZGOjLSLemfa00heasc=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "e4822aea2a6d1cdd36653c134cacfd64c97ff4fa",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixpkgs.lib",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1717432640,
"narHash": "sha256-+f9c4/ZX5MWDOuB1rKoWj+lBNm0z0rs4CK47HBLxy1o=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "88269ab3044128b7c2f4c7d68448b2fb50456870",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "release-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1733477122,
"narHash": "sha256-qamMCz5mNpQmgBwc8SB5tVMlD5sbwVIToVZtSxMph9s=",
"owner": "cachix",
"repo": "devenv-nixpkgs",
"rev": "7bd9e84d0452f6d2e63b6e6da29fe73fac951857",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "rolling",
"repo": "devenv-nixpkgs",
"type": "github"
}
},
"nixpkgs_4": {
"locked": {
"lastModified": 1744536153,
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"devenv": "devenv",
"flake-parts": "flake-parts_2",
"nixpkgs": "nixpkgs_4"
}
}
},
"root": "root",
"version": 7
}

View File

@@ -1,46 +0,0 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
flake-parts.url = "github:hercules-ci/flake-parts";
devenv.url = "github:cachix/devenv";
};
outputs =
inputs@{ flake-parts, ... }:
flake-parts.lib.mkFlake { inherit inputs; } {
imports = [
inputs.devenv.flakeModule
];
systems = [
"x86_64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
perSystem =
{ pkgs, ... }:
rec {
devenv.shells = {
default = {
languages = {
go.enable = true;
};
pre-commit.hooks = {
nixpkgs-fmt.enable = true;
};
packages = with pkgs; [
golangci-lint
];
# https://github.com/cachix/devenv/issues/528#issuecomment-1556108767
containers = pkgs.lib.mkForce { };
};
ci = devenv.shells.default;
};
};
};
}

View File

@@ -173,6 +173,25 @@
// Public: "I made it through!"
// }
//
// # Custom Decoding with Unmarshaler
//
// Types can implement the Unmarshaler interface to control their own decoding. The interface
// behaves similarly to how UnmarshalJSON does in the standard library. It can be used as an
// alternative or companion to a DecodeHook.
//
// type TrimmedString string
//
// func (t *TrimmedString) UnmarshalMapstructure(input any) error {
// str, ok := input.(string)
// if !ok {
// return fmt.Errorf("expected string, got %T", input)
// }
// *t = TrimmedString(strings.TrimSpace(str))
// return nil
// }
//
// See the Unmarshaler interface documentation for more details.
//
// # Other Configuration
//
// mapstructure is highly configurable. See the DecoderConfig struct
@@ -218,6 +237,17 @@ type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, any) (any, error)
// values.
type DecodeHookFuncValue func(from reflect.Value, to reflect.Value) (any, error)
// Unmarshaler is the interface implemented by types that can unmarshal
// themselves. UnmarshalMapstructure receives the input data (potentially
// transformed by DecodeHook) and should populate the receiver with the
// decoded values.
//
// The Unmarshaler interface takes precedence over the default decoding
// logic for any type (structs, slices, maps, primitives, etc.).
type Unmarshaler interface {
UnmarshalMapstructure(any) error
}
// DecoderConfig is the configuration that is used to create a new decoder
// and allows customization of various aspects of decoding.
type DecoderConfig struct {
@@ -281,6 +311,13 @@ type DecoderConfig struct {
// }
Squash bool
// Deep will map structures in slices instead of copying them
//
// type Parent struct {
// Children []Child `mapstructure:",deep"`
// }
Deep bool
// Metadata is the struct that will contain extra metadata about
// the decoding. If this is nil, then no metadata will be tracked.
Metadata *Metadata
@@ -290,9 +327,15 @@ type DecoderConfig struct {
Result any
// The tag name that mapstructure reads for field names. This
// defaults to "mapstructure"
// defaults to "mapstructure". Multiple tag names can be specified
// as a comma-separated list (e.g., "yaml,json"), and the first
// matching non-empty tag will be used.
TagName string
// RootName specifies the name to use for the root element in error messages. For example:
// '<rootName>' has unset fields: <fieldName>
RootName string
// The option of the value in the tag that indicates a field should
// be squashed. This defaults to "squash".
SquashTagOption string
@@ -304,11 +347,34 @@ type DecoderConfig struct {
// MatchName is the function used to match the map key to the struct
// field name or tag. Defaults to `strings.EqualFold`. This can be used
// to implement case-sensitive tag values, support snake casing, etc.
//
// MatchName is used as a fallback comparison when the direct key lookup fails.
// See also MapFieldName for transforming field names before lookup.
MatchName func(mapKey, fieldName string) bool
// DecodeNil, if set to true, will cause the DecodeHook (if present) to run
// even if the input is nil. This can be used to provide default values.
DecodeNil bool
// MapFieldName is the function used to convert the struct field name to the map's key name.
//
// This is useful for automatically converting between naming conventions without
// explicitly tagging each field. For example, to convert Go's PascalCase field names
// to snake_case map keys:
//
// MapFieldName: func(s string) string {
// return strcase.ToSnake(s)
// }
//
// When decoding from a map to a struct, the transformed field name is used for
// the initial lookup. If not found, MatchName is used as a fallback comparison.
// Explicit struct tags always take precedence over MapFieldName.
MapFieldName func(string) string
// DisableUnmarshaler, if set to true, disables the use of the Unmarshaler
// interface. Types implementing Unmarshaler will be decoded using the
// standard struct decoding logic instead.
DisableUnmarshaler bool
}
// A Decoder takes a raw interface value and turns it into structured
@@ -445,6 +511,12 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) {
config.MatchName = strings.EqualFold
}
if config.MapFieldName == nil {
config.MapFieldName = func(s string) string {
return s
}
}
result := &Decoder{
config: config,
}
@@ -458,7 +530,7 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) {
// Decode decodes the given raw interface to the target pointer specified
// by the configuration.
func (d *Decoder) Decode(input any) error {
err := d.decode("", input, reflect.ValueOf(d.config.Result).Elem())
err := d.decode(d.config.RootName, input, reflect.ValueOf(d.config.Result).Elem())
// Retain some of the original behavior when multiple errors ocurr
var joinedErr interface{ Unwrap() []error }
@@ -540,36 +612,50 @@ func (d *Decoder) decode(name string, input any, outVal reflect.Value) error {
var err error
addMetaKey := true
switch outputKind {
case reflect.Bool:
err = d.decodeBool(name, input, outVal)
case reflect.Interface:
err = d.decodeBasic(name, input, outVal)
case reflect.String:
err = d.decodeString(name, input, outVal)
case reflect.Int:
err = d.decodeInt(name, input, outVal)
case reflect.Uint:
err = d.decodeUint(name, input, outVal)
case reflect.Float32:
err = d.decodeFloat(name, input, outVal)
case reflect.Complex64:
err = d.decodeComplex(name, input, outVal)
case reflect.Struct:
err = d.decodeStruct(name, input, outVal)
case reflect.Map:
err = d.decodeMap(name, input, outVal)
case reflect.Ptr:
addMetaKey, err = d.decodePtr(name, input, outVal)
case reflect.Slice:
err = d.decodeSlice(name, input, outVal)
case reflect.Array:
err = d.decodeArray(name, input, outVal)
case reflect.Func:
err = d.decodeFunc(name, input, outVal)
default:
// If we reached this point then we weren't able to decode it
return newDecodeError(name, fmt.Errorf("unsupported type: %s", outputKind))
// Check if the target implements Unmarshaler and use it if not disabled
unmarshaled := false
if !d.config.DisableUnmarshaler {
if unmarshaler, ok := getUnmarshaler(outVal); ok {
if err = unmarshaler.UnmarshalMapstructure(input); err != nil {
err = newDecodeError(name, err)
}
unmarshaled = true
}
}
if !unmarshaled {
switch outputKind {
case reflect.Bool:
err = d.decodeBool(name, input, outVal)
case reflect.Interface:
err = d.decodeBasic(name, input, outVal)
case reflect.String:
err = d.decodeString(name, input, outVal)
case reflect.Int:
err = d.decodeInt(name, input, outVal)
case reflect.Uint:
err = d.decodeUint(name, input, outVal)
case reflect.Float32:
err = d.decodeFloat(name, input, outVal)
case reflect.Complex64:
err = d.decodeComplex(name, input, outVal)
case reflect.Struct:
err = d.decodeStruct(name, input, outVal)
case reflect.Map:
err = d.decodeMap(name, input, outVal)
case reflect.Ptr:
addMetaKey, err = d.decodePtr(name, input, outVal)
case reflect.Slice:
err = d.decodeSlice(name, input, outVal)
case reflect.Array:
err = d.decodeArray(name, input, outVal)
case reflect.Func:
err = d.decodeFunc(name, input, outVal)
default:
// If we reached this point then we weren't able to decode it
return newDecodeError(name, fmt.Errorf("unsupported type: %s", outputKind))
}
}
// If we reached here, then we successfully decoded SOMETHING, so
@@ -668,7 +754,7 @@ func (d *Decoder) decodeString(name string, data any, val reflect.Value) error {
case reflect.Uint8:
var uints []uint8
if dataKind == reflect.Array {
uints = make([]uint8, dataVal.Len(), dataVal.Len())
uints = make([]uint8, dataVal.Len())
for i := range uints {
uints[i] = dataVal.Index(i).Interface().(uint8)
}
@@ -1060,8 +1146,8 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
)
}
tagValue := f.Tag.Get(d.config.TagName)
keyName := f.Name
tagValue, _ := getTagValue(f, d.config.TagName)
keyName := d.config.MapFieldName(f.Name)
if tagValue == "" && d.config.IgnoreUntaggedFields {
continue
@@ -1070,6 +1156,9 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
// If Squash is set in the config, we squash the field down.
squash := d.config.Squash && v.Kind() == reflect.Struct && f.Anonymous
// If Deep is set in the config, set as default value.
deep := d.config.Deep
v = dereferencePtrToStructIfNeeded(v, d.config.TagName)
// Determine the name of the key in the map
@@ -1078,12 +1167,12 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
continue
}
// If "omitempty" is specified in the tag, it ignores empty values.
if strings.Index(tagValue[index+1:], "omitempty") != -1 && isEmptyValue(v) {
if strings.Contains(tagValue[index+1:], "omitempty") && isEmptyValue(v) {
continue
}
// If "omitzero" is specified in the tag, it ignores zero values.
if strings.Index(tagValue[index+1:], "omitzero") != -1 && v.IsZero() {
if strings.Contains(tagValue[index+1:], "omitzero") && v.IsZero() {
continue
}
@@ -1103,7 +1192,7 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
)
}
} else {
if strings.Index(tagValue[index+1:], "remain") != -1 {
if strings.Contains(tagValue[index+1:], "remain") {
if v.Kind() != reflect.Map {
return newDecodeError(
name+"."+f.Name,
@@ -1118,6 +1207,9 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
continue
}
}
deep = deep || strings.Contains(tagValue[index+1:], "deep")
if keyNameTagValue := tagValue[:index]; keyNameTagValue != "" {
keyName = keyNameTagValue
}
@@ -1164,6 +1256,41 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
valMap.SetMapIndex(reflect.ValueOf(keyName), vMap)
}
case reflect.Slice:
if deep {
var childType reflect.Type
switch v.Type().Elem().Kind() {
case reflect.Struct:
childType = reflect.TypeOf(map[string]any{})
default:
childType = v.Type().Elem()
}
sType := reflect.SliceOf(childType)
addrVal := reflect.New(sType)
vSlice := reflect.MakeSlice(sType, v.Len(), v.Cap())
if v.Len() > 0 {
reflect.Indirect(addrVal).Set(vSlice)
err := d.decode(keyName, v.Interface(), reflect.Indirect(addrVal))
if err != nil {
return err
}
}
vSlice = reflect.Indirect(addrVal)
valMap.SetMapIndex(reflect.ValueOf(keyName), vSlice)
break
}
// When deep mapping is not needed, fallthrough to normal copy
fallthrough
default:
valMap.SetMapIndex(reflect.ValueOf(keyName), v)
}
@@ -1471,7 +1598,10 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
remain := false
// We always parse the tags cause we're looking for other tags too
tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",")
tagParts := getTagParts(fieldType, d.config.TagName)
if len(tagParts) == 0 {
tagParts = []string{""}
}
for _, tag := range tagParts[1:] {
if tag == d.config.SquashTagOption {
squash = true
@@ -1492,6 +1622,18 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
if !fieldVal.IsNil() {
structs = append(structs, fieldVal.Elem().Elem())
}
case reflect.Ptr:
if fieldVal.Type().Elem().Kind() == reflect.Struct {
if fieldVal.IsNil() {
fieldVal.Set(reflect.New(fieldVal.Type().Elem()))
}
structs = append(structs, fieldVal.Elem())
} else {
errs = append(errs, newDecodeError(
name+"."+fieldType.Name,
fmt.Errorf("unsupported type for squashed pointer: %s", fieldVal.Type().Elem().Kind()),
))
}
default:
errs = append(errs, newDecodeError(
name+"."+fieldType.Name,
@@ -1516,13 +1658,15 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
field, fieldValue := f.field, f.val
fieldName := field.Name
tagValue := field.Tag.Get(d.config.TagName)
tagValue, _ := getTagValue(field, d.config.TagName)
if tagValue == "" && d.config.IgnoreUntaggedFields {
continue
}
tagValue = strings.SplitN(tagValue, ",", 2)[0]
if tagValue != "" {
fieldName = tagValue
} else {
fieldName = d.config.MapFieldName(fieldName)
}
rawMapKey := reflect.ValueOf(fieldName)
@@ -1605,8 +1749,14 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
}
sort.Strings(keys)
// Improve error message when name is empty by showing the target struct type
// in the case where it is empty for embedded structs.
errorName := name
if errorName == "" {
errorName = val.Type().String()
}
errs = append(errs, newDecodeError(
name,
errorName,
fmt.Errorf("has invalid keys: %s", strings.Join(keys, ", ")),
))
}
@@ -1692,7 +1842,7 @@ func isStructTypeConvertibleToMap(typ reflect.Type, checkMapstructureTags bool,
if f.PkgPath == "" && !checkMapstructureTags { // check for unexported fields
return true
}
if checkMapstructureTags && f.Tag.Get(tagName) != "" { // check for mapstructure tags inside
if checkMapstructureTags && hasAnyTag(f, tagName) { // check for mapstructure tags inside
return true
}
}
@@ -1700,13 +1850,99 @@ func isStructTypeConvertibleToMap(typ reflect.Type, checkMapstructureTags bool,
}
func dereferencePtrToStructIfNeeded(v reflect.Value, tagName string) reflect.Value {
if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
if v.Kind() != reflect.Ptr {
return v
}
deref := v.Elem()
derefT := deref.Type()
if isStructTypeConvertibleToMap(derefT, true, tagName) {
return deref
switch v.Elem().Kind() {
case reflect.Slice:
return v.Elem()
case reflect.Struct:
deref := v.Elem()
derefT := deref.Type()
if isStructTypeConvertibleToMap(derefT, true, tagName) {
return deref
}
return v
default:
return v
}
return v
}
func hasAnyTag(field reflect.StructField, tagName string) bool {
_, ok := getTagValue(field, tagName)
return ok
}
func getTagParts(field reflect.StructField, tagName string) []string {
tagValue, ok := getTagValue(field, tagName)
if !ok {
return nil
}
return strings.Split(tagValue, ",")
}
func getTagValue(field reflect.StructField, tagName string) (string, bool) {
for _, name := range splitTagNames(tagName) {
if tag := field.Tag.Get(name); tag != "" {
return tag, true
}
}
return "", false
}
func splitTagNames(tagName string) []string {
if tagName == "" {
return []string{"mapstructure"}
}
parts := strings.Split(tagName, ",")
result := make([]string, 0, len(parts))
for _, name := range parts {
name = strings.TrimSpace(name)
if name != "" {
result = append(result, name)
}
}
return result
}
// unmarshalerType is cached for performance
var unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
// getUnmarshaler checks if the value implements Unmarshaler and returns
// the Unmarshaler and a boolean indicating if it was found. It handles both
// pointer and value receivers.
func getUnmarshaler(val reflect.Value) (Unmarshaler, bool) {
// Skip invalid or nil values
if !val.IsValid() {
return nil, false
}
switch val.Kind() {
case reflect.Pointer, reflect.Interface:
if val.IsNil() {
return nil, false
}
}
// Check pointer receiver first (most common case)
if val.CanAddr() {
ptrVal := val.Addr()
// Quick check: if no methods, can't implement any interface
if ptrVal.Type().NumMethod() > 0 && ptrVal.Type().Implements(unmarshalerType) {
return ptrVal.Interface().(Unmarshaler), true
}
}
// Check value receiver
// Quick check: if no methods, can't implement any interface
if val.Type().NumMethod() > 0 && val.CanInterface() && val.Type().Implements(unmarshalerType) {
return val.Interface().(Unmarshaler), true
}
return nil, false
}

View File

@@ -1450,16 +1450,25 @@ func (n *MappingValueNode) toString() string {
}
return fmt.Sprintf("%s%s: %s", space, n.Key.String(), value)
} else if keyIndentLevel < valueIndentLevel && !n.IsFlowStyle {
valueStr := n.Value.String()
// For flow-style values indented on the next line, we need to add the proper indentation
if m, ok := n.Value.(*MappingNode); ok && m.IsFlowStyle {
valueIndent := strings.Repeat(" ", n.Value.GetToken().Position.Column-1)
valueStr = valueIndent + valueStr
} else if s, ok := n.Value.(*SequenceNode); ok && s.IsFlowStyle {
valueIndent := strings.Repeat(" ", n.Value.GetToken().Position.Column-1)
valueStr = valueIndent + valueStr
}
if keyComment != nil {
return fmt.Sprintf(
"%s%s: %s\n%s",
space,
n.Key.stringWithoutComment(),
keyComment.String(),
n.Value.String(),
valueStr,
)
}
return fmt.Sprintf("%s%s:\n%s", space, n.Key.String(), n.Value.String())
return fmt.Sprintf("%s%s:\n%s", space, n.Key.String(), valueStr)
} else if m, ok := n.Value.(*MappingNode); ok && (m.IsFlowStyle || len(m.Values) == 0) {
return fmt.Sprintf("%s%s: %s", space, n.Key.String(), n.Value.String())
} else if s, ok := n.Value.(*SequenceNode); ok && (s.IsFlowStyle || len(s.Values) == 0) {
@@ -1614,7 +1623,11 @@ func (n *SequenceNode) flowStyleString() string {
for _, value := range n.Values {
values = append(values, value.String())
}
return fmt.Sprintf("[%s]", strings.Join(values, ", "))
seqText := fmt.Sprintf("[%s]", strings.Join(values, ", "))
if n.Comment != nil {
return addCommentString(seqText, n.Comment)
}
return seqText
}
func (n *SequenceNode) blockStyleString() string {

View File

@@ -40,6 +40,7 @@ type Decoder struct {
isResolvedReference bool
validator StructValidator
disallowUnknownField bool
allowedFieldPrefixes []string
allowDuplicateMapKey bool
useOrderedMap bool
useJSONUnmarshaler bool
@@ -287,7 +288,9 @@ func (d *Decoder) addSequenceNodeCommentToMap(node *ast.SequenceNode) {
texts = append(texts, comment.Token.Value)
}
if len(texts) != 0 {
d.addCommentToMap(node.Values[0].GetPath(), HeadComment(texts...))
if len(node.Values) != 0 {
d.addCommentToMap(node.Values[0].GetPath(), HeadComment(texts...))
}
}
}
}
@@ -462,8 +465,10 @@ func (d *Decoder) nodeToValue(ctx context.Context, node ast.Node) (any, error) {
}
return v.Interface(), nil
}
aliasName := n.Value.GetToken().Value
return nil, errors.ErrSyntax(fmt.Sprintf("could not find alias %q", aliasName), n.Value.GetToken())
if node, exists := d.anchorNodeMap[text]; exists {
return d.nodeToValue(ctx, node)
}
return nil, errors.ErrSyntax(fmt.Sprintf("could not find alias %q", text), n.Value.GetToken())
case *ast.LiteralNode:
return n.Value.GetValue(), nil
case *ast.MappingKeyNode:
@@ -1446,12 +1451,21 @@ func (d *Decoder) decodeStruct(ctx context.Context, dst reflect.Value, src ast.N
// Unknown fields are expected (they could be fields from the parent struct).
if len(unknownFields) != 0 && d.disallowUnknownField && src.GetToken() != nil {
for key, node := range unknownFields {
return errors.ErrUnknownField(fmt.Sprintf(`unknown field "%s"`, key), node.GetToken())
var ok bool
for _, prefix := range d.allowedFieldPrefixes {
if strings.HasPrefix(key, prefix) {
ok = true
break
}
}
if !ok {
return errors.ErrUnknownField(fmt.Sprintf(`unknown field "%s"`, key), node.GetToken())
}
}
}
if d.validator != nil {
if err := d.validator.Struct(dst.Addr().Interface()); err != nil {
if err := d.validator.Struct(dst.Interface()); err != nil {
ev := reflect.ValueOf(err)
if ev.Type().Kind() == reflect.Slice {
for i := 0; i < ev.Len(); i++ {
@@ -1740,14 +1754,11 @@ func (d *Decoder) decodeMap(ctx context.Context, dst reflect.Value, src ast.Node
return err
}
} else {
keyVal, err := d.nodeToValue(ctx, key)
keyVal, err := d.createDecodedNewValue(ctx, keyType, reflect.Value{}, key)
if err != nil {
return err
}
k = reflect.ValueOf(keyVal)
if k.IsValid() && k.Type().ConvertibleTo(keyType) {
k = k.Convert(keyType)
}
k = keyVal
}
if k.IsValid() {

View File

@@ -712,9 +712,15 @@ func (e *Encoder) encodeMap(ctx context.Context, value reflect.Value, column int
anchorNode.Value = encoded
encoded = anchorNode
}
kn, err := e.encodeValue(ctx, reflect.ValueOf(key), column)
keyNode, ok := kn.(ast.MapKeyNode)
if !ok || err != nil {
keyNode = e.encodeString(fmt.Sprint(key), column)
}
node.Values = append(node.Values, ast.MappingValue(
nil,
e.encodeString(keyText, column),
keyNode,
encoded,
))
e.setSmartAnchor(vRef, keyText)

View File

@@ -351,8 +351,9 @@ func (f *Formatter) formatMapping(n *ast.MappingNode) string {
var ret string
if n.IsFlowStyle {
ret = f.origin(n.Start)
} else {
ret += f.formatCommentGroup(n.Comment)
}
ret += f.formatCommentGroup(n.Comment)
for _, value := range n.Values {
if value.CollectEntry != nil {
ret += f.origin(value.CollectEntry)
@@ -361,6 +362,7 @@ func (f *Formatter) formatMapping(n *ast.MappingNode) string {
}
if n.IsFlowStyle {
ret += f.origin(n.End)
ret += f.formatCommentGroup(n.Comment)
}
return ret
}
@@ -377,8 +379,7 @@ func (f *Formatter) formatSequence(n *ast.SequenceNode) string {
var ret string
if n.IsFlowStyle {
ret = f.origin(n.Start)
}
if n.Comment != nil {
} else {
// add head comment.
ret += f.formatCommentGroup(n.Comment)
}
@@ -387,6 +388,7 @@ func (f *Formatter) formatSequence(n *ast.SequenceNode) string {
}
if n.IsFlowStyle {
ret += f.origin(n.End)
ret += f.formatCommentGroup(n.Comment)
}
ret += f.formatCommentGroup(n.FootComment)
return ret

View File

@@ -69,6 +69,15 @@ func DisallowUnknownField() DecodeOption {
}
}
// AllowFieldPrefixes, when paired with [DisallowUnknownField], allows fields
// with the specified prefixes to bypass the unknown field check.
func AllowFieldPrefixes(prefixes ...string) DecodeOption {
return func(d *Decoder) error {
d.allowedFieldPrefixes = append(d.allowedFieldPrefixes, prefixes...)
return nil
}
}
// AllowDuplicateMapKey ignore syntax error when mapping keys that are duplicates.
func AllowDuplicateMapKey() DecodeOption {
return func(d *Decoder) error {

View File

@@ -426,6 +426,11 @@ func (p *parser) parseFlowMap(ctx *context) (*ast.MappingNode, error) {
if node.End == nil {
return nil, errors.ErrSyntax("could not find flow mapping end token '}'", node.Start)
}
// set line comment if exists. e.g.) } # comment
if err := setLineComment(ctx, node, ctx.currentToken()); err != nil {
return nil, err
}
ctx.goNext() // skip mapping end token.
return node, nil
}
@@ -1066,6 +1071,11 @@ func (p *parser) parseFlowSequence(ctx *context) (*ast.SequenceNode, error) {
if node.End == nil {
return nil, errors.ErrSyntax("sequence end token ']' not found", node.Start)
}
// set line comment if exists. e.g.) ] # comment
if err := setLineComment(ctx, node, ctx.currentToken()); err != nil {
return nil, err
}
ctx.goNext() // skip sequence end token.
return node, nil
}

View File

@@ -258,6 +258,10 @@ func (p *Path) Filter(target, v interface{}) error {
// FilterFile filter from ast.File by YAMLPath.
func (p *Path) FilterFile(f *ast.File) (ast.Node, error) {
for _, doc := range f.Docs {
// For simplicity, directives cannot be the target of operations
if doc.Body != nil && doc.Body.Type() == ast.DirectiveType {
continue
}
node, err := p.FilterNode(doc.Body)
if err != nil {
return nil, err
@@ -352,6 +356,10 @@ func (p *Path) ReplaceWithFile(dst *ast.File, src *ast.File) error {
// ReplaceNode replace ast.File with ast.Node.
func (p *Path) ReplaceWithNode(dst *ast.File, node ast.Node) error {
for _, doc := range dst.Docs {
// For simplicity, directives cannot be the target of operations
if doc.Body != nil && doc.Body.Type() == ast.DirectiveType {
continue
}
if node.Type() == ast.DocumentType {
node = node.(*ast.DocumentNode).Body
}
@@ -364,7 +372,7 @@ func (p *Path) ReplaceWithNode(dst *ast.File, node ast.Node) error {
// AnnotateSource add annotation to passed source ( see section 5.1 in README.md ).
func (p *Path) AnnotateSource(source []byte, colored bool) ([]byte, error) {
file, err := parser.ParseBytes([]byte(source), 0)
file, err := parser.ParseBytes(source, 0)
if err != nil {
return nil, err
}

View File

@@ -777,6 +777,15 @@ func (s *Scanner) scanComment(ctx *Context) bool {
func (s *Scanner) scanMultiLine(ctx *Context, c rune) error {
state := ctx.getMultiLineState()
ctx.addOriginBuf(c)
// normalize CR and CRLF to LF
if c == '\r' {
if ctx.nextChar() == '\n' {
ctx.addOriginBuf('\n')
s.progress(ctx, 1)
s.offset++
}
c = '\n'
}
if ctx.isEOS() {
if s.isFirstCharAtLine && c == ' ' {
state.addIndent(ctx, s.column)
@@ -1148,14 +1157,25 @@ func (s *Scanner) scanMultiLineHeaderOption(ctx *Context) error {
s.progress(ctx, 1) // skip '|' or '>' character
var progress int
var crlf bool
for idx, c := range ctx.src[ctx.idx:] {
progress = idx
ctx.addOriginBuf(c)
if s.isNewLineChar(c) {
nextIdx := ctx.idx + idx + 1
if c == '\r' && nextIdx < len(ctx.src) && ctx.src[nextIdx] == '\n' {
crlf = true
continue // process \n in the next iteration
}
break
}
}
value := strings.TrimRight(ctx.source(ctx.idx, ctx.idx+progress), " ")
endPos := ctx.idx + progress
if crlf {
// Exclude \r
endPos = endPos - 1
}
value := strings.TrimRight(ctx.source(ctx.idx, endPos), " ")
commentValueIndex := strings.Index(value, "#")
opt := value
if commentValueIndex > 0 {
@@ -1189,7 +1209,7 @@ func (s *Scanner) scanMultiLineHeaderOption(ctx *Context) error {
ctx.setFolded(s.lastDelimColumn, opt)
}
if commentIndex > 0 {
comment := string(value[commentValueIndex+1:])
comment := value[commentValueIndex+1:]
s.offset += len(headerBuf)
s.column += len(headerBuf)
ctx.addToken(token.Comment(comment, string(ctx.obuf[len(headerBuf):]), s.pos()))

View File

@@ -324,3 +324,34 @@ func RegisterCustomUnmarshalerContext[T any](unmarshaler func(context.Context, *
return unmarshaler(ctx, v.(*T), b)
}
}
// RawMessage is a raw encoded YAML value. It implements [BytesMarshaler] and
// [BytesUnmarshaler] and can be used to delay YAML decoding or precompute a YAML
// encoding.
// It also implements [json.Marshaler] and [json.Unmarshaler].
//
// This is similar to [json.RawMessage] in the stdlib.
type RawMessage []byte
func (m RawMessage) MarshalYAML() ([]byte, error) {
if m == nil {
return []byte("null"), nil
}
return m, nil
}
func (m *RawMessage) UnmarshalYAML(dt []byte) error {
if m == nil {
return errors.New("yaml.RawMessage: UnmarshalYAML on nil pointer")
}
*m = append((*m)[0:0], dt...)
return nil
}
func (m *RawMessage) UnmarshalJSON(b []byte) error {
return m.UnmarshalYAML(b)
}
func (m RawMessage) MarshalJSON() ([]byte, error) {
return YAMLToJSON(m)
}

View File

@@ -6,22 +6,21 @@
//
// As a simple example:
//
// type Options struct {
// Query string `url:"q"`
// ShowAll bool `url:"all"`
// Page int `url:"page"`
// }
// type Options struct {
// Query string `url:"q"`
// ShowAll bool `url:"all"`
// Page int `url:"page"`
// }
//
// opt := Options{ "foo", true, 2 }
// v, _ := query.Values(opt)
// fmt.Print(v.Encode()) // will output: "q=foo&all=true&page=2"
// opt := Options{ "foo", true, 2 }
// v, _ := query.Values(opt)
// fmt.Print(v.Encode()) // will output: "q=foo&all=true&page=2"
//
// The exact mapping between Go values and url.Values is described in the
// documentation for the Values() function.
package query
import (
"bytes"
"fmt"
"net/url"
"reflect"
@@ -47,8 +46,8 @@ type Encoder interface {
//
// Each exported struct field is encoded as a URL parameter unless
//
// - the field's tag is "-", or
// - the field is empty and its tag specifies the "omitempty" option
// - the field's tag is "-", or
// - the field is empty and its tag specifies the "omitempty" option
//
// The empty values are false, 0, any nil pointer or interface value, any array
// slice, map, or string of length zero, and any type (such as time.Time) that
@@ -59,19 +58,19 @@ type Encoder interface {
// field's tag value is the key name, followed by an optional comma and
// options. For example:
//
// // Field is ignored by this package.
// Field int `url:"-"`
// // Field is ignored by this package.
// Field int `url:"-"`
//
// // Field appears as URL parameter "myName".
// Field int `url:"myName"`
// // Field appears as URL parameter "myName".
// Field int `url:"myName"`
//
// // Field appears as URL parameter "myName" and the field is omitted if
// // its value is empty
// Field int `url:"myName,omitempty"`
// // Field appears as URL parameter "myName" and the field is omitted if
// // its value is empty
// Field int `url:"myName,omitempty"`
//
// // Field appears as URL parameter "Field" (the default), but the field
// // is skipped if empty. Note the leading comma.
// Field int `url:",omitempty"`
// // Field appears as URL parameter "Field" (the default), but the field
// // is skipped if empty. Note the leading comma.
// Field int `url:",omitempty"`
//
// For encoding individual field values, the following type-dependent rules
// apply:
@@ -88,8 +87,8 @@ type Encoder interface {
// "url" tag) will use the value of the "layout" tag as a layout passed to
// time.Format. For example:
//
// // Encode a time.Time as YYYY-MM-DD
// Field time.Time `layout:"2006-01-02"`
// // Encode a time.Time as YYYY-MM-DD
// Field time.Time `layout:"2006-01-02"`
//
// Slice and Array values default to encoding as multiple URL values of the
// same name. Including the "comma" option signals that the field should be
@@ -103,9 +102,9 @@ type Encoder interface {
// from the "url" tag) will use the value of the "del" tag as the delimiter.
// For example:
//
// // Encode a slice of bools as ints ("1" for true, "0" for false),
// // separated by exclamation points "!".
// Field []bool `url:",int" del:"!"`
// // Encode a slice of bools as ints ("1" for true, "0" for false),
// // separated by exclamation points "!".
// Field []bool `url:",int" del:"!"`
//
// Anonymous struct fields are usually encoded as if their inner exported
// fields were fields in the outer struct, subject to the standard Go
@@ -114,10 +113,10 @@ type Encoder interface {
//
// Non-nil pointer values are encoded as the value pointed to.
//
// Nested structs are encoded including parent fields in value names for
// scoping. e.g:
// Nested structs have their fields processed recursively and are encoded
// including parent fields in value names for scoping. For example,
//
// "user[name]=acme&user[addr][postcode]=1234&user[addr][city]=SFO"
// "user[name]=acme&user[addr][postcode]=1234&user[addr][city]=SFO"
//
// All other values are encoded using their default string representation.
//
@@ -125,6 +124,11 @@ type Encoder interface {
// as multiple URL values of the same name.
func Values(v interface{}) (url.Values, error) {
values := make(url.Values)
if v == nil {
return values, nil
}
val := reflect.ValueOf(v)
for val.Kind() == reflect.Ptr {
if val.IsNil() {
@@ -133,10 +137,6 @@ func Values(v interface{}) (url.Values, error) {
val = val.Elem()
}
if v == nil {
return values, nil
}
if val.Kind() != reflect.Struct {
return nil, fmt.Errorf("query: Values() expects struct input. Got %v", val.Kind())
}
@@ -209,6 +209,11 @@ func reflectValue(values url.Values, val reflect.Value, scope string) error {
}
if sv.Kind() == reflect.Slice || sv.Kind() == reflect.Array {
if sv.Len() == 0 {
// skip if slice or array is empty
continue
}
var del string
if opts.Contains("comma") {
del = ","
@@ -223,7 +228,7 @@ func reflectValue(values url.Values, val reflect.Value, scope string) error {
}
if del != "" {
s := new(bytes.Buffer)
s := new(strings.Builder)
first := true
for i := 0; i < sv.Len(); i++ {
if first {

View File

@@ -2,11 +2,12 @@ package jsoniter
import (
"fmt"
"github.com/modern-go/reflect2"
"io"
"reflect"
"sort"
"unsafe"
"github.com/modern-go/reflect2"
)
func decoderOfMap(ctx *ctx, typ reflect2.Type) ValDecoder {
@@ -106,15 +107,17 @@ func encoderOfMapKey(ctx *ctx, typ reflect2.Type) ValEncoder {
}
}
if typ == textMarshalerType {
return &directTextMarshalerEncoder{
stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
if typ.Kind() != reflect.String {
if typ == textMarshalerType {
return &directTextMarshalerEncoder{
stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
}
}
}
if typ.Implements(textMarshalerType) {
return &textMarshalerEncoder{
valType: typ,
stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
if typ.Implements(textMarshalerType) {
return &textMarshalerEncoder{
valType: typ,
stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
}
}
}

View File

@@ -27,6 +27,14 @@ func (stream *Stream) WriteFloat32(val float32) {
}
}
stream.buf = strconv.AppendFloat(stream.buf, float64(val), fmt, -1, 32)
if fmt == 'e' {
// clean up e-09 to e-9
n := len(stream.buf)
if n >= 4 && stream.buf[n-4] == 'e' && stream.buf[n-3] == '-' && stream.buf[n-2] == '0' {
stream.buf[n-2] = stream.buf[n-1]
stream.buf = stream.buf[:n-1]
}
}
}
// WriteFloat32Lossy write float32 to stream with ONLY 6 digits precision although much much faster
@@ -76,6 +84,14 @@ func (stream *Stream) WriteFloat64(val float64) {
}
}
stream.buf = strconv.AppendFloat(stream.buf, float64(val), fmt, -1, 64)
if fmt == 'e' {
// clean up e-09 to e-9
n := len(stream.buf)
if n >= 4 && stream.buf[n-4] == 'e' && stream.buf[n-3] == '-' && stream.buf[n-2] == '0' {
stream.buf[n-2] = stream.buf[n-1]
stream.buf = stream.buf[:n-1]
}
}
}
// WriteFloat64Lossy write float64 to stream with ONLY 6 digits precision although much much faster

View File

@@ -1,5 +1,5 @@
//go:build (appengine || js || nacl || tinygo || wasm) && !windows
// +build appengine js nacl tinygo wasm
//go:build (appengine || js || nacl || tinygo || wasm || wasip1 || wasip2) && !windows
// +build appengine js nacl tinygo wasm wasip1 wasip2
// +build !windows
package isatty

View File

@@ -31,6 +31,10 @@ func init() {
if procGetFileInformationByHandleEx.Find() != nil {
procGetFileInformationByHandleEx = nil
}
// Check if NtQueryObject is available.
if procNtQueryObject.Find() != nil {
procNtQueryObject = nil
}
}
// IsTerminal return true if the file descriptor is terminal.
@@ -45,7 +49,7 @@ func IsTerminal(fd uintptr) bool {
// \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master
func isCygwinPipeName(name string) bool {
token := strings.Split(name, "-")
if len(token) < 5 {
if len(token) != 5 {
return false
}
@@ -75,10 +79,10 @@ func isCygwinPipeName(name string) bool {
return true
}
// getFileNameByHandle use the undocomented ntdll NtQueryObject to get file full name from file handler
// getFileNameByHandle use the undocumented ntdll NtQueryObject to get file full name from file handler
// since GetFileInformationByHandleEx is not available under windows Vista and still some old fashion
// guys are using Windows XP, this is a workaround for those guys, it will also work on system from
// Windows vista to 10
// Windows Vista to 10
// see https://stackoverflow.com/a/18792477 for details
func getFileNameByHandle(fd uintptr) (string, error) {
if procNtQueryObject == nil {

315
vendor/github.com/miekg/dns/README.md generated vendored
View File

@@ -3,6 +3,16 @@
[![Go Report Card](https://goreportcard.com/badge/github.com/miekg/dns)](https://goreportcard.com/report/miekg/dns)
[![](https://godoc.org/github.com/miekg/dns?status.svg)](https://godoc.org/github.com/miekg/dns)
DNS version 2 is now available at <https://codeberg.org/miekg/dns>, check it out if you want to
help shape the next 15 years of the Go DNS package.
The version here will see no new features and less and less development, and my time (if any) will be fully
devoted towards v2.
**December 2025**: v2 should be (already) a good replacement, the coming months would be a good time to
migrate, see [this file describing the
differences](https://codeberg.org/miekg/dns/src/branch/main/README-diff-with-v1.md), to help you get started.
# Alternative (more granular) approach to a DNS library
> Less is more.
@@ -17,96 +27,97 @@ avoiding breaking changes wherever reasonable. We support the last two versions
# Goals
* KISS;
* Fast;
* Small API. If it's easy to code in Go, don't make a function for it.
- KISS;
- Fast;
- Small API. If it's easy to code in Go, don't make a function for it.
# Users
A not-so-up-to-date-list-that-may-be-actually-current:
* https://github.com/coredns/coredns
* https://github.com/abh/geodns
* https://github.com/baidu/bfe
* http://www.statdns.com/
* http://www.dnsinspect.com/
* https://github.com/chuangbo/jianbing-dictionary-dns
* http://www.dns-lg.com/
* https://github.com/fcambus/rrda
* https://github.com/kenshinx/godns
* https://github.com/skynetservices/skydns
* https://github.com/hashicorp/consul
* https://github.com/DevelopersPL/godnsagent
* https://github.com/duedil-ltd/discodns
* https://github.com/StalkR/dns-reverse-proxy
* https://github.com/tianon/rawdns
* https://mesosphere.github.io/mesos-dns/
* https://github.com/fcambus/statzone
* https://github.com/benschw/dns-clb-go
* https://github.com/corny/dnscheck for <http://public-dns.info/>
* https://github.com/miekg/unbound
* https://github.com/miekg/exdns
* https://dnslookup.org
* https://github.com/looterz/grimd
* https://github.com/phamhongviet/serf-dns
* https://github.com/mehrdadrad/mylg
* https://github.com/bamarni/dockness
* https://github.com/fffaraz/microdns
* https://github.com/ipdcode/hades <https://jd.com>
* https://github.com/StackExchange/dnscontrol/
* https://www.dnsperf.com/
* https://dnssectest.net/
* https://github.com/oif/apex
* https://github.com/jedisct1/dnscrypt-proxy
* https://github.com/jedisct1/rpdns
* https://github.com/xor-gate/sshfp
* https://github.com/rs/dnstrace
* https://blitiri.com.ar/p/dnss ([github mirror](https://github.com/albertito/dnss))
* https://render.com
* https://github.com/peterzen/goresolver
* https://github.com/folbricht/routedns
* https://domainr.com/
* https://zonedb.org/
* https://router7.org/
* https://github.com/fortio/dnsping
* https://github.com/Luzilla/dnsbl_exporter
* https://github.com/bodgit/tsig
* https://github.com/v2fly/v2ray-core (test only)
* https://kuma.io/
* https://www.misaka.io/services/dns
* https://ping.sx/dig
* https://fleetdeck.io/
* https://github.com/markdingo/autoreverse
* https://github.com/slackhq/nebula
* https://addr.tools/
* https://dnscheck.tools/
* https://github.com/egbakou/domainverifier
* https://github.com/semihalev/sdns
* https://github.com/wintbiit/NineDNS
* https://linuxcontainers.org/incus/
* https://ifconfig.es
* https://github.com/zmap/zdns
* https://framagit.org/bortzmeyer/check-soa
- https://github.com/coredns/coredns
- https://github.com/abh/geodns
- https://github.com/baidu/bfe
- http://www.statdns.com/
- http://www.dnsinspect.com/
- https://github.com/chuangbo/jianbing-dictionary-dns
- http://www.dns-lg.com/
- https://github.com/fcambus/rrda
- https://github.com/kenshinx/godns
- https://github.com/skynetservices/skydns
- https://github.com/hashicorp/consul
- https://github.com/DevelopersPL/godnsagent
- https://github.com/duedil-ltd/discodns
- https://github.com/StalkR/dns-reverse-proxy
- https://github.com/tianon/rawdns
- https://mesosphere.github.io/mesos-dns/
- https://github.com/fcambus/statzone
- https://github.com/benschw/dns-clb-go
- https://github.com/corny/dnscheck for <http://public-dns.info/>
- https://github.com/miekg/unbound
- https://github.com/miekg/exdns
- https://dnslookup.org
- https://github.com/looterz/grimd
- https://github.com/phamhongviet/serf-dns
- https://github.com/mehrdadrad/mylg
- https://github.com/bamarni/dockness
- https://github.com/fffaraz/microdns
- https://github.com/ipdcode/hades <https://jd.com>
- https://github.com/StackExchange/dnscontrol/
- https://www.dnsperf.com/
- https://dnssectest.net/
- https://github.com/oif/apex
- https://github.com/jedisct1/dnscrypt-proxy (migrated to v2)
- https://github.com/jedisct1/rpdns
- https://github.com/xor-gate/sshfp
- https://github.com/rs/dnstrace
- https://blitiri.com.ar/p/dnss ([github mirror](https://github.com/albertito/dnss))
- https://render.com
- https://github.com/peterzen/goresolver
- https://github.com/folbricht/routedns
- https://domainr.com/
- https://zonedb.org/
- https://router7.org/
- https://github.com/fortio/dnsping
- https://github.com/Luzilla/dnsbl_exporter
- https://github.com/bodgit/tsig
- https://github.com/v2fly/v2ray-core (test only)
- https://kuma.io/
- https://www.misaka.io/services/dns
- https://ping.sx/dig
- https://fleetdeck.io/
- https://github.com/markdingo/autoreverse
- https://github.com/slackhq/nebula
- https://addr.tools/
- https://dnscheck.tools/
- https://github.com/egbakou/domainverifier
- https://github.com/semihalev/sdns
- https://github.com/wintbiit/NineDNS
- https://linuxcontainers.org/incus/
- https://ifconfig.es
- https://github.com/zmap/zdns
- https://framagit.org/bortzmeyer/check-soa
- https://github.com/jkerdreux-imt/owns
Send pull request if you want to be listed here.
# Features
* UDP/TCP queries, IPv4 and IPv6
* RFC 1035 zone file parsing ($INCLUDE, $ORIGIN, $TTL and $GENERATE (for all record types) are supported
* Fast
* Server side programming (mimicking the net/http package)
* Client side programming
* DNSSEC: signing, validating and key generation for DSA, RSA, ECDSA and Ed25519
* EDNS0, NSID, Cookies
* AXFR/IXFR
* TSIG, SIG(0)
* DNS over TLS (DoT): encrypted connection between client and server over TCP
* DNS name compression
- UDP/TCP queries, IPv4 and IPv6
- RFC 1035 zone file parsing ($INCLUDE, $ORIGIN, $TTL and $GENERATE (for all record types) are supported
- Fast
- Server side programming (mimicking the net/http package)
- Client side programming
- DNSSEC: signing, validating and key generation for DSA, RSA, ECDSA and Ed25519
- EDNS0, NSID, Cookies
- AXFR/IXFR
- TSIG, SIG(0)
- DNS over TLS (DoT): encrypted connection between client and server over TCP
- DNS name compression
Have fun!
Miek Gieben - 2010-2012 - <miek@miek.nl>
Miek Gieben - 2010-2012 - <miek@miek.nl>
DNS Authors 2012-
# Building
@@ -126,81 +137,83 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
## Supported RFCs
*all of them*
_all of them_
* 103{4,5} - DNS standard
* 1183 - ISDN, X25 and other deprecated records
* 1348 - NSAP record (removed the record)
* 1982 - Serial Arithmetic
* 1876 - LOC record
* 1995 - IXFR
* 1996 - DNS notify
* 2136 - DNS Update (dynamic updates)
* 2181 - RRset definition - there is no RRset type though, just []RR
* 2537 - RSAMD5 DNS keys
* 2065 - DNSSEC (updated in later RFCs)
* 2671 - EDNS record
* 2782 - SRV record
* 2845 - TSIG record
* 2915 - NAPTR record
* 2929 - DNS IANA Considerations
* 3110 - RSASHA1 DNS keys
* 3123 - APL record
* 3225 - DO bit (DNSSEC OK)
* 340{1,2,3} - NAPTR record
* 3445 - Limiting the scope of (DNS)KEY
* 3596 - AAAA record
* 3597 - Unknown RRs
* 4025 - A Method for Storing IPsec Keying Material in DNS
* 403{3,4,5} - DNSSEC + validation functions
* 4255 - SSHFP record
* 4343 - Case insensitivity
* 4408 - SPF record
* 4509 - SHA256 Hash in DS
* 4592 - Wildcards in the DNS
* 4635 - HMAC SHA TSIG
* 4701 - DHCID
* 4892 - id.server
* 5001 - NSID
* 5155 - NSEC3 record
* 5205 - HIP record
* 5702 - SHA2 in the DNS
* 5936 - AXFR
* 5966 - TCP implementation recommendations
* 6605 - ECDSA
* 6725 - IANA Registry Update
* 6742 - ILNP DNS
* 6840 - Clarifications and Implementation Notes for DNS Security
* 6844 - CAA record
* 6891 - EDNS0 update
* 6895 - DNS IANA considerations
* 6944 - DNSSEC DNSKEY Algorithm Status
* 6975 - Algorithm Understanding in DNSSEC
* 7043 - EUI48/EUI64 records
* 7314 - DNS (EDNS) EXPIRE Option
* 7477 - CSYNC RR
* 7828 - edns-tcp-keepalive EDNS0 Option
* 7553 - URI record
* 7858 - DNS over TLS: Initiation and Performance Considerations
* 7871 - EDNS0 Client Subnet
* 7873 - Domain Name System (DNS) Cookies
* 8080 - EdDSA for DNSSEC
* 8490 - DNS Stateful Operations
* 8499 - DNS Terminology
* 8659 - DNS Certification Authority Authorization (CAA) Resource Record
* 8777 - DNS Reverse IP Automatic Multicast Tunneling (AMT) Discovery
* 8914 - Extended DNS Errors
* 8976 - Message Digest for DNS Zones (ZONEMD RR)
* 9460 - Service Binding and Parameter Specification via the DNS
* 9461 - Service Binding Mapping for DNS Servers
* 9462 - Discovery of Designated Resolvers
* 9460 - SVCB and HTTPS Records
* 9606 - DNS Resolver Information
* Draft - Compact Denial of Existence in DNSSEC
- 103{4,5} - DNS standard
- 1183 - ISDN, X25 and other deprecated records
- 1348 - NSAP record (removed the record)
- 1982 - Serial Arithmetic
- 1876 - LOC record
- 1995 - IXFR
- 1996 - DNS notify
- 2136 - DNS Update (dynamic updates)
- 2181 - RRset definition - there is no RRset type though, just []RR
- 2537 - RSAMD5 DNS keys
- 2065 - DNSSEC (updated in later RFCs)
- 2671 - EDNS record
- 2782 - SRV record
- 2845 - TSIG record
- 2915 - NAPTR record
- 2929 - DNS IANA Considerations
- 3110 - RSASHA1 DNS keys
- 3123 - APL record
- 3225 - DO bit (DNSSEC OK)
- 340{1,2,3} - NAPTR record
- 3445 - Limiting the scope of (DNS)KEY
- 3596 - AAAA record
- 3597 - Unknown RRs
- 4025 - A Method for Storing IPsec Keying Material in DNS
- 403{3,4,5} - DNSSEC + validation functions
- 4255 - SSHFP record
- 4343 - Case insensitivity
- 4408 - SPF record
- 4509 - SHA256 Hash in DS
- 4592 - Wildcards in the DNS
- 4635 - HMAC SHA TSIG
- 4701 - DHCID
- 4892 - id.server
- 5001 - NSID
- 5155 - NSEC3 record
- 5205 - HIP record
- 5702 - SHA2 in the DNS
- 5936 - AXFR
- 5966 - TCP implementation recommendations
- 6605 - ECDSA
- 6725 - IANA Registry Update
- 6742 - ILNP DNS
- 6840 - Clarifications and Implementation Notes for DNS Security
- 6844 - CAA record
- 6891 - EDNS0 update
- 6895 - DNS IANA considerations
- 6944 - DNSSEC DNSKEY Algorithm Status
- 6975 - Algorithm Understanding in DNSSEC
- 7043 - EUI48/EUI64 records
- 7314 - DNS (EDNS) EXPIRE Option
- 7477 - CSYNC RR
- 7828 - edns-tcp-keepalive EDNS0 Option
- 7553 - URI record
- 7858 - DNS over TLS: Initiation and Performance Considerations
- 7871 - EDNS0 Client Subnet
- 7873 - Domain Name System (DNS) Cookies
- 8080 - EdDSA for DNSSEC
- 8490 - DNS Stateful Operations
- 8499 - DNS Terminology
- 8659 - DNS Certification Authority Authorization (CAA) Resource Record
- 8777 - DNS Reverse IP Automatic Multicast Tunneling (AMT) Discovery
- 8914 - Extended DNS Errors
- 8976 - Message Digest for DNS Zones (ZONEMD RR)
- 9460 - Service Binding and Parameter Specification via the DNS
- 9461 - Service Binding Mapping for DNS Servers
- 9462 - Discovery of Designated Resolvers
- 9460 - SVCB and HTTPS Records
- 9567 - DNS Error Reporting
- 9606 - DNS Resolver Information
- 9660 - DNS Zone Version (ZONEVERSION) Option
- Draft - Compact Denial of Existence in DNSSEC
## Loosely Based Upon
* ldns - <https://nlnetlabs.nl/projects/ldns/about/>
* NSD - <https://nlnetlabs.nl/projects/nsd/about/>
* Net::DNS - <http://www.net-dns.org/>
* GRONG - <https://github.com/bortzmeyer/grong>
- ldns - <https://nlnetlabs.nl/projects/ldns/about/>
- NSD - <https://nlnetlabs.nl/projects/nsd/about/>
- Net::DNS - <http://www.net-dns.org/>
- GRONG - <https://github.com/bortzmeyer/grong>

View File

@@ -57,8 +57,8 @@ type Client struct {
// Client.Dialer) or context.Context.Deadline (see ExchangeContext)
Timeout time.Duration
DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds, or net.Dialer.Timeout if expiring earlier - overridden by Timeout when that value is non-zero
ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero
WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero
ReadTimeout time.Duration // net.Conn.SetReadDeadline value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero
WriteTimeout time.Duration // net.Conn.SetWriteDeadline value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero
TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2)
TsigProvider TsigProvider // An implementation of the TsigProvider interface. If defined it replaces TsigSecret and is used for all TSIG operations.
@@ -92,6 +92,9 @@ func (c *Client) dialTimeout() time.Duration {
}
func (c *Client) readTimeout() time.Duration {
if c.Timeout != 0 {
return c.Timeout
}
if c.ReadTimeout != 0 {
return c.ReadTimeout
}
@@ -99,6 +102,9 @@ func (c *Client) readTimeout() time.Duration {
}
func (c *Client) writeTimeout() time.Duration {
if c.Timeout != 0 {
return c.Timeout
}
if c.WriteTimeout != 0 {
return c.WriteTimeout
}

131
vendor/github.com/miekg/dns/edns.go generated vendored
View File

@@ -24,6 +24,8 @@ const (
EDNS0TCPKEEPALIVE = 0xb // EDNS0 tcp keep alive (See RFC 7828)
EDNS0PADDING = 0xc // EDNS0 padding (See RFC 7830)
EDNS0EDE = 0xf // EDNS0 extended DNS errors (See RFC 8914)
EDNS0REPORTING = 0x12 // EDNS0 reporting (See RFC 9567)
EDNS0ZONEVERSION = 0x13 // EDNS0 Zone Version (See RFC 9660)
EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (See RFC 6891)
EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (See RFC 6891)
_DO = 1 << 15 // DNSSEC OK
@@ -60,6 +62,10 @@ func makeDataOpt(code uint16) EDNS0 {
return new(EDNS0_EDE)
case EDNS0ESU:
return new(EDNS0_ESU)
case EDNS0REPORTING:
return new(EDNS0_REPORTING)
case EDNS0ZONEVERSION:
return new(EDNS0_ZONEVERSION)
default:
e := new(EDNS0_LOCAL)
e.Code = code
@@ -75,17 +81,16 @@ type OPT struct {
func (rr *OPT) String() string {
s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; "
s += "flags:"
if rr.Do() {
if rr.Co() {
s += "flags: do, co; "
} else {
s += "flags: do; "
}
} else {
s += "flags:; "
s += " do"
}
if rr.Hdr.Ttl&0x7FFF != 0 {
s += fmt.Sprintf("MBZ: 0x%04x, ", rr.Hdr.Ttl&0x7FFF)
if rr.Co() {
s += " co"
}
s += "; "
if z := rr.Z(); z != 0 {
s += fmt.Sprintf("MBZ: 0x%04x, ", z)
}
s += "udp: " + strconv.Itoa(int(rr.UDPSize()))
@@ -127,6 +132,10 @@ func (rr *OPT) String() string {
s += "\n; EDE: " + o.String()
case *EDNS0_ESU:
s += "\n; ESU: " + o.String()
case *EDNS0_REPORTING:
s += "\n; REPORT-CHANNEL: " + o.String()
case *EDNS0_ZONEVERSION:
s += "\n; ZONEVERSION: " + o.String()
}
}
return s
@@ -308,10 +317,6 @@ type EDNS0_SUBNET struct {
func (e *EDNS0_SUBNET) Option() uint16 { return EDNS0SUBNET }
func (e *EDNS0_SUBNET) pack() ([]byte, error) {
b := make([]byte, 4)
binary.BigEndian.PutUint16(b[0:], e.Family)
b[2] = e.SourceNetmask
b[3] = e.SourceScope
switch e.Family {
case 0:
// "dig" sets AddressFamily to 0 if SourceNetmask is also 0
@@ -319,16 +324,27 @@ func (e *EDNS0_SUBNET) pack() ([]byte, error) {
if e.SourceNetmask != 0 {
return nil, errors.New("bad address family")
}
b := make([]byte, 4)
b[3] = e.SourceScope
return b, nil
case 1:
if e.SourceNetmask > net.IPv4len*8 {
return nil, errors.New("bad netmask")
}
if len(e.Address.To4()) != net.IPv4len {
ip4 := e.Address.To4()
if len(ip4) != net.IPv4len {
return nil, errors.New("bad address")
}
ip := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8))
needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
b = append(b, ip[:needLength]...)
b := make([]byte, 4+needLength)
binary.BigEndian.PutUint16(b[0:], e.Family)
b[2] = e.SourceNetmask
b[3] = e.SourceScope
if needLength > 0 {
ip := ip4.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8))
copy(b[4:], ip[:needLength])
}
return b, nil
case 2:
if e.SourceNetmask > net.IPv6len*8 {
return nil, errors.New("bad netmask")
@@ -336,13 +352,19 @@ func (e *EDNS0_SUBNET) pack() ([]byte, error) {
if len(e.Address) != net.IPv6len {
return nil, errors.New("bad address")
}
ip := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8))
needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
b = append(b, ip[:needLength]...)
b := make([]byte, 4+needLength)
binary.BigEndian.PutUint16(b[0:], e.Family)
b[2] = e.SourceNetmask
b[3] = e.SourceScope
if needLength > 0 {
ip := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8))
copy(b[4:], ip[:needLength])
}
return b, nil
default:
return nil, errors.New("bad address family")
}
return b, nil
}
func (e *EDNS0_SUBNET) unpack(b []byte) error {
@@ -875,3 +897,74 @@ func (e *EDNS0_ESU) unpack(b []byte) error {
e.Uri = string(b)
return nil
}
// EDNS0_REPORTING implements the EDNS0 Reporting Channel option (RFC 9567).
type EDNS0_REPORTING struct {
Code uint16 // always EDNS0REPORTING
AgentDomain string
}
func (e *EDNS0_REPORTING) Option() uint16 { return EDNS0REPORTING }
func (e *EDNS0_REPORTING) String() string { return e.AgentDomain }
func (e *EDNS0_REPORTING) copy() EDNS0 { return &EDNS0_REPORTING{e.Code, e.AgentDomain} }
func (e *EDNS0_REPORTING) pack() ([]byte, error) {
b := make([]byte, 255)
off1, err := PackDomainName(Fqdn(e.AgentDomain), b, 0, nil, false)
if err != nil {
return nil, fmt.Errorf("bad agent domain: %w", err)
}
return b[:off1], nil
}
func (e *EDNS0_REPORTING) unpack(b []byte) error {
domain, _, err := UnpackDomainName(b, 0)
if err != nil {
return fmt.Errorf("bad agent domain: %w", err)
}
e.AgentDomain = domain
return nil
}
// EDNS0_ZONEVERSION implements the EDNS0 Zone Version option (RFC 9660).
type EDNS0_ZONEVERSION struct {
// always EDNS0ZONEVERSION (19)
Code uint16
// An unsigned 1-octet Label Count indicating
// the number of labels for the name of the zone that VERSION value refers to.
LabelCount uint8
// An unsigned 1-octet type number distinguishing the format and meaning of version.
// 0 SOA-SERIAL, 1-245 Unassigned, 246-255 Reserved for private use, see RFC 9660.
Type uint8
// An opaque octet string conveying the zone version data (VERSION).
Version string
}
func (e *EDNS0_ZONEVERSION) Option() uint16 { return EDNS0ZONEVERSION }
func (e *EDNS0_ZONEVERSION) String() string { return e.Version }
func (e *EDNS0_ZONEVERSION) copy() EDNS0 {
return &EDNS0_ZONEVERSION{e.Code, e.LabelCount, e.Type, e.Version}
}
func (e *EDNS0_ZONEVERSION) pack() ([]byte, error) {
b := []byte{
// first octet label count
e.LabelCount,
// second octet is type
e.Type,
}
if len(e.Version) > 0 {
b = append(b, []byte(e.Version)...)
}
return b, nil
}
func (e *EDNS0_ZONEVERSION) unpack(b []byte) error {
if len(b) < 2 {
return ErrBuf
}
e.LabelCount = b[0]
e.Type = b[1]
if len(b) > 2 {
e.Version = string(b[2:])
} else {
e.Version = ""
}
return nil
}

4
vendor/github.com/miekg/dns/msg.go generated vendored
View File

@@ -338,11 +338,13 @@ loop:
return off + 2, nil
}
// Trailing root label
if off < len(msg) {
msg[off] = 0
return off + 1, nil
}
return off + 1, nil
return off, ErrBuf
}
// isRootLabel returns whether s or bs, from off to end, is the root

10
vendor/github.com/miekg/dns/scan.go generated vendored
View File

@@ -5,6 +5,7 @@ import (
"fmt"
"io"
"io/fs"
"math"
"os"
"path"
"path/filepath"
@@ -1231,7 +1232,7 @@ func typeToInt(token string) (uint16, bool) {
// stringToTTL parses things like 2w, 2m, etc, and returns the time in seconds.
func stringToTTL(token string) (uint32, bool) {
var s, i uint32
var s, i uint
for _, c := range token {
switch c {
case 's', 'S':
@@ -1251,12 +1252,15 @@ func stringToTTL(token string) (uint32, bool) {
i = 0
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
i *= 10
i += uint32(c) - '0'
i += uint(c) - '0'
default:
return 0, false
}
}
return s + i, true
if s+i > math.MaxUint32 {
return 0, false
}
return uint32(s + i), true
}
// Parse LOC records' <digits>[.<digits>][mM] into a

View File

@@ -194,7 +194,9 @@ type DecorateWriter func(Writer) Writer
// rejected (or ignored) by the MsgAcceptFunc, or passed to this function.
type MsgInvalidFunc func(m []byte, err error)
func DefaultMsgInvalidFunc(m []byte, err error) {}
var DefaultMsgInvalidFunc MsgInvalidFunc = defaultMsgInvalidFunc
func defaultMsgInvalidFunc(m []byte, err error) {}
// A Server defines parameters for running an DNS server.
type Server struct {

View File

@@ -3,7 +3,7 @@ package dns
import "fmt"
// Version is current version of this library.
var Version = v{1, 1, 68}
var Version = v{1, 1, 72}
// v holds the version of this library.
type v struct {

View File

@@ -1,8 +1,6 @@
# Objx
[![Build Status](https://travis-ci.org/stretchr/objx.svg?branch=master)](https://travis-ci.org/stretchr/objx)
[![Go Report Card](https://goreportcard.com/badge/github.com/stretchr/objx)](https://goreportcard.com/report/github.com/stretchr/objx)
[![Maintainability](https://api.codeclimate.com/v1/badges/1d64bc6c8474c2074f2b/maintainability)](https://codeclimate.com/github/stretchr/objx/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/1d64bc6c8474c2074f2b/test_coverage)](https://codeclimate.com/github/stretchr/objx/test_coverage)
[![Sourcegraph](https://sourcegraph.com/github.com/stretchr/objx/-/badge.svg)](https://sourcegraph.com/github.com/stretchr/objx)
[![GoDoc](https://pkg.go.dev/badge/github.com/stretchr/objx?utm_source=godoc)](https://pkg.go.dev/github.com/stretchr/objx)
@@ -19,49 +17,62 @@ Objx provides the `objx.Map` type, which is a `map[string]interface{}` that expo
### Pattern
Objx uses a predictable pattern to make access data from within `map[string]interface{}` easy. Call one of the `objx.` functions to create your `objx.Map` to get going:
m, err := objx.FromJSON(json)
```go
m, err := objx.FromJSON(json)
```
NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong, the rest will be optimistic and try to figure things out without panicking.
Use `Get` to access the value you're interested in. You can use dot and array
notation too:
m.Get("places[0].latlng")
```go
m.Get("places[0].latlng")
```
Once you have sought the `Value` you're interested in, you can use the `Is*` methods to determine its type.
if m.Get("code").IsStr() { // Your code... }
```go
if m.Get("code").IsStr() { // Your code... }
```
Or you can just assume the type, and use one of the strong type methods to extract the real value:
m.Get("code").Int()
```go
m.Get("code").Int()
```
If there's no value there (or if it's the wrong type) then a default value will be returned, or you can be explicit about the default value.
Get("code").Int(-1)
```go
Get("code").Int(-1)
```
If you're dealing with a slice of data as a value, Objx provides many useful methods for iterating, manipulating and selecting that data. You can find out more by exploring the index below.
### Reading data
A simple example of how to use Objx:
// Use MustFromJSON to make an objx.Map from some JSON
m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`)
```go
// Use MustFromJSON to make an objx.Map from some JSON
m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`)
// Get the details
name := m.Get("name").Str()
age := m.Get("age").Int()
// Get the details
name := m.Get("name").Str()
age := m.Get("age").Int()
// Get their nickname (or use their name if they don't have one)
nickname := m.Get("nickname").Str(name)
// Get their nickname (or use their name if they don't have one)
nickname := m.Get("nickname").Str(name)
```
### Ranging
Since `objx.Map` is a `map[string]interface{}` you can treat it as such. For example, to `range` the data, do what you would expect:
m := objx.MustFromJSON(json)
for key, value := range m {
// Your code...
}
```go
m := objx.MustFromJSON(json)
for key, value := range m {
// Your code...
}
```
## Installation
To install Objx, use go get:

View File

@@ -1,65 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
import (
"context"
"io"
"net/http"
"net/url"
"strings"
)
// DefaultClient is the default Client and is used by Get, Head, Post and PostForm.
// Please be careful of initialization order - for example, if you change
// the global propagator, the DefaultClient might still be using the old one.
//
// Deprecated: [DefaultClient] will be removed in a future release.
// Create your own [http.Client] based on the [Transport] example: https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp#example-NewTransport
var DefaultClient = &http.Client{Transport: NewTransport(http.DefaultTransport)}
// Get is a convenient replacement for http.Get that adds a span around the request.
//
// Deprecated: [Get] will be removed in a future release.
// Create your own [http.Client] based on the [Transport] example: https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp#example-NewTransport
func Get(ctx context.Context, targetURL string) (resp *http.Response, err error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, targetURL, http.NoBody)
if err != nil {
return nil, err
}
return DefaultClient.Do(req)
}
// Head is a convenient replacement for http.Head that adds a span around the request.
//
// Deprecated: [Head] will be removed in a future release.
// Create your own [http.Client] based on the [Transport] example: https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp#example-NewTransport
func Head(ctx context.Context, targetURL string) (resp *http.Response, err error) {
req, err := http.NewRequestWithContext(ctx, http.MethodHead, targetURL, http.NoBody)
if err != nil {
return nil, err
}
return DefaultClient.Do(req)
}
// Post is a convenient replacement for http.Post that adds a span around the request.
//
// Deprecated: [Post] will be removed in a future release.
// Create your own [http.Client] based on the [Transport] example: https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp#example-NewTransport
func Post(ctx context.Context, targetURL, contentType string, body io.Reader) (resp *http.Response, err error) {
req, err := http.NewRequestWithContext(ctx, http.MethodPost, targetURL, body)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", contentType)
return DefaultClient.Do(req)
}
// PostForm is a convenient replacement for http.PostForm that adds a span around the request.
//
// Deprecated: [PostForm] will be removed in a future release.
// Create your own [http.Client] based on the [Transport] example: https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp#example-NewTransport
func PostForm(ctx context.Context, targetURL string, data url.Values) (resp *http.Response, err error) {
return Post(ctx, targetURL, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}

View File

@@ -23,5 +23,5 @@ const (
type Filter func(*http.Request) bool
func newTracer(tp trace.TracerProvider) trace.Tracer {
return tp.Tracer(ScopeName, trace.WithInstrumentationVersion(Version()))
return tp.Tracer(ScopeName, trace.WithInstrumentationVersion(Version))
}

View File

@@ -66,7 +66,7 @@ func newConfig(opts ...Option) *config {
c.Meter = c.MeterProvider.Meter(
ScopeName,
metric.WithInstrumentationVersion(Version()),
metric.WithInstrumentationVersion(Version),
)
return c
@@ -92,18 +92,6 @@ func WithMeterProvider(provider metric.MeterProvider) Option {
})
}
// WithPublicEndpoint configures the Handler to link the span with an incoming
// span context. If this option is not provided, then the association is a child
// association instead of a link.
//
// Deprecated: Use [WithPublicEndpointFn] instead.
// To migrate, replace WithPublicEndpoint() with:
//
// WithPublicEndpointFn(func(*http.Request) bool { return true })
func WithPublicEndpoint() Option {
return WithPublicEndpointFn(func(*http.Request) bool { return true })
}
// WithPublicEndpointFn runs with every request, and allows conditionally
// configuring the Handler to link the span with an incoming span context. If
// this option is not provided or returns false, then the association is a
@@ -206,6 +194,9 @@ func WithServerName(server string) Option {
// WithMetricAttributesFn returns an Option to set a function that maps an HTTP request to a slice of attribute.KeyValue.
// These attributes will be included in metrics for every request.
//
// Deprecated: WithMetricAttributesFn is deprecated and will be removed in a
// future release. Use [Labeler] instead.
func WithMetricAttributesFn(metricAttributesFn func(r *http.Request) []attribute.KeyValue) Option {
return optionFunc(func(c *config) {
c.MetricAttributesFn = metricAttributesFn

View File

@@ -184,30 +184,26 @@ func (h *middleware) serveHTTP(w http.ResponseWriter, r *http.Request, next http
statusCode := rww.StatusCode()
bytesWritten := rww.BytesWritten()
span.SetStatus(h.semconv.Status(statusCode))
bytesRead := bw.BytesRead()
span.SetAttributes(h.semconv.ResponseTraceAttrs(semconv.ResponseTelemetry{
StatusCode: statusCode,
ReadBytes: bw.BytesRead(),
ReadBytes: bytesRead,
ReadError: bw.Error(),
WriteBytes: bytesWritten,
WriteError: rww.Error(),
})...)
// Use floating point division here for higher precision (instead of Millisecond method).
elapsedTime := float64(time.Since(requestStartTime)) / float64(time.Millisecond)
metricAttributes := semconv.MetricAttributes{
Req: r,
StatusCode: statusCode,
AdditionalAttributes: append(labeler.Get(), h.metricAttributesFromRequest(r)...),
}
h.semconv.RecordMetrics(ctx, semconv.ServerMetricData{
ServerName: h.server,
ResponseSize: bytesWritten,
MetricAttributes: metricAttributes,
ServerName: h.server,
ResponseSize: bytesWritten,
MetricAttributes: semconv.MetricAttributes{
Req: r,
StatusCode: statusCode,
AdditionalAttributes: append(labeler.Get(), h.metricAttributesFromRequest(r)...),
},
MetricData: semconv.MetricData{
RequestSize: bw.BytesRead(),
ElapsedTime: elapsedTime,
RequestSize: bytesRead,
RequestDuration: time.Since(requestStartTime),
},
})
}
@@ -219,21 +215,3 @@ func (h *middleware) metricAttributesFromRequest(r *http.Request) []attribute.Ke
}
return attributeForRequest
}
// WithRouteTag annotates spans and metrics with the provided route name
// with HTTP route attribute.
//
// Deprecated: spans are automatically annotated with the route attribute.
// To annotate metrics, use the [WithMetricAttributesFn] option.
func WithRouteTag(route string, h http.Handler) http.Handler {
attr := semconv.NewHTTPServer(nil).Route(route)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
span := trace.SpanFromContext(r.Context())
span.SetAttributes(attr)
labeler, _ := LabelerFromContext(r.Context())
labeler.Add(attr)
h.ServeHTTP(w, r)
})
}

View File

@@ -61,7 +61,7 @@ func (w *RespWriterWrapper) Write(p []byte) (int, error) {
// WriteHeader persists initial statusCode for span attribution.
// All calls to WriteHeader will be propagated to the underlying ResponseWriter
// and will persist the statusCode from the first call.
// and will persist the statusCode from the first call (except for informational response status codes).
// Blocking consecutive calls to WriteHeader alters expected behavior and will
// remove warning logs from net/http where developers will notice incorrect handler implementations.
func (w *RespWriterWrapper) WriteHeader(statusCode int) {
@@ -77,6 +77,13 @@ func (w *RespWriterWrapper) WriteHeader(statusCode int) {
// parent method.
func (w *RespWriterWrapper) writeHeader(statusCode int) {
if !w.wroteHeader {
// Ignore informational response status codes.
// Based on https://github.com/golang/go/blob/go1.24.1/src/net/http/server.go#L1216
if statusCode >= 100 && statusCode <= 199 && statusCode != http.StatusSwitchingProtocols {
w.ResponseWriter.WriteHeader(statusCode)
return
}
w.wroteHeader = true
w.statusCode = statusCode
}

View File

@@ -12,7 +12,6 @@ import (
"context"
"fmt"
"net/http"
"reflect"
"slices"
"strconv"
"strings"
@@ -20,11 +19,11 @@ import (
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/semconv/v1.37.0"
"go.opentelemetry.io/otel/semconv/v1.37.0/httpconv"
"go.opentelemetry.io/otel/semconv/v1.40.0"
"go.opentelemetry.io/otel/semconv/v1.40.0/httpconv"
)
type HTTPClient struct{
type HTTPClient struct {
requestBodySize httpconv.ClientRequestBodySize
requestDuration httpconv.ClientRequestDuration
}
@@ -58,14 +57,14 @@ func (n HTTPClient) Status(code int) (codes.Code, string) {
// RequestTraceAttrs returns trace attributes for an HTTP request made by a client.
func (n HTTPClient) RequestTraceAttrs(req *http.Request) []attribute.KeyValue {
/*
below attributes are returned:
- http.request.method
- http.request.method.original
- url.full
- server.address
- server.port
- network.protocol.name
- network.protocol.version
below attributes are returned:
- http.request.method
- http.request.method.original
- url.full
- server.address
- server.port
- network.protocol.name
- network.protocol.version
*/
numOfAttributes := 3 // URL, server address, proto, and method.
@@ -140,9 +139,9 @@ func (n HTTPClient) RequestTraceAttrs(req *http.Request) []attribute.KeyValue {
// ResponseTraceAttrs returns trace attributes for an HTTP response made by a client.
func (n HTTPClient) ResponseTraceAttrs(resp *http.Response) []attribute.KeyValue {
/*
below attributes are returned:
- http.response.status_code
- error.type
below attributes are returned:
- http.response.status_code
- error.type
*/
var count int
if resp.StatusCode > 0 {
@@ -165,23 +164,6 @@ func (n HTTPClient) ResponseTraceAttrs(resp *http.Response) []attribute.KeyValue
return attrs
}
func (n HTTPClient) ErrorType(err error) attribute.KeyValue {
t := reflect.TypeOf(err)
var value string
if t.PkgPath() == "" && t.Name() == "" {
// Likely a builtin type.
value = t.String()
} else {
value = fmt.Sprintf("%s.%s", t.PkgPath(), t.Name())
}
if value == "" {
return semconv.ErrorTypeOther
}
return semconv.ErrorTypeKey.String(value)
}
func (n HTTPClient) method(method string) (attribute.KeyValue, attribute.KeyValue) {
if method == "" {
return semconv.HTTPRequestMethodGet, attribute.KeyValue{}
@@ -265,22 +247,26 @@ func (o MetricOpts) AddOptions() metric.AddOption {
return o.addOptions
}
func (n HTTPClient) MetricOptions(ma MetricAttributes) map[string]MetricOpts {
opts := map[string]MetricOpts{}
func (n HTTPClient) MetricOptions(ma MetricAttributes) MetricOpts {
attributes := n.MetricAttributes(ma.Req, ma.StatusCode, ma.AdditionalAttributes)
set := metric.WithAttributeSet(attribute.NewSet(attributes...))
opts["new"] = MetricOpts{
return MetricOpts{
measurement: set,
addOptions: set,
}
return opts
}
func (n HTTPClient) RecordMetrics(ctx context.Context, md MetricData, opts map[string]MetricOpts) {
n.requestBodySize.Inst().Record(ctx, md.RequestSize, opts["new"].MeasurementOption())
n.requestDuration.Inst().Record(ctx, md.ElapsedTime/1000, opts["new"].MeasurementOption())
func (n HTTPClient) RecordMetrics(ctx context.Context, md MetricData, opts MetricOpts) {
recordOpts := metricRecordOptionPool.Get().(*[]metric.RecordOption)
defer func() {
*recordOpts = (*recordOpts)[:0]
metricRecordOptionPool.Put(recordOpts)
}()
*recordOpts = append(*recordOpts, opts.MeasurementOption())
n.requestBodySize.Inst().Record(ctx, md.RequestSize, *recordOpts...)
n.requestDuration.Inst().Record(ctx, durationToSeconds(md.RequestDuration), *recordOpts...)
}
// TraceAttributes returns attributes for httptrace.

View File

@@ -15,12 +15,13 @@ import (
"slices"
"strings"
"sync"
"time"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/semconv/v1.37.0"
"go.opentelemetry.io/otel/semconv/v1.37.0/httpconv"
"go.opentelemetry.io/otel/semconv/v1.40.0"
"go.opentelemetry.io/otel/semconv/v1.40.0/httpconv"
)
type RequestTraceAttrsOpts struct {
@@ -36,7 +37,7 @@ type ResponseTelemetry struct {
WriteError error
}
type HTTPServer struct{
type HTTPServer struct {
requestBodySizeHistogram httpconv.ServerRequestBodySize
responseBodySizeHistogram httpconv.ServerResponseBodySize
requestDurationHistogram httpconv.ServerRequestDuration
@@ -245,19 +246,11 @@ type MetricAttributes struct {
}
type MetricData struct {
RequestSize int64
// The request duration, in milliseconds
ElapsedTime float64
RequestSize int64
RequestDuration time.Duration
}
var (
metricAddOptionPool = &sync.Pool{
New: func() any {
return &[]metric.AddOption{}
},
}
metricRecordOptionPool = &sync.Pool{
New: func() any {
return &[]metric.RecordOption{}
@@ -272,7 +265,7 @@ func (n HTTPServer) RecordMetrics(ctx context.Context, md ServerMetricData) {
*recordOpts = append(*recordOpts, o)
n.requestBodySizeHistogram.Inst().Record(ctx, md.RequestSize, *recordOpts...)
n.responseBodySizeHistogram.Inst().Record(ctx, md.ResponseSize, *recordOpts...)
n.requestDurationHistogram.Inst().Record(ctx, md.ElapsedTime/1000.0, o)
n.requestDurationHistogram.Inst().Record(ctx, durationToSeconds(md.RequestDuration), o)
*recordOpts = (*recordOpts)[:0]
metricRecordOptionPool.Put(recordOpts)
}
@@ -373,8 +366,8 @@ func (n HTTPServer) MetricAttributes(server string, req *http.Request, statusCod
}
if route != "" {
num++
}
num++
}
attributes := slices.Grow(additionalAttributes, num)
attributes = append(attributes,
@@ -397,7 +390,7 @@ func (n HTTPServer) MetricAttributes(server string, req *http.Request, statusCod
}
if route != "" {
attributes = append(attributes, semconv.HTTPRoute(route))
}
attributes = append(attributes, semconv.HTTPRoute(route))
}
return attributes
}

View File

@@ -11,10 +11,11 @@ import (
"net/http"
"strconv"
"strings"
"time"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
semconvNew "go.opentelemetry.io/otel/semconv/v1.37.0"
semconvNew "go.opentelemetry.io/otel/semconv/v1.40.0"
)
// SplitHostPort splits a network address hostport of the form "host",
@@ -125,3 +126,8 @@ func standardizeHTTPMethod(method string) string {
}
return method
}
func durationToSeconds(d time.Duration) float64 {
// Use floating point division here for higher precision (instead of Seconds method).
return float64(d) / float64(time.Second)
}

View File

@@ -15,6 +15,7 @@ import (
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/propagation"
otelsemconv "go.opentelemetry.io/otel/semconv/v1.40.0"
"go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/internal/request"
@@ -102,9 +103,7 @@ func (t *Transport) RoundTrip(r *http.Request) (*http.Response, error) {
}
}
opts := append([]trace.SpanStartOption{}, t.spanStartOptions...) // start with the configured options
ctx, span := tracer.Start(r.Context(), t.spanNameFormatter("", r), opts...)
ctx, span := tracer.Start(r.Context(), t.spanNameFormatter("", r), t.spanStartOptions...)
if t.clientTrace != nil {
ctx = httptrace.WithClientTrace(ctx, t.clientTrace(ctx))
@@ -117,12 +116,26 @@ func (t *Transport) RoundTrip(r *http.Request) (*http.Response, error) {
r = r.Clone(ctx) // According to RoundTripper spec, we shouldn't modify the origin request.
// if request body is nil or NoBody, we don't want to mutate the body as it
// will affect the identity of it in an unforeseeable way because we assert
// ReadCloser fulfills a certain interface and it is indeed nil or NoBody.
bw := request.NewBodyWrapper(r.Body, func(int64) {})
if r.Body != nil && r.Body != http.NoBody {
r.Body = bw
var lastBW *request.BodyWrapper // Records the last body wrapper. Can be nil.
maybeWrapBody := func(body io.ReadCloser) io.ReadCloser {
if body == nil || body == http.NoBody {
return body
}
bw := request.NewBodyWrapper(body, func(int64) {})
lastBW = bw
return bw
}
r.Body = maybeWrapBody(r.Body)
if r.GetBody != nil {
originalGetBody := r.GetBody
r.GetBody = func() (io.ReadCloser, error) {
b, err := originalGetBody()
if err != nil {
lastBW = nil // The underlying transport will fail to make a retry request, hence, record no data.
return nil, err
}
return maybeWrapBody(b), nil
}
}
span.SetAttributes(t.semconv.RequestTraceAttrs(r)...)
@@ -130,52 +143,38 @@ func (t *Transport) RoundTrip(r *http.Request) (*http.Response, error) {
res, err := t.rt.RoundTrip(r)
// Defer metrics recording function to record the metrics on error or no error.
defer func() {
metricAttributes := semconv.MetricAttributes{
// Record the metrics on error or no error.
statusCode := 0
if err == nil {
statusCode = res.StatusCode
}
var requestSize int64
if lastBW != nil {
requestSize = lastBW.BytesRead()
}
t.semconv.RecordMetrics(
ctx,
semconv.MetricData{
RequestSize: requestSize,
RequestDuration: time.Since(requestStartTime),
},
t.semconv.MetricOptions(semconv.MetricAttributes{
Req: r,
StatusCode: statusCode,
AdditionalAttributes: append(labeler.Get(), t.metricAttributesFromRequest(r)...),
}
if err == nil {
metricAttributes.StatusCode = res.StatusCode
}
metricOpts := t.semconv.MetricOptions(metricAttributes)
metricData := semconv.MetricData{
RequestSize: bw.BytesRead(),
}
if err == nil {
readRecordFunc := func(int64) {}
res.Body = newWrappedBody(span, readRecordFunc, res.Body)
}
// Use floating point division here for higher precision (instead of Millisecond method).
elapsedTime := float64(time.Since(requestStartTime)) / float64(time.Millisecond)
metricData.ElapsedTime = elapsedTime
t.semconv.RecordMetrics(ctx, metricData, metricOpts)
}()
}),
)
if err != nil {
// set error type attribute if the error is part of the predefined
// error types.
// otherwise, record it as an exception
if errType := t.semconv.ErrorType(err); errType.Valid() {
span.SetAttributes(errType)
} else {
span.RecordError(err)
}
span.SetAttributes(otelsemconv.ErrorType(err))
span.SetStatus(codes.Error, err.Error())
span.End()
return res, err
}
readRecordFunc := func(int64) {}
res.Body = newWrappedBody(span, readRecordFunc, res.Body)
// traces
span.SetAttributes(t.semconv.ResponseTraceAttrs(res)...)
span.SetStatus(t.semconv.Status(res.StatusCode))
@@ -229,7 +228,7 @@ func (wb *wrappedBody) Write(p []byte) (int, error) {
// This will not panic given the guard in newWrappedBody.
n, err := wb.body.(io.Writer).Write(p)
if err != nil {
wb.span.RecordError(err)
wb.span.SetAttributes(otelsemconv.ErrorType(err))
wb.span.SetStatus(codes.Error, err.Error())
}
return n, err
@@ -247,7 +246,7 @@ func (wb *wrappedBody) Read(b []byte) (int, error) {
wb.recordBytesRead()
wb.span.End()
default:
wb.span.RecordError(err)
wb.span.SetAttributes(otelsemconv.ErrorType(err))
wb.span.SetStatus(codes.Error, err.Error())
}
return n, err

View File

@@ -4,7 +4,4 @@
package otelhttp // import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
// Version is the current release version of the otelhttp instrumentation.
func Version() string {
return "0.64.0"
// This string is updated by the pre_release.sh script during release
}
const Version = "0.67.0"

View File

@@ -67,6 +67,8 @@ var (
RequestMethodPut RequestMethodAttr = "PUT"
// RequestMethodTrace is the TRACE method.
RequestMethodTrace RequestMethodAttr = "TRACE"
// RequestMethodQuery is the QUERY method.
RequestMethodQuery RequestMethodAttr = "QUERY"
// RequestMethodOther is the any HTTP method that the instrumentation has no
// prior knowledge of.
RequestMethodOther RequestMethodAttr = "_OTHER"
@@ -158,7 +160,10 @@ func (m ClientActiveRequests) Add(
attrs ...attribute.KeyValue,
) {
if len(attrs) == 0 {
m.Int64UpDownCounter.Add(ctx, incr)
m.Int64UpDownCounter.Add(ctx, incr, metric.WithAttributes(
attribute.String("server.address", serverAddress),
attribute.Int("server.port", serverPort),
))
return
}
@@ -172,7 +177,7 @@ func (m ClientActiveRequests) Add(
*o,
metric.WithAttributes(
append(
attrs,
attrs[:len(attrs):len(attrs)],
attribute.String("server.address", serverAddress),
attribute.Int("server.port", serverPort),
)...,
@@ -298,7 +303,10 @@ func (m ClientConnectionDuration) Record(
attrs ...attribute.KeyValue,
) {
if len(attrs) == 0 {
m.Float64Histogram.Record(ctx, val)
m.Float64Histogram.Record(ctx, val, metric.WithAttributes(
attribute.String("server.address", serverAddress),
attribute.Int("server.port", serverPort),
))
return
}
@@ -312,7 +320,7 @@ func (m ClientConnectionDuration) Record(
*o,
metric.WithAttributes(
append(
attrs,
attrs[:len(attrs):len(attrs)],
attribute.String("server.address", serverAddress),
attribute.Int("server.port", serverPort),
)...,
@@ -441,7 +449,11 @@ func (m ClientOpenConnections) Add(
attrs ...attribute.KeyValue,
) {
if len(attrs) == 0 {
m.Int64UpDownCounter.Add(ctx, incr)
m.Int64UpDownCounter.Add(ctx, incr, metric.WithAttributes(
attribute.String("http.connection.state", string(connectionState)),
attribute.String("server.address", serverAddress),
attribute.Int("server.port", serverPort),
))
return
}
@@ -455,7 +467,7 @@ func (m ClientOpenConnections) Add(
*o,
metric.WithAttributes(
append(
attrs,
attrs[:len(attrs):len(attrs)],
attribute.String("http.connection.state", string(connectionState)),
attribute.String("server.address", serverAddress),
attribute.Int("server.port", serverPort),
@@ -590,7 +602,11 @@ func (m ClientRequestBodySize) Record(
attrs ...attribute.KeyValue,
) {
if len(attrs) == 0 {
m.Int64Histogram.Record(ctx, val)
m.Int64Histogram.Record(ctx, val, metric.WithAttributes(
attribute.String("http.request.method", string(requestMethod)),
attribute.String("server.address", serverAddress),
attribute.Int("server.port", serverPort),
))
return
}
@@ -604,7 +620,7 @@ func (m ClientRequestBodySize) Record(
*o,
metric.WithAttributes(
append(
attrs,
attrs[:len(attrs):len(attrs)],
attribute.String("http.request.method", string(requestMethod)),
attribute.String("server.address", serverAddress),
attribute.Int("server.port", serverPort),
@@ -766,7 +782,11 @@ func (m ClientRequestDuration) Record(
attrs ...attribute.KeyValue,
) {
if len(attrs) == 0 {
m.Float64Histogram.Record(ctx, val)
m.Float64Histogram.Record(ctx, val, metric.WithAttributes(
attribute.String("http.request.method", string(requestMethod)),
attribute.String("server.address", serverAddress),
attribute.Int("server.port", serverPort),
))
return
}
@@ -780,7 +800,7 @@ func (m ClientRequestDuration) Record(
*o,
metric.WithAttributes(
append(
attrs,
attrs[:len(attrs):len(attrs)],
attribute.String("http.request.method", string(requestMethod)),
attribute.String("server.address", serverAddress),
attribute.Int("server.port", serverPort),
@@ -942,7 +962,11 @@ func (m ClientResponseBodySize) Record(
attrs ...attribute.KeyValue,
) {
if len(attrs) == 0 {
m.Int64Histogram.Record(ctx, val)
m.Int64Histogram.Record(ctx, val, metric.WithAttributes(
attribute.String("http.request.method", string(requestMethod)),
attribute.String("server.address", serverAddress),
attribute.Int("server.port", serverPort),
))
return
}
@@ -956,7 +980,7 @@ func (m ClientResponseBodySize) Record(
*o,
metric.WithAttributes(
append(
attrs,
attrs[:len(attrs):len(attrs)],
attribute.String("http.request.method", string(requestMethod)),
attribute.String("server.address", serverAddress),
attribute.Int("server.port", serverPort),
@@ -1116,7 +1140,10 @@ func (m ServerActiveRequests) Add(
attrs ...attribute.KeyValue,
) {
if len(attrs) == 0 {
m.Int64UpDownCounter.Add(ctx, incr)
m.Int64UpDownCounter.Add(ctx, incr, metric.WithAttributes(
attribute.String("http.request.method", string(requestMethod)),
attribute.String("url.scheme", urlScheme),
))
return
}
@@ -1130,7 +1157,7 @@ func (m ServerActiveRequests) Add(
*o,
metric.WithAttributes(
append(
attrs,
attrs[:len(attrs):len(attrs)],
attribute.String("http.request.method", string(requestMethod)),
attribute.String("url.scheme", urlScheme),
)...,
@@ -1253,7 +1280,10 @@ func (m ServerRequestBodySize) Record(
attrs ...attribute.KeyValue,
) {
if len(attrs) == 0 {
m.Int64Histogram.Record(ctx, val)
m.Int64Histogram.Record(ctx, val, metric.WithAttributes(
attribute.String("http.request.method", string(requestMethod)),
attribute.String("url.scheme", urlScheme),
))
return
}
@@ -1267,7 +1297,7 @@ func (m ServerRequestBodySize) Record(
*o,
metric.WithAttributes(
append(
attrs,
attrs[:len(attrs):len(attrs)],
attribute.String("http.request.method", string(requestMethod)),
attribute.String("url.scheme", urlScheme),
)...,
@@ -1318,8 +1348,9 @@ func (ServerRequestBodySize) AttrResponseStatusCode(val int) attribute.KeyValue
}
// AttrRoute returns an optional attribute for the "http.route" semantic
// convention. It represents the matched route, that is, the path template in the
// format used by the respective server framework.
// convention. It represents the matched route template for the request. This
// MUST be low-cardinality and include all static path segments, with dynamic
// path segments represented with placeholders.
func (ServerRequestBodySize) AttrRoute(val string) attribute.KeyValue {
return attribute.String("http.route", val)
}
@@ -1436,7 +1467,10 @@ func (m ServerRequestDuration) Record(
attrs ...attribute.KeyValue,
) {
if len(attrs) == 0 {
m.Float64Histogram.Record(ctx, val)
m.Float64Histogram.Record(ctx, val, metric.WithAttributes(
attribute.String("http.request.method", string(requestMethod)),
attribute.String("url.scheme", urlScheme),
))
return
}
@@ -1450,7 +1484,7 @@ func (m ServerRequestDuration) Record(
*o,
metric.WithAttributes(
append(
attrs,
attrs[:len(attrs):len(attrs)],
attribute.String("http.request.method", string(requestMethod)),
attribute.String("url.scheme", urlScheme),
)...,
@@ -1494,8 +1528,9 @@ func (ServerRequestDuration) AttrResponseStatusCode(val int) attribute.KeyValue
}
// AttrRoute returns an optional attribute for the "http.route" semantic
// convention. It represents the matched route, that is, the path template in the
// format used by the respective server framework.
// convention. It represents the matched route template for the request. This
// MUST be low-cardinality and include all static path segments, with dynamic
// path segments represented with placeholders.
func (ServerRequestDuration) AttrRoute(val string) attribute.KeyValue {
return attribute.String("http.route", val)
}
@@ -1619,7 +1654,10 @@ func (m ServerResponseBodySize) Record(
attrs ...attribute.KeyValue,
) {
if len(attrs) == 0 {
m.Int64Histogram.Record(ctx, val)
m.Int64Histogram.Record(ctx, val, metric.WithAttributes(
attribute.String("http.request.method", string(requestMethod)),
attribute.String("url.scheme", urlScheme),
))
return
}
@@ -1633,7 +1671,7 @@ func (m ServerResponseBodySize) Record(
*o,
metric.WithAttributes(
append(
attrs,
attrs[:len(attrs):len(attrs)],
attribute.String("http.request.method", string(requestMethod)),
attribute.String("url.scheme", urlScheme),
)...,
@@ -1684,8 +1722,9 @@ func (ServerResponseBodySize) AttrResponseStatusCode(val int) attribute.KeyValue
}
// AttrRoute returns an optional attribute for the "http.route" semantic
// convention. It represents the matched route, that is, the path template in the
// format used by the respective server framework.
// convention. It represents the matched route template for the request. This
// MUST be low-cardinality and include all static path segments, with dynamic
// path segments represented with placeholders.
func (ServerResponseBodySize) AttrRoute(val string) attribute.KeyValue {
return attribute.String("http.route", val)
}

View File

@@ -586,7 +586,7 @@ func (c *cbcCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader
// Length of encrypted portion of the packet (header, payload, padding).
// Enforce minimum padding and packet size.
encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPaddingSize)
encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPacketSize)
// Enforce block size.
encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize

View File

@@ -274,10 +274,14 @@ func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (MultiA
}
// Filter algorithms based on those supported by MultiAlgorithmSigner.
// Iterate over the signer's algorithms first to preserve its preference order.
supportedKeyAlgos := algorithmsForKeyFormat(keyFormat)
var keyAlgos []string
for _, algo := range algorithmsForKeyFormat(keyFormat) {
if slices.Contains(as.Algorithms(), underlyingAlgo(algo)) {
keyAlgos = append(keyAlgos, algo)
for _, signerAlgo := range as.Algorithms() {
if idx := slices.IndexFunc(supportedKeyAlgos, func(algo string) bool {
return underlyingAlgo(algo) == signerAlgo
}); idx >= 0 {
keyAlgos = append(keyAlgos, supportedKeyAlgos[idx])
}
}

View File

@@ -6,6 +6,7 @@ package hpack
import (
"fmt"
"strings"
)
// headerFieldTable implements a list of HeaderFields.
@@ -54,10 +55,16 @@ func (t *headerFieldTable) len() int {
// addEntry adds a new entry.
func (t *headerFieldTable) addEntry(f HeaderField) {
// Prevent f from escaping to the heap.
f2 := HeaderField{
Name: strings.Clone(f.Name),
Value: strings.Clone(f.Value),
Sensitive: f.Sensitive,
}
id := uint64(t.len()) + t.evictCount + 1
t.byName[f.Name] = id
t.byNameValue[pairNameValue{f.Name, f.Value}] = id
t.ents = append(t.ents, f)
t.byName[f2.Name] = id
t.byNameValue[pairNameValue{f2.Name, f2.Value}] = id
t.ents = append(t.ents, f2)
}
// evictOldest evicts the n oldest entries in the table.

View File

@@ -4,13 +4,17 @@
// Package http2 implements the HTTP/2 protocol.
//
// This package is low-level and intended to be used directly by very
// few people. Most users will use it indirectly through the automatic
// use by the net/http package (from Go 1.6 and later).
// For use in earlier Go versions see ConfigureServer. (Transport support
// requires Go 1.6 or later)
// Almost no users should need to import this package directly.
// The net/http package supports HTTP/2 natively.
//
// See https://http2.github.io/ for more information on HTTP/2.
// To enable or disable HTTP/2 support in net/http clients and servers, see
// [http.Transport.Protocols] and [http.Server.Protocols].
//
// To configure HTTP/2 parameters, see
// [http.Transport.HTTP2] and [http.Server.HTTP2].
//
// To create HTTP/1 or HTTP/2 connections, see
// [http.Transport.NewClientConn].
package http2 // import "golang.org/x/net/http2"
import (

View File

@@ -164,6 +164,8 @@ type Server struct {
// NewWriteScheduler constructs a write scheduler for a connection.
// If nil, a default scheduler is chosen.
//
// Deprecated: User-provided write schedulers are deprecated.
NewWriteScheduler func() WriteScheduler
// CountError, if non-nil, is called on HTTP/2 server errors.

View File

@@ -712,19 +712,12 @@ func canRetryError(err error) bool {
return true
}
if se, ok := err.(StreamError); ok {
if se.Code == ErrCodeProtocol && se.Cause == errFromPeer {
// See golang/go#47635, golang/go#42777
return true
}
return se.Code == ErrCodeRefusedStream
}
return false
}
func (t *Transport) dialClientConn(ctx context.Context, addr string, singleUse bool) (*ClientConn, error) {
if t.transportTestHooks != nil {
return t.newClientConn(nil, singleUse, nil)
}
host, _, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
@@ -2865,6 +2858,9 @@ func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error {
var seenMaxConcurrentStreams bool
err := f.ForeachSetting(func(s Setting) error {
if err := s.Valid(); err != nil {
return err
}
switch s.ID {
case SettingMaxFrameSize:
cc.maxFrameSize = s.Val
@@ -2896,9 +2892,6 @@ func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error {
cc.henc.SetMaxDynamicTableSize(s.Val)
cc.peerMaxHeaderTableSize = s.Val
case SettingEnableConnectProtocol:
if err := s.Valid(); err != nil {
return err
}
// If the peer wants to send us SETTINGS_ENABLE_CONNECT_PROTOCOL,
// we require that it do so in the first SETTINGS frame.
//
@@ -3233,10 +3226,6 @@ func (gz *gzipReader) Close() error {
return gz.body.Close()
}
type errorReader struct{ err error }
func (r errorReader) Read(p []byte) (int, error) { return 0, r.err }
// isConnectionCloseRequest reports whether req should use its own
// connection for a single request and then close the connection.
func isConnectionCloseRequest(req *http.Request) bool {

View File

@@ -8,6 +8,8 @@ import "fmt"
// WriteScheduler is the interface implemented by HTTP/2 write schedulers.
// Methods are never called concurrently.
//
// Deprecated: User-provided write schedulers are deprecated.
type WriteScheduler interface {
// OpenStream opens a new stream in the write scheduler.
// It is illegal to call this with streamID=0 or with a streamID that is
@@ -38,6 +40,8 @@ type WriteScheduler interface {
}
// OpenStreamOptions specifies extra options for WriteScheduler.OpenStream.
//
// Deprecated: User-provided write schedulers are deprecated.
type OpenStreamOptions struct {
// PusherID is zero if the stream was initiated by the client. Otherwise,
// PusherID names the stream that pushed the newly opened stream.
@@ -47,6 +51,8 @@ type OpenStreamOptions struct {
}
// FrameWriteRequest is a request to write a frame.
//
// Deprecated: User-provided write schedulers are deprecated.
type FrameWriteRequest struct {
// write is the interface value that does the writing, once the
// WriteScheduler has selected this frame to write. The write

View File

@@ -14,6 +14,8 @@ import (
const priorityDefaultWeightRFC7540 = 15 // 16 = 15 + 1
// PriorityWriteSchedulerConfig configures a priorityWriteScheduler.
//
// Deprecated: User-provided write schedulers are deprecated.
type PriorityWriteSchedulerConfig struct {
// MaxClosedNodesInTree controls the maximum number of closed streams to
// retain in the priority tree. Setting this to zero saves a small amount
@@ -55,6 +57,9 @@ type PriorityWriteSchedulerConfig struct {
// NewPriorityWriteScheduler constructs a WriteScheduler that schedules
// frames by following HTTP/2 priorities as described in RFC 7540 Section 5.3.
// If cfg is nil, default options are used.
//
// Deprecated: The RFC 7540 write scheduler has known bugs and performance issues,
// and RFC 7540 prioritization was deprecated in RFC 9113.
func NewPriorityWriteScheduler(cfg *PriorityWriteSchedulerConfig) WriteScheduler {
return newPriorityWriteSchedulerRFC7540(cfg)
}

View File

@@ -10,6 +10,8 @@ import "math"
// priorities. Control frames like SETTINGS and PING are written before DATA
// frames, but if no control frames are queued and multiple streams have queued
// HEADERS or DATA frames, Pop selects a ready stream arbitrarily.
//
// Deprecated: User-provided write schedulers are deprecated.
func NewRandomWriteScheduler() WriteScheduler {
return &randomWriteScheduler{sq: make(map[uint32]*writeQueue)}
}

View File

@@ -6,6 +6,8 @@
package cpu
import "runtime"
func doinit() {
setMinimalFeatures()

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 !darwin && !linux && !netbsd && !openbsd && !windows && arm64
//go:build !darwin && !linux && !netbsd && !openbsd && arm64
package cpu

View File

@@ -1,42 +0,0 @@
// Copyright 2026 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
import (
"golang.org/x/sys/windows"
)
func doinit() {
// set HasASIMD and HasFP to true as per
// https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#base-requirements
//
// The ARM64 version of Windows always presupposes that it's running on an ARMv8 or later architecture.
// Both floating-point and NEON support are presumed to be present in hardware.
//
ARM64.HasASIMD = true
ARM64.HasFP = true
if windows.IsProcessorFeaturePresent(windows.PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) {
ARM64.HasAES = true
ARM64.HasPMULL = true
ARM64.HasSHA1 = true
ARM64.HasSHA2 = true
}
ARM64.HasSHA3 = windows.IsProcessorFeaturePresent(windows.PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE)
ARM64.HasCRC32 = windows.IsProcessorFeaturePresent(windows.PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE)
ARM64.HasSHA512 = windows.IsProcessorFeaturePresent(windows.PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE)
ARM64.HasATOMICS = windows.IsProcessorFeaturePresent(windows.PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)
if windows.IsProcessorFeaturePresent(windows.PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) {
ARM64.HasASIMDDP = true
ARM64.HasASIMDRDM = true
}
if windows.IsProcessorFeaturePresent(windows.PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE) {
ARM64.HasLRCPC = true
ARM64.HasSM3 = true
}
ARM64.HasSVE = windows.IsProcessorFeaturePresent(windows.PF_ARM_SVE_INSTRUCTIONS_AVAILABLE)
ARM64.HasSVE2 = windows.IsProcessorFeaturePresent(windows.PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE)
ARM64.HasJSCVT = windows.IsProcessorFeaturePresent(windows.PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE)
}

View File

@@ -163,42 +163,7 @@ func (p *Proc) Addr() uintptr {
// (according to the semantics of the specific function being called) before consulting
// the error. The error will be guaranteed to contain windows.Errno.
func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
switch len(a) {
case 0:
return syscall.Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
case 1:
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
case 2:
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
case 3:
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
case 4:
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
case 5:
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
case 6:
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
case 7:
return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
case 8:
return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
case 9:
return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
case 10:
return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0)
case 11:
return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0)
case 12:
return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11])
case 13:
return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0)
case 14:
return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0)
case 15:
return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14])
default:
panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
}
return syscall.SyscallN(p.Addr(), a...)
}
// A LazyDLL implements access to a single DLL.

View File

@@ -1438,13 +1438,17 @@ func GetSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformati
}
// GetNamedSecurityInfo queries the security information for a given named object and returns the self-relative security
// descriptor result on the Go heap.
// descriptor result on the Go heap. The security descriptor might be nil, even when err is nil, if the object exists
// but has no security descriptor.
func GetNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION) (sd *SECURITY_DESCRIPTOR, err error) {
var winHeapSD *SECURITY_DESCRIPTOR
err = getNamedSecurityInfo(objectName, objectType, securityInformation, nil, nil, nil, nil, &winHeapSD)
if err != nil {
return
}
if winHeapSD == nil {
return nil, nil
}
defer LocalFree(Handle(unsafe.Pointer(winHeapSD)))
return winHeapSD.copySelfRelativeSecurityDescriptor(), nil
}

View File

@@ -61,13 +61,42 @@ func (r *responseDeduper) addAll(dr *DriverResponse) {
}
func (r *responseDeduper) addPackage(p *Package) {
if r.seenPackages[p.ID] != nil {
if prev := r.seenPackages[p.ID]; prev != nil {
// Package already seen in a previous response. Merge the file lists,
// removing duplicates. This can happen when the same package appears
// in multiple driver responses that are being merged together.
prev.GoFiles = appendUniqueStrings(prev.GoFiles, p.GoFiles)
prev.CompiledGoFiles = appendUniqueStrings(prev.CompiledGoFiles, p.CompiledGoFiles)
prev.OtherFiles = appendUniqueStrings(prev.OtherFiles, p.OtherFiles)
prev.IgnoredFiles = appendUniqueStrings(prev.IgnoredFiles, p.IgnoredFiles)
prev.EmbedFiles = appendUniqueStrings(prev.EmbedFiles, p.EmbedFiles)
prev.EmbedPatterns = appendUniqueStrings(prev.EmbedPatterns, p.EmbedPatterns)
return
}
r.seenPackages[p.ID] = p
r.dr.Packages = append(r.dr.Packages, p)
}
// appendUniqueStrings appends elements from src to dst, skipping duplicates.
func appendUniqueStrings(dst, src []string) []string {
if len(src) == 0 {
return dst
}
seen := make(map[string]bool, len(dst))
for _, s := range dst {
seen[s] = true
}
for _, s := range src {
if !seen[s] {
dst = append(dst, s)
}
}
return dst
}
func (r *responseDeduper) addRoot(id string) {
if r.seenRoots[id] {
return
@@ -832,6 +861,8 @@ func golistargs(cfg *Config, words []string, goVersion int) []string {
// go list doesn't let you pass -test and -find together,
// probably because you'd just get the TestMain.
fmt.Sprintf("-find=%t", !cfg.Tests && cfg.Mode&findFlags == 0 && !usesExportData(cfg)),
// VCS information is not needed when not printing Stale or StaleReason fields
"-buildvcs=false",
}
// golang/go#60456: with go1.21 and later, go list serves pgo variants, which

View File

@@ -403,6 +403,10 @@ func mergeResponses(responses ...*DriverResponse) *DriverResponse {
if len(responses) == 0 {
return nil
}
// No dedup needed
if len(responses) == 1 {
return responses[0]
}
response := newDeduper()
response.dr.NotHandled = false
response.dr.Compiler = responses[0].Compiler

View File

@@ -524,7 +524,7 @@ func (f *finder) find(T types.Type, path []byte) []byte {
for i := 0; i < T.NumMethods(); i++ {
m := T.Method(i)
if f.seenMethods[m] {
return nil
continue // break cycles (see TestIssue70418)
}
path2 := appendOpArg(path, opMethod, i)
if m == f.obj {

View File

@@ -35,6 +35,10 @@ type pkgReader struct {
// laterFns holds functions that need to be invoked at the end of
// import reading.
//
// TODO(mdempsky): Is it safe to have a single "later" slice or do
// we need to have multiple passes? See comments on CL 386002 and
// go.dev/issue/52104.
laterFns []func()
// laterFors is used in case of 'type A B' to ensure that B is processed before A.
laterFors map[types.Type]int
@@ -158,12 +162,11 @@ type reader struct {
// A readerDict holds the state for type parameters that parameterize
// the current unified IR element.
type readerDict struct {
// bounds is a slice of typeInfos corresponding to the underlying
// bounds of the element's type parameters.
bounds []typeInfo
rtbounds []typeInfo // contains constraint types for each parameter in rtparams
rtparams []*types.TypeParam // contains receiver type parameters for an element
// tparams is a slice of the constructed TypeParams for the element.
tparams []*types.TypeParam
tbounds []typeInfo // contains constraint types for each parameter in tparams
tparams []*types.TypeParam // contains type parameters for an element
// derived is a slice of types derived from tparams, which may be
// instantiated while reading the current element.
@@ -353,7 +356,11 @@ func (r *reader) doTyp() (res types.Type) {
return name.Type()
case pkgbits.TypeTypeParam:
return r.dict.tparams[r.Len()]
n := r.Len()
if n < len(r.dict.rtbounds) {
return r.dict.rtparams[n]
}
return r.dict.tparams[n-len(r.dict.rtbounds)]
case pkgbits.TypeArray:
len := int64(r.Uint64())
@@ -534,7 +541,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
pos := r.pos()
var tparams []*types.TypeParam
if r.Version().Has(pkgbits.AliasTypeParamNames) {
tparams = r.typeParamNames()
tparams = r.typeParamNames(false)
}
typ := r.typ()
declare(aliases.New(pos, objPkg, objName, typ, tparams))
@@ -547,8 +554,15 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
case pkgbits.ObjFunc:
pos := r.pos()
tparams := r.typeParamNames()
sig := r.signature(nil, nil, tparams)
var rtparams []*types.TypeParam
var recv *types.Var
if r.Version().Has(pkgbits.GenericMethods) && r.Bool() {
r.selector()
rtparams = r.typeParamNames(true)
recv = r.param()
}
tparams := r.typeParamNames(false)
sig := r.signature(recv, rtparams, tparams)
declare(types.NewFunc(pos, objPkg, objName, sig))
case pkgbits.ObjType:
@@ -558,7 +572,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
named := types.NewNamed(obj, nil, nil)
declare(obj)
named.SetTypeParams(r.typeParamNames())
named.SetTypeParams(r.typeParamNames(false))
setUnderlying := func(underlying types.Type) {
// If the underlying type is an interface, we need to
@@ -638,9 +652,20 @@ func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict {
errorf("unexpected object with %v implicit type parameter(s)", implicits)
}
dict.bounds = make([]typeInfo, r.Len())
for i := range dict.bounds {
dict.bounds[i] = r.typInfo()
nreceivers := 0
if r.Version().Has(pkgbits.GenericMethods) && r.Bool() {
nreceivers = r.Len()
}
nexplicits := r.Len()
dict.rtbounds = make([]typeInfo, nreceivers)
for i := range dict.rtbounds {
dict.rtbounds[i] = r.typInfo()
}
dict.tbounds = make([]typeInfo, nexplicits)
for i := range dict.tbounds {
dict.tbounds[i] = r.typInfo()
}
dict.derived = make([]derivedInfo, r.Len())
@@ -659,15 +684,24 @@ func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict {
return &dict
}
func (r *reader) typeParamNames() []*types.TypeParam {
func (r *reader) typeParamNames(isGenMeth bool) []*types.TypeParam {
r.Sync(pkgbits.SyncTypeParamNames)
// Note: This code assumes it only processes objects without
// implement type parameters. This is currently fine, because
// reader is only used to read in exported declarations, which are
// always package scoped.
// Note: This code assumes there are no implicit type parameters.
// This is fine since it only reads exported declarations, which
// never have implicits.
if len(r.dict.bounds) == 0 {
var in []typeInfo
var out *[]*types.TypeParam
if isGenMeth {
in = r.dict.rtbounds
out = &r.dict.rtparams
} else {
in = r.dict.tbounds
out = &r.dict.tparams
}
if len(in) == 0 {
return nil
}
@@ -676,40 +710,34 @@ func (r *reader) typeParamNames() []*types.TypeParam {
// create all the TypeNames and TypeParams, then we construct and
// set the bound type.
r.dict.tparams = make([]*types.TypeParam, len(r.dict.bounds))
for i := range r.dict.bounds {
// We have to save tparams outside of the closure, because typeParamNames
// can be called multiple times with the same dictionary instance.
tparams := make([]*types.TypeParam, len(in))
*out = tparams
for i := range in {
pos := r.pos()
pkg, name := r.localIdent()
tname := types.NewTypeName(pos, pkg, name, nil)
r.dict.tparams[i] = types.NewTypeParam(tname, nil)
tparams[i] = types.NewTypeParam(tname, nil)
}
typs := make([]types.Type, len(r.dict.bounds))
for i, bound := range r.dict.bounds {
typs[i] = r.p.typIdx(bound, r.dict)
// The reader dictionary will continue mutating before we have time
// to call delayed functions; make a local copy of the constraints.
types := make([]types.Type, len(in))
for i, info := range in {
types[i] = r.p.typIdx(info, r.dict)
}
// TODO(mdempsky): This is subtle, elaborate further.
//
// We have to save tparams outside of the closure, because
// typeParamNames() can be called multiple times with the same
// dictionary instance.
//
// Also, this needs to happen later to make sure SetUnderlying has
// been called.
//
// TODO(mdempsky): Is it safe to have a single "later" slice or do
// we need to have multiple passes? See comments on CL 386002 and
// go.dev/issue/52104.
tparams := r.dict.tparams
// This needs to happen later to make sure SetUnderlying has been called.
r.p.later(func() {
for i, typ := range typs {
for i, typ := range types {
tparams[i].SetConstraint(typ)
}
})
return r.dict.tparams
return tparams
}
func (r *reader) method() *types.Func {
@@ -717,7 +745,7 @@ func (r *reader) method() *types.Func {
pos := r.pos()
pkg, name := r.selector()
rparams := r.typeParamNames()
rparams := r.typeParamNames(false)
sig := r.signature(r.param(), rparams, nil)
_ = r.pos() // TODO(mdempsky): Remove; this is a hacker for linker.go.

View File

@@ -26,6 +26,9 @@ func GoVersion(ctx context.Context, inv Invocation, r *Runner) (int, error) {
inv.BuildFlags = nil // This is not a build command.
inv.ModFlag = ""
inv.ModFile = ""
// Set GO111MODULE=off so that we are immune to errors in go.{work,mod}.
// Unfortunately, this breaks the Go 1.21+ toolchain directive and
// may affect the set of ReleaseTags; see #68495.
inv.Env = append(inv.Env[:len(inv.Env):len(inv.Env)], "GO111MODULE=off")
stdoutBytes, err := r.Run(ctx, inv)

View File

@@ -1,100 +0,0 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package imports
import (
"context"
"sync"
"time"
"golang.org/x/tools/internal/modindex"
)
// This code is here rather than in the modindex package
// to avoid import loops
// TODO(adonovan): this code is only used by a test in this package.
// Can we delete it? Or is there a plan to call NewIndexSource from
// cmd/goimports?
// implements Source using modindex, so only for module cache.
//
// this is perhaps over-engineered. A new Index is read at first use.
// And then Update is called after every 15 minutes, and a new Index
// is read if the index changed. It is not clear the Mutex is needed.
type IndexSource struct {
modcachedir string
mu sync.Mutex
index *modindex.Index // (access via getIndex)
expires time.Time
}
// create a new Source. Called from NewView in cache/session.go.
func NewIndexSource(cachedir string) *IndexSource {
return &IndexSource{modcachedir: cachedir}
}
func (s *IndexSource) LoadPackageNames(ctx context.Context, srcDir string, paths []ImportPath) (map[ImportPath]PackageName, error) {
/// This is used by goimports to resolve the package names of imports of the
// current package, which is irrelevant for the module cache.
return nil, nil
}
func (s *IndexSource) ResolveReferences(ctx context.Context, filename string, missing References) ([]*Result, error) {
index, err := s.getIndex()
if err != nil {
return nil, err
}
var cs []modindex.Candidate
for pkg, nms := range missing {
for nm := range nms {
x := index.Lookup(pkg, nm, false)
cs = append(cs, x...)
}
}
found := make(map[string]*Result)
for _, c := range cs {
var x *Result
if x = found[c.ImportPath]; x == nil {
x = &Result{
Import: &ImportInfo{
ImportPath: c.ImportPath,
Name: "",
},
Package: &PackageInfo{
Name: c.PkgName,
Exports: make(map[string]bool),
},
}
found[c.ImportPath] = x
}
x.Package.Exports[c.Name] = true
}
var ans []*Result
for _, x := range found {
ans = append(ans, x)
}
return ans, nil
}
func (s *IndexSource) getIndex() (*modindex.Index, error) {
s.mu.Lock()
defer s.mu.Unlock()
// (s.index = nil => s.expires is zero,
// so the first condition is strictly redundant.
// But it makes the postcondition very clear.)
if s.index == nil || time.Now().After(s.expires) {
index, err := modindex.Update(s.modcachedir)
if err != nil {
return nil, err
}
s.index = index
s.expires = index.ValidAt.Add(15 * time.Minute) // (refresh period)
}
// Inv: s.index != nil
return s.index, nil
}

View File

@@ -1,131 +0,0 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package modindex
import (
"fmt"
"log"
"os"
"path/filepath"
"regexp"
"strings"
"sync"
"time"
"golang.org/x/mod/semver"
"golang.org/x/tools/internal/gopathwalk"
)
type directory struct {
path string // relative to GOMODCACHE
importPath string
version string // semantic version
}
// bestDirByImportPath returns the best directory for each import
// path, where "best" means most recent semantic version. These import
// paths are inferred from the GOMODCACHE-relative dir names in dirs.
func bestDirByImportPath(dirs []string) (map[string]directory, error) {
dirsByPath := make(map[string]directory)
for _, dir := range dirs {
importPath, version, err := dirToImportPathVersion(dir)
if err != nil {
return nil, err
}
new := directory{
path: dir,
importPath: importPath,
version: version,
}
if old, ok := dirsByPath[importPath]; !ok || compareDirectory(new, old) < 0 {
dirsByPath[importPath] = new
}
}
return dirsByPath, nil
}
// compareDirectory defines an ordering of path@version directories,
// by descending version, then by ascending path.
func compareDirectory(x, y directory) int {
if sign := -semver.Compare(x.version, y.version); sign != 0 {
return sign // latest first
}
return strings.Compare(string(x.path), string(y.path))
}
// modCacheRegexp splits a relpathpath into module, module version, and package.
var modCacheRegexp = regexp.MustCompile(`(.*)@([^/\\]*)(.*)`)
// dirToImportPathVersion computes import path and semantic version
// from a GOMODCACHE-relative directory name.
func dirToImportPathVersion(dir string) (string, string, error) {
m := modCacheRegexp.FindStringSubmatch(string(dir))
// m[1] is the module path
// m[2] is the version major.minor.patch(-<pre release identifier)
// m[3] is the rest of the package path
if len(m) != 4 {
return "", "", fmt.Errorf("bad dir %s", dir)
}
if !semver.IsValid(m[2]) {
return "", "", fmt.Errorf("bad semantic version %s", m[2])
}
// ToSlash is required to convert Windows file paths
// into Go package import paths.
return filepath.ToSlash(m[1] + m[3]), m[2], nil
}
// findDirs returns an unordered list of relevant package directories,
// relative to the specified module cache root. The result includes only
// module dirs whose mtime is within (start, end).
func findDirs(root string, start, end time.Time) []string {
var (
resMu sync.Mutex
res []string
)
addDir := func(root gopathwalk.Root, dir string) {
// TODO(pjw): do we need to check times?
resMu.Lock()
defer resMu.Unlock()
res = append(res, relative(root.Path, dir))
}
skipDir := func(_ gopathwalk.Root, dir string) bool {
// The cache directory is already ignored in gopathwalk.
if filepath.Base(dir) == "internal" {
return true
}
// Skip toolchains.
if strings.Contains(dir, "toolchain@") {
return true
}
// Don't look inside @ directories that are too old/new.
if strings.Contains(filepath.Base(dir), "@") {
st, err := os.Stat(dir)
if err != nil {
log.Printf("can't stat dir %s %v", dir, err)
return true
}
mtime := st.ModTime()
return mtime.Before(start) || mtime.After(end)
}
return false
}
// TODO(adonovan): parallelize this. Even with a hot buffer cache,
// find $(go env GOMODCACHE) -type d
// can easily take up a minute.
roots := []gopathwalk.Root{{Path: root, Type: gopathwalk.RootModuleCache}}
gopathwalk.WalkSkip(roots, addDir, skipDir, gopathwalk.Options{
ModulesEnabled: true,
Concurrency: 1, // TODO(pjw): adjust concurrency
// Logf: log.Printf,
})
return res
}

View File

@@ -1,292 +0,0 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package modindex
import (
"bufio"
"crypto/sha256"
"encoding/csv"
"fmt"
"io"
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"time"
)
/*
The on-disk index ("payload") is a text file.
The first 3 lines are header information containing CurrentVersion,
the value of GOMODCACHE, and the validity date of the index.
(This is when the code started building the index.)
Following the header are sections of lines, one section for each
import path. These sections are sorted by package name.
The first line of each section, marked by a leading :, contains
the package name, the import path, the name of the directory relative
to GOMODCACHE, and its semantic version.
The rest of each section consists of one line per exported symbol.
The lines are sorted by the symbol's name and contain the name,
an indication of its lexical type (C, T, V, F), and if it is the
name of a function, information about the signature.
The fields in the section header lines are separated by commas, and
in the unlikely event this would be confusing, the csv package is used
to write (and read) them.
In the lines containing exported names, C=const, V=var, T=type, F=func.
If it is a func, the next field is the number of returned values,
followed by pairs consisting of formal parameter names and types.
All these fields are separated by spaces. Any spaces in a type
(e.g., chan struct{}) are replaced by $s on the disk. The $s are
turned back into spaces when read.
Here is an index header (the comments are not part of the index):
0 // version (of the index format)
/usr/local/google/home/pjw/go/pkg/mod // GOMODCACHE
2024-09-11 18:55:09 // validity date of the index
Here is an index section:
:yaml,gopkg.in/yaml.v1,gopkg.in/yaml.v1@v1.0.0-20140924161607-9f9df34309c0,v1.0.0-20140924161607-9f9df34309c0
Getter T
Marshal F 2 in interface{}
Setter T
Unmarshal F 1 in []byte out interface{}
The package name is yaml, the import path is gopkg.in/yaml.v1.
Getter and Setter are types, and Marshal and Unmarshal are functions.
The latter returns one value and has two arguments, 'in' and 'out'
whose types are []byte and interface{}.
*/
// CurrentVersion tells readers about the format of the index.
const CurrentVersion int = 0
// Index is returned by [Read].
type Index struct {
Version int
GOMODCACHE string // absolute path of Go module cache dir
ValidAt time.Time // moment at which the index was up to date
Entries []Entry
}
func (ix *Index) String() string {
return fmt.Sprintf("Index(%s v%d has %d entries at %v)",
ix.GOMODCACHE, ix.Version, len(ix.Entries), ix.ValidAt)
}
// An Entry contains information for an import path.
type Entry struct {
Dir string // package directory relative to GOMODCACHE; uses OS path separator
ImportPath string
PkgName string
Version string
Names []string // exported names and information
}
// IndexDir is where the module index is stored.
// Each logical index entry consists of a pair of files:
//
// - the "payload" (index-VERSION-XXX), whose name is
// randomized, holds the actual index; and
// - the "link" (index-name-VERSION-HASH),
// whose name is predictable, contains the
// name of the payload file.
//
// Since the link file is small (<512B),
// reads and writes to it may be assumed atomic.
var IndexDir string = func() string {
var dir string
if testing.Testing() {
dir = os.TempDir()
} else {
var err error
dir, err = os.UserCacheDir()
// shouldn't happen, but TempDir is better than
// creating ./goimports
if err != nil {
dir = os.TempDir()
}
}
dir = filepath.Join(dir, "goimports")
if err := os.MkdirAll(dir, 0777); err != nil {
dir = "" // #75505, people complain about the error message
}
return dir
}()
// Read reads the latest version of the on-disk index
// for the specified Go module cache directory.
// If there is no index, it returns a nil Index and an fs.ErrNotExist error.
func Read(gomodcache string) (*Index, error) {
gomodcache, err := filepath.Abs(gomodcache)
if err != nil {
return nil, err
}
if IndexDir == "" {
return nil, os.ErrNotExist
}
// Read the "link" file for the specified gomodcache directory.
// It names the payload file.
content, err := os.ReadFile(filepath.Join(IndexDir, linkFileBasename(gomodcache)))
if err != nil {
return nil, err
}
payloadFile := filepath.Join(IndexDir, string(content))
// Read the index out of the payload file.
f, err := os.Open(payloadFile)
if err != nil {
return nil, err
}
defer f.Close()
return readIndexFrom(gomodcache, bufio.NewReader(f))
}
func readIndexFrom(gomodcache string, r io.Reader) (*Index, error) {
scan := bufio.NewScanner(r)
// version
if !scan.Scan() {
return nil, fmt.Errorf("unexpected scan error: %v", scan.Err())
}
version, err := strconv.Atoi(scan.Text())
if err != nil {
return nil, err
}
if version != CurrentVersion {
return nil, fmt.Errorf("got version %d, expected %d", version, CurrentVersion)
}
// gomodcache
if !scan.Scan() {
return nil, fmt.Errorf("scanner error reading module cache dir: %v", scan.Err())
}
// TODO(pjw): need to check that this is the expected cache dir
// so the tag should be passed in to this function
if dir := string(scan.Text()); dir != gomodcache {
return nil, fmt.Errorf("index file GOMODCACHE mismatch: got %q, want %q", dir, gomodcache)
}
// changed
if !scan.Scan() {
return nil, fmt.Errorf("scanner error reading index creation time: %v", scan.Err())
}
changed, err := time.ParseInLocation(time.DateTime, scan.Text(), time.Local)
if err != nil {
return nil, err
}
// entries
var (
curEntry *Entry
entries []Entry
)
for scan.Scan() {
v := scan.Text()
if v[0] == ':' {
if curEntry != nil {
entries = append(entries, *curEntry)
}
// as directories may contain commas and quotes, they need to be read as csv.
rdr := strings.NewReader(v[1:])
cs := csv.NewReader(rdr)
flds, err := cs.Read()
if err != nil {
return nil, err
}
if len(flds) != 4 {
return nil, fmt.Errorf("header contains %d fields, not 4: %q", len(v), v)
}
curEntry = &Entry{
PkgName: flds[0],
ImportPath: flds[1],
Dir: relative(gomodcache, flds[2]),
Version: flds[3],
}
continue
}
curEntry.Names = append(curEntry.Names, v)
}
if err := scan.Err(); err != nil {
return nil, fmt.Errorf("scanner failed while reading modindex entry: %v", err)
}
if curEntry != nil {
entries = append(entries, *curEntry)
}
return &Index{
Version: version,
GOMODCACHE: gomodcache,
ValidAt: changed,
Entries: entries,
}, nil
}
// write writes the index file and updates the index directory to refer to it.
func write(gomodcache string, ix *Index) error {
if IndexDir == "" {
return os.ErrNotExist
}
// Write the index into a payload file with a fresh name.
f, err := os.CreateTemp(IndexDir, fmt.Sprintf("index-%d-*", CurrentVersion))
if err != nil {
return err // e.g. disk full, or index dir deleted
}
if err := writeIndexToFile(ix, bufio.NewWriter(f)); err != nil {
_ = f.Close() // ignore error
return err
}
if err := f.Close(); err != nil {
return err
}
// Write the name of the payload file into a link file.
indexDirFile := filepath.Join(IndexDir, linkFileBasename(gomodcache))
content := []byte(filepath.Base(f.Name()))
return os.WriteFile(indexDirFile, content, 0666)
}
func writeIndexToFile(x *Index, w *bufio.Writer) error {
fmt.Fprintf(w, "%d\n", x.Version)
fmt.Fprintf(w, "%s\n", x.GOMODCACHE)
tm := x.ValidAt.Truncate(time.Second) // round the time down
fmt.Fprintf(w, "%s\n", tm.Format(time.DateTime))
for _, e := range x.Entries {
if e.ImportPath == "" {
continue // shouldn't happen
}
// PJW: maybe always write these headers as csv?
if strings.ContainsAny(string(e.Dir), ",\"") {
cw := csv.NewWriter(w)
cw.Write([]string{":" + e.PkgName, e.ImportPath, string(e.Dir), e.Version})
cw.Flush()
} else {
fmt.Fprintf(w, ":%s,%s,%s,%s\n", e.PkgName, e.ImportPath, e.Dir, e.Version)
}
for _, x := range e.Names {
fmt.Fprintf(w, "%s\n", x)
}
}
return w.Flush()
}
// linkFileBasename returns the base name of the link file in the
// index directory that holds the name of the payload file for the
// specified (absolute) Go module cache dir.
func linkFileBasename(gomodcache string) string {
// Note: coupled to logic in ./gomodindex/cmd.go. TODO: factor.
h := sha256.Sum256([]byte(gomodcache)) // collision-resistant hash
return fmt.Sprintf("index-name-%d-%032x", CurrentVersion, h)
}
func relative(base, file string) string {
if rel, err := filepath.Rel(base, file); err == nil {
return rel
}
return file
}

View File

@@ -1,184 +0,0 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package modindex
import (
"slices"
"strconv"
"strings"
"golang.org/x/mod/module"
)
type Candidate struct {
PkgName string
Name string
Dir string
ImportPath string
Type LexType
Deprecated bool
// information for Funcs
Results int16 // how many results
Sig []Field // arg names and types
}
type Field struct {
Arg, Type string
}
type LexType int8
const (
Const LexType = iota
Var
Type
Func
)
// LookupAll only returns those Candidates whose import path
// finds all the names.
func (ix *Index) LookupAll(pkgName string, names ...string) map[string][]Candidate {
// this can be made faster when benchmarks show that it needs to be
names = uniquify(names)
byImpPath := make(map[string][]Candidate)
for _, nm := range names {
cands := ix.Lookup(pkgName, nm, false)
for _, c := range cands {
byImpPath[c.ImportPath] = append(byImpPath[c.ImportPath], c)
}
}
for k, v := range byImpPath {
if len(v) != len(names) {
delete(byImpPath, k)
}
}
return byImpPath
}
// remove duplicates
func uniquify(in []string) []string {
if len(in) == 0 {
return in
}
in = slices.Clone(in)
slices.Sort(in)
return slices.Compact(in)
}
// Lookup finds all the symbols in the index with the given PkgName and name.
// If prefix is true, it finds all of these with name as a prefix.
func (ix *Index) Lookup(pkgName, name string, prefix bool) []Candidate {
loc, ok := slices.BinarySearchFunc(ix.Entries, pkgName, func(e Entry, pkg string) int {
return strings.Compare(e.PkgName, pkgName)
})
if !ok {
return nil // didn't find the package
}
var ans []Candidate
// loc is the first entry for this package name, but there may be several
for i := loc; i < len(ix.Entries); i++ {
e := ix.Entries[i]
if e.PkgName != pkgName {
break // end of sorted package names
}
nloc, ok := slices.BinarySearchFunc(e.Names, name, func(s string, name string) int {
if strings.HasPrefix(s, name) {
return 0
}
if s < name {
return -1
}
return 1
})
if !ok {
continue // didn't find the name, nor any symbols with name as a prefix
}
for j := nloc; j < len(e.Names); j++ {
nstr := e.Names[j]
// benchmarks show this makes a difference when there are a lot of Possibilities
flds := fastSplit(nstr)
if !(flds[0] == name || prefix && strings.HasPrefix(flds[0], name)) {
// past range of matching Names
break
}
if len(flds) < 2 {
continue // should never happen
}
impPath, err := module.UnescapePath(e.ImportPath)
if err != nil {
continue
}
px := Candidate{
PkgName: pkgName,
Name: flds[0],
Dir: string(e.Dir),
ImportPath: impPath,
Type: asLexType(flds[1][0]),
Deprecated: len(flds[1]) > 1 && flds[1][1] == 'D',
}
if px.Type == Func {
n, err := strconv.Atoi(flds[2])
if err != nil {
continue // should never happen
}
px.Results = int16(n)
if len(flds) >= 4 {
sig := strings.Split(flds[3], " ")
for i := range sig {
// $ cannot otherwise occur. removing the spaces
// almost works, but for chan struct{}, e.g.
sig[i] = strings.Replace(sig[i], "$", " ", -1)
}
px.Sig = toFields(sig)
}
}
ans = append(ans, px)
}
}
return ans
}
func toFields(sig []string) []Field {
ans := make([]Field, len(sig)/2)
for i := range ans {
ans[i] = Field{Arg: sig[2*i], Type: sig[2*i+1]}
}
return ans
}
// benchmarks show this is measurably better than strings.Split
// split into first 4 fields separated by single space
func fastSplit(x string) []string {
ans := make([]string, 0, 4)
nxt := 0
start := 0
for i := 0; i < len(x); i++ {
if x[i] != ' ' {
continue
}
ans = append(ans, x[start:i])
nxt++
start = i + 1
if nxt >= 3 {
break
}
}
ans = append(ans, x[start:])
return ans
}
func asLexType(c byte) LexType {
switch c {
case 'C':
return Const
case 'V':
return Var
case 'T':
return Type
case 'F':
return Func
}
return -1
}

View File

@@ -1,119 +0,0 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package modindex contains code for building and searching an
// [Index] of the Go module cache.
package modindex
// The directory containing the index, returned by
// [IndexDir], contains a file index-name-<ver> that contains the name
// of the current index. We believe writing that short file is atomic.
// [Read] reads that file to get the file name of the index.
// WriteIndex writes an index with a unique name and then
// writes that name into a new version of index-name-<ver>.
// (<ver> stands for the CurrentVersion of the index format.)
import (
"maps"
"os"
"path/filepath"
"slices"
"strings"
"time"
"golang.org/x/mod/semver"
)
// Update updates the index for the specified Go
// module cache directory, creating it as needed.
// On success it returns the current index.
func Update(gomodcache string) (*Index, error) {
prev, err := Read(gomodcache)
if err != nil {
if !os.IsNotExist(err) {
return nil, err
}
prev = nil
}
return update(gomodcache, prev)
}
// update builds, writes, and returns the current index.
//
// If old is nil, the new index is built from all of GOMODCACHE;
// otherwise it is built from the old index plus cache updates
// since the previous index's time.
func update(gomodcache string, old *Index) (*Index, error) {
gomodcache, err := filepath.Abs(gomodcache)
if err != nil {
return nil, err
}
new, changed, err := build(gomodcache, old)
if err != nil {
return nil, err
}
if old == nil || changed {
if err := write(gomodcache, new); err != nil {
return nil, err
}
}
return new, nil
}
// build returns a new index for the specified Go module cache (an
// absolute path).
//
// If an old index is provided, only directories more recent than it
// that it are scanned; older directories are provided by the old
// Index.
//
// The boolean result indicates whether new entries were found.
func build(gomodcache string, old *Index) (*Index, bool, error) {
// Set the time window.
var start time.Time // = dawn of time
if old != nil {
start = old.ValidAt
}
now := time.Now()
end := now.Add(24 * time.Hour) // safely in the future
// Enumerate GOMODCACHE package directories.
// Choose the best (latest) package for each import path.
pkgDirs := findDirs(gomodcache, start, end)
dirByPath, err := bestDirByImportPath(pkgDirs)
if err != nil {
return nil, false, err
}
// For each import path it might occur only in
// dirByPath, only in old, or in both.
// If both, use the semantically later one.
var entries []Entry
if old != nil {
for _, entry := range old.Entries {
dir, ok := dirByPath[entry.ImportPath]
if !ok || semver.Compare(dir.version, entry.Version) <= 0 {
// New dir is missing or not more recent; use old entry.
entries = append(entries, entry)
delete(dirByPath, entry.ImportPath)
}
}
}
// Extract symbol information for all the new directories.
newEntries := extractSymbols(gomodcache, maps.Values(dirByPath))
entries = append(entries, newEntries...)
slices.SortFunc(entries, func(x, y Entry) int {
if n := strings.Compare(x.PkgName, y.PkgName); n != 0 {
return n
}
return strings.Compare(x.ImportPath, y.ImportPath)
})
return &Index{
GOMODCACHE: gomodcache,
ValidAt: now, // time before the directories were scanned
Entries: entries,
}, len(newEntries) > 0, nil
}

View File

@@ -1,244 +0,0 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package modindex
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"go/types"
"iter"
"os"
"path/filepath"
"runtime"
"slices"
"strings"
"sync"
"golang.org/x/sync/errgroup"
)
// The name of a symbol contains information about the symbol:
// <name> T for types, TD if the type is deprecated
// <name> C for consts, CD if the const is deprecated
// <name> V for vars, VD if the var is deprecated
// and for funcs: <name> F <num of return values> (<arg-name> <arg-type>)*
// any spaces in <arg-type> are replaced by $s so that the fields
// of the name are space separated. F is replaced by FD if the func
// is deprecated.
type symbol struct {
pkg string // name of the symbols's package
name string // declared name
kind string // T, C, V, or F, followed by D if deprecated
sig string // signature information, for F
}
// extractSymbols returns a (new, unordered) array of Entries, one for
// each provided package directory, describing its exported symbols.
func extractSymbols(cwd string, dirs iter.Seq[directory]) []Entry {
var (
mu sync.Mutex
entries []Entry
)
var g errgroup.Group
g.SetLimit(max(2, runtime.GOMAXPROCS(0)/2))
for dir := range dirs {
g.Go(func() error {
thedir := filepath.Join(cwd, string(dir.path))
mode := parser.SkipObjectResolution | parser.ParseComments
// Parse all Go files in dir and extract symbols.
dirents, err := os.ReadDir(thedir)
if err != nil {
return nil // log this someday?
}
var syms []symbol
for _, dirent := range dirents {
if !strings.HasSuffix(dirent.Name(), ".go") ||
strings.HasSuffix(dirent.Name(), "_test.go") {
continue
}
fname := filepath.Join(thedir, dirent.Name())
tr, err := parser.ParseFile(token.NewFileSet(), fname, nil, mode)
if err != nil {
continue // ignore errors, someday log them?
}
syms = append(syms, getFileExports(tr)...)
}
// Create an entry for the package.
pkg, names := processSyms(syms)
if pkg != "" {
mu.Lock()
defer mu.Unlock()
entries = append(entries, Entry{
PkgName: pkg,
Dir: dir.path,
ImportPath: dir.importPath,
Version: dir.version,
Names: names,
})
}
return nil
})
}
g.Wait() // ignore error
return entries
}
func getFileExports(f *ast.File) []symbol {
pkg := f.Name.Name
if pkg == "main" || pkg == "" {
return nil
}
var ans []symbol
// should we look for //go:build ignore?
for _, decl := range f.Decls {
switch decl := decl.(type) {
case *ast.FuncDecl:
if decl.Recv != nil {
// ignore methods, as we are completing package selections
continue
}
name := decl.Name.Name
dtype := decl.Type
// not looking at dtype.TypeParams. That is, treating
// generic functions just like non-generic ones.
sig := dtype.Params
kind := "F"
if isDeprecated(decl.Doc) {
kind += "D"
}
result := []string{fmt.Sprintf("%d", dtype.Results.NumFields())}
for _, x := range sig.List {
// This code creates a string representing the type.
// TODO(pjw): it may be fragile:
// 1. x.Type could be nil, perhaps in ill-formed code
// 2. ExprString might someday change incompatibly to
// include struct tags, which can be arbitrary strings
if x.Type == nil {
// Can this happen without a parse error? (Files with parse
// errors are ignored in getSymbols)
continue // maybe report this someday
}
tp := types.ExprString(x.Type)
if len(tp) == 0 {
// Can this happen?
continue // maybe report this someday
}
// This is only safe if ExprString never returns anything with a $
// The only place a $ can occur seems to be in a struct tag, which
// can be an arbitrary string literal, and ExprString does not presently
// print struct tags. So for this to happen the type of a formal parameter
// has to be a explicit struct, e.g. foo(x struct{a int "$"}) and ExprString
// would have to show the struct tag. Even testing for this case seems
// a waste of effort, but let's remember the possibility
if strings.Contains(tp, "$") {
continue
}
tp = strings.Replace(tp, " ", "$", -1)
if len(x.Names) == 0 {
result = append(result, "_")
result = append(result, tp)
} else {
for _, y := range x.Names {
result = append(result, y.Name)
result = append(result, tp)
}
}
}
sigs := strings.Join(result, " ")
if s := newsym(pkg, name, kind, sigs); s != nil {
ans = append(ans, *s)
}
case *ast.GenDecl:
depr := isDeprecated(decl.Doc)
switch decl.Tok {
case token.CONST, token.VAR:
tp := "V"
if decl.Tok == token.CONST {
tp = "C"
}
if depr {
tp += "D"
}
for _, sp := range decl.Specs {
for _, x := range sp.(*ast.ValueSpec).Names {
if s := newsym(pkg, x.Name, tp, ""); s != nil {
ans = append(ans, *s)
}
}
}
case token.TYPE:
tp := "T"
if depr {
tp += "D"
}
for _, sp := range decl.Specs {
if s := newsym(pkg, sp.(*ast.TypeSpec).Name.Name, tp, ""); s != nil {
ans = append(ans, *s)
}
}
}
}
}
return ans
}
func newsym(pkg, name, kind, sig string) *symbol {
if len(name) == 0 || !ast.IsExported(name) {
return nil
}
sym := symbol{pkg: pkg, name: name, kind: kind, sig: sig}
return &sym
}
func isDeprecated(doc *ast.CommentGroup) bool {
if doc == nil {
return false
}
// go.dev/wiki/Deprecated Paragraph starting 'Deprecated:'
// This code fails for /* Deprecated: */, but it's the code from
// gopls/internal/analysis/deprecated
for line := range strings.SplitSeq(doc.Text(), "\n\n") {
if strings.HasPrefix(line, "Deprecated:") {
return true
}
}
return false
}
// return the package name and the value for the symbols.
// if there are multiple packages, choose one arbitrarily
// the returned slice is sorted lexicographically
func processSyms(syms []symbol) (string, []string) {
if len(syms) == 0 {
return "", nil
}
slices.SortFunc(syms, func(l, r symbol) int {
return strings.Compare(l.name, r.name)
})
pkg := syms[0].pkg
var names []string
for _, s := range syms {
if s.pkg != pkg {
// Symbols came from two files in same dir
// with different package declarations.
continue
}
var nx string
if s.sig != "" {
nx = fmt.Sprintf("%s %s %s", s.name, s.kind, s.sig)
} else {
nx = fmt.Sprintf("%s %s", s.name, s.kind)
}
names = append(names, nx)
}
return pkg, names
}

View File

@@ -28,6 +28,15 @@ const (
// - remove derived info "needed" bool
V2
// V3: introduces a more compact format for composite literal element lists
// - negative lengths indicate that (some) elements may have keys
// - positive lengths indicate that no element has a key
// - a negative struct field index indicates an embedded field
V3
// V4: encodes generic methods as standalone function objects
V4
numVersions = iota
)
@@ -61,6 +70,12 @@ const (
// whether a type was a derived type.
DerivedInfoNeeded
// Composite literals use a more compact format for element lists.
CompactCompLiterals
// Generic methods may appear as standalone function objects.
GenericMethods
numFields = iota
)
@@ -68,6 +83,8 @@ const (
var introduced = [numFields]Version{
Flags: V1,
AliasTypeParamNames: V2,
CompactCompLiterals: V3,
GenericMethods: V4,
}
// removed is the version a field was removed in or 0 for fields

View File

@@ -11,7 +11,9 @@ import (
// CoreType returns the core type of T or nil if T does not have a core type.
//
// See https://go.dev/ref/spec#Core_types for the definition of a core type.
// As of Go1.25, the notion of a core type has been removed from the language spec.
// See https://go.dev/blog/coretypes for more details.
// TODO(mkalil): We should eventually consider removing all uses of CoreType.
func CoreType(T types.Type) types.Type {
U := T.Underlying()
if _, ok := U.(*types.Interface); !ok {
@@ -34,7 +36,7 @@ func CoreType(T types.Type) types.Type {
}
if identical == len(terms) {
// https://go.dev/ref/spec#Core_types
// From the deprecated core types spec:
// "There is a single type U which is the underlying type of all types in the type set of T"
return U
}
@@ -42,7 +44,7 @@ func CoreType(T types.Type) types.Type {
if !ok {
return nil // no core type as identical < len(terms) and U is not a channel.
}
// https://go.dev/ref/spec#Core_types
// From the deprecated core types spec:
// "the type chan E if T contains only bidirectional channels, or the type chan<- E or
// <-chan E depending on the direction of the directional channels present."
for chans := identical; chans < len(terms); chans++ {

View File

@@ -194,3 +194,51 @@ func Imports(pkg *types.Package, path string) bool {
}
return false
}
// ObjectKind returns a description of the object's kind.
//
// from objectKind in go/types
func ObjectKind(obj types.Object) string {
switch obj := obj.(type) {
case *types.PkgName:
return "package name"
case *types.Const:
return "constant"
case *types.TypeName:
if obj.IsAlias() {
return "type alias"
} else if _, ok := obj.Type().(*types.TypeParam); ok {
return "type parameter"
} else {
return "defined type"
}
case *types.Var:
switch obj.Kind() {
case PackageVar:
return "package-level variable"
case LocalVar:
return "local variable"
case RecvVar:
return "receiver"
case ParamVar:
return "parameter"
case ResultVar:
return "result variable"
case FieldVar:
return "struct field"
}
case *types.Func:
if obj.Signature().Recv() != nil {
return "method"
} else {
return "function"
}
case *types.Label:
return "label"
case *types.Builtin:
return "built-in function"
case *types.Nil:
return "untyped nil"
}
return "unknown symbol"
}

View File

@@ -19,6 +19,7 @@ const (
Go1_24 = "go1.24"
Go1_25 = "go1.25"
Go1_26 = "go1.26"
Go1_27 = "go1.27"
)
// Future is an invalid unknown Go version sometime in the future.

Some files were not shown because too many files have changed in this diff Show More