From 5a9cfc022c834e6ab47c833f6ed9b1e9bbfb912b Mon Sep 17 00:00:00 2001 From: bluepython508 <16466646+bluepython508@users.noreply.github.com> Date: Wed, 9 Apr 2025 01:00:12 +0100 Subject: [PATCH] Update dependencies --- flake.lock | 6 +- go.mod | 82 +- go.sum | 188 +- .../aws/accountid_endpoint_mode.go | 18 + .../aws/aws-sdk-go-v2/aws/checksum.go | 33 + .../aws/aws-sdk-go-v2/aws/config.go | 30 + .../aws/aws-sdk-go-v2/aws/credentials.go | 3 + .../aws/aws-sdk-go-v2/aws/endpoints.go | 26 +- .../aws-sdk-go-v2/aws/go_module_metadata.go | 2 +- .../aws/middleware/middleware.go | 10 +- .../aws/middleware/private/metrics/metrics.go | 319 - .../aws/middleware/request_id_retriever.go | 16 +- .../aws/middleware/user_agent.go | 102 +- .../aws-sdk-go-v2/aws/protocol/query/array.go | 29 +- .../aws/protocol/query/object.go | 11 +- .../aws-sdk-go-v2/aws/protocol/query/value.go | 2 + .../aws/aws-sdk-go-v2/aws/ratelimit/none.go | 20 + .../aws/retry/attempt_metrics.go | 51 + .../aws/aws-sdk-go-v2/aws/retry/middleware.go | 94 +- .../aws/retry/retryable_error.go | 27 + .../aws/aws-sdk-go-v2/aws/retry/standard.go | 11 + .../aws/signer/internal/v4/headers.go | 11 +- .../aws-sdk-go-v2/aws/signer/v4/middleware.go | 86 +- .../aws/aws-sdk-go-v2/aws/signer/v4/v4.go | 66 +- .../aws/transport/http/client.go | 36 +- .../http/response_error_middleware.go | 10 +- .../aws/aws-sdk-go-v2/config/CHANGELOG.md | 262 + .../aws/aws-sdk-go-v2/config/config.go | 11 +- .../aws/aws-sdk-go-v2/config/env_config.go | 245 +- .../config/go_module_metadata.go | 2 +- .../aws/aws-sdk-go-v2/config/load_options.go | 97 +- .../aws/aws-sdk-go-v2/config/provider.go | 51 + .../aws/aws-sdk-go-v2/config/resolve.go | 46 + .../config/resolve_credentials.go | 15 +- .../aws/aws-sdk-go-v2/config/shared_config.go | 96 + .../aws-sdk-go-v2/credentials/CHANGELOG.md | 242 + .../endpointcreds/internal/client/client.go | 1 + .../credentials/endpointcreds/provider.go | 1 + .../credentials/go_module_metadata.go | 2 +- .../credentials/processcreds/provider.go | 4 + .../credentials/ssocreds/sso_cached_token.go | 2 +- .../ssocreds/sso_credentials_provider.go | 1 + .../stscreds/assume_role_provider.go | 6 + .../stscreds/web_identity_provider.go | 19 + .../feature/ec2/imds/CHANGELOG.md | 137 + .../feature/ec2/imds/api_client.go | 4 + .../aws/aws-sdk-go-v2/feature/ec2/imds/doc.go | 5 +- .../feature/ec2/imds/go_module_metadata.go | 2 +- .../feature/ec2/imds/request_middleware.go | 6 + .../internal/auth/smithy/v4signer_adapter.go | 6 +- .../internal/configsources/CHANGELOG.md | 132 + .../configsources/go_module_metadata.go | 2 +- .../aws-sdk-go-v2/internal/context/context.go | 52 + .../endpoints/awsrulesfn/partition.go | 11 +- .../endpoints/awsrulesfn/partitions.go | 94 +- .../endpoints/awsrulesfn/partitions.json | 17 +- .../internal/endpoints/v2/CHANGELOG.md | 134 + .../endpoints/v2/go_module_metadata.go | 2 +- .../aws-sdk-go-v2/internal/ini/CHANGELOG.md | 16 + .../internal/ini/go_module_metadata.go | 2 +- .../aws/aws-sdk-go-v2/internal/ini/strings.go | 4 - .../internal/middleware/middleware.go | 42 + .../internal/accept-encoding/CHANGELOG.md | 36 + .../accept-encoding/go_module_metadata.go | 2 +- .../internal/presigned-url/CHANGELOG.md | 142 + .../service/internal/presigned-url/context.go | 12 +- .../presigned-url/go_module_metadata.go | 2 +- .../aws-sdk-go-v2/service/sso/CHANGELOG.md | 198 + .../aws-sdk-go-v2/service/sso/api_client.go | 463 +- .../service/sso/api_op_GetRoleCredentials.go | 40 +- .../service/sso/api_op_ListAccountRoles.go | 59 +- .../service/sso/api_op_ListAccounts.go | 64 +- .../service/sso/api_op_Logout.go | 64 +- .../aws/aws-sdk-go-v2/service/sso/auth.go | 43 +- .../service/sso/deserializers.go | 39 +- .../aws/aws-sdk-go-v2/service/sso/doc.go | 22 +- .../aws-sdk-go-v2/service/sso/endpoints.go | 36 +- .../aws-sdk-go-v2/service/sso/generated.json | 4 +- .../service/sso/go_module_metadata.go | 2 +- .../sso/internal/endpoints/endpoints.go | 34 +- .../aws/aws-sdk-go-v2/service/sso/options.go | 39 +- .../aws-sdk-go-v2/service/sso/serializers.go | 33 +- .../aws-sdk-go-v2/service/sso/types/types.go | 20 +- .../service/ssooidc/CHANGELOG.md | 195 + .../service/ssooidc/api_client.go | 463 +- .../service/ssooidc/api_op_CreateToken.go | 102 +- .../ssooidc/api_op_CreateTokenWithIAM.go | 103 +- .../service/ssooidc/api_op_RegisterClient.go | 66 +- .../api_op_StartDeviceAuthorization.go | 44 +- .../aws/aws-sdk-go-v2/service/ssooidc/auth.go | 43 +- .../service/ssooidc/deserializers.go | 122 + .../aws/aws-sdk-go-v2/service/ssooidc/doc.go | 43 +- .../service/ssooidc/endpoints.go | 36 +- .../service/ssooidc/generated.json | 4 +- .../service/ssooidc/go_module_metadata.go | 2 +- .../ssooidc/internal/endpoints/endpoints.go | 34 +- .../aws-sdk-go-v2/service/ssooidc/options.go | 39 +- .../service/ssooidc/serializers.go | 81 + .../service/ssooidc/types/errors.go | 32 +- .../aws-sdk-go-v2/service/sts/CHANGELOG.md | 219 + .../aws-sdk-go-v2/service/sts/api_client.go | 465 +- .../service/sts/api_op_AssumeRole.go | 498 +- .../service/sts/api_op_AssumeRoleWithSAML.go | 404 +- .../sts/api_op_AssumeRoleWithWebIdentity.go | 435 +- .../service/sts/api_op_AssumeRoot.go | 220 + .../sts/api_op_DecodeAuthorizationMessage.go | 81 +- .../service/sts/api_op_GetAccessKeyInfo.go | 85 +- .../service/sts/api_op_GetCallerIdentity.go | 61 +- .../service/sts/api_op_GetFederationToken.go | 353 +- .../service/sts/api_op_GetSessionToken.go | 140 +- .../aws/aws-sdk-go-v2/service/sts/auth.go | 43 +- .../service/sts/deserializers.go | 212 + .../aws/aws-sdk-go-v2/service/sts/doc.go | 12 +- .../aws-sdk-go-v2/service/sts/endpoints.go | 36 +- .../aws-sdk-go-v2/service/sts/generated.json | 5 +- .../service/sts/go_module_metadata.go | 2 +- .../sts/internal/endpoints/endpoints.go | 19 +- .../aws/aws-sdk-go-v2/service/sts/options.go | 39 +- .../aws-sdk-go-v2/service/sts/serializers.go | 143 + .../aws-sdk-go-v2/service/sts/types/errors.go | 30 +- .../aws-sdk-go-v2/service/sts/types/types.go | 50 +- .../aws-sdk-go-v2/service/sts/validators.go | 42 + vendor/github.com/aws/smithy-go/.gitignore | 3 + vendor/github.com/aws/smithy-go/CHANGELOG.md | 76 + .../github.com/aws/smithy-go/CONTRIBUTING.md | 31 + vendor/github.com/aws/smithy-go/Makefile | 14 +- vendor/github.com/aws/smithy-go/README.md | 74 +- .../aws/smithy-go/changelog-template.json | 9 + .../encoding/httpbinding/path_replace.go | 30 +- .../aws/smithy-go/go_module_metadata.go | 2 +- .../aws/smithy-go/metrics/metrics.go | 136 + .../github.com/aws/smithy-go/metrics/nop.go | 67 + .../aws/smithy-go/middleware/context.go | 41 + vendor/github.com/aws/smithy-go/modman.toml | 1 - vendor/github.com/aws/smithy-go/properties.go | 19 +- .../aws/smithy-go/tracing/context.go | 96 + .../github.com/aws/smithy-go/tracing/nop.go | 32 + .../aws/smithy-go/tracing/tracing.go | 95 + .../aws/smithy-go/transport/http/client.go | 45 +- .../aws/smithy-go/transport/http/host.go | 2 +- .../aws/smithy-go/transport/http/metrics.go | 198 + .../http/middleware_close_response_body.go | 8 +- .../aws/smithy-go/transport/http/request.go | 5 +- .../bits-and-blooms/bitset/.gitignore | 26 - .../bits-and-blooms/bitset/.travis.yml | 37 - .../github.com/bits-and-blooms/bitset/LICENSE | 27 - .../bits-and-blooms/bitset/README.md | 159 - .../bits-and-blooms/bitset/SECURITY.md | 5 - .../bitset/azure-pipelines.yml | 39 - .../bits-and-blooms/bitset/bitset.go | 1184 -- .../bits-and-blooms/bitset/popcnt.go | 53 - .../bits-and-blooms/bitset/popcnt_19.go | 62 - .../bits-and-blooms/bitset/popcnt_amd64.go | 68 - .../bits-and-blooms/bitset/popcnt_amd64.s | 104 - .../bits-and-blooms/bitset/popcnt_generic.go | 25 - .../bits-and-blooms/bitset/select.go | 45 - .../bitset/trailing_zeros_18.go | 15 - .../bitset/trailing_zeros_19.go | 10 - .../fxamacker/cbor/v2/.golangci.yml | 53 +- vendor/github.com/fxamacker/cbor/v2/README.md | 29 +- .../fxamacker/cbor/v2/bytestring.go | 4 +- vendor/github.com/fxamacker/cbor/v2/cache.go | 89 +- vendor/github.com/fxamacker/cbor/v2/common.go | 182 + vendor/github.com/fxamacker/cbor/v2/decode.go | 1345 +- .../github.com/fxamacker/cbor/v2/diagnose.go | 405 +- vendor/github.com/fxamacker/cbor/v2/encode.go | 865 +- .../fxamacker/cbor/v2/encode_map.go | 37 +- .../fxamacker/cbor/v2/encode_map_go117.go | 33 +- .../fxamacker/cbor/v2/simplevalue.go | 8 +- vendor/github.com/fxamacker/cbor/v2/stream.go | 16 +- .../fxamacker/cbor/v2/structfields.go | 18 +- vendor/github.com/fxamacker/cbor/v2/tag.go | 14 +- vendor/github.com/fxamacker/cbor/v2/valid.go | 152 +- vendor/github.com/gaissmai/bart/.gitignore | 27 + vendor/github.com/gaissmai/bart/.golangci.yml | 34 + vendor/github.com/gaissmai/bart/README.md | 163 +- vendor/github.com/gaissmai/bart/SECURITY.md | 5 + .../gaissmai/bart/allot_lookuptbl.go | 542 + vendor/github.com/gaissmai/bart/base_index.go | 1164 +- vendor/github.com/gaissmai/bart/dumper.go | 253 +- .../gaissmai/bart/internal/bitset/bitset.go | 326 + .../gaissmai/bart/internal/sparse/array.go | 160 + vendor/github.com/gaissmai/bart/jsonify.go | 25 +- .../github.com/gaissmai/bart/lpm_lookuptbl.go | 538 + vendor/github.com/gaissmai/bart/node.go | 1263 +- vendor/github.com/gaissmai/bart/overlaps.go | 305 + vendor/github.com/gaissmai/bart/stringify.go | 176 +- vendor/github.com/gaissmai/bart/table.go | 1466 +- .../go-json-experiment/json/README.md | 48 +- .../go-json-experiment/json/arshal.go | 183 +- .../go-json-experiment/json/arshal_any.go | 148 +- .../go-json-experiment/json/arshal_default.go | 831 +- .../go-json-experiment/json/arshal_funcs.go | 110 +- .../go-json-experiment/json/arshal_inlined.go | 52 +- .../go-json-experiment/json/arshal_methods.go | 360 +- .../go-json-experiment/json/arshal_time.go | 187 +- .../json/benchmark-marshal-concrete.png | Bin 24890 -> 0 bytes .../json/benchmark-marshal-interface.png | Bin 24868 -> 0 bytes .../json/benchmark-marshal-rawvalue.png | Bin 25032 -> 0 bytes .../json/benchmark-unmarshal-concrete.png | Bin 25104 -> 0 bytes .../json/benchmark-unmarshal-interface.png | Bin 24214 -> 0 bytes .../json/benchmark-unmarshal-rawvalue.png | Bin 24810 -> 0 bytes .../github.com/go-json-experiment/json/doc.go | 36 +- .../go-json-experiment/json/errors.go | 348 +- .../go-json-experiment/json/fields.go | 317 +- .../json/internal/internal.go | 25 + .../json/internal/jsonflags/flags.go | 83 +- .../json/internal/jsonopts/options.go | 68 +- .../json/internal/jsonwire/decode.go | 29 +- .../json/internal/jsonwire/encode.go | 134 +- .../json/internal/jsonwire/wire.go | 76 +- .../json/jsontext/decode.go | 278 +- .../json/jsontext/encode.go | 266 +- .../json/jsontext/errors.go | 152 +- .../json/jsontext/export.go | 14 +- .../json/jsontext/options.go | 149 +- .../go-json-experiment/json/jsontext/quote.go | 16 +- .../go-json-experiment/json/jsontext/state.go | 225 +- .../go-json-experiment/json/jsontext/token.go | 56 +- .../go-json-experiment/json/jsontext/value.go | 324 +- .../go-json-experiment/json/migrate.sh | 243 + .../go-json-experiment/json/options.go | 39 +- vendor/github.com/gorilla/csrf/csrf.go | 89 +- .../github.com/illarion/gonotify/v2/README.md | 67 - .../illarion/gonotify/v2/inotify.go | 290 - .../illarion/gonotify/{v2 => v3}/.gitignore | 0 .../illarion/gonotify/{v2 => v3}/LICENSE | 0 .../github.com/illarion/gonotify/v3/README.md | 71 + .../gonotify/{v2 => v3}/dirwatcher.go | 92 +- .../illarion/gonotify/{v2 => v3}/event.go | 2 +- .../gonotify/{v2 => v3}/filewatcher.go | 52 +- .../illarion/gonotify/v3/inotify.go | 527 + .../illarion/gonotify/v3/syscallf/rm_watch.go | 17 + vendor/github.com/josharian/native/doc.go | 8 - .../josharian/native/endian_generic.go | 22 - vendor/github.com/josharian/native/license | 7 - vendor/github.com/josharian/native/readme.md | 12 - .../klauspost/compress/.goreleaser.yml | 10 +- .../github.com/klauspost/compress/README.md | 62 +- .../klauspost/compress/fse/decompress.go | 2 +- .../klauspost/compress/huff0/decompress.go | 4 +- .../compress/internal/snapref/encode_other.go | 2 +- vendor/github.com/klauspost/compress/s2sx.mod | 2 +- .../klauspost/compress/zstd/blockdec.go | 7 +- .../klauspost/compress/zstd/blockenc.go | 20 + .../klauspost/compress/zstd/decodeheader.go | 56 +- .../klauspost/compress/zstd/decoder.go | 2 +- .../klauspost/compress/zstd/dict.go | 31 + .../klauspost/compress/zstd/enc_best.go | 49 +- .../klauspost/compress/zstd/enc_better.go | 45 +- .../klauspost/compress/zstd/enc_dfast.go | 16 +- .../klauspost/compress/zstd/encoder.go | 45 +- .../compress/zstd/encoder_options.go | 6 +- .../klauspost/compress/zstd/framedec.go | 4 +- .../klauspost/compress/zstd/frameenc.go | 2 +- .../compress/zstd/fse_decoder_generic.go | 11 +- .../zstd/internal/xxhash/xxhash_arm64.s | 4 +- .../klauspost/compress/zstd/matchlen_amd64.s | 10 +- .../klauspost/compress/zstd/seqdec_amd64.go | 4 +- .../klauspost/compress/zstd/seqdec_amd64.s | 144 +- .../klauspost/compress/zstd/zstd.go | 4 + vendor/github.com/mdlayher/netlink/README.md | 8 + .../github.com/mdlayher/netlink/attribute.go | 5 +- .../github.com/mdlayher/netlink/nlenc/doc.go | 4 +- .../tailscale/golang-x-crypto/LICENSE | 27 - .../tailscale/golang-x-crypto/PATENTS | 22 - .../internal/poly1305/mac_noasm.go | 9 - .../internal/poly1305/poly1305.go | 99 - .../internal/poly1305/sum_amd64.go | 47 - .../internal/poly1305/sum_amd64.s | 108 - .../internal/poly1305/sum_generic.go | 312 - .../internal/poly1305/sum_ppc64le.go | 47 - .../internal/poly1305/sum_ppc64le.s | 181 - .../internal/poly1305/sum_s390x.go | 76 - .../internal/poly1305/sum_s390x.s | 503 - .../tailscale/peercred/peercred_solaris.go | 53 + .../build/assets/index-BbZBz4S-.js.gz | Bin 0 -> 92422 bytes .../build/assets/index-D59OWpX6.css.gz | Bin 7780 -> 0 bytes .../build/assets/index-DUHvXbWu.js.gz | Bin 93284 -> 0 bytes .../build/assets/index-DVk8gqX9.css.gz | Bin 0 -> 7797 bytes .../web-client-prebuilt/build/index.html | 4 +- .../tailscale/wireguard-go/ipc/uapi_fake.go | 2 +- .../tailscale/wireguard-go/tun/tun_linux.go | 22 +- .../github.com/tcnksm/go-httpstat/.travis.yml | 19 - vendor/github.com/tcnksm/go-httpstat/LICENSE | 21 - vendor/github.com/tcnksm/go-httpstat/Makefile | 26 - .../github.com/tcnksm/go-httpstat/README.md | 23 - vendor/github.com/tcnksm/go-httpstat/go18.go | 121 - .../github.com/tcnksm/go-httpstat/httpstat.go | 147 - .../github.com/tcnksm/go-httpstat/pre_go18.go | 114 - .../github.com/u-root/uio/rand/random_std.go | 1 + .../github.com/u-root/uio/rand/random_unix.go | 1 + .../u-root/uio/uio/archivereader.go | 4 + vendor/github.com/u-root/uio/uio/buffer.go | 4 +- .../github.com/u-root/uio/uio/linewriter.go | 57 - .../github.com/u-root/uio/uio/multiwriter.go | 37 - vendor/github.com/u-root/uio/uio/null.go | 12 +- vendor/github.com/u-root/uio/uio/progress.go | 2 +- vendor/go4.org/mem/mem.go | 24 + vendor/golang.org/x/crypto/LICENSE | 4 +- .../golang.org/x/crypto/argon2/blamka_amd64.s | 2974 +++- .../x/crypto/blake2b/blake2bAVX2_amd64.s | 5169 ++++++- .../x/crypto/blake2b/blake2b_amd64.s | 1691 ++- .../x/crypto/blake2s/blake2s_amd64.s | 2579 +++- .../x/crypto/chacha20/chacha_noasm.go | 2 +- .../{chacha_ppc64le.go => chacha_ppc64x.go} | 2 +- .../{chacha_ppc64le.s => chacha_ppc64x.s} | 114 +- .../chacha20poly1305/chacha20poly1305_amd64.s | 11493 +++++++++++++--- .../x/crypto/internal/poly1305/mac_noasm.go | 2 +- .../x/crypto/internal/poly1305/sum_amd64.s | 133 +- .../{sum_ppc64le.go => sum_ppc64x.go} | 2 +- .../poly1305/{sum_ppc64le.s => sum_ppc64x.s} | 30 +- .../x/crypto/salsa20/salsa/salsa20_amd64.s | 1742 +-- .../x/crypto}/ssh/buffer.go | 0 .../x/crypto}/ssh/certs.go | 0 .../x/crypto}/ssh/channel.go | 0 .../x/crypto}/ssh/cipher.go | 2 +- .../x/crypto}/ssh/client.go | 0 .../x/crypto}/ssh/client_auth.go | 23 +- .../x/crypto}/ssh/common.go | 0 .../x/crypto}/ssh/connection.go | 5 - .../x/crypto}/ssh/doc.go | 2 +- .../x/crypto}/ssh/handshake.go | 61 +- .../ssh/internal/bcrypt_pbkdf/bcrypt_pbkdf.go | 0 .../x/crypto}/ssh/kex.go | 0 .../x/crypto}/ssh/keys.go | 54 +- .../x/crypto}/ssh/mac.go | 0 .../x/crypto}/ssh/messages.go | 0 .../x/crypto}/ssh/mux.go | 0 .../x/crypto}/ssh/server.go | 315 +- .../x/crypto}/ssh/session.go | 0 .../x/crypto}/ssh/ssh_gss.go | 0 .../x/crypto}/ssh/streamlocal.go | 0 .../x/crypto}/ssh/tcpip.go | 0 .../x/crypto}/ssh/transport.go | 0 vendor/golang.org/x/exp/LICENSE | 4 +- .../x/exp/constraints/constraints.go | 2 + vendor/golang.org/x/exp/maps/maps.go | 58 +- vendor/golang.org/x/mod/LICENSE | 4 +- vendor/golang.org/x/net/LICENSE | 4 +- .../golang.org/x/net/http/httpproxy/proxy.go | 10 +- .../x/net/http2/client_conn_pool.go | 8 +- vendor/golang.org/x/net/http2/config.go | 122 + vendor/golang.org/x/net/http2/config_go124.go | 61 + .../x/net/http2/config_pre_go124.go | 16 + vendor/golang.org/x/net/http2/frame.go | 4 +- vendor/golang.org/x/net/http2/http2.go | 112 +- vendor/golang.org/x/net/http2/server.go | 355 +- vendor/golang.org/x/net/http2/transport.go | 831 +- vendor/golang.org/x/net/http2/unencrypted.go | 32 + vendor/golang.org/x/net/http2/write.go | 13 +- .../x/net/internal/httpcommon/ascii.go | 53 + .../httpcommon}/headermap.go | 24 +- .../x/net/internal/httpcommon/request.go | 467 + .../net/internal/socket/zsys_openbsd_ppc64.go | 28 +- .../internal/socket/zsys_openbsd_riscv64.go | 28 +- vendor/golang.org/x/net/proxy/per_host.go | 8 +- vendor/golang.org/x/net/route/address.go | 71 +- vendor/golang.org/x/net/route/sys_netbsd.go | 2 +- vendor/golang.org/x/net/route/zsys_darwin.go | 8 +- .../golang.org/x/net/route/zsys_dragonfly.go | 8 +- .../x/net/route/zsys_freebsd_386.go | 20 +- .../x/net/route/zsys_freebsd_amd64.go | 20 +- .../x/net/route/zsys_freebsd_arm.go | 20 +- .../x/net/route/zsys_freebsd_arm64.go | 20 +- .../x/net/route/zsys_freebsd_riscv64.go | 20 +- vendor/golang.org/x/net/route/zsys_netbsd.go | 8 +- vendor/golang.org/x/net/route/zsys_openbsd.go | 5 +- vendor/golang.org/x/sync/LICENSE | 4 +- vendor/golang.org/x/sync/errgroup/errgroup.go | 1 + vendor/golang.org/x/sys/LICENSE | 4 +- .../golang.org/x/sys/cpu/asm_darwin_x86_gc.s | 17 + vendor/golang.org/x/sys/cpu/cpu.go | 24 + vendor/golang.org/x/sys/cpu/cpu_arm64.go | 12 + vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go | 61 + vendor/golang.org/x/sys/cpu/cpu_gc_x86.go | 4 +- .../x/sys/cpu/{cpu_x86.s => cpu_gc_x86.s} | 2 +- vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go | 6 - .../golang.org/x/sys/cpu/cpu_linux_arm64.go | 4 + .../golang.org/x/sys/cpu/cpu_linux_noinit.go | 2 +- .../golang.org/x/sys/cpu/cpu_linux_riscv64.go | 137 + .../cpu/cpu_other_x86.go} | 11 +- vendor/golang.org/x/sys/cpu/cpu_riscv64.go | 11 +- vendor/golang.org/x/sys/cpu/cpu_x86.go | 27 +- .../x/sys/cpu/syscall_darwin_x86_gc.go | 98 + vendor/golang.org/x/sys/unix/README.md | 2 +- vendor/golang.org/x/sys/unix/auxv.go | 36 + .../golang.org/x/sys/unix/auxv_unsupported.go | 13 + vendor/golang.org/x/sys/unix/ioctl_linux.go | 96 + vendor/golang.org/x/sys/unix/mkerrors.sh | 18 +- vendor/golang.org/x/sys/unix/syscall_aix.go | 2 +- .../golang.org/x/sys/unix/syscall_darwin.go | 49 + .../x/sys/unix/syscall_dragonfly.go | 12 + vendor/golang.org/x/sys/unix/syscall_hurd.go | 1 + vendor/golang.org/x/sys/unix/syscall_linux.go | 65 +- .../x/sys/unix/syscall_linux_arm64.go | 2 + .../x/sys/unix/syscall_linux_loong64.go | 2 + .../x/sys/unix/syscall_linux_riscv64.go | 2 + .../golang.org/x/sys/unix/syscall_openbsd.go | 1 + .../golang.org/x/sys/unix/syscall_solaris.go | 87 + .../x/sys/unix/syscall_zos_s390x.go | 104 +- .../golang.org/x/sys/unix/vgetrandom_linux.go | 13 + .../unix/vgetrandom_unsupported.go} | 11 +- .../x/sys/unix/zerrors_darwin_amd64.go | 12 + .../x/sys/unix/zerrors_darwin_arm64.go | 12 + vendor/golang.org/x/sys/unix/zerrors_linux.go | 102 +- .../x/sys/unix/zerrors_linux_386.go | 30 + .../x/sys/unix/zerrors_linux_amd64.go | 30 + .../x/sys/unix/zerrors_linux_arm.go | 30 + .../x/sys/unix/zerrors_linux_arm64.go | 32 + .../x/sys/unix/zerrors_linux_loong64.go | 30 + .../x/sys/unix/zerrors_linux_mips.go | 30 + .../x/sys/unix/zerrors_linux_mips64.go | 30 + .../x/sys/unix/zerrors_linux_mips64le.go | 30 + .../x/sys/unix/zerrors_linux_mipsle.go | 30 + .../x/sys/unix/zerrors_linux_ppc.go | 30 + .../x/sys/unix/zerrors_linux_ppc64.go | 30 + .../x/sys/unix/zerrors_linux_ppc64le.go | 30 + .../x/sys/unix/zerrors_linux_riscv64.go | 30 + .../x/sys/unix/zerrors_linux_s390x.go | 30 + .../x/sys/unix/zerrors_linux_sparc64.go | 30 + .../x/sys/unix/zerrors_zos_s390x.go | 2 + .../x/sys/unix/zsyscall_darwin_amd64.go | 68 + .../x/sys/unix/zsyscall_darwin_amd64.s | 15 + .../x/sys/unix/zsyscall_darwin_arm64.go | 68 + .../x/sys/unix/zsyscall_darwin_arm64.s | 15 + .../golang.org/x/sys/unix/zsyscall_linux.go | 43 +- .../x/sys/unix/zsyscall_openbsd_386.go | 24 + .../x/sys/unix/zsyscall_openbsd_386.s | 5 + .../x/sys/unix/zsyscall_openbsd_amd64.go | 24 + .../x/sys/unix/zsyscall_openbsd_amd64.s | 5 + .../x/sys/unix/zsyscall_openbsd_arm.go | 24 + .../x/sys/unix/zsyscall_openbsd_arm.s | 5 + .../x/sys/unix/zsyscall_openbsd_arm64.go | 24 + .../x/sys/unix/zsyscall_openbsd_arm64.s | 5 + .../x/sys/unix/zsyscall_openbsd_mips64.go | 24 + .../x/sys/unix/zsyscall_openbsd_mips64.s | 5 + .../x/sys/unix/zsyscall_openbsd_ppc64.go | 24 + .../x/sys/unix/zsyscall_openbsd_ppc64.s | 6 + .../x/sys/unix/zsyscall_openbsd_riscv64.go | 24 + .../x/sys/unix/zsyscall_openbsd_riscv64.s | 5 + .../x/sys/unix/zsyscall_solaris_amd64.go | 114 + .../x/sys/unix/zsysnum_linux_386.go | 5 + .../x/sys/unix/zsysnum_linux_amd64.go | 6 + .../x/sys/unix/zsysnum_linux_arm.go | 5 + .../x/sys/unix/zsysnum_linux_arm64.go | 7 +- .../x/sys/unix/zsysnum_linux_loong64.go | 7 + .../x/sys/unix/zsysnum_linux_mips.go | 5 + .../x/sys/unix/zsysnum_linux_mips64.go | 5 + .../x/sys/unix/zsysnum_linux_mips64le.go | 5 + .../x/sys/unix/zsysnum_linux_mipsle.go | 5 + .../x/sys/unix/zsysnum_linux_ppc.go | 5 + .../x/sys/unix/zsysnum_linux_ppc64.go | 5 + .../x/sys/unix/zsysnum_linux_ppc64le.go | 5 + .../x/sys/unix/zsysnum_linux_riscv64.go | 7 +- .../x/sys/unix/zsysnum_linux_s390x.go | 5 + .../x/sys/unix/zsysnum_linux_sparc64.go | 5 + .../x/sys/unix/ztypes_darwin_amd64.go | 73 + .../x/sys/unix/ztypes_darwin_arm64.go | 73 + .../x/sys/unix/ztypes_freebsd_386.go | 1 + .../x/sys/unix/ztypes_freebsd_amd64.go | 1 + .../x/sys/unix/ztypes_freebsd_arm.go | 1 + .../x/sys/unix/ztypes_freebsd_arm64.go | 1 + .../x/sys/unix/ztypes_freebsd_riscv64.go | 1 + vendor/golang.org/x/sys/unix/ztypes_linux.go | 234 +- .../x/sys/unix/ztypes_linux_riscv64.go | 33 + .../golang.org/x/sys/unix/ztypes_zos_s390x.go | 6 + .../golang.org/x/sys/windows/dll_windows.go | 13 +- .../x/sys/windows/security_windows.go | 2 +- .../x/sys/windows/svc/mgr/config.go | 2 +- .../x/sys/windows/svc/mgr/recovery.go | 4 +- .../x/sys/windows/syscall_windows.go | 52 +- .../golang.org/x/sys/windows/types_windows.go | 199 +- .../x/sys/windows/zsyscall_windows.go | 158 +- vendor/golang.org/x/term/LICENSE | 4 +- vendor/golang.org/x/term/README.md | 11 +- vendor/golang.org/x/term/term_windows.go | 1 + vendor/golang.org/x/text/LICENSE | 4 +- vendor/golang.org/x/time/LICENSE | 4 +- vendor/golang.org/x/time/rate/rate.go | 28 +- vendor/golang.org/x/tools/LICENSE | 4 +- .../x/tools/go/gcexportdata/gcexportdata.go | 117 +- vendor/golang.org/x/tools/go/packages/doc.go | 15 +- .../x/tools/go/packages/external.go | 15 +- .../golang.org/x/tools/go/packages/golist.go | 48 +- .../x/tools/go/packages/loadmode_string.go | 73 +- .../x/tools/go/packages/packages.go | 413 +- .../golang.org/x/tools/go/packages/visit.go | 9 + .../x/tools/go/types/objectpath/objectpath.go | 139 +- .../x/tools/go/types/typeutil/callee.go | 68 + .../x/tools/go/types/typeutil/imports.go | 30 + .../x/tools/go/types/typeutil/map.go | 470 + .../tools/go/types/typeutil/methodsetcache.go | 71 + .../x/tools/go/types/typeutil/ui.go | 53 + .../x/tools/internal/aliases/aliases.go | 10 +- .../x/tools/internal/aliases/aliases_go121.go | 31 - .../x/tools/internal/aliases/aliases_go122.go | 55 +- .../x/tools/internal/gcimporter/bimport.go | 61 - .../x/tools/internal/gcimporter/exportdata.go | 448 +- .../x/tools/internal/gcimporter/gcimporter.go | 182 +- .../x/tools/internal/gcimporter/iexport.go | 284 +- .../x/tools/internal/gcimporter/iimport.go | 55 +- .../internal/gcimporter/iimport_go122.go | 53 + .../internal/gcimporter/newInterface10.go | 22 - .../internal/gcimporter/newInterface11.go | 14 - .../tools/internal/gcimporter/predeclared.go | 91 + .../x/tools/internal/gcimporter/support.go | 30 + .../internal/gcimporter/support_go118.go | 34 - .../x/tools/internal/gcimporter/unified_no.go | 10 - .../tools/internal/gcimporter/unified_yes.go | 10 - .../tools/internal/gcimporter/ureader_yes.go | 59 +- .../x/tools/internal/gocommand/invoke.go | 60 +- .../internal/gocommand/invoke_notunix.go | 13 + .../x/tools/internal/gocommand/invoke_unix.go | 13 + .../internal/packagesinternal/packages.go | 6 +- .../x/tools/internal/pkgbits/decoder.go | 38 +- .../x/tools/internal/pkgbits/encoder.go | 43 +- .../x/tools/internal/pkgbits/frames_go1.go | 21 - .../x/tools/internal/pkgbits/frames_go17.go | 28 - .../x/tools/internal/pkgbits/support.go | 2 +- .../x/tools/internal/pkgbits/sync.go | 23 + .../internal/pkgbits/syncmarker_string.go | 7 +- .../x/tools/internal/pkgbits/version.go | 85 + .../x/tools/internal/stdlib/manifest.go | 221 +- .../internal/tokeninternal/tokeninternal.go | 137 - .../x/tools/internal/typeparams/common.go | 68 + .../x/tools/internal/typeparams/coretype.go | 155 + .../x/tools/internal/typeparams/free.go | 131 + .../x/tools/internal/typeparams/normalize.go | 218 + .../x/tools/internal/typeparams/termlist.go | 163 + .../x/tools/internal/typeparams/typeterm.go | 169 + .../x/tools/internal/typesinternal/element.go | 133 + .../tools/internal/typesinternal/errorcode.go | 10 +- .../tools/internal/typesinternal/qualifier.go | 46 + .../x/tools/internal/typesinternal/recv.go | 11 +- .../x/tools/internal/typesinternal/types.go | 62 + .../x/tools/internal/typesinternal/varkind.go | 40 + .../tools/internal/typesinternal/zerovalue.go | 392 + .../x/tools/internal/versions/toolchain.go | 14 - .../internal/versions/toolchain_go119.go | 14 - .../x/tools/internal/versions/types.go | 28 +- .../x/tools/internal/versions/types_go121.go | 30 - .../x/tools/internal/versions/types_go122.go | 41 - vendor/gvisor.dev/gvisor/pkg/buffer/buffer.go | 7 +- .../gvisor/pkg/cpuid/cpuid_amd64.go | 23 +- .../pkg/cpuid/cpuid_amd64_state_autogen.go | 4 +- .../gvisor/pkg/cpuid/cpuid_arm64.go | 44 + .../pkg/cpuid/cpuid_arm64_state_autogen.go | 4 +- .../gvisor/pkg/cpuid/hwcap_amd64.go | 24 + .../gvisor/pkg/cpuid/hwcap_arm64.go | 79 + .../gvisor/pkg/cpuid/native_amd64.go | 34 +- .../gvisor/pkg/cpuid/native_arm64.go | 4 +- .../gvisor/pkg/cpuid/static_amd64.go | 4 +- .../gvisor/pkg/sleep/sleep_unsafe.go | 1 + .../pkg/sleep/sleep_unsafe_state_autogen.go | 29 + .../gvisor.dev/gvisor/pkg/state/addr_set.go | 66 +- vendor/gvisor.dev/gvisor/pkg/state/decode.go | 11 +- vendor/gvisor.dev/gvisor/pkg/state/encode.go | 13 +- vendor/gvisor.dev/gvisor/pkg/state/state.go | 4 +- vendor/gvisor.dev/gvisor/pkg/state/types.go | 2 +- .../gvisor.dev/gvisor/pkg/state/wire/wire.go | 189 +- vendor/gvisor.dev/gvisor/pkg/sync/aliases.go | 15 + .../gvisor/pkg/sync/runtime_go121_unsafe.go | 2 +- .../gvisor/pkg/sync/runtime_go124_unsafe.go | 14 + vendor/gvisor.dev/gvisor/pkg/tcpip/errors.go | 18 + .../gvisor/pkg/tcpip/header/ipv4.go | 65 + .../tcpip/header/ipv6_extension_headers.go | 78 +- .../internal/fragmentation/reassembler.go | 4 +- .../network/internal/ip/ip_state_autogen.go | 3 + .../pkg/tcpip/network/internal/ip/stats.go | 9 +- .../gvisor/pkg/tcpip/network/ipv4/ipv4.go | 19 +- .../gvisor/pkg/tcpip/network/ipv6/ipv6.go | 22 + .../gvisor/pkg/tcpip/network/ipv6/ndp.go | 3 + .../gvisor.dev/gvisor/pkg/tcpip/socketops.go | 15 + .../tcpip/stack/addressable_endpoint_state.go | 10 +- .../gvisor/pkg/tcpip/stack/bridge.go | 99 +- .../gvisor/pkg/tcpip/stack/gro/gro.go | 34 +- .../pkg/tcpip/stack/gro/gro_state_autogen.go | 108 + .../gvisor/pkg/tcpip/stack/iptables.go | 20 +- .../gvisor/pkg/tcpip/stack/neighbor_entry.go | 42 +- .../gvisor.dev/gvisor/pkg/tcpip/stack/nic.go | 13 +- .../gvisor/pkg/tcpip/stack/packet_buffer.go | 1 + .../gvisor/pkg/tcpip/stack/pending_packets.go | 7 +- .../gvisor/pkg/tcpip/stack/registration.go | 72 +- .../gvisor/pkg/tcpip/stack/save_restore.go | 29 + .../gvisor/pkg/tcpip/stack/stack.go | 140 +- .../pkg/tcpip/stack/stack_state_autogen.go | 989 +- vendor/gvisor.dev/gvisor/pkg/tcpip/tcpip.go | 19 +- .../gvisor/pkg/tcpip/tcpip_state_autogen.go | 63 + .../pkg/tcpip/transport/icmp/endpoint.go | 2 +- .../tcpip/transport/icmp/endpoint_state.go | 10 +- .../transport/icmp/icmp_state_autogen.go | 47 +- .../pkg/tcpip/transport/icmp/protocol.go | 3 + .../transport/internal/network/endpoint.go | 23 +- .../internal/network/network_state_autogen.go | 75 +- .../pkg/tcpip/transport/packet/endpoint.go | 2 +- .../tcpip/transport/packet/endpoint_state.go | 12 +- .../transport/packet/packet_state_autogen.go | 51 +- .../pkg/tcpip/transport/raw/endpoint.go | 2 +- .../pkg/tcpip/transport/raw/endpoint_state.go | 17 +- .../tcpip/transport/raw/raw_state_autogen.go | 51 +- .../gvisor/pkg/tcpip/transport/tcp/accept.go | 15 +- .../gvisor/pkg/tcpip/transport/tcp/connect.go | 187 +- .../gvisor/pkg/tcpip/transport/tcp/cubic.go | 22 +- .../pkg/tcpip/transport/tcp/dispatcher.go | 21 +- .../pkg/tcpip/transport/tcp/endpoint.go | 95 +- .../pkg/tcpip/transport/tcp/endpoint_state.go | 160 +- .../pkg/tcpip/transport/tcp/forwarder.go | 56 + .../pkg/tcpip/transport/tcp/protocol.go | 58 +- .../gvisor/pkg/tcpip/transport/tcp/rack.go | 11 +- .../gvisor/pkg/tcpip/transport/tcp/rcv.go | 6 +- .../gvisor/pkg/tcpip/transport/tcp/reno.go | 12 + .../gvisor/pkg/tcpip/transport/tcp/segment.go | 2 +- .../gvisor/pkg/tcpip/transport/tcp/snd.go | 110 +- .../{stack/tcp.go => transport/tcp/state.go} | 16 +- .../tcpip/transport/tcp/tcp_state_autogen.go | 833 +- .../pkg/tcpip/transport/udp/endpoint.go | 14 +- .../pkg/tcpip/transport/udp/endpoint_state.go | 16 +- .../pkg/tcpip/transport/udp/forwarder.go | 6 +- .../pkg/tcpip/transport/udp/protocol.go | 3 + .../tcpip/transport/udp/udp_state_autogen.go | 71 +- vendor/gvisor.dev/gvisor/pkg/waiter/waiter.go | 36 +- vendor/modules.txt | 178 +- vendor/tailscale.com/.golangci.yml | 7 - vendor/tailscale.com/ALPINE.txt | 2 +- vendor/tailscale.com/Dockerfile | 6 +- vendor/tailscale.com/Dockerfile.base | 11 +- vendor/tailscale.com/Makefile | 7 +- vendor/tailscale.com/README.md | 2 +- vendor/tailscale.com/VERSION.txt | 2 +- vendor/tailscale.com/appc/appconnector.go | 50 +- vendor/tailscale.com/atomicfile/atomicfile.go | 7 +- .../atomicfile/atomicfile_notwindows.go | 14 + .../atomicfile/atomicfile_windows.go | 33 + vendor/tailscale.com/atomicfile/mksyscall.go | 8 + .../atomicfile/zsyscall_windows.go | 52 + vendor/tailscale.com/build_dist.sh | 2 +- vendor/tailscale.com/build_docker.sh | 17 +- .../localclient.go => local/local.go} | 290 +- vendor/tailscale.com/client/tailscale/acl.go | 19 +- .../client/tailscale/apitype/apitype.go | 18 + .../tailscale.com/client/tailscale/devices.go | 19 +- vendor/tailscale.com/client/tailscale/dns.go | 8 +- vendor/tailscale.com/client/tailscale/keys.go | 16 +- .../client/tailscale/localclient_aliases.go | 106 + .../tailscale.com/client/tailscale/routes.go | 4 +- .../tailscale.com/client/tailscale/tailnet.go | 5 +- .../client/tailscale/tailscale.go | 85 +- vendor/tailscale.com/client/web/web.go | 120 +- .../clientupdate/clientupdate.go | 14 +- .../control/controlclient/auto.go | 83 +- .../control/controlclient/direct.go | 142 +- .../control/controlclient/errors.go | 51 + .../control/controlclient/map.go | 180 +- .../control/controlclient/noise.go | 42 +- .../control/controlclient/sign_supported.go | 13 +- .../control/controlhttp/client.go | 16 +- .../control/controlhttp/client_js.go | 5 +- .../control/controlhttp/constants.go | 17 +- .../controlhttpcommon/controlhttpcommon.go | 15 + .../control/controlhttp/server.go | 217 - .../control/controlknobs/controlknobs.go | 43 +- vendor/tailscale.com/derp/derp.go | 20 +- vendor/tailscale.com/derp/derp_server.go | 368 +- .../derp/derphttp/derphttp_client.go | 30 +- .../derp/derphttp/derphttp_server.go | 11 +- .../tailscale.com/derp/derphttp/websocket.go | 4 +- .../derp/derphttp/websocket_stub.go | 8 + .../tailscale.com/derp/dropreason_string.go | 33 - vendor/tailscale.com/drive/drive_view.go | 4 +- vendor/tailscale.com/envknob/envknob.go | 25 +- .../envknob/featureknob/featureknob.go | 67 + vendor/tailscale.com/envknob/features.go | 39 - .../{wgengine => feature}/capture/capture.go | 74 +- .../feature/condregister/condregister.go | 7 + .../feature/condregister/maybe_capture.go | 8 + .../feature/condregister/maybe_tap.go | 8 + .../feature/condregister/maybe_wakeonlan.go | 8 + vendor/tailscale.com/feature/feature.go | 54 + .../{net/tstun => feature/tap}/tap_linux.go | 205 +- .../feature/wakeonlan/wakeonlan.go | 243 + vendor/tailscale.com/go.toolchain.branch | 2 +- vendor/tailscale.com/go.toolchain.rev | 2 +- vendor/tailscale.com/health/health.go | 98 +- vendor/tailscale.com/health/state.go | 27 +- vendor/tailscale.com/hostinfo/hostinfo.go | 53 +- .../tailscale.com/hostinfo/hostinfo_linux.go | 13 +- vendor/tailscale.com/hostinfo/wol.go | 106 - vendor/tailscale.com/ipn/auditlog/auditlog.go | 466 + vendor/tailscale.com/ipn/backend.go | 30 +- vendor/tailscale.com/ipn/conf.go | 18 + vendor/tailscale.com/ipn/desktop/doc.go | 6 + vendor/tailscale.com/ipn/desktop/mksyscall.go | 24 + vendor/tailscale.com/ipn/desktop/session.go | 58 + vendor/tailscale.com/ipn/desktop/sessions.go | 60 + .../ipn/desktop/sessions_notwindows.go | 15 + .../ipn/desktop/sessions_windows.go | 672 + .../ipn/desktop/zsyscall_windows.go | 159 + vendor/tailscale.com/ipn/doc.go | 2 +- vendor/tailscale.com/ipn/ipn_clone.go | 74 + vendor/tailscale.com/ipn/ipn_view.go | 164 +- vendor/tailscale.com/ipn/ipnauth/access.go | 17 + vendor/tailscale.com/ipn/ipnauth/actor.go | 87 + .../ipn/ipnauth/actor_windows.go | 102 + .../ipn/ipnauth/ipnauth_notwindows.go | 4 +- .../ipn/ipnauth/ipnauth_windows.go | 10 +- vendor/tailscale.com/ipn/ipnauth/policy.go | 74 + vendor/tailscale.com/ipn/ipnauth/self.go | 51 + .../tailscale.com/ipn/ipnauth/test_actor.go | 48 + vendor/tailscale.com/ipn/ipnlocal/bus.go | 160 + vendor/tailscale.com/ipn/ipnlocal/c2n.go | 88 +- vendor/tailscale.com/ipn/ipnlocal/cert.go | 136 +- .../ipn/ipnlocal/desktop_sessions.go | 178 + vendor/tailscale.com/ipn/ipnlocal/drive.go | 8 +- vendor/tailscale.com/ipn/ipnlocal/expiry.go | 2 +- vendor/tailscale.com/ipn/ipnlocal/local.go | 1890 ++- .../ipn/ipnlocal/network-lock.go | 10 +- vendor/tailscale.com/ipn/ipnlocal/peerapi.go | 135 +- vendor/tailscale.com/ipn/ipnlocal/profiles.go | 271 +- vendor/tailscale.com/ipn/ipnlocal/serve.go | 133 +- vendor/tailscale.com/ipn/ipnlocal/ssh.go | 24 +- .../tailscale.com/ipn/ipnlocal/web_client.go | 14 +- .../ipn/ipnlocal/web_client_stub.go | 4 +- vendor/tailscale.com/ipn/ipnstate/ipnstate.go | 35 +- .../tailscale.com/ipn/localapi/debugderp.go | 33 +- vendor/tailscale.com/ipn/localapi/localapi.go | 174 +- vendor/tailscale.com/ipn/prefs.go | 11 + vendor/tailscale.com/ipn/serve.go | 250 +- .../ipn/store/awsstore/store_aws.go | 111 +- .../ipn/store/awsstore/store_aws_stub.go | 18 - .../ipn/store/kubestore/store_kube.go | 439 +- .../tailscale.com/ipn/store/mem/store_mem.go | 17 + vendor/tailscale.com/ipn/store/store_aws.go | 10 +- vendor/tailscale.com/kube/kubeapi/api.go | 65 +- .../tailscale.com/kube/kubeclient/client.go | 334 +- .../kube/kubeclient/fake_client.go | 24 +- .../tailscale.com/kube/kubetypes/metrics.go | 26 - vendor/tailscale.com/kube/kubetypes/types.go | 54 + vendor/tailscale.com/licenses/README.md | 35 + vendor/tailscale.com/licenses/android.md | 83 +- vendor/tailscale.com/licenses/apple.md | 76 +- vendor/tailscale.com/licenses/tailscale.md | 85 +- vendor/tailscale.com/licenses/windows.md | 73 +- vendor/tailscale.com/logpolicy/logpolicy.go | 214 +- vendor/tailscale.com/logtail/api.md | 4 +- vendor/tailscale.com/logtail/logtail.go | 31 +- vendor/tailscale.com/metrics/metrics.go | 35 + .../net/bakedroots/bakedroots.go | 149 + .../net/captivedetection/captivedetection.go | 36 +- .../net/captivedetection/endpoints.go | 2 +- vendor/tailscale.com/net/connstats/stats.go | 22 +- vendor/tailscale.com/net/dns/direct_linux.go | 52 +- vendor/tailscale.com/net/dns/manager.go | 72 +- .../tailscale.com/net/dns/manager_default.go | 2 +- .../tailscale.com/net/dns/manager_solaris.go | 14 + .../tailscale.com/net/dns/manager_windows.go | 74 +- vendor/tailscale.com/net/dns/nm.go | 4 +- vendor/tailscale.com/net/dns/resolvd.go | 3 +- vendor/tailscale.com/net/dns/resolved.go | 9 +- .../tailscale.com/net/dns/resolver/tsdns.go | 2 +- vendor/tailscale.com/net/ipset/ipset.go | 8 +- vendor/tailscale.com/net/netcheck/netcheck.go | 214 +- .../net/netmon/interfaces_android.go | 51 +- .../net/netmon/interfaces_linux.go | 37 +- vendor/tailscale.com/net/netmon/loghelper.go | 42 + vendor/tailscale.com/net/netmon/netmon.go | 2 +- .../tailscale.com/net/netmon/netmon_darwin.go | 14 +- vendor/tailscale.com/net/netmon/state.go | 31 +- .../tailscale.com/net/netutil/ip_forward.go | 26 + vendor/tailscale.com/net/packet/capture.go | 75 + vendor/tailscale.com/net/packet/geneve.go | 104 + vendor/tailscale.com/net/packet/packet.go | 8 - vendor/tailscale.com/net/portmapper/upnp.go | 5 +- vendor/tailscale.com/net/socks5/socks5.go | 131 +- .../net/sockstats/sockstats_tsgo.go | 8 +- .../net/tlsdial/blockblame/blockblame.go | 104 + vendor/tailscale.com/net/tlsdial/tlsdial.go | 163 +- vendor/tailscale.com/net/tsaddr/tsaddr.go | 21 +- vendor/tailscale.com/net/tsdial/dnsmap.go | 9 +- .../net/tshttpproxy/tshttpproxy_synology.go | 17 +- .../net/tstun/tap_unsupported.go | 8 - vendor/tailscale.com/net/tstun/tstun_stub.go | 2 +- vendor/tailscale.com/net/tstun/tun.go | 11 +- vendor/tailscale.com/net/tstun/wrap.go | 140 +- vendor/tailscale.com/paths/paths_unix.go | 2 +- vendor/tailscale.com/safesocket/safesocket.go | 6 +- .../safesocket/safesocket_darwin.go | 395 +- vendor/tailscale.com/syncs/shardedint.go | 69 + vendor/tailscale.com/syncs/shardvalue.go | 36 + vendor/tailscale.com/syncs/shardvalue_go.go | 36 + .../syncs/shardvalue_tailscale.go | 24 + vendor/tailscale.com/syncs/syncs.go | 62 + vendor/tailscale.com/tailcfg/c2ntypes.go | 15 + vendor/tailscale.com/tailcfg/derpmap.go | 34 +- vendor/tailscale.com/tailcfg/tailcfg.go | 491 +- vendor/tailscale.com/tailcfg/tailcfg_clone.go | 37 +- vendor/tailscale.com/tailcfg/tailcfg_view.go | 227 +- vendor/tailscale.com/tempfork/acme/README.md | 14 + .../tempfork}/acme/acme.go | 6 +- .../tempfork}/acme/http.go | 21 +- .../tempfork}/acme/jws.go | 0 .../tempfork}/acme/rfc8555.go | 0 .../tempfork}/acme/types.go | 13 +- .../tempfork}/acme/version_go112.go | 0 .../tailscale.com/tempfork/httprec/httprec.go | 258 + vendor/tailscale.com/tsd/tsd.go | 8 + vendor/tailscale.com/tsnet/tsnet.go | 153 +- vendor/tailscale.com/tsweb/varz/varz.go | 10 +- vendor/tailscale.com/types/bools/bools.go | 37 + .../types/dnstype/dnstype_view.go | 4 +- vendor/tailscale.com/types/lazy/deferred.go | 9 +- vendor/tailscale.com/types/lazy/lazy.go | 35 - vendor/tailscale.com/types/netmap/netmap.go | 122 +- vendor/tailscale.com/types/netmap/nodemut.go | 6 +- vendor/tailscale.com/types/opt/value.go | 18 +- vendor/tailscale.com/types/persist/persist.go | 22 +- .../types/persist/persist_clone.go | 15 +- .../types/persist/persist_view.go | 22 +- vendor/tailscale.com/types/result/result.go | 49 + vendor/tailscale.com/types/views/views.go | 273 +- .../util/clientmetric/clientmetric.go | 51 + vendor/tailscale.com/util/dnsname/dnsname.go | 21 +- .../util/goroutines/goroutines.go | 2 +- .../tailscale.com/util/goroutines/tracker.go | 66 + .../tailscale.com/util/lineiter/lineiter.go | 72 + .../tailscale.com/util/lineread/lineread.go | 37 - vendor/tailscale.com/util/linuxfw/nftables.go | 6 +- vendor/tailscale.com/util/set/slice.go | 4 +- vendor/tailscale.com/util/slicesx/slicesx.go | 51 + .../util/syspolicy/caching_handler.go | 122 - .../tailscale.com/util/syspolicy/handler.go | 134 +- .../util/syspolicy/handler_windows.go | 105 - .../util/syspolicy/internal/internal.go | 7 +- .../syspolicy/internal/metrics/metrics.go | 319 + .../internal/metrics/test_handler.go | 88 + .../util/syspolicy/policy_keys.go | 138 +- .../util/syspolicy/policy_keys_windows.go | 38 - .../util/syspolicy/rsop/change_callbacks.go | 107 + .../util/syspolicy/rsop/resultant_policy.go | 456 + .../tailscale.com/util/syspolicy/rsop/rsop.go | 174 + .../util/syspolicy/rsop/store_registration.go | 98 + .../util/syspolicy/setting/key.go | 2 +- .../util/syspolicy/setting/origin.go | 21 +- .../util/syspolicy/setting/policy_scope.go | 3 + .../util/syspolicy/setting/raw_item.go | 133 +- .../util/syspolicy/setting/setting.go | 3 + .../util/syspolicy/setting/snapshot.go | 50 + .../util/syspolicy/setting/summary.go | 21 +- .../util/syspolicy/source/env_policy_store.go | 159 + .../util/syspolicy/source/policy_reader.go | 394 + .../util/syspolicy/source/policy_source.go | 146 + .../syspolicy/source/policy_store_windows.go | 528 + .../util/syspolicy/source/test_store.go | 449 + .../tailscale.com/util/syspolicy/syspolicy.go | 152 +- .../util/syspolicy/syspolicy_windows.go | 92 + vendor/tailscale.com/util/uniq/slice.go | 62 - .../tailscale.com/util/usermetric/metrics.go | 85 + .../util/usermetric/usermetric.go | 14 + .../util/winutil/gp/policylock_windows.go | 38 +- vendor/tailscale.com/version-embed.go | 1 + vendor/tailscale.com/version/distro/distro.go | 27 +- vendor/tailscale.com/version/print.go | 5 +- vendor/tailscale.com/version/prop.go | 45 +- vendor/tailscale.com/version/version.go | 43 +- .../version/version_checkformat.go | 17 + .../wgengine/capture/ts-dissector.lua | 169 - .../tailscale.com/wgengine/filter/filter.go | 51 +- .../wgengine/magicsock/debughttp.go | 3 +- .../tailscale.com/wgengine/magicsock/derp.go | 58 +- .../wgengine/magicsock/endpoint.go | 57 +- .../wgengine/magicsock/magicsock.go | 293 +- .../wgengine/magicsock/magicsock_notplan9.go | 31 + .../wgengine/magicsock/magicsock_plan9.go | 12 + .../wgengine/netstack/gro/gro.go | 1 + .../wgengine/netstack/link_endpoint.go | 53 +- .../wgengine/netstack/netstack.go | 148 +- vendor/tailscale.com/wgengine/pendopen.go | 17 +- .../wgengine/router/router_linux.go | 52 +- vendor/tailscale.com/wgengine/userspace.go | 14 +- vendor/tailscale.com/wgengine/watchdog.go | 4 +- .../wgengine/wgcfg/nmcfg/nmcfg.go | 32 +- vendor/tailscale.com/wgengine/wgengine.go | 4 +- 882 files changed, 68930 insertions(+), 24201 deletions(-) create mode 100644 vendor/github.com/aws/aws-sdk-go-v2/aws/accountid_endpoint_mode.go create mode 100644 vendor/github.com/aws/aws-sdk-go-v2/aws/checksum.go delete mode 100644 vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/metrics.go create mode 100644 vendor/github.com/aws/aws-sdk-go-v2/aws/ratelimit/none.go create mode 100644 vendor/github.com/aws/aws-sdk-go-v2/aws/retry/attempt_metrics.go create mode 100644 vendor/github.com/aws/aws-sdk-go-v2/internal/context/context.go create mode 100644 vendor/github.com/aws/aws-sdk-go-v2/internal/middleware/middleware.go create mode 100644 vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRoot.go create mode 100644 vendor/github.com/aws/smithy-go/changelog-template.json create mode 100644 vendor/github.com/aws/smithy-go/metrics/metrics.go create mode 100644 vendor/github.com/aws/smithy-go/metrics/nop.go create mode 100644 vendor/github.com/aws/smithy-go/middleware/context.go create mode 100644 vendor/github.com/aws/smithy-go/tracing/context.go create mode 100644 vendor/github.com/aws/smithy-go/tracing/nop.go create mode 100644 vendor/github.com/aws/smithy-go/tracing/tracing.go create mode 100644 vendor/github.com/aws/smithy-go/transport/http/metrics.go delete mode 100644 vendor/github.com/bits-and-blooms/bitset/.gitignore delete mode 100644 vendor/github.com/bits-and-blooms/bitset/.travis.yml delete mode 100644 vendor/github.com/bits-and-blooms/bitset/LICENSE delete mode 100644 vendor/github.com/bits-and-blooms/bitset/README.md delete mode 100644 vendor/github.com/bits-and-blooms/bitset/SECURITY.md delete mode 100644 vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml delete mode 100644 vendor/github.com/bits-and-blooms/bitset/bitset.go delete mode 100644 vendor/github.com/bits-and-blooms/bitset/popcnt.go delete mode 100644 vendor/github.com/bits-and-blooms/bitset/popcnt_19.go delete mode 100644 vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go delete mode 100644 vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s delete mode 100644 vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go delete mode 100644 vendor/github.com/bits-and-blooms/bitset/select.go delete mode 100644 vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go delete mode 100644 vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go create mode 100644 vendor/github.com/fxamacker/cbor/v2/common.go create mode 100644 vendor/github.com/gaissmai/bart/.gitignore create mode 100644 vendor/github.com/gaissmai/bart/.golangci.yml create mode 100644 vendor/github.com/gaissmai/bart/SECURITY.md create mode 100644 vendor/github.com/gaissmai/bart/allot_lookuptbl.go create mode 100644 vendor/github.com/gaissmai/bart/internal/bitset/bitset.go create mode 100644 vendor/github.com/gaissmai/bart/internal/sparse/array.go create mode 100644 vendor/github.com/gaissmai/bart/lpm_lookuptbl.go create mode 100644 vendor/github.com/gaissmai/bart/overlaps.go delete mode 100644 vendor/github.com/go-json-experiment/json/benchmark-marshal-concrete.png delete mode 100644 vendor/github.com/go-json-experiment/json/benchmark-marshal-interface.png delete mode 100644 vendor/github.com/go-json-experiment/json/benchmark-marshal-rawvalue.png delete mode 100644 vendor/github.com/go-json-experiment/json/benchmark-unmarshal-concrete.png delete mode 100644 vendor/github.com/go-json-experiment/json/benchmark-unmarshal-interface.png delete mode 100644 vendor/github.com/go-json-experiment/json/benchmark-unmarshal-rawvalue.png create mode 100644 vendor/github.com/go-json-experiment/json/migrate.sh delete mode 100644 vendor/github.com/illarion/gonotify/v2/README.md delete mode 100644 vendor/github.com/illarion/gonotify/v2/inotify.go rename vendor/github.com/illarion/gonotify/{v2 => v3}/.gitignore (100%) rename vendor/github.com/illarion/gonotify/{v2 => v3}/LICENSE (100%) create mode 100644 vendor/github.com/illarion/gonotify/v3/README.md rename vendor/github.com/illarion/gonotify/{v2 => v3}/dirwatcher.go (69%) rename vendor/github.com/illarion/gonotify/{v2 => v3}/event.go (99%) rename vendor/github.com/illarion/gonotify/{v2 => v3}/filewatcher.go (63%) create mode 100644 vendor/github.com/illarion/gonotify/v3/inotify.go create mode 100644 vendor/github.com/illarion/gonotify/v3/syscallf/rm_watch.go delete mode 100644 vendor/github.com/josharian/native/doc.go delete mode 100644 vendor/github.com/josharian/native/endian_generic.go delete mode 100644 vendor/github.com/josharian/native/license delete mode 100644 vendor/github.com/josharian/native/readme.md delete mode 100644 vendor/github.com/tailscale/golang-x-crypto/LICENSE delete mode 100644 vendor/github.com/tailscale/golang-x-crypto/PATENTS delete mode 100644 vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/mac_noasm.go delete mode 100644 vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/poly1305.go delete mode 100644 vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_amd64.go delete mode 100644 vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_amd64.s delete mode 100644 vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_generic.go delete mode 100644 vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_ppc64le.go delete mode 100644 vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_ppc64le.s delete mode 100644 vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_s390x.go delete mode 100644 vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_s390x.s create mode 100644 vendor/github.com/tailscale/peercred/peercred_solaris.go create mode 100644 vendor/github.com/tailscale/web-client-prebuilt/build/assets/index-BbZBz4S-.js.gz delete mode 100644 vendor/github.com/tailscale/web-client-prebuilt/build/assets/index-D59OWpX6.css.gz delete mode 100644 vendor/github.com/tailscale/web-client-prebuilt/build/assets/index-DUHvXbWu.js.gz create mode 100644 vendor/github.com/tailscale/web-client-prebuilt/build/assets/index-DVk8gqX9.css.gz delete mode 100644 vendor/github.com/tcnksm/go-httpstat/.travis.yml delete mode 100644 vendor/github.com/tcnksm/go-httpstat/LICENSE delete mode 100644 vendor/github.com/tcnksm/go-httpstat/Makefile delete mode 100644 vendor/github.com/tcnksm/go-httpstat/README.md delete mode 100644 vendor/github.com/tcnksm/go-httpstat/go18.go delete mode 100644 vendor/github.com/tcnksm/go-httpstat/httpstat.go delete mode 100644 vendor/github.com/tcnksm/go-httpstat/pre_go18.go delete mode 100644 vendor/github.com/u-root/uio/uio/linewriter.go delete mode 100644 vendor/github.com/u-root/uio/uio/multiwriter.go rename vendor/golang.org/x/crypto/chacha20/{chacha_ppc64le.go => chacha_ppc64x.go} (89%) rename vendor/golang.org/x/crypto/chacha20/{chacha_ppc64le.s => chacha_ppc64x.s} (76%) rename vendor/golang.org/x/crypto/internal/poly1305/{sum_ppc64le.go => sum_ppc64x.go} (95%) rename vendor/golang.org/x/crypto/internal/poly1305/{sum_ppc64le.s => sum_ppc64x.s} (89%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/buffer.go (100%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/certs.go (100%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/channel.go (100%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/cipher.go (99%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/client.go (100%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/client_auth.go (96%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/common.go (100%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/connection.go (94%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/doc.go (95%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/handshake.go (92%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/internal/bcrypt_pbkdf/bcrypt_pbkdf.go (100%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/kex.go (100%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/keys.go (95%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/mac.go (100%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/messages.go (100%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/mux.go (100%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/server.go (73%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/session.go (100%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/ssh_gss.go (100%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/streamlocal.go (100%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/tcpip.go (100%) rename vendor/{github.com/tailscale/golang-x-crypto => golang.org/x/crypto}/ssh/transport.go (100%) create mode 100644 vendor/golang.org/x/net/http2/config.go create mode 100644 vendor/golang.org/x/net/http2/config_go124.go create mode 100644 vendor/golang.org/x/net/http2/config_pre_go124.go create mode 100644 vendor/golang.org/x/net/http2/unencrypted.go create mode 100644 vendor/golang.org/x/net/internal/httpcommon/ascii.go rename vendor/golang.org/x/net/{http2 => internal/httpcommon}/headermap.go (74%) create mode 100644 vendor/golang.org/x/net/internal/httpcommon/request.go create mode 100644 vendor/golang.org/x/sys/cpu/asm_darwin_x86_gc.s create mode 100644 vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go rename vendor/golang.org/x/sys/cpu/{cpu_x86.s => cpu_gc_x86.s} (94%) create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go rename vendor/golang.org/x/{tools/internal/versions/toolchain_go121.go => sys/cpu/cpu_other_x86.go} (50%) create mode 100644 vendor/golang.org/x/sys/cpu/syscall_darwin_x86_gc.go create mode 100644 vendor/golang.org/x/sys/unix/auxv.go create mode 100644 vendor/golang.org/x/sys/unix/auxv_unsupported.go create mode 100644 vendor/golang.org/x/sys/unix/vgetrandom_linux.go rename vendor/golang.org/x/{tools/internal/versions/toolchain_go120.go => sys/unix/vgetrandom_unsupported.go} (56%) create mode 100644 vendor/golang.org/x/tools/go/types/typeutil/callee.go create mode 100644 vendor/golang.org/x/tools/go/types/typeutil/imports.go create mode 100644 vendor/golang.org/x/tools/go/types/typeutil/map.go create mode 100644 vendor/golang.org/x/tools/go/types/typeutil/methodsetcache.go create mode 100644 vendor/golang.org/x/tools/go/types/typeutil/ui.go delete mode 100644 vendor/golang.org/x/tools/internal/aliases/aliases_go121.go create mode 100644 vendor/golang.org/x/tools/internal/gcimporter/iimport_go122.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/newInterface10.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/newInterface11.go create mode 100644 vendor/golang.org/x/tools/internal/gcimporter/predeclared.go create mode 100644 vendor/golang.org/x/tools/internal/gcimporter/support.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/support_go118.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/unified_no.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/unified_yes.go create mode 100644 vendor/golang.org/x/tools/internal/gocommand/invoke_notunix.go create mode 100644 vendor/golang.org/x/tools/internal/gocommand/invoke_unix.go delete mode 100644 vendor/golang.org/x/tools/internal/pkgbits/frames_go1.go delete mode 100644 vendor/golang.org/x/tools/internal/pkgbits/frames_go17.go create mode 100644 vendor/golang.org/x/tools/internal/pkgbits/version.go delete mode 100644 vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/common.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/coretype.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/free.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/normalize.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/termlist.go create mode 100644 vendor/golang.org/x/tools/internal/typeparams/typeterm.go create mode 100644 vendor/golang.org/x/tools/internal/typesinternal/element.go create mode 100644 vendor/golang.org/x/tools/internal/typesinternal/qualifier.go create mode 100644 vendor/golang.org/x/tools/internal/typesinternal/varkind.go create mode 100644 vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go delete mode 100644 vendor/golang.org/x/tools/internal/versions/toolchain.go delete mode 100644 vendor/golang.org/x/tools/internal/versions/toolchain_go119.go delete mode 100644 vendor/golang.org/x/tools/internal/versions/types_go121.go delete mode 100644 vendor/golang.org/x/tools/internal/versions/types_go122.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/cpuid/hwcap_amd64.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/cpuid/hwcap_arm64.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/sync/runtime_go124_unsafe.go create mode 100644 vendor/gvisor.dev/gvisor/pkg/tcpip/stack/save_restore.go rename vendor/gvisor.dev/gvisor/pkg/tcpip/{stack/tcp.go => transport/tcp/state.go} (97%) create mode 100644 vendor/tailscale.com/atomicfile/atomicfile_notwindows.go create mode 100644 vendor/tailscale.com/atomicfile/atomicfile_windows.go create mode 100644 vendor/tailscale.com/atomicfile/mksyscall.go create mode 100644 vendor/tailscale.com/atomicfile/zsyscall_windows.go rename vendor/tailscale.com/client/{tailscale/localclient.go => local/local.go} (79%) create mode 100644 vendor/tailscale.com/client/tailscale/localclient_aliases.go create mode 100644 vendor/tailscale.com/control/controlclient/errors.go create mode 100644 vendor/tailscale.com/control/controlhttp/controlhttpcommon/controlhttpcommon.go delete mode 100644 vendor/tailscale.com/control/controlhttp/server.go create mode 100644 vendor/tailscale.com/derp/derphttp/websocket_stub.go delete mode 100644 vendor/tailscale.com/derp/dropreason_string.go create mode 100644 vendor/tailscale.com/envknob/featureknob/featureknob.go delete mode 100644 vendor/tailscale.com/envknob/features.go rename vendor/tailscale.com/{wgengine => feature}/capture/capture.go (79%) create mode 100644 vendor/tailscale.com/feature/condregister/condregister.go create mode 100644 vendor/tailscale.com/feature/condregister/maybe_capture.go create mode 100644 vendor/tailscale.com/feature/condregister/maybe_tap.go create mode 100644 vendor/tailscale.com/feature/condregister/maybe_wakeonlan.go create mode 100644 vendor/tailscale.com/feature/feature.go rename vendor/tailscale.com/{net/tstun => feature/tap}/tap_linux.go (66%) create mode 100644 vendor/tailscale.com/feature/wakeonlan/wakeonlan.go delete mode 100644 vendor/tailscale.com/hostinfo/wol.go create mode 100644 vendor/tailscale.com/ipn/auditlog/auditlog.go create mode 100644 vendor/tailscale.com/ipn/desktop/doc.go create mode 100644 vendor/tailscale.com/ipn/desktop/mksyscall.go create mode 100644 vendor/tailscale.com/ipn/desktop/session.go create mode 100644 vendor/tailscale.com/ipn/desktop/sessions.go create mode 100644 vendor/tailscale.com/ipn/desktop/sessions_notwindows.go create mode 100644 vendor/tailscale.com/ipn/desktop/sessions_windows.go create mode 100644 vendor/tailscale.com/ipn/desktop/zsyscall_windows.go create mode 100644 vendor/tailscale.com/ipn/ipnauth/access.go create mode 100644 vendor/tailscale.com/ipn/ipnauth/actor_windows.go create mode 100644 vendor/tailscale.com/ipn/ipnauth/policy.go create mode 100644 vendor/tailscale.com/ipn/ipnauth/self.go create mode 100644 vendor/tailscale.com/ipn/ipnauth/test_actor.go create mode 100644 vendor/tailscale.com/ipn/ipnlocal/bus.go create mode 100644 vendor/tailscale.com/ipn/ipnlocal/desktop_sessions.go delete mode 100644 vendor/tailscale.com/ipn/store/awsstore/store_aws_stub.go delete mode 100644 vendor/tailscale.com/kube/kubetypes/metrics.go create mode 100644 vendor/tailscale.com/kube/kubetypes/types.go create mode 100644 vendor/tailscale.com/licenses/README.md create mode 100644 vendor/tailscale.com/net/bakedroots/bakedroots.go create mode 100644 vendor/tailscale.com/net/dns/manager_solaris.go create mode 100644 vendor/tailscale.com/net/netmon/loghelper.go create mode 100644 vendor/tailscale.com/net/packet/capture.go create mode 100644 vendor/tailscale.com/net/packet/geneve.go create mode 100644 vendor/tailscale.com/net/tlsdial/blockblame/blockblame.go delete mode 100644 vendor/tailscale.com/net/tstun/tap_unsupported.go create mode 100644 vendor/tailscale.com/syncs/shardedint.go create mode 100644 vendor/tailscale.com/syncs/shardvalue.go create mode 100644 vendor/tailscale.com/syncs/shardvalue_go.go create mode 100644 vendor/tailscale.com/syncs/shardvalue_tailscale.go create mode 100644 vendor/tailscale.com/tempfork/acme/README.md rename vendor/{github.com/tailscale/golang-x-crypto => tailscale.com/tempfork}/acme/acme.go (99%) rename vendor/{github.com/tailscale/golang-x-crypto => tailscale.com/tempfork}/acme/http.go (96%) rename vendor/{github.com/tailscale/golang-x-crypto => tailscale.com/tempfork}/acme/jws.go (100%) rename vendor/{github.com/tailscale/golang-x-crypto => tailscale.com/tempfork}/acme/rfc8555.go (100%) rename vendor/{github.com/tailscale/golang-x-crypto => tailscale.com/tempfork}/acme/types.go (97%) rename vendor/{github.com/tailscale/golang-x-crypto => tailscale.com/tempfork}/acme/version_go112.go (100%) create mode 100644 vendor/tailscale.com/tempfork/httprec/httprec.go create mode 100644 vendor/tailscale.com/types/bools/bools.go create mode 100644 vendor/tailscale.com/types/result/result.go create mode 100644 vendor/tailscale.com/util/goroutines/tracker.go create mode 100644 vendor/tailscale.com/util/lineiter/lineiter.go delete mode 100644 vendor/tailscale.com/util/lineread/lineread.go delete mode 100644 vendor/tailscale.com/util/syspolicy/caching_handler.go delete mode 100644 vendor/tailscale.com/util/syspolicy/handler_windows.go create mode 100644 vendor/tailscale.com/util/syspolicy/internal/metrics/metrics.go create mode 100644 vendor/tailscale.com/util/syspolicy/internal/metrics/test_handler.go delete mode 100644 vendor/tailscale.com/util/syspolicy/policy_keys_windows.go create mode 100644 vendor/tailscale.com/util/syspolicy/rsop/change_callbacks.go create mode 100644 vendor/tailscale.com/util/syspolicy/rsop/resultant_policy.go create mode 100644 vendor/tailscale.com/util/syspolicy/rsop/rsop.go create mode 100644 vendor/tailscale.com/util/syspolicy/rsop/store_registration.go create mode 100644 vendor/tailscale.com/util/syspolicy/source/env_policy_store.go create mode 100644 vendor/tailscale.com/util/syspolicy/source/policy_reader.go create mode 100644 vendor/tailscale.com/util/syspolicy/source/policy_source.go create mode 100644 vendor/tailscale.com/util/syspolicy/source/policy_store_windows.go create mode 100644 vendor/tailscale.com/util/syspolicy/source/test_store.go create mode 100644 vendor/tailscale.com/util/syspolicy/syspolicy_windows.go delete mode 100644 vendor/tailscale.com/util/uniq/slice.go create mode 100644 vendor/tailscale.com/util/usermetric/metrics.go create mode 100644 vendor/tailscale.com/version/version_checkformat.go delete mode 100644 vendor/tailscale.com/wgengine/capture/ts-dissector.lua create mode 100644 vendor/tailscale.com/wgengine/magicsock/magicsock_notplan9.go create mode 100644 vendor/tailscale.com/wgengine/magicsock/magicsock_plan9.go diff --git a/flake.lock b/flake.lock index 6e84dae..5e8a32a 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1730200266, - "narHash": "sha256-l253w0XMT8nWHGXuXqyiIC/bMvh1VRszGXgdpQlfhvU=", + "lastModified": 1743964447, + "narHash": "sha256-nEo1t3Q0F+0jQ36HJfbJtiRU4OI+/0jX/iITURKe3EE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "807e9154dcb16384b1b765ebe9cd2bba2ac287fd", + "rev": "063dece00c5a77e4a0ea24e5e5a5bd75232806f8", "type": "github" }, "original": { diff --git a/go.mod b/go.mod index 6ab8cd4..9ec83cf 100644 --- a/go.mod +++ b/go.mod @@ -1,37 +1,36 @@ module ben.soroos.net/tsnet-proxy -go 1.23.1 +go 1.24.0 -toolchain go1.23.2 +toolchain go1.24.1 -require tailscale.com v1.76.3 +require tailscale.com v1.82.0 require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/akutz/memconn v0.1.0 // indirect github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect - github.com/aws/aws-sdk-go-v2 v1.24.1 // indirect - github.com/aws/aws-sdk-go-v2/config v1.26.5 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.16.16 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect + github.com/aws/aws-sdk-go-v2 v1.36.0 // indirect + github.com/aws/aws-sdk-go-v2/config v1.29.5 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.58 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.31 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.31 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.12 // indirect github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect - github.com/aws/smithy-go v1.19.0 // indirect - github.com/bits-and-blooms/bitset v1.13.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.14 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.33.13 // indirect + github.com/aws/smithy-go v1.22.2 // indirect github.com/coder/websocket v1.8.12 // indirect github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e // indirect - github.com/fxamacker/cbor/v2 v2.6.0 // indirect - github.com/gaissmai/bart v0.11.1 // indirect - github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/gaissmai/bart v0.18.0 // indirect + github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect @@ -39,18 +38,17 @@ require ( github.com/google/go-cmp v0.6.0 // indirect github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/gorilla/csrf v1.7.2 // indirect + github.com/gorilla/csrf v1.7.3-0.20250123201450-9dd6af1f6d30 // indirect github.com/gorilla/securecookie v1.1.2 // indirect github.com/hdevalence/ed25519consensus v0.2.0 // indirect - github.com/illarion/gonotify/v2 v2.0.3 // indirect + github.com/illarion/gonotify/v3 v3.0.2 // indirect github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 // indirect github.com/jsimonetti/rtnetlink v1.4.0 // indirect - github.com/klauspost/compress v1.17.4 // indirect + github.com/klauspost/compress v1.17.11 // indirect github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a // indirect github.com/mdlayher/genetlink v1.3.2 // indirect - github.com/mdlayher/netlink v1.7.2 // indirect + github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect github.com/mdlayher/sdnotify v1.0.0 // indirect github.com/mdlayher/socket v0.5.0 // indirect github.com/miekg/dns v1.1.58 // indirect @@ -60,30 +58,28 @@ require ( github.com/safchain/ethtool v0.3.0 // indirect github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect - github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4 // indirect github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a // indirect github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 // indirect - github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4 // indirect - github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1 // indirect - github.com/tailscale/wireguard-go v0.0.0-20240905161824-799c1978fafc // indirect - github.com/tcnksm/go-httpstat v0.2.0 // indirect - github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e // indirect + github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc // indirect + github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 // indirect + github.com/tailscale/wireguard-go v0.0.0-20250107165329-0b8b35511f19 // indirect + github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect github.com/vishvananda/netns v0.0.4 // indirect github.com/x448/float16 v0.8.4 // indirect - go4.org/mem v0.0.0-20220726221520-4f986261bf13 // indirect + go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect - golang.org/x/crypto v0.25.0 // indirect - golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect - golang.org/x/mod v0.19.0 // indirect - golang.org/x/net v0.27.0 // indirect - golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.22.0 // indirect - golang.org/x/term v0.22.0 // indirect - golang.org/x/text v0.16.0 // indirect - golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.23.0 // indirect + golang.org/x/crypto v0.35.0 // indirect + golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/net v0.36.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/term v0.29.0 // indirect + golang.org/x/text v0.22.0 // indirect + golang.org/x/time v0.10.0 // indirect + golang.org/x/tools v0.30.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect - gvisor.dev/gvisor v0.0.0-20240722211153-64c016c92987 // indirect + gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633 // indirect ) diff --git a/go.sum b/go.sum index 0d9b13d..7e7d91c 100644 --- a/go.sum +++ b/go.sum @@ -10,36 +10,34 @@ github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7V github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= -github.com/aws/aws-sdk-go-v2 v1.24.1 h1:xAojnj+ktS95YZlDf0zxWBkbFtymPeDP+rvUQIH3uAU= -github.com/aws/aws-sdk-go-v2 v1.24.1/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= -github.com/aws/aws-sdk-go-v2/config v1.26.5 h1:lodGSevz7d+kkFJodfauThRxK9mdJbyutUxGq1NNhvw= -github.com/aws/aws-sdk-go-v2/config v1.26.5/go.mod h1:DxHrz6diQJOc9EwDslVRh84VjjrE17g+pVZXUeSxaDU= -github.com/aws/aws-sdk-go-v2/credentials v1.16.16 h1:8q6Rliyv0aUFAVtzaldUEcS+T5gbadPbWdV1WcAddK8= -github.com/aws/aws-sdk-go-v2/credentials v1.16.16/go.mod h1:UHVZrdUsv63hPXFo1H7c5fEneoVo9UXiz36QG1GEPi0= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 h1:c5I5iH+DZcH3xOIMlz3/tCKJDaHFwYEmxvlh2fAcFo8= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11/go.mod h1:cRrYDYAMUohBJUtUnOhydaMHtiK/1NZ0Otc9lIb6O0Y= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 h1:vF+Zgd9s+H4vOXd5BMaPWykta2a6Ih0AKLq/X6NYKn4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10/go.mod h1:6BkRjejp/GR4411UGqkX8+wFMbFbqsUIimfK4XjOKR4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 h1:nYPe006ktcqUji8S2mqXf9c/7NdiKriOwMvWQHgYztw= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10/go.mod h1:6UV4SZkVvmODfXKql4LCbaZUpF7HO2BX38FgBf9ZOLw= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 h1:DBYTXwIGQSGs9w4jKm60F5dmCQ3EEruxdc0MFh+3EY4= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10/go.mod h1:wohMUQiFdzo0NtxbBg0mSRGZ4vL3n0dKjLTINdcIino= +github.com/aws/aws-sdk-go-v2 v1.36.0 h1:b1wM5CcE65Ujwn565qcwgtOTT1aT4ADOHHgglKjG7fk= +github.com/aws/aws-sdk-go-v2 v1.36.0/go.mod h1:5PMILGVKiW32oDzjj6RU52yrNrDPUHcbZQYr1sM7qmM= +github.com/aws/aws-sdk-go-v2/config v1.29.5 h1:4lS2IB+wwkj5J43Tq/AwvnscBerBJtQQ6YS7puzCI1k= +github.com/aws/aws-sdk-go-v2/config v1.29.5/go.mod h1:SNzldMlDVbN6nWxM7XsUiNXPSa1LWlqiXtvh/1PrJGg= +github.com/aws/aws-sdk-go-v2/credentials v1.17.58 h1:/d7FUpAPU8Lf2KUdjniQvfNdlMID0Sd9pS23FJ3SS9Y= +github.com/aws/aws-sdk-go-v2/credentials v1.17.58/go.mod h1:aVYW33Ow10CyMQGFgC0ptMRIqJWvJ4nxZb0sUiuQT/A= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27 h1:7lOW8NUwE9UZekS1DYoiPdVAqZ6A+LheHWb+mHbNOq8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27/go.mod h1:w1BASFIPOPUae7AgaH4SbjNbfdkxuggLyGfNFTn8ITY= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.31 h1:lWm9ucLSRFiI4dQQafLrEOmEDGry3Swrz0BIRdiHJqQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.31/go.mod h1:Huu6GG0YTfbPphQkDSo4dEGmQRTKb9k9G7RdtyQWxuI= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.31 h1:ACxDklUKKXb48+eg5ROZXi1vDgfMyfIA/WyvqHcHI0o= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.31/go.mod h1:yadnfsDwqXeVaohbGc/RaD287PuyRw2wugkh5ZL2J6k= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 h1:Pg9URiobXy85kgFev3og2CuOZ8JZUBENF+dcgWBaYNk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 h1:D4oz8/CzT9bAEYtVhSBmFj2dNOtaHOtMKc2vHBwYizA= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2/go.mod h1:Za3IHqTQ+yNcRHxu1OFucBh0ACZT4j4VQFF0BqpZcLY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.12 h1:O+8vD2rGjfihBewr5bT+QUfYUHIxCVgG61LHoT59shM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.12/go.mod h1:usVdWJaosa66NMvmCrr08NcWDBRv4E6+YFG2pUdw1Lk= github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7 h1:a8HvP/+ew3tKwSXqL3BCSjiuicr+XTU2eFYeogV9GJE= github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7/go.mod h1:Q7XIWsMo0JcMpI/6TGD6XXcXcV1DbTj6e9BKNntIMIM= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 h1:eajuO3nykDPdYicLlP3AGgOyVN3MOlFmZv7WGTuJPow= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.7/go.mod h1:+mJNDdF+qiUlNKNC3fxn74WWNN+sOiGOEImje+3ScPM= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 h1:QPMJf+Jw8E1l7zqhZmMlFw6w1NmfkfiSK8mS4zOx3BA= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7/go.mod h1:ykf3COxYI0UJmxcfcxcVuz7b6uADi1FkiUz6Eb7AgM8= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 h1:NzO4Vrau795RkUdSHKEwiR01FaGzGOH1EETJ+5QHnm0= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.7/go.mod h1:6h2YuIoxaMSCFf5fi1EgZAwdfkGMgDY+DVfa61uLe4U= -github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= -github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= -github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= -github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.14 h1:c5WJ3iHz7rLIgArznb3JCSQT3uUMiz9DLZhIX+1G8ok= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.14/go.mod h1:+JJQTxB6N4niArC14YNtxcQtwEqzS3o9Z32n7q33Rfs= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13 h1:f1L/JtUkVODD+k1+IiSJUUv8A++2qVr+Xvb3xWXETMU= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13/go.mod h1:tvqlFoja8/s0o+UruA1Nrezo/df0PzdunMDDurUfg6U= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.13 h1:3LXNnmtH3TURctC23hnC0p/39Q5gre3FI7BNOiDcVWc= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.13/go.mod h1:7Yn+p66q/jt38qMoVfNvjbm3D89mGBnkwDcijgtih8w= +github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= +github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk= github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso= github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= @@ -61,14 +59,14 @@ github.com/dsnet/try v0.0.3 h1:ptR59SsrcFUYbT/FhAbKTV6iLkeD6O18qfIWRml2fqI= github.com/dsnet/try v0.0.3/go.mod h1:WBM8tRpUmnXXhY1U6/S8dt6UWdHTQ7y8A5YSkRCkq40= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fxamacker/cbor/v2 v2.6.0 h1:sU6J2usfADwWlYDAFhZBQ6TnLFBHxgesMrQfQgk1tWA= -github.com/fxamacker/cbor/v2 v2.6.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/gaissmai/bart v0.11.1 h1:5Uv5XwsaFBRo4E5VBcb9TzY8B7zxFf+U7isDxqOrRfc= -github.com/gaissmai/bart v0.11.1/go.mod h1:KHeYECXQiBjTzQz/om2tqn3sZF1J7hw9m6z41ftj3fg= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/gaissmai/bart v0.18.0 h1:jQLBT/RduJu0pv/tLwXE+xKPgtWJejbxuXAR+wLJafo= +github.com/gaissmai/bart v0.18.0/go.mod h1:JJzMAhNF5Rjo4SF4jWBrANuJfqY+FvsFhW7t1UZJ+XY= github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I= github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo= -github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg= -github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA= +github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 h1:F8d1AJ6M9UQCavhwmO6ZsrYLfG8zVFWfEfMS2MXPkSY= +github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 h1:sQspH8M4niEijh3PFscJRLDnkL547IeP7kpPe3uUhEg= @@ -85,14 +83,14 @@ github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 h1:wG8RYIyctLhdF github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/csrf v1.7.2 h1:oTUjx0vyf2T+wkrx09Trsev1TE+/EbDAeHtSTbtC2eI= -github.com/gorilla/csrf v1.7.2/go.mod h1:F1Fj3KG23WYHE6gozCmBAezKookxbIvUJT+121wTuLk= +github.com/gorilla/csrf v1.7.3-0.20250123201450-9dd6af1f6d30 h1:fiJdrgVBkjZ5B1HJ2WQwNOaXB+QyYcNXTA3t1XYLz0M= +github.com/gorilla/csrf v1.7.3-0.20250123201450-9dd6af1f6d30/go.mod h1:F1Fj3KG23WYHE6gozCmBAezKookxbIvUJT+121wTuLk= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU= github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= -github.com/illarion/gonotify/v2 v2.0.3 h1:B6+SKPo/0Sw8cRJh1aLzNEeNVFfzE3c6N+o+vyxM+9A= -github.com/illarion/gonotify/v2 v2.0.3/go.mod h1:38oIJTgFqupkEydkkClkbL6i5lXV/bxdH9do5TALPEE= +github.com/illarion/gonotify/v3 v3.0.2 h1:O7S6vcopHexutmpObkeWsnzMJt/r1hONIEogeVNmJMk= +github.com/illarion/gonotify/v3 v3.0.2/go.mod h1:HWGPdPe817GfvY3w7cx6zkbzNZfi3QjcBm/wgVvEL1U= github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 h1:9K06NfxkBh25x56yVhWWlKFE8YpicaSfHwoV8SFbueA= github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI= github.com/jellydator/ttlcache/v3 v3.1.0 h1:0gPFG0IHHP6xyUyXq+JaD8fwkDCqgqwohXNJBcYE71g= @@ -101,13 +99,10 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= -github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 h1:elKwZS1OcdQ0WwEDBeqxKwb7WB62QX8bvZ/FJnVXIfk= -github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86/go.mod h1:aFAMtuldEgx/4q7iSGazk22+IcgvtiC+HIimFO9XlS8= github.com/jsimonetti/rtnetlink v1.4.0 h1:Z1BF0fRgcETPEa0Kt0MRk3yV5+kF1FWTni6KUFKrq2I= github.com/jsimonetti/rtnetlink v1.4.0/go.mod h1:5W1jDvWdnthFJ7fxYX1GMK07BUpI4oskfOqvPteYS6E= -github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= -github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a h1:+RR6SqnTkDLWyICxS1xpjCi/3dhyV+TgZwA6Ww3KncQ= github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a/go.mod h1:YTtCCM3ryyfiu4F7t8HQ1mxvp1UBdWM2r6Xa+nGWvDk= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= @@ -118,8 +113,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw= github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o= -github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= -github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= +github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 h1:A1Cq6Ysb0GM0tpKMbdCXCIfBclan4oHk1Jb+Hrejirg= +github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42/go.mod h1:BB4YCPDOzfy7FniQ/lxuYQ3dgmM2cZumHbK8RpTjN2o= github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ3c= github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE= github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI= @@ -128,9 +123,10 @@ github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= -github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= @@ -140,107 +136,103 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus-community/pro-bing v0.4.0 h1:YMbv+i08gQz97OZZBwLyvmmQEEzyfyrrjEaAchdy3R4= github.com/prometheus-community/pro-bing v0.4.0/go.mod h1:b7wRYZtCcPmt4Sz319BykUU241rWLe1VFXyiyWK/dH4= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= -github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= -github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0= github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e h1:PtWT87weP5LWHEY//SWsYkSO3RWRZo4OSWagh3YD2vQ= github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e/go.mod h1:XrBNfAFN+pwoWuksbFS9Ccxnopa15zJGgXRFN90l3K4= github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 h1:Gzfnfk2TWrk8Jj4P4c1a3CtQyMaTVCznlkLZI++hok4= github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55/go.mod h1:4k4QO+dQ3R5FofL+SanAUZe+/QfeK0+OIuwDIRu2vSg= -github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4 h1:rXZGgEa+k2vJM8xT0PoSKfVXwFGPQ3z3CJfmnHJkZZw= -github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4/go.mod h1:ikbF+YT089eInTp9f2vmvy4+ZVnW5hzX1q2WknxSprQ= +github.com/tailscale/golang-x-crypto v0.0.0-20250218230618-9a281fd8faca h1:ecjHwH73Yvqf/oIdQ2vxAX+zc6caQsYdPzsxNW1J3G8= +github.com/tailscale/golang-x-crypto v0.0.0-20250218230618-9a281fd8faca/go.mod h1:ikbF+YT089eInTp9f2vmvy4+ZVnW5hzX1q2WknxSprQ= github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 h1:4chzWmimtJPxRs2O36yuGRW3f9SYV+bMTTvMBI0EKio= github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05/go.mod h1:PdCqy9JzfWMJf1H5UJW2ip33/d4YkoKN0r67yKH1mG8= github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a h1:SJy1Pu0eH1C29XwJucQo73FrleVK6t4kYz4NVhp34Yw= github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a/go.mod h1:DFSS3NAGHthKo1gTlmEcSBiZrRJXi28rLNd/1udP1c8= github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 h1:uFsXVBE9Qr4ZoF094vE6iYTLDl0qCiKzYXlL6UeWObU= github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7/go.mod h1:NzVQi3Mleb+qzq8VmcWpSkcSYxXIg0DkI6XDzpVkhJ0= -github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4 h1:Gz0rz40FvFVLTBk/K8UNAenb36EbDSnh+q7Z9ldcC8w= -github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4/go.mod h1:phI29ccmHQBc+wvroosENp1IF9195449VDnFDhJ4rJU= -github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1 h1:tdUdyPqJ0C97SJfjB9tW6EylTtreyee9C44de+UBG0g= -github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1/go.mod h1:agQPE6y6ldqCOui2gkIh7ZMztTkIQKH049tv8siLuNQ= +github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc h1:24heQPtnFR+yfntqhI3oAu9i27nEojcQ4NuBQOo5ZFA= +github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc/go.mod h1:f93CXfllFsO9ZQVq+Zocb1Gp4G5Fz0b0rXHLOzt/Djc= +github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 h1:UBPHPtv8+nEAy2PD8RyAhOYvau1ek0HDJqLS/Pysi14= +github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976/go.mod h1:agQPE6y6ldqCOui2gkIh7ZMztTkIQKH049tv8siLuNQ= github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6 h1:l10Gi6w9jxvinoiq15g8OToDdASBni4CyJOdHY1Hr8M= github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6/go.mod h1:ZXRML051h7o4OcI0d3AaILDIad/Xw0IkXaHM17dic1Y= -github.com/tailscale/wireguard-go v0.0.0-20240905161824-799c1978fafc h1:cezaQN9pvKVaw56Ma5qr/G646uKIYP0yQf+OyWN/okc= -github.com/tailscale/wireguard-go v0.0.0-20240905161824-799c1978fafc/go.mod h1:BOm5fXUBFM+m9woLNBoxI9TaBXXhGNP50LX/TGIvGb4= +github.com/tailscale/wireguard-go v0.0.0-20250107165329-0b8b35511f19 h1:BcEJP2ewTIK2ZCsqgl6YGpuO6+oKqqag5HHb7ehljKw= +github.com/tailscale/wireguard-go v0.0.0-20250107165329-0b8b35511f19/go.mod h1:BOm5fXUBFM+m9woLNBoxI9TaBXXhGNP50LX/TGIvGb4= github.com/tailscale/xnet v0.0.0-20240729143630-8497ac4dab2e h1:zOGKqN5D5hHhiYUp091JqK7DPCqSARyUfduhGUY8Bek= github.com/tailscale/xnet v0.0.0-20240729143630-8497ac4dab2e/go.mod h1:orPd6JZXXRyuDusYilywte7k094d7dycXXU5YnWsrwg= github.com/tc-hib/winres v0.2.1 h1:YDE0FiP0VmtRaDn7+aaChp1KiF4owBiJa5l964l5ujA= github.com/tc-hib/winres v0.2.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk= -github.com/tcnksm/go-httpstat v0.2.0 h1:rP7T5e5U2HfmOBmZzGgGZjBQ5/GluWUylujl0tJ04I0= -github.com/tcnksm/go-httpstat v0.2.0/go.mod h1:s3JVJFtQxtBEBC9dwcdTTXS9xFnM3SXAZwPG41aurT8= github.com/u-root/u-root v0.12.0 h1:K0AuBFriwr0w/PGS3HawiAw89e3+MU7ks80GpghAsNs= github.com/u-root/u-root v0.12.0/go.mod h1:FYjTOh4IkIZHhjsd17lb8nYW6udgXdJhG1c0r6u0arI= -github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e h1:BA9O3BmlTmpjbvajAwzWx4Wo2TRVdpPXZEeemGQcajw= -github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= +github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM= +github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -go4.org/mem v0.0.0-20220726221520-4f986261bf13 h1:CbZeCBZ0aZj8EfVgnqQcYZgf0lpZ3H9rmp5nkDTAst8= -go4.org/mem v0.0.0-20220726221520-4f986261bf13/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g= +go4.org/mem v0.0.0-20240501181205-ae6ca9944745 h1:Tl++JLUCe4sxGu8cTpDzRLd3tN7US4hOxG5YpKCzkek= +go4.org/mem v0.0.0-20240501181205-ae6ca9944745/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= -golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= -golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= +golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= +golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac h1:l5+whBCLH3iH2ZNHYLbAe58bo7yrN4mVcnkHDYz5vvs= +golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScyxUhjuVHR3HGaDPMn9rMSUUbxo= golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f h1:phY1HzDcf18Aq9A8KkmRtY9WvOFIxN8wgfvy6Zm1DV8= golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= -golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= -golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= -golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ= +golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA= +golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= -golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= -golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= +golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= +golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gvisor.dev/gvisor v0.0.0-20240722211153-64c016c92987 h1:TU8z2Lh3Bbq77w0t1eG8yRlLcNHzZu3x6mhoH2Mk0c8= -gvisor.dev/gvisor v0.0.0-20240722211153-64c016c92987/go.mod h1:sxc3Uvk/vHcd3tj7/DHVBoR5wvWT/MmRq2pj7HRJnwU= +gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633 h1:2gap+Kh/3F47cO6hAu3idFvsJ0ue6TRcEi2IUkv/F8k= +gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633/go.mod h1:5DMfjtclAbTIjbXqO1qCe2K5GKKxWz2JHvCChuTcJEM= honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I= honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs= howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= -tailscale.com v1.76.3 h1:UBfYxqgsSAjutLix2doZBfTw8bBuE7Cj1DzsREow1wA= -tailscale.com v1.76.3/go.mod h1:myCwmhYBvMCF/5OgBYuIW42zscuEo30bAml7wABVZLk= +tailscale.com v1.82.0 h1:pposomel4h6Je4brJydcdc2ixNQWDaZyGr5v5MdRr/o= +tailscale.com v1.82.0/go.mod h1:iU6kohVzG+bP0/5XjqBAnW8/6nSG/Du++bO+x7VJZD0= diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/accountid_endpoint_mode.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/accountid_endpoint_mode.go new file mode 100644 index 0000000..6504a21 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/accountid_endpoint_mode.go @@ -0,0 +1,18 @@ +package aws + +// AccountIDEndpointMode controls how a resolved AWS account ID is handled for endpoint routing. +type AccountIDEndpointMode string + +const ( + // AccountIDEndpointModeUnset indicates the AWS account ID will not be used for endpoint routing + AccountIDEndpointModeUnset AccountIDEndpointMode = "" + + // AccountIDEndpointModePreferred indicates the AWS account ID will be used for endpoint routing if present + AccountIDEndpointModePreferred = "preferred" + + // AccountIDEndpointModeRequired indicates an error will be returned if the AWS account ID is not resolved from identity + AccountIDEndpointModeRequired = "required" + + // AccountIDEndpointModeDisabled indicates the AWS account ID will be ignored during endpoint routing + AccountIDEndpointModeDisabled = "disabled" +) diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/checksum.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/checksum.go new file mode 100644 index 0000000..4152caa --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/checksum.go @@ -0,0 +1,33 @@ +package aws + +// RequestChecksumCalculation controls request checksum calculation workflow +type RequestChecksumCalculation int + +const ( + // RequestChecksumCalculationUnset is the unset value for RequestChecksumCalculation + RequestChecksumCalculationUnset RequestChecksumCalculation = iota + + // RequestChecksumCalculationWhenSupported indicates request checksum will be calculated + // if the operation supports input checksums + RequestChecksumCalculationWhenSupported + + // RequestChecksumCalculationWhenRequired indicates request checksum will be calculated + // if required by the operation or if user elects to set a checksum algorithm in request + RequestChecksumCalculationWhenRequired +) + +// ResponseChecksumValidation controls response checksum validation workflow +type ResponseChecksumValidation int + +const ( + // ResponseChecksumValidationUnset is the unset value for ResponseChecksumValidation + ResponseChecksumValidationUnset ResponseChecksumValidation = iota + + // ResponseChecksumValidationWhenSupported indicates response checksum will be validated + // if the operation supports output checksums + ResponseChecksumValidationWhenSupported + + // ResponseChecksumValidationWhenRequired indicates response checksum will only + // be validated if the operation requires output checksum validation + ResponseChecksumValidationWhenRequired +) diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/config.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/config.go index 2264200..a015cc5 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/config.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/config.go @@ -162,6 +162,36 @@ type Config struct { // This variable is sourced from environment variable AWS_REQUEST_MIN_COMPRESSION_SIZE_BYTES or // the shared config profile attribute request_min_compression_size_bytes RequestMinCompressSizeBytes int64 + + // Controls how a resolved AWS account ID is handled for endpoint routing. + AccountIDEndpointMode AccountIDEndpointMode + + // RequestChecksumCalculation determines when request checksum calculation is performed. + // + // There are two possible values for this setting: + // + // 1. RequestChecksumCalculationWhenSupported (default): The checksum is always calculated + // if the operation supports it, regardless of whether the user sets an algorithm in the request. + // + // 2. RequestChecksumCalculationWhenRequired: The checksum is only calculated if the user + // explicitly sets a checksum algorithm in the request. + // + // This setting is sourced from the environment variable AWS_REQUEST_CHECKSUM_CALCULATION + // or the shared config profile attribute "request_checksum_calculation". + RequestChecksumCalculation RequestChecksumCalculation + + // ResponseChecksumValidation determines when response checksum validation is performed + // + // There are two possible values for this setting: + // + // 1. ResponseChecksumValidationWhenSupported (default): The checksum is always validated + // if the operation supports it, regardless of whether the user sets the validation mode to ENABLED in request. + // + // 2. ResponseChecksumValidationWhenRequired: The checksum is only validated if the user + // explicitly sets the validation mode to ENABLED in the request + // This variable is sourced from environment variable AWS_RESPONSE_CHECKSUM_VALIDATION or + // the shared config profile attribute "response_checksum_validation". + ResponseChecksumValidation ResponseChecksumValidation } // NewConfig returns a new Config pointer that can be chained with builder diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/credentials.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/credentials.go index 714d4ad..98ba770 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/credentials.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/credentials.go @@ -90,6 +90,9 @@ type Credentials struct { // The time the credentials will expire at. Should be ignored if CanExpire // is false. Expires time.Time + + // The ID of the account for the credentials. + AccountID string } // Expired returns if the credentials have expired. diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/endpoints.go index aa10a9b..99edbf3 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/endpoints.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/endpoints.go @@ -70,6 +70,10 @@ func GetUseFIPSEndpoint(options ...interface{}) (value FIPSEndpointState, found // The SDK will automatically resolve these endpoints per API client using an // internal endpoint resolvers. If you'd like to provide custom endpoint // resolving behavior you can implement the EndpointResolver interface. +// +// Deprecated: This structure was used with the global [EndpointResolver] +// interface, which has been deprecated in favor of service-specific endpoint +// resolution. See the deprecation docs on that interface for more information. type Endpoint struct { // The base URL endpoint the SDK API clients will use to make API calls to. // The SDK will suffix URI path and query elements to this endpoint. @@ -124,6 +128,8 @@ type Endpoint struct { } // EndpointSource is the endpoint source type. +// +// Deprecated: The global [Endpoint] structure is deprecated. type EndpointSource int const ( @@ -161,19 +167,25 @@ func (e *EndpointNotFoundError) Unwrap() error { // API clients will fallback to attempting to resolve the endpoint using its // internal default endpoint resolver. // -// Deprecated: See EndpointResolverWithOptions +// Deprecated: The global endpoint resolution interface is deprecated. The API +// for endpoint resolution is now unique to each service and is set via the +// EndpointResolverV2 field on service client options. Setting a value for +// EndpointResolver on aws.Config or service client options will prevent you +// from using any endpoint-related service features released after the +// introduction of EndpointResolverV2. You may also encounter broken or +// unexpected behavior when using the old global interface with services that +// use many endpoint-related customizations such as S3. type EndpointResolver interface { ResolveEndpoint(service, region string) (Endpoint, error) } // EndpointResolverFunc wraps a function to satisfy the EndpointResolver interface. // -// Deprecated: See EndpointResolverWithOptionsFunc +// Deprecated: The global endpoint resolution interface is deprecated. See +// deprecation docs on [EndpointResolver]. type EndpointResolverFunc func(service, region string) (Endpoint, error) // ResolveEndpoint calls the wrapped function and returns the results. -// -// Deprecated: See EndpointResolverWithOptions.ResolveEndpoint func (e EndpointResolverFunc) ResolveEndpoint(service, region string) (Endpoint, error) { return e(service, region) } @@ -184,11 +196,17 @@ func (e EndpointResolverFunc) ResolveEndpoint(service, region string) (Endpoint, // available. If the EndpointResolverWithOptions returns an EndpointNotFoundError error, // API clients will fallback to attempting to resolve the endpoint using its // internal default endpoint resolver. +// +// Deprecated: The global endpoint resolution interface is deprecated. See +// deprecation docs on [EndpointResolver]. type EndpointResolverWithOptions interface { ResolveEndpoint(service, region string, options ...interface{}) (Endpoint, error) } // EndpointResolverWithOptionsFunc wraps a function to satisfy the EndpointResolverWithOptions interface. +// +// Deprecated: The global endpoint resolution interface is deprecated. See +// deprecation docs on [EndpointResolver]. type EndpointResolverWithOptionsFunc func(service, region string, options ...interface{}) (Endpoint, error) // ResolveEndpoint calls the wrapped function and returns the results. diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go index 66d0963..512d8d8 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/go_module_metadata.go @@ -3,4 +3,4 @@ package aws // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.24.1" +const goModuleVersion = "1.36.0" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/middleware.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/middleware.go index 9bd0dfb..6d5f007 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/middleware.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/middleware.go @@ -139,16 +139,16 @@ func AddRecordResponseTiming(stack *middleware.Stack) error { // raw response within the response metadata. type rawResponseKey struct{} -// addRawResponse middleware adds raw response on to the metadata -type addRawResponse struct{} +// AddRawResponse middleware adds raw response on to the metadata +type AddRawResponse struct{} // ID the identifier for the ClientRequestID -func (m *addRawResponse) ID() string { +func (m *AddRawResponse) ID() string { return "AddRawResponseToMetadata" } // HandleDeserialize adds raw response on the middleware metadata -func (m addRawResponse) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( +func (m AddRawResponse) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( out middleware.DeserializeOutput, metadata middleware.Metadata, err error, ) { out, metadata, err = next.HandleDeserialize(ctx, in) @@ -159,7 +159,7 @@ func (m addRawResponse) HandleDeserialize(ctx context.Context, in middleware.Des // AddRawResponseToMetadata adds middleware to the middleware stack that // store raw response on to the metadata. func AddRawResponseToMetadata(stack *middleware.Stack) error { - return stack.Deserialize.Add(&addRawResponse{}, middleware.Before) + return stack.Deserialize.Add(&AddRawResponse{}, middleware.Before) } // GetRawResponse returns raw response set on metadata diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/metrics.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/metrics.go deleted file mode 100644 index b0133f4..0000000 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics/metrics.go +++ /dev/null @@ -1,319 +0,0 @@ -// Package metrics implements metrics gathering for SDK development purposes. -// -// This package is designated as private and is intended for use only by the -// AWS client runtime. The exported API therein is not considered stable and -// is subject to breaking changes without notice. -package metrics - -import ( - "context" - "encoding/json" - "fmt" - "sync" - "time" - - "github.com/aws/smithy-go/middleware" -) - -const ( - // ServiceIDKey is the key for the service ID metric. - ServiceIDKey = "ServiceId" - // OperationNameKey is the key for the operation name metric. - OperationNameKey = "OperationName" - // ClientRequestIDKey is the key for the client request ID metric. - ClientRequestIDKey = "ClientRequestId" - // APICallDurationKey is the key for the API call duration metric. - APICallDurationKey = "ApiCallDuration" - // APICallSuccessfulKey is the key for the API call successful metric. - APICallSuccessfulKey = "ApiCallSuccessful" - // MarshallingDurationKey is the key for the marshalling duration metric. - MarshallingDurationKey = "MarshallingDuration" - // InThroughputKey is the key for the input throughput metric. - InThroughputKey = "InThroughput" - // OutThroughputKey is the key for the output throughput metric. - OutThroughputKey = "OutThroughput" - // RetryCountKey is the key for the retry count metric. - RetryCountKey = "RetryCount" - // HTTPStatusCodeKey is the key for the HTTP status code metric. - HTTPStatusCodeKey = "HttpStatusCode" - // AWSExtendedRequestIDKey is the key for the AWS extended request ID metric. - AWSExtendedRequestIDKey = "AwsExtendedRequestId" - // AWSRequestIDKey is the key for the AWS request ID metric. - AWSRequestIDKey = "AwsRequestId" - // BackoffDelayDurationKey is the key for the backoff delay duration metric. - BackoffDelayDurationKey = "BackoffDelayDuration" - // StreamThroughputKey is the key for the stream throughput metric. - StreamThroughputKey = "Throughput" - // ConcurrencyAcquireDurationKey is the key for the concurrency acquire duration metric. - ConcurrencyAcquireDurationKey = "ConcurrencyAcquireDuration" - // PendingConcurrencyAcquiresKey is the key for the pending concurrency acquires metric. - PendingConcurrencyAcquiresKey = "PendingConcurrencyAcquires" - // SigningDurationKey is the key for the signing duration metric. - SigningDurationKey = "SigningDuration" - // UnmarshallingDurationKey is the key for the unmarshalling duration metric. - UnmarshallingDurationKey = "UnmarshallingDuration" - // TimeToFirstByteKey is the key for the time to first byte metric. - TimeToFirstByteKey = "TimeToFirstByte" - // ServiceCallDurationKey is the key for the service call duration metric. - ServiceCallDurationKey = "ServiceCallDuration" - // EndpointResolutionDurationKey is the key for the endpoint resolution duration metric. - EndpointResolutionDurationKey = "EndpointResolutionDuration" - // AttemptNumberKey is the key for the attempt number metric. - AttemptNumberKey = "AttemptNumber" - // MaxConcurrencyKey is the key for the max concurrency metric. - MaxConcurrencyKey = "MaxConcurrency" - // AvailableConcurrencyKey is the key for the available concurrency metric. - AvailableConcurrencyKey = "AvailableConcurrency" -) - -// MetricPublisher provides the interface to provide custom MetricPublishers. -// PostRequestMetrics will be invoked by the MetricCollection middleware to post request. -// PostStreamMetrics will be invoked by ReadCloserWithMetrics to post stream metrics. -type MetricPublisher interface { - PostRequestMetrics(*MetricData) error - PostStreamMetrics(*MetricData) error -} - -// Serializer provides the interface to provide custom Serializers. -// Serialize will transform any input object in its corresponding string representation. -type Serializer interface { - Serialize(obj interface{}) (string, error) -} - -// DefaultSerializer is an implementation of the Serializer interface. -type DefaultSerializer struct{} - -// Serialize uses the default JSON serializer to obtain the string representation of an object. -func (DefaultSerializer) Serialize(obj interface{}) (string, error) { - bytes, err := json.Marshal(obj) - if err != nil { - return "", err - } - return string(bytes), nil -} - -type metricContextKey struct{} - -// MetricContext contains fields to store metric-related information. -type MetricContext struct { - connectionCounter *SharedConnectionCounter - publisher MetricPublisher - data *MetricData -} - -// MetricData stores the collected metric data. -type MetricData struct { - RequestStartTime time.Time - RequestEndTime time.Time - APICallDuration time.Duration - SerializeStartTime time.Time - SerializeEndTime time.Time - MarshallingDuration time.Duration - ResolveEndpointStartTime time.Time - ResolveEndpointEndTime time.Time - EndpointResolutionDuration time.Duration - InThroughput float64 - OutThroughput float64 - RetryCount int - Success uint8 - StatusCode int - ClientRequestID string - ServiceID string - OperationName string - PartitionID string - Region string - RequestContentLength int64 - Stream StreamMetrics - Attempts []AttemptMetrics -} - -// StreamMetrics stores metrics related to streaming data. -type StreamMetrics struct { - ReadDuration time.Duration - ReadBytes int64 - Throughput float64 -} - -// AttemptMetrics stores metrics related to individual attempts. -type AttemptMetrics struct { - ServiceCallStart time.Time - ServiceCallEnd time.Time - ServiceCallDuration time.Duration - FirstByteTime time.Time - TimeToFirstByte time.Duration - ConnRequestedTime time.Time - ConnObtainedTime time.Time - ConcurrencyAcquireDuration time.Duration - CredentialFetchStartTime time.Time - CredentialFetchEndTime time.Time - SignStartTime time.Time - SignEndTime time.Time - SigningDuration time.Duration - DeserializeStartTime time.Time - DeserializeEndTime time.Time - UnMarshallingDuration time.Duration - RetryDelay time.Duration - ResponseContentLength int64 - StatusCode int - RequestID string - ExtendedRequestID string - HTTPClient string - MaxConcurrency int - PendingConnectionAcquires int - AvailableConcurrency int - ActiveRequests int - ReusedConnection bool -} - -// Data returns the MetricData associated with the MetricContext. -func (mc *MetricContext) Data() *MetricData { - return mc.data -} - -// ConnectionCounter returns the SharedConnectionCounter associated with the MetricContext. -func (mc *MetricContext) ConnectionCounter() *SharedConnectionCounter { - return mc.connectionCounter -} - -// Publisher returns the MetricPublisher associated with the MetricContext. -func (mc *MetricContext) Publisher() MetricPublisher { - return mc.publisher -} - -// ComputeRequestMetrics calculates and populates derived metrics based on the collected data. -func (md *MetricData) ComputeRequestMetrics() { - - for idx := range md.Attempts { - attempt := &md.Attempts[idx] - attempt.ConcurrencyAcquireDuration = attempt.ConnObtainedTime.Sub(attempt.ConnRequestedTime) - attempt.SigningDuration = attempt.SignEndTime.Sub(attempt.SignStartTime) - attempt.UnMarshallingDuration = attempt.DeserializeEndTime.Sub(attempt.DeserializeStartTime) - attempt.TimeToFirstByte = attempt.FirstByteTime.Sub(attempt.ServiceCallStart) - attempt.ServiceCallDuration = attempt.ServiceCallEnd.Sub(attempt.ServiceCallStart) - } - - md.APICallDuration = md.RequestEndTime.Sub(md.RequestStartTime) - md.MarshallingDuration = md.SerializeEndTime.Sub(md.SerializeStartTime) - md.EndpointResolutionDuration = md.ResolveEndpointEndTime.Sub(md.ResolveEndpointStartTime) - - md.RetryCount = len(md.Attempts) - 1 - - latestAttempt, err := md.LatestAttempt() - - if err != nil { - fmt.Printf("error retrieving attempts data due to: %s. Skipping Throughput metrics", err.Error()) - } else { - - md.StatusCode = latestAttempt.StatusCode - - if md.Success == 1 { - if latestAttempt.ResponseContentLength > 0 && latestAttempt.ServiceCallDuration > 0 { - md.InThroughput = float64(latestAttempt.ResponseContentLength) / latestAttempt.ServiceCallDuration.Seconds() - } - if md.RequestContentLength > 0 && latestAttempt.ServiceCallDuration > 0 { - md.OutThroughput = float64(md.RequestContentLength) / latestAttempt.ServiceCallDuration.Seconds() - } - } - } -} - -// LatestAttempt returns the latest attempt metrics. -// It returns an error if no attempts are initialized. -func (md *MetricData) LatestAttempt() (*AttemptMetrics, error) { - if md.Attempts == nil || len(md.Attempts) == 0 { - return nil, fmt.Errorf("no attempts initialized. NewAttempt() should be called first") - } - return &md.Attempts[len(md.Attempts)-1], nil -} - -// NewAttempt initializes new attempt metrics. -func (md *MetricData) NewAttempt() { - if md.Attempts == nil { - md.Attempts = []AttemptMetrics{} - } - md.Attempts = append(md.Attempts, AttemptMetrics{}) -} - -// SharedConnectionCounter is a counter shared across API calls. -type SharedConnectionCounter struct { - mu sync.Mutex - - activeRequests int - pendingConnectionAcquire int -} - -// ActiveRequests returns the count of active requests. -func (cc *SharedConnectionCounter) ActiveRequests() int { - cc.mu.Lock() - defer cc.mu.Unlock() - - return cc.activeRequests -} - -// PendingConnectionAcquire returns the count of pending connection acquires. -func (cc *SharedConnectionCounter) PendingConnectionAcquire() int { - cc.mu.Lock() - defer cc.mu.Unlock() - - return cc.pendingConnectionAcquire -} - -// AddActiveRequest increments the count of active requests. -func (cc *SharedConnectionCounter) AddActiveRequest() { - cc.mu.Lock() - defer cc.mu.Unlock() - - cc.activeRequests++ -} - -// RemoveActiveRequest decrements the count of active requests. -func (cc *SharedConnectionCounter) RemoveActiveRequest() { - cc.mu.Lock() - defer cc.mu.Unlock() - - cc.activeRequests-- -} - -// AddPendingConnectionAcquire increments the count of pending connection acquires. -func (cc *SharedConnectionCounter) AddPendingConnectionAcquire() { - cc.mu.Lock() - defer cc.mu.Unlock() - - cc.pendingConnectionAcquire++ -} - -// RemovePendingConnectionAcquire decrements the count of pending connection acquires. -func (cc *SharedConnectionCounter) RemovePendingConnectionAcquire() { - cc.mu.Lock() - defer cc.mu.Unlock() - - cc.pendingConnectionAcquire-- -} - -// InitMetricContext initializes the metric context with the provided counter and publisher. -// It returns the updated context. -func InitMetricContext( - ctx context.Context, counter *SharedConnectionCounter, publisher MetricPublisher, -) context.Context { - if middleware.GetStackValue(ctx, metricContextKey{}) == nil { - ctx = middleware.WithStackValue(ctx, metricContextKey{}, &MetricContext{ - connectionCounter: counter, - publisher: publisher, - data: &MetricData{ - Attempts: []AttemptMetrics{}, - Stream: StreamMetrics{}, - }, - }) - } - return ctx -} - -// Context returns the metric context from the given context. -// It returns nil if the metric context is not found. -func Context(ctx context.Context) *MetricContext { - mctx := middleware.GetStackValue(ctx, metricContextKey{}) - if mctx == nil { - return nil - } - return mctx.(*MetricContext) -} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/request_id_retriever.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/request_id_retriever.go index 7ce48c6..128b60a 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/request_id_retriever.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/request_id_retriever.go @@ -4,6 +4,7 @@ import ( "context" "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" ) @@ -11,18 +12,22 @@ import ( func AddRequestIDRetrieverMiddleware(stack *middleware.Stack) error { // add error wrapper middleware before operation deserializers so that it can wrap the error response // returned by operation deserializers - return stack.Deserialize.Insert(&requestIDRetriever{}, "OperationDeserializer", middleware.Before) + return stack.Deserialize.Insert(&RequestIDRetriever{}, "OperationDeserializer", middleware.Before) } -type requestIDRetriever struct { +// RequestIDRetriever middleware captures the AWS service request ID from the +// raw response. +type RequestIDRetriever struct { } // ID returns the middleware identifier -func (m *requestIDRetriever) ID() string { +func (m *RequestIDRetriever) ID() string { return "RequestIDRetriever" } -func (m *requestIDRetriever) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( +// HandleDeserialize pulls the AWS request ID from the response, storing it in +// operation metadata. +func (m *RequestIDRetriever) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( out middleware.DeserializeOutput, metadata middleware.Metadata, err error, ) { out, metadata, err = next.HandleDeserialize(ctx, in) @@ -41,6 +46,9 @@ func (m *requestIDRetriever) HandleDeserialize(ctx context.Context, in middlewar if v := resp.Header.Get(h); len(v) != 0 { // set reqID on metadata for successful responses. SetRequestIDMetadata(&metadata, v) + + span, _ := tracing.GetSpan(ctx) + span.SetProperty("aws.request_id", v) break } } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/user_agent.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/user_agent.go index af3447d..01d758d 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/user_agent.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/middleware/user_agent.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "runtime" + "sort" "strings" "github.com/aws/aws-sdk-go-v2/aws" @@ -30,8 +31,12 @@ const ( FrameworkMetadata AdditionalMetadata ApplicationIdentifier + FeatureMetadata2 ) +// Hardcoded value to specify which version of the user agent we're using +const uaMetadata = "ua/2.1" + func (k SDKAgentKeyType) string() string { switch k { case APIMetadata: @@ -50,6 +55,8 @@ func (k SDKAgentKeyType) string() string { return "lib" case ApplicationIdentifier: return "app" + case FeatureMetadata2: + return "m" case AdditionalMetadata: fallthrough default: @@ -64,12 +71,42 @@ var validChars = map[rune]bool{ '-': true, '.': true, '^': true, '_': true, '`': true, '|': true, '~': true, } -// requestUserAgent is a build middleware that set the User-Agent for the request. -type requestUserAgent struct { +// UserAgentFeature enumerates tracked SDK features. +type UserAgentFeature string + +// Enumerates UserAgentFeature. +const ( + UserAgentFeatureResourceModel UserAgentFeature = "A" // n/a (we don't generate separate resource types) + UserAgentFeatureWaiter = "B" + UserAgentFeaturePaginator = "C" + UserAgentFeatureRetryModeLegacy = "D" // n/a (equivalent to standard) + UserAgentFeatureRetryModeStandard = "E" + UserAgentFeatureRetryModeAdaptive = "F" + UserAgentFeatureS3Transfer = "G" + UserAgentFeatureS3CryptoV1N = "H" // n/a (crypto client is external) + UserAgentFeatureS3CryptoV2 = "I" // n/a + UserAgentFeatureS3ExpressBucket = "J" + UserAgentFeatureS3AccessGrants = "K" // not yet implemented + UserAgentFeatureGZIPRequestCompression = "L" + UserAgentFeatureProtocolRPCV2CBOR = "M" + UserAgentFeatureRequestChecksumCRC32 = "U" + UserAgentFeatureRequestChecksumCRC32C = "V" + UserAgentFeatureRequestChecksumCRC64 = "W" + UserAgentFeatureRequestChecksumSHA1 = "X" + UserAgentFeatureRequestChecksumSHA256 = "Y" + UserAgentFeatureRequestChecksumWhenSupported = "Z" + UserAgentFeatureRequestChecksumWhenRequired = "a" + UserAgentFeatureResponseChecksumWhenSupported = "b" + UserAgentFeatureResponseChecksumWhenRequired = "c" +) + +// RequestUserAgent is a build middleware that set the User-Agent for the request. +type RequestUserAgent struct { sdkAgent, userAgent *smithyhttp.UserAgentBuilder + features map[UserAgentFeature]struct{} } -// newRequestUserAgent returns a new requestUserAgent which will set the User-Agent and X-Amz-User-Agent for the +// NewRequestUserAgent returns a new requestUserAgent which will set the User-Agent and X-Amz-User-Agent for the // request. // // User-Agent example: @@ -79,14 +116,16 @@ type requestUserAgent struct { // X-Amz-User-Agent example: // // aws-sdk-go-v2/1.2.3 md/GOOS/linux md/GOARCH/amd64 lang/go/1.15 -func newRequestUserAgent() *requestUserAgent { +func NewRequestUserAgent() *RequestUserAgent { userAgent, sdkAgent := smithyhttp.NewUserAgentBuilder(), smithyhttp.NewUserAgentBuilder() addProductName(userAgent) + addUserAgentMetadata(userAgent) addProductName(sdkAgent) - r := &requestUserAgent{ + r := &RequestUserAgent{ sdkAgent: sdkAgent, userAgent: userAgent, + features: map[UserAgentFeature]struct{}{}, } addSDKMetadata(r) @@ -94,7 +133,7 @@ func newRequestUserAgent() *requestUserAgent { return r } -func addSDKMetadata(r *requestUserAgent) { +func addSDKMetadata(r *RequestUserAgent) { r.AddSDKAgentKey(OperatingSystemMetadata, getNormalizedOSName()) r.AddSDKAgentKeyValue(LanguageMetadata, "go", languageVersion) r.AddSDKAgentKeyValue(AdditionalMetadata, "GOOS", runtime.GOOS) @@ -108,6 +147,10 @@ func addProductName(builder *smithyhttp.UserAgentBuilder) { builder.AddKeyValue(aws.SDKName, aws.SDKVersion) } +func addUserAgentMetadata(builder *smithyhttp.UserAgentBuilder) { + builder.AddKey(uaMetadata) +} + // AddUserAgentKey retrieves a requestUserAgent from the provided stack, or initializes one. func AddUserAgentKey(key string) func(*middleware.Stack) error { return func(stack *middleware.Stack) error { @@ -162,18 +205,18 @@ func AddRequestUserAgentMiddleware(stack *middleware.Stack) error { return err } -func getOrAddRequestUserAgent(stack *middleware.Stack) (*requestUserAgent, error) { - id := (*requestUserAgent)(nil).ID() +func getOrAddRequestUserAgent(stack *middleware.Stack) (*RequestUserAgent, error) { + id := (*RequestUserAgent)(nil).ID() bm, ok := stack.Build.Get(id) if !ok { - bm = newRequestUserAgent() + bm = NewRequestUserAgent() err := stack.Build.Add(bm, middleware.After) if err != nil { return nil, err } } - requestUserAgent, ok := bm.(*requestUserAgent) + requestUserAgent, ok := bm.(*RequestUserAgent) if !ok { return nil, fmt.Errorf("%T for %s middleware did not match expected type", bm, id) } @@ -182,34 +225,40 @@ func getOrAddRequestUserAgent(stack *middleware.Stack) (*requestUserAgent, error } // AddUserAgentKey adds the component identified by name to the User-Agent string. -func (u *requestUserAgent) AddUserAgentKey(key string) { +func (u *RequestUserAgent) AddUserAgentKey(key string) { u.userAgent.AddKey(strings.Map(rules, key)) } // AddUserAgentKeyValue adds the key identified by the given name and value to the User-Agent string. -func (u *requestUserAgent) AddUserAgentKeyValue(key, value string) { +func (u *RequestUserAgent) AddUserAgentKeyValue(key, value string) { u.userAgent.AddKeyValue(strings.Map(rules, key), strings.Map(rules, value)) } -// AddUserAgentKey adds the component identified by name to the User-Agent string. -func (u *requestUserAgent) AddSDKAgentKey(keyType SDKAgentKeyType, key string) { +// AddUserAgentFeature adds the feature ID to the tracking list to be emitted +// in the final User-Agent string. +func (u *RequestUserAgent) AddUserAgentFeature(feature UserAgentFeature) { + u.features[feature] = struct{}{} +} + +// AddSDKAgentKey adds the component identified by name to the User-Agent string. +func (u *RequestUserAgent) AddSDKAgentKey(keyType SDKAgentKeyType, key string) { // TODO: should target sdkAgent u.userAgent.AddKey(keyType.string() + "/" + strings.Map(rules, key)) } -// AddUserAgentKeyValue adds the key identified by the given name and value to the User-Agent string. -func (u *requestUserAgent) AddSDKAgentKeyValue(keyType SDKAgentKeyType, key, value string) { +// AddSDKAgentKeyValue adds the key identified by the given name and value to the User-Agent string. +func (u *RequestUserAgent) AddSDKAgentKeyValue(keyType SDKAgentKeyType, key, value string) { // TODO: should target sdkAgent u.userAgent.AddKeyValue(keyType.string(), strings.Map(rules, key)+"#"+strings.Map(rules, value)) } // ID the name of the middleware. -func (u *requestUserAgent) ID() string { +func (u *RequestUserAgent) ID() string { return "UserAgent" } // HandleBuild adds or appends the constructed user agent to the request. -func (u *requestUserAgent) HandleBuild(ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler) ( +func (u *RequestUserAgent) HandleBuild(ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler) ( out middleware.BuildOutput, metadata middleware.Metadata, err error, ) { switch req := in.Request.(type) { @@ -224,12 +273,15 @@ func (u *requestUserAgent) HandleBuild(ctx context.Context, in middleware.BuildI return next.HandleBuild(ctx, in) } -func (u *requestUserAgent) addHTTPUserAgent(request *smithyhttp.Request) { +func (u *RequestUserAgent) addHTTPUserAgent(request *smithyhttp.Request) { const userAgent = "User-Agent" + if len(u.features) > 0 { + updateHTTPHeader(request, userAgent, buildFeatureMetrics(u.features)) + } updateHTTPHeader(request, userAgent, u.userAgent.Build()) } -func (u *requestUserAgent) addHTTPSDKAgent(request *smithyhttp.Request) { +func (u *RequestUserAgent) addHTTPSDKAgent(request *smithyhttp.Request) { const sdkAgent = "X-Amz-User-Agent" updateHTTPHeader(request, sdkAgent, u.sdkAgent.Build()) } @@ -259,3 +311,13 @@ func rules(r rune) rune { return '-' } } + +func buildFeatureMetrics(features map[UserAgentFeature]struct{}) string { + fs := make([]string, 0, len(features)) + for f := range features { + fs = append(fs, string(f)) + } + + sort.Strings(fs) + return fmt.Sprintf("%s/%s", FeatureMetadata2.string(), strings.Join(fs, ",")) +} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/array.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/array.go index 47ebc0f..6669a3d 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/array.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/array.go @@ -1,8 +1,8 @@ package query import ( - "fmt" "net/url" + "strconv" ) // Array represents the encoding of Query lists and sets. A Query array is a @@ -21,19 +21,8 @@ type Array struct { // keys for each element in the list. For example, an entry might have the // key "ParentStructure.ListName.member.MemberName.1". // - // While this is currently represented as a string that gets added to, it - // could also be represented as a stack that only gets condensed into a - // string when a finalized key is created. This could potentially reduce - // allocations. + // When the array is not flat the prefix will contain the memberName otherwise the memberName is ignored prefix string - // Whether the list is flat or not. A list that is not flat will produce the - // following entry to the url.Values for a given entry: - // ListName.MemberName.1=value - // A list that is flat will produce the following: - // ListName.1=value - flat bool - // The location name of the member. In most cases this should be "member". - memberName string // Elements are stored in values, so we keep track of the list size here. size int32 // Empty lists are encoded as "=", if we add a value later we will @@ -45,11 +34,14 @@ func newArray(values url.Values, prefix string, flat bool, memberName string) *A emptyValue := newValue(values, prefix, flat) emptyValue.String("") + if !flat { + // This uses string concatenation in place of fmt.Sprintf as fmt.Sprintf has a much higher resource overhead + prefix = prefix + keySeparator + memberName + } + return &Array{ values: values, prefix: prefix, - flat: flat, - memberName: memberName, emptyValue: emptyValue, } } @@ -63,10 +55,7 @@ func (a *Array) Value() Value { // Query lists start a 1, so adjust the size first a.size++ - prefix := a.prefix - if !a.flat { - prefix = fmt.Sprintf("%s.%s", prefix, a.memberName) - } // Lists can't have flat members - return newValue(a.values, fmt.Sprintf("%s.%d", prefix, a.size), false) + // This uses string concatenation in place of fmt.Sprintf as fmt.Sprintf has a much higher resource overhead + return newValue(a.values, a.prefix+keySeparator+strconv.FormatInt(int64(a.size), 10), false) } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/object.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/object.go index 455b925..305a8ac 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/object.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/object.go @@ -1,9 +1,6 @@ package query -import ( - "fmt" - "net/url" -) +import "net/url" // Object represents the encoding of Query structures and unions. A Query // object is a representation of a mapping of string keys to arbitrary @@ -56,14 +53,16 @@ func (o *Object) FlatKey(name string) Value { func (o *Object) key(name string, flatValue bool) Value { if o.prefix != "" { - return newValue(o.values, fmt.Sprintf("%s.%s", o.prefix, name), flatValue) + // This uses string concatenation in place of fmt.Sprintf as fmt.Sprintf has a much higher resource overhead + return newValue(o.values, o.prefix+keySeparator+name, flatValue) } return newValue(o.values, name, flatValue) } func (o *Object) keyWithValues(name string, flatValue bool) Value { if o.prefix != "" { - return newAppendValue(o.values, fmt.Sprintf("%s.%s", o.prefix, name), flatValue) + // This uses string concatenation in place of fmt.Sprintf as fmt.Sprintf has a much higher resource overhead + return newAppendValue(o.values, o.prefix+keySeparator+name, flatValue) } return newAppendValue(o.values, name, flatValue) } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/value.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/value.go index a925152..8063c59 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/value.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/protocol/query/value.go @@ -7,6 +7,8 @@ import ( "github.com/aws/smithy-go/encoding/httpbinding" ) +const keySeparator = "." + // Value represents a Query Value type. type Value struct { // The query values to add the value to. diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/ratelimit/none.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/ratelimit/none.go new file mode 100644 index 0000000..8c78364 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/ratelimit/none.go @@ -0,0 +1,20 @@ +package ratelimit + +import "context" + +// None implements a no-op rate limiter which effectively disables client-side +// rate limiting (also known as "retry quotas"). +// +// GetToken does nothing and always returns a nil error. The returned +// token-release function does nothing, and always returns a nil error. +// +// AddTokens does nothing and always returns a nil error. +var None = &none{} + +type none struct{} + +func (*none) GetToken(ctx context.Context, cost uint) (func() error, error) { + return func() error { return nil }, nil +} + +func (*none) AddTokens(v uint) error { return nil } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/attempt_metrics.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/attempt_metrics.go new file mode 100644 index 0000000..bfa5bf7 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/attempt_metrics.go @@ -0,0 +1,51 @@ +package retry + +import ( + "context" + + "github.com/aws/smithy-go/metrics" + "github.com/aws/smithy-go/middleware" +) + +type attemptMetrics struct { + Attempts metrics.Int64Counter + Errors metrics.Int64Counter + + AttemptDuration metrics.Float64Histogram +} + +func newAttemptMetrics(meter metrics.Meter) (*attemptMetrics, error) { + m := &attemptMetrics{} + var err error + + m.Attempts, err = meter.Int64Counter("client.call.attempts", func(o *metrics.InstrumentOptions) { + o.UnitLabel = "{attempt}" + o.Description = "The number of attempts for an individual operation" + }) + if err != nil { + return nil, err + } + m.Errors, err = meter.Int64Counter("client.call.errors", func(o *metrics.InstrumentOptions) { + o.UnitLabel = "{error}" + o.Description = "The number of errors for an operation" + }) + if err != nil { + return nil, err + } + m.AttemptDuration, err = meter.Float64Histogram("client.call.attempt_duration", func(o *metrics.InstrumentOptions) { + o.UnitLabel = "s" + o.Description = "The time it takes to connect to the service, send the request, and get back HTTP status code and headers (including time queued waiting to be sent)" + }) + if err != nil { + return nil, err + } + + return m, nil +} + +func withOperationMetadata(ctx context.Context) metrics.RecordMetricOption { + return func(o *metrics.RecordMetricOptions) { + o.Properties.Set("rpc.service", middleware.GetServiceID(ctx)) + o.Properties.Set("rpc.method", middleware.GetOperationName(ctx)) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/middleware.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/middleware.go index dc703d4..52d59b0 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/middleware.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/middleware.go @@ -2,17 +2,22 @@ package retry import ( "context" + "errors" "fmt" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" "strconv" "strings" "time" + internalcontext "github.com/aws/aws-sdk-go-v2/internal/context" + "github.com/aws/smithy-go" + "github.com/aws/aws-sdk-go-v2/aws" awsmiddle "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/internal/sdk" "github.com/aws/smithy-go/logging" + "github.com/aws/smithy-go/metrics" smithymiddle "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/tracing" "github.com/aws/smithy-go/transport/http" ) @@ -35,10 +40,17 @@ type Attempt struct { // attempts are reached. LogAttempts bool + // A Meter instance for recording retry-related metrics. + OperationMeter metrics.Meter + retryer aws.RetryerV2 requestCloner RequestCloner } +// define the threshold at which we will consider certain kind of errors to be probably +// caused by clock skew +const skewThreshold = 4 * time.Minute + // NewAttemptMiddleware returns a new Attempt retry middleware. func NewAttemptMiddleware(retryer aws.Retryer, requestCloner RequestCloner, optFns ...func(*Attempt)) *Attempt { m := &Attempt{ @@ -48,6 +60,10 @@ func NewAttemptMiddleware(retryer aws.Retryer, requestCloner RequestCloner, optF for _, fn := range optFns { fn(m) } + if m.OperationMeter == nil { + m.OperationMeter = metrics.NopMeterProvider{}.Meter("") + } + return m } @@ -73,6 +89,11 @@ func (r *Attempt) HandleFinalize(ctx context.Context, in smithymiddle.FinalizeIn maxAttempts := r.retryer.MaxAttempts() releaseRetryToken := nopRelease + retryMetrics, err := newAttemptMetrics(r.OperationMeter) + if err != nil { + return out, metadata, err + } + for { attemptNum++ attemptInput := in @@ -86,8 +107,29 @@ func (r *Attempt) HandleFinalize(ctx context.Context, in smithymiddle.FinalizeIn AttemptClockSkew: attemptClockSkew, }) + // Setting clock skew to be used on other context (like signing) + ctx = internalcontext.SetAttemptSkewContext(ctx, attemptClockSkew) + var attemptResult AttemptResult + + attemptCtx, span := tracing.StartSpan(attemptCtx, "Attempt", func(o *tracing.SpanOptions) { + o.Properties.Set("operation.attempt", attemptNum) + }) + retryMetrics.Attempts.Add(ctx, 1, withOperationMetadata(ctx)) + + start := sdk.NowTime() out, attemptResult, releaseRetryToken, err = r.handleAttempt(attemptCtx, attemptInput, releaseRetryToken, next) + elapsed := sdk.NowTime().Sub(start) + + retryMetrics.AttemptDuration.Record(ctx, float64(elapsed)/1e9, withOperationMetadata(ctx)) + if err != nil { + retryMetrics.Errors.Add(ctx, 1, withOperationMetadata(ctx), func(o *metrics.RecordMetricOptions) { + o.Properties.Set("exception.type", errorType(err)) + }) + } + + span.End() + attemptClockSkew, _ = awsmiddle.GetAttemptSkew(attemptResult.ResponseMetadata) // AttemptResult Retried states that the attempt was not successful, and @@ -185,6 +227,8 @@ func (r *Attempt) handleAttempt( return out, attemptResult, nopRelease, err } + err = wrapAsClockSkew(ctx, err) + //------------------------------ // Is Retryable and Should Retry //------------------------------ @@ -226,13 +270,6 @@ func (r *Attempt) handleAttempt( // that time. Potentially early exist if the sleep is canceled via the // context. retryDelay, reqErr := r.retryer.RetryDelay(attemptNum, err) - mctx := metrics.Context(ctx) - if mctx != nil { - attempt, err := mctx.Data().LatestAttempt() - if err != nil { - attempt.RetryDelay = retryDelay - } - } if reqErr != nil { return out, attemptResult, releaseRetryToken, reqErr } @@ -247,6 +284,37 @@ func (r *Attempt) handleAttempt( return out, attemptResult, releaseRetryToken, err } +// errors that, if detected when we know there's a clock skew, +// can be retried and have a high chance of success +var possibleSkewCodes = map[string]struct{}{ + "InvalidSignatureException": {}, + "SignatureDoesNotMatch": {}, + "AuthFailure": {}, +} + +var definiteSkewCodes = map[string]struct{}{ + "RequestExpired": {}, + "RequestInTheFuture": {}, + "RequestTimeTooSkewed": {}, +} + +// wrapAsClockSkew checks if this error could be related to a clock skew +// error and if so, wrap the error. +func wrapAsClockSkew(ctx context.Context, err error) error { + var v interface{ ErrorCode() string } + if !errors.As(err, &v) { + return err + } + if _, ok := definiteSkewCodes[v.ErrorCode()]; ok { + return &retryableClockSkewError{Err: err} + } + _, isPossibleSkewCode := possibleSkewCodes[v.ErrorCode()] + if skew := internalcontext.GetAttemptSkewContext(ctx); skew > skewThreshold && isPossibleSkewCode { + return &retryableClockSkewError{Err: err} + } + return err +} + // MetricsHeader attaches SDK request metric header for retries to the transport type MetricsHeader struct{} @@ -338,3 +406,13 @@ func AddRetryMiddlewares(stack *smithymiddle.Stack, options AddRetryMiddlewaresO } return nil } + +// Determines the value of exception.type for metrics purposes. We prefer an +// API-specific error code, otherwise it's just the Go type for the value. +func errorType(err error) string { + var terr smithy.APIError + if errors.As(err, &terr) { + return terr.ErrorCode() + } + return fmt.Sprintf("%T", err) +} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/retryable_error.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/retryable_error.go index 987affd..1b485f9 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/retryable_error.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/retryable_error.go @@ -2,6 +2,7 @@ package retry import ( "errors" + "fmt" "net" "net/url" "strings" @@ -115,7 +116,13 @@ func (r RetryableConnectionError) IsErrorRetryable(err error) aws.Ternary { case errors.As(err, &conErr) && conErr.ConnectionError(): retryable = true + case strings.Contains(err.Error(), "use of closed network connection"): + fallthrough case strings.Contains(err.Error(), "connection reset"): + // The errors "connection reset" and "use of closed network connection" + // are effectively the same. It appears to be the difference between + // sync and async read of TCP RST in the stdlib's net.Conn read loop. + // see #2737 retryable = true case errors.As(err, &urlErr): @@ -199,3 +206,23 @@ func (r RetryableErrorCode) IsErrorRetryable(err error) aws.Ternary { return aws.TrueTernary } + +// retryableClockSkewError marks errors that can be caused by clock skew +// (difference between server time and client time). +// This is returned when there's certain confidence that adjusting the client time +// could allow a retry to succeed +type retryableClockSkewError struct{ Err error } + +func (e *retryableClockSkewError) Error() string { + return fmt.Sprintf("Probable clock skew error: %v", e.Err) +} + +// Unwrap returns the wrapped error. +func (e *retryableClockSkewError) Unwrap() error { + return e.Err +} + +// RetryableError allows the retryer to retry this request +func (e *retryableClockSkewError) RetryableError() bool { + return true +} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/standard.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/standard.go index 25abffc..d5ea932 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/standard.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/retry/standard.go @@ -123,6 +123,17 @@ type StandardOptions struct { // Provides the rate limiting strategy for rate limiting attempt retries // across all attempts the retryer is being used with. + // + // A RateLimiter operates as a token bucket with a set capacity, where + // attempt failures events consume tokens. A retry attempt that attempts to + // consume more tokens than what's available results in operation failure. + // The default implementation is parameterized as follows: + // - a capacity of 500 (DefaultRetryRateTokens) + // - a retry caused by a timeout costs 10 tokens (DefaultRetryCost) + // - a retry caused by other errors costs 5 tokens (DefaultRetryTimeoutCost) + // - an operation that succeeds on the 1st attempt adds 1 token (DefaultNoRetryIncrement) + // + // You can disable rate limiting by setting this field to ratelimit.None. RateLimiter RateLimiter // The cost to deduct from the RateLimiter's token bucket per retry. diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/headers.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/headers.go index ca738f2..d99b32c 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/headers.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4/headers.go @@ -4,10 +4,11 @@ package v4 var IgnoredHeaders = Rules{ ExcludeList{ MapRule{ - "Authorization": struct{}{}, - "User-Agent": struct{}{}, - "X-Amzn-Trace-Id": struct{}{}, - "Expect": struct{}{}, + "Authorization": struct{}{}, + "User-Agent": struct{}{}, + "X-Amzn-Trace-Id": struct{}{}, + "Expect": struct{}{}, + "Transfer-Encoding": struct{}{}, }, }, } @@ -38,7 +39,6 @@ var RequiredSignedHeaders = Rules{ "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Algorithm": struct{}{}, "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key": struct{}{}, "X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key-Md5": struct{}{}, - "X-Amz-Expected-Bucket-Owner": struct{}{}, "X-Amz-Grant-Full-control": struct{}{}, "X-Amz-Grant-Read": struct{}{}, "X-Amz-Grant-Read-Acp": struct{}{}, @@ -46,7 +46,6 @@ var RequiredSignedHeaders = Rules{ "X-Amz-Grant-Write-Acp": struct{}{}, "X-Amz-Metadata-Directive": struct{}{}, "X-Amz-Mfa": struct{}{}, - "X-Amz-Request-Payer": struct{}{}, "X-Amz-Server-Side-Encryption": struct{}{}, "X-Amz-Server-Side-Encryption-Aws-Kms-Key-Id": struct{}{}, "X-Amz-Server-Side-Encryption-Context": struct{}{}, diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/middleware.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/middleware.go index f39a369..8a46220 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/middleware.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/middleware.go @@ -11,11 +11,11 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" - "github.com/aws/aws-sdk-go-v2/aws/middleware/private/metrics" v4Internal "github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4" internalauth "github.com/aws/aws-sdk-go-v2/internal/auth" "github.com/aws/aws-sdk-go-v2/internal/sdk" "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" ) @@ -85,12 +85,12 @@ func (m *dynamicPayloadSigningMiddleware) HandleFinalize( } if req.IsHTTPS() { - return (&unsignedPayload{}).HandleFinalize(ctx, in, next) + return (&UnsignedPayload{}).HandleFinalize(ctx, in, next) } - return (&computePayloadSHA256{}).HandleFinalize(ctx, in, next) + return (&ComputePayloadSHA256{}).HandleFinalize(ctx, in, next) } -// unsignedPayload sets the SigV4 request payload hash to unsigned. +// UnsignedPayload sets the SigV4 request payload hash to unsigned. // // Will not set the Unsigned Payload magic SHA value, if a SHA has already been // stored in the context. (e.g. application pre-computed SHA256 before making @@ -98,21 +98,21 @@ func (m *dynamicPayloadSigningMiddleware) HandleFinalize( // // This middleware does not check the X-Amz-Content-Sha256 header, if that // header is serialized a middleware must translate it into the context. -type unsignedPayload struct{} +type UnsignedPayload struct{} // AddUnsignedPayloadMiddleware adds unsignedPayload to the operation // middleware stack func AddUnsignedPayloadMiddleware(stack *middleware.Stack) error { - return stack.Finalize.Insert(&unsignedPayload{}, "ResolveEndpointV2", middleware.After) + return stack.Finalize.Insert(&UnsignedPayload{}, "ResolveEndpointV2", middleware.After) } // ID returns the unsignedPayload identifier -func (m *unsignedPayload) ID() string { +func (m *UnsignedPayload) ID() string { return computePayloadHashMiddlewareID } // HandleFinalize sets the payload hash magic value to the unsigned sentinel. -func (m *unsignedPayload) HandleFinalize( +func (m *UnsignedPayload) HandleFinalize( ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler, ) ( out middleware.FinalizeOutput, metadata middleware.Metadata, err error, @@ -123,7 +123,7 @@ func (m *unsignedPayload) HandleFinalize( return next.HandleFinalize(ctx, in) } -// computePayloadSHA256 computes SHA256 payload hash to sign. +// ComputePayloadSHA256 computes SHA256 payload hash to sign. // // Will not set the Unsigned Payload magic SHA value, if a SHA has already been // stored in the context. (e.g. application pre-computed SHA256 before making @@ -131,12 +131,12 @@ func (m *unsignedPayload) HandleFinalize( // // This middleware does not check the X-Amz-Content-Sha256 header, if that // header is serialized a middleware must translate it into the context. -type computePayloadSHA256 struct{} +type ComputePayloadSHA256 struct{} // AddComputePayloadSHA256Middleware adds computePayloadSHA256 to the // operation middleware stack func AddComputePayloadSHA256Middleware(stack *middleware.Stack) error { - return stack.Finalize.Insert(&computePayloadSHA256{}, "ResolveEndpointV2", middleware.After) + return stack.Finalize.Insert(&ComputePayloadSHA256{}, "ResolveEndpointV2", middleware.After) } // RemoveComputePayloadSHA256Middleware removes computePayloadSHA256 from the @@ -147,13 +147,13 @@ func RemoveComputePayloadSHA256Middleware(stack *middleware.Stack) error { } // ID is the middleware name -func (m *computePayloadSHA256) ID() string { +func (m *ComputePayloadSHA256) ID() string { return computePayloadHashMiddlewareID } // HandleFinalize computes the payload hash for the request, storing it to the // context. This is a no-op if a caller has previously set that value. -func (m *computePayloadSHA256) HandleFinalize( +func (m *ComputePayloadSHA256) HandleFinalize( ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler, ) ( out middleware.FinalizeOutput, metadata middleware.Metadata, err error, @@ -162,6 +162,9 @@ func (m *computePayloadSHA256) HandleFinalize( return next.HandleFinalize(ctx, in) } + _, span := tracing.StartSpan(ctx, "ComputePayloadSHA256") + defer span.End() + req, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, &HashComputationError{ @@ -187,6 +190,7 @@ func (m *computePayloadSHA256) HandleFinalize( ctx = SetPayloadHash(ctx, hex.EncodeToString(hash.Sum(nil))) + span.End() return next.HandleFinalize(ctx, in) } @@ -196,35 +200,35 @@ func (m *computePayloadSHA256) HandleFinalize( // Use this to disable computing the Payload SHA256 checksum and instead use // UNSIGNED-PAYLOAD for the SHA256 value. func SwapComputePayloadSHA256ForUnsignedPayloadMiddleware(stack *middleware.Stack) error { - _, err := stack.Finalize.Swap(computePayloadHashMiddlewareID, &unsignedPayload{}) + _, err := stack.Finalize.Swap(computePayloadHashMiddlewareID, &UnsignedPayload{}) return err } -// contentSHA256Header sets the X-Amz-Content-Sha256 header value to +// ContentSHA256Header sets the X-Amz-Content-Sha256 header value to // the Payload hash stored in the context. -type contentSHA256Header struct{} +type ContentSHA256Header struct{} // AddContentSHA256HeaderMiddleware adds ContentSHA256Header to the // operation middleware stack func AddContentSHA256HeaderMiddleware(stack *middleware.Stack) error { - return stack.Finalize.Insert(&contentSHA256Header{}, computePayloadHashMiddlewareID, middleware.After) + return stack.Finalize.Insert(&ContentSHA256Header{}, computePayloadHashMiddlewareID, middleware.After) } // RemoveContentSHA256HeaderMiddleware removes contentSHA256Header middleware // from the operation middleware stack func RemoveContentSHA256HeaderMiddleware(stack *middleware.Stack) error { - _, err := stack.Finalize.Remove((*contentSHA256Header)(nil).ID()) + _, err := stack.Finalize.Remove((*ContentSHA256Header)(nil).ID()) return err } // ID returns the ContentSHA256HeaderMiddleware identifier -func (m *contentSHA256Header) ID() string { +func (m *ContentSHA256Header) ID() string { return "SigV4ContentSHA256Header" } // HandleFinalize sets the X-Amz-Content-Sha256 header value to the Payload hash // stored in the context. -func (m *contentSHA256Header) HandleFinalize( +func (m *ContentSHA256Header) HandleFinalize( ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler, ) ( out middleware.FinalizeOutput, metadata middleware.Metadata, err error, @@ -301,22 +305,7 @@ func (s *SignHTTPRequestMiddleware) HandleFinalize(ctx context.Context, in middl return out, metadata, &SigningError{Err: fmt.Errorf("computed payload hash missing from context")} } - mctx := metrics.Context(ctx) - - if mctx != nil { - if attempt, err := mctx.Data().LatestAttempt(); err == nil { - attempt.CredentialFetchStartTime = sdk.NowTime() - } - } - credentials, err := s.credentialsProvider.Retrieve(ctx) - - if mctx != nil { - if attempt, err := mctx.Data().LatestAttempt(); err == nil { - attempt.CredentialFetchEndTime = sdk.NowTime() - } - } - if err != nil { return out, metadata, &SigningError{Err: fmt.Errorf("failed to retrieve credentials: %w", err)} } @@ -337,20 +326,7 @@ func (s *SignHTTPRequestMiddleware) HandleFinalize(ctx context.Context, in middl }) } - if mctx != nil { - if attempt, err := mctx.Data().LatestAttempt(); err == nil { - attempt.SignStartTime = sdk.NowTime() - } - } - err = s.signer.SignHTTP(ctx, credentials, req.Request, payloadHash, signingName, signingRegion, sdk.NowTime(), signerOptions...) - - if mctx != nil { - if attempt, err := mctx.Data().LatestAttempt(); err == nil { - attempt.SignEndTime = sdk.NowTime() - } - } - if err != nil { return out, metadata, &SigningError{Err: fmt.Errorf("failed to sign http request, %w", err)} } @@ -360,18 +336,21 @@ func (s *SignHTTPRequestMiddleware) HandleFinalize(ctx context.Context, in middl return next.HandleFinalize(ctx, in) } -type streamingEventsPayload struct{} +// StreamingEventsPayload signs input event stream messages. +type StreamingEventsPayload struct{} // AddStreamingEventsPayload adds the streamingEventsPayload middleware to the stack. func AddStreamingEventsPayload(stack *middleware.Stack) error { - return stack.Finalize.Add(&streamingEventsPayload{}, middleware.Before) + return stack.Finalize.Add(&StreamingEventsPayload{}, middleware.Before) } -func (s *streamingEventsPayload) ID() string { +// ID identifies the middleware. +func (s *StreamingEventsPayload) ID() string { return computePayloadHashMiddlewareID } -func (s *streamingEventsPayload) HandleFinalize( +// HandleFinalize marks the input stream to be signed with SigV4. +func (s *StreamingEventsPayload) HandleFinalize( ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler, ) ( out middleware.FinalizeOutput, metadata middleware.Metadata, err error, @@ -393,8 +372,9 @@ func GetSignedRequestSignature(r *http.Request) ([]byte, error) { const authHeaderSignatureElem = "Signature=" if auth := r.Header.Get(authorizationHeader); len(auth) != 0 { - ps := strings.Split(auth, ", ") + ps := strings.Split(auth, ",") for _, p := range ps { + p = strings.TrimSpace(p) if idx := strings.Index(p, authHeaderSignatureElem); idx >= 0 { sig := p[len(authHeaderSignatureElem):] if len(sig) == 0 { diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/v4.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/v4.go index bb61904..7ed91d5 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/v4.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/signer/v4/v4.go @@ -1,48 +1,41 @@ -// Package v4 implements signing for AWS V4 signer +// Package v4 implements the AWS signature version 4 algorithm (commonly known +// as SigV4). // -// Provides request signing for request that need to be signed with -// AWS V4 Signatures. +// For more information about SigV4, see [Signing AWS API requests] in the IAM +// user guide. // -// # Standalone Signer +// While this implementation CAN work in an external context, it is developed +// primarily for SDK use and you may encounter fringe behaviors around header +// canonicalization. // -// Generally using the signer outside of the SDK should not require any additional +// # Pre-escaping a request URI // -// The signer does this by taking advantage of the URL.EscapedPath method. If your request URI requires +// AWS v4 signature validation requires that the canonical string's URI path +// component must be the escaped form of the HTTP request's path. // -// additional escaping you many need to use the URL.Opaque to define what the raw URI should be sent -// to the service as. +// The Go HTTP client will perform escaping automatically on the HTTP request. +// This may cause signature validation errors because the request differs from +// the URI path or query from which the signature was generated. // -// The signer will first check the URL.Opaque field, and use its value if set. -// The signer does require the URL.Opaque field to be set in the form of: +// Because of this, we recommend that you explicitly escape the request when +// using this signer outside of the SDK to prevent possible signature mismatch. +// This can be done by setting URL.Opaque on the request. The signer will +// prefer that value, falling back to the return of URL.EscapedPath if unset. +// +// When setting URL.Opaque you must do so in the form of: // // "///" // // // e.g. // "//example.com/some/path" // -// The leading "//" and hostname are required or the URL.Opaque escaping will -// not work correctly. +// The leading "//" and hostname are required or the escaping will not work +// correctly. // -// If URL.Opaque is not set the signer will fallback to the URL.EscapedPath() -// method and using the returned value. +// The TestStandaloneSign unit test provides a complete example of using the +// signer outside of the SDK and pre-escaping the URI path. // -// AWS v4 signature validation requires that the canonical string's URI path -// element must be the URI escaped form of the HTTP request's path. -// http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html -// -// The Go HTTP client will perform escaping automatically on the request. Some -// of these escaping may cause signature validation errors because the HTTP -// request differs from the URI path or query that the signature was generated. -// https://golang.org/pkg/net/url/#URL.EscapedPath -// -// Because of this, it is recommended that when using the signer outside of the -// SDK that explicitly escaping the request prior to being signed is preferable, -// and will help prevent signature validation errors. This can be done by setting -// the URL.Opaque or URL.RawPath. The SDK will use URL.Opaque first and then -// call URL.EscapedPath() if Opaque is not set. -// -// Test `TestStandaloneSign` provides a complete example of using the signer -// outside of the SDK and pre-escaping the URI path. +// [Signing AWS API requests]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-signing.html package v4 import ( @@ -401,7 +394,18 @@ func (s *httpSigner) buildCredentialScope() string { func buildQuery(r v4Internal.Rule, header http.Header) (url.Values, http.Header) { query := url.Values{} unsignedHeaders := http.Header{} + + // A list of headers to be converted to lower case to mitigate a limitation from S3 + lowerCaseHeaders := map[string]string{ + "X-Amz-Expected-Bucket-Owner": "x-amz-expected-bucket-owner", // see #2508 + "X-Amz-Request-Payer": "x-amz-request-payer", // see #2764 + } + for k, h := range header { + if newKey, ok := lowerCaseHeaders[k]; ok { + k = newKey + } + if r.IsValid(k) { query[k] = h } else { diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/client.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/client.go index 26d9071..8d7c35a 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/client.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/client.go @@ -1,13 +1,16 @@ package http import ( + "context" "crypto/tls" - "github.com/aws/aws-sdk-go-v2/aws" "net" "net/http" "reflect" "sync" "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/smithy-go/tracing" ) // Defaults for the HTTPTransportBuilder. @@ -179,7 +182,7 @@ func defaultHTTPTransport() *http.Transport { tr := &http.Transport{ Proxy: http.ProxyFromEnvironment, - DialContext: dialer.DialContext, + DialContext: traceDialContext(dialer.DialContext), TLSHandshakeTimeout: DefaultHTTPTransportTLSHandleshakeTimeout, MaxIdleConns: DefaultHTTPTransportMaxIdleConns, MaxIdleConnsPerHost: DefaultHTTPTransportMaxIdleConnsPerHost, @@ -194,6 +197,35 @@ func defaultHTTPTransport() *http.Transport { return tr } +type dialContext func(ctx context.Context, network, addr string) (net.Conn, error) + +func traceDialContext(dc dialContext) dialContext { + return func(ctx context.Context, network, addr string) (net.Conn, error) { + span, _ := tracing.GetSpan(ctx) + span.SetProperty("net.peer.name", addr) + + conn, err := dc(ctx, network, addr) + if err != nil { + return conn, err + } + + raddr := conn.RemoteAddr() + if raddr == nil { + return conn, err + } + + host, port, err := net.SplitHostPort(raddr.String()) + if err != nil { // don't blow up just because we couldn't parse + span.SetProperty("net.peer.addr", raddr.String()) + } else { + span.SetProperty("net.peer.host", host) + span.SetProperty("net.peer.port", port) + } + + return conn, err + } +} + // shallowCopyStruct creates a shallow copy of the passed in source struct, and // returns that copy of the same struct type. func shallowCopyStruct(src interface{}) interface{} { diff --git a/vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/response_error_middleware.go b/vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/response_error_middleware.go index 8fd14ce..a1ad20f 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/response_error_middleware.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/aws/transport/http/response_error_middleware.go @@ -12,18 +12,20 @@ import ( func AddResponseErrorMiddleware(stack *middleware.Stack) error { // add error wrapper middleware before request id retriever middleware so that it can wrap the error response // returned by operation deserializers - return stack.Deserialize.Insert(&responseErrorWrapper{}, "RequestIDRetriever", middleware.Before) + return stack.Deserialize.Insert(&ResponseErrorWrapper{}, "RequestIDRetriever", middleware.Before) } -type responseErrorWrapper struct { +// ResponseErrorWrapper wraps operation errors with ResponseError. +type ResponseErrorWrapper struct { } // ID returns the middleware identifier -func (m *responseErrorWrapper) ID() string { +func (m *ResponseErrorWrapper) ID() string { return "ResponseErrorWrapper" } -func (m *responseErrorWrapper) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( +// HandleDeserialize wraps the stack error with smithyhttp.ResponseError. +func (m *ResponseErrorWrapper) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( out middleware.DeserializeOutput, metadata middleware.Metadata, err error, ) { out, metadata, err = next.HandleDeserialize(ctx, in) diff --git a/vendor/github.com/aws/aws-sdk-go-v2/config/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/config/CHANGELOG.md index 5243736..9da5e6a 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/config/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/config/CHANGELOG.md @@ -1,3 +1,265 @@ +# v1.29.5 (2025-02-04) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.29.4 (2025-01-31) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.29.3 (2025-01-30) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.29.2 (2025-01-24) + +* **Bug Fix**: Fix env config naming and usage of deprecated ioutil +* **Dependency Update**: Updated to the latest SDK module versions +* **Dependency Update**: Upgrade to smithy-go v1.22.2. + +# v1.29.1 (2025-01-17) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.29.0 (2025-01-15) + +* **Feature**: S3 client behavior is updated to always calculate a checksum by default for operations that support it (such as PutObject or UploadPart), or require it (such as DeleteObjects). The checksum algorithm used by default now becomes CRC32. Checksum behavior can be configured using `when_supported` and `when_required` options - in code using RequestChecksumCalculation, in shared config using request_checksum_calculation, or as env variable using AWS_REQUEST_CHECKSUM_CALCULATION. The S3 client attempts to validate response checksums for all S3 API operations that support checksums. However, if the SDK has not implemented the specified checksum algorithm then this validation is skipped. Checksum validation behavior can be configured using `when_supported` and `when_required` options - in code using ResponseChecksumValidation, in shared config using response_checksum_validation, or as env variable using AWS_RESPONSE_CHECKSUM_VALIDATION. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.11 (2025-01-14) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.10 (2025-01-10) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.9 (2025-01-09) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.8 (2025-01-08) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.7 (2024-12-19) + +* **Bug Fix**: Fix improper use of printf-style functions. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.6 (2024-12-02) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.5 (2024-11-18) + +* **Dependency Update**: Update to smithy-go v1.22.1. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.4 (2024-11-14) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.3 (2024-11-07) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.2 (2024-11-06) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.1 (2024-10-28) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.0 (2024-10-16) + +* **Feature**: Adds the LoadOptions hook `WithBaseEndpoint` for setting global endpoint override in-code. + +# v1.27.43 (2024-10-08) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.42 (2024-10-07) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.41 (2024-10-04) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.40 (2024-10-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.39 (2024-09-27) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.38 (2024-09-25) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.37 (2024-09-23) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.36 (2024-09-20) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.35 (2024-09-17) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.34 (2024-09-16) + +* **Bug Fix**: Read `AWS_CONTAINER_CREDENTIALS_FULL_URI` env variable if set when reading a profile with `credential_source`. Also ensure `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` is always read before it + +# v1.27.33 (2024-09-04) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.32 (2024-09-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.31 (2024-08-26) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.30 (2024-08-23) + +* **Bug Fix**: Don't fail credentials unit tests if credentials are found on a file + +# v1.27.29 (2024-08-22) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.28 (2024-08-15) + +* **Dependency Update**: Bump minimum Go version to 1.21. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.27 (2024-07-18) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.26 (2024-07-10.2) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.25 (2024-07-10) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.24 (2024-07-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.23 (2024-06-28) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.22 (2024-06-26) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.21 (2024-06-19) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.20 (2024-06-18) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.19 (2024-06-17) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.18 (2024-06-07) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.17 (2024-06-03) + +* **Documentation**: Add deprecation docs to global endpoint resolution interfaces. These APIs were previously deprecated with the introduction of service-specific endpoint resolution (EndpointResolverV2 and BaseEndpoint on service client options). +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.16 (2024-05-23) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.15 (2024-05-16) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.14 (2024-05-15) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.13 (2024-05-10) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.12 (2024-05-08) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.11 (2024-04-05) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.10 (2024-03-29) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.9 (2024-03-21) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.8 (2024-03-18) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.7 (2024-03-07) + +* **Bug Fix**: Remove dependency on go-cmp. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.6 (2024-03-05) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.5 (2024-03-04) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.4 (2024-02-23) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.3 (2024-02-22) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.2 (2024-02-21) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.1 (2024-02-20) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.26.6 (2024-01-22) + +* **Bug Fix**: Remove invalid escaping of shared config values. All values in the shared config file will now be interpreted literally, save for fully-quoted strings which are unwrapped for legacy reasons. +* **Dependency Update**: Updated to the latest SDK module versions + # v1.26.5 (2024-01-18) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/config/config.go b/vendor/github.com/aws/aws-sdk-go-v2/config/config.go index 50582d8..09d9b63 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/config/config.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/config/config.go @@ -80,6 +80,15 @@ var defaultAWSConfigResolvers = []awsConfigResolver{ // Sets the RequestMinCompressSizeBytes if present in env var or shared config profile resolveRequestMinCompressSizeBytes, + + // Sets the AccountIDEndpointMode if present in env var or shared config profile + resolveAccountIDEndpointMode, + + // Sets the RequestChecksumCalculation if present in env var or shared config profile + resolveRequestChecksumCalculation, + + // Sets the ResponseChecksumValidation if present in env var or shared config profile + resolveResponseChecksumValidation, } // A Config represents a generic configuration value or set of values. This type @@ -209,7 +218,7 @@ func resolveConfigLoaders(options *LoadOptions) []loader { loaders[0] = loadEnvConfig // specification of a profile should cause a load failure if it doesn't exist - if os.Getenv(awsProfileEnvVar) != "" || options.SharedConfigProfile != "" { + if os.Getenv(awsProfileEnv) != "" || options.SharedConfigProfile != "" { loaders[1] = loadSharedConfig } else { loaders[1] = loadSharedConfigIgnoreNotExist diff --git a/vendor/github.com/aws/aws-sdk-go-v2/config/env_config.go b/vendor/github.com/aws/aws-sdk-go-v2/config/env_config.go index 8855019..9db507e 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/config/env_config.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/config/env_config.go @@ -5,7 +5,6 @@ import ( "context" "fmt" "io" - "io/ioutil" "os" "strconv" "strings" @@ -21,83 +20,89 @@ const CredentialsSourceName = "EnvConfigCredentials" // Environment variables that will be read for configuration values. const ( - awsAccessKeyIDEnvVar = "AWS_ACCESS_KEY_ID" - awsAccessKeyEnvVar = "AWS_ACCESS_KEY" + awsAccessKeyIDEnv = "AWS_ACCESS_KEY_ID" + awsAccessKeyEnv = "AWS_ACCESS_KEY" - awsSecretAccessKeyEnvVar = "AWS_SECRET_ACCESS_KEY" - awsSecretKeyEnvVar = "AWS_SECRET_KEY" + awsSecretAccessKeyEnv = "AWS_SECRET_ACCESS_KEY" + awsSecretKeyEnv = "AWS_SECRET_KEY" - awsSessionTokenEnvVar = "AWS_SESSION_TOKEN" + awsSessionTokenEnv = "AWS_SESSION_TOKEN" - awsContainerCredentialsEndpointEnvVar = "AWS_CONTAINER_CREDENTIALS_FULL_URI" - awsContainerCredentialsRelativePathEnvVar = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" - awsContainerPProviderAuthorizationEnvVar = "AWS_CONTAINER_AUTHORIZATION_TOKEN" + awsContainerCredentialsFullURIEnv = "AWS_CONTAINER_CREDENTIALS_FULL_URI" + awsContainerCredentialsRelativeURIEnv = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" + awsContainerAuthorizationTokenEnv = "AWS_CONTAINER_AUTHORIZATION_TOKEN" - awsRegionEnvVar = "AWS_REGION" - awsDefaultRegionEnvVar = "AWS_DEFAULT_REGION" + awsRegionEnv = "AWS_REGION" + awsDefaultRegionEnv = "AWS_DEFAULT_REGION" - awsProfileEnvVar = "AWS_PROFILE" - awsDefaultProfileEnvVar = "AWS_DEFAULT_PROFILE" + awsProfileEnv = "AWS_PROFILE" + awsDefaultProfileEnv = "AWS_DEFAULT_PROFILE" - awsSharedCredentialsFileEnvVar = "AWS_SHARED_CREDENTIALS_FILE" + awsSharedCredentialsFileEnv = "AWS_SHARED_CREDENTIALS_FILE" - awsConfigFileEnvVar = "AWS_CONFIG_FILE" + awsConfigFileEnv = "AWS_CONFIG_FILE" - awsCustomCABundleEnvVar = "AWS_CA_BUNDLE" + awsCABundleEnv = "AWS_CA_BUNDLE" - awsWebIdentityTokenFilePathEnvVar = "AWS_WEB_IDENTITY_TOKEN_FILE" + awsWebIdentityTokenFileEnv = "AWS_WEB_IDENTITY_TOKEN_FILE" - awsRoleARNEnvVar = "AWS_ROLE_ARN" - awsRoleSessionNameEnvVar = "AWS_ROLE_SESSION_NAME" + awsRoleARNEnv = "AWS_ROLE_ARN" + awsRoleSessionNameEnv = "AWS_ROLE_SESSION_NAME" - awsEnableEndpointDiscoveryEnvVar = "AWS_ENABLE_ENDPOINT_DISCOVERY" + awsEnableEndpointDiscoveryEnv = "AWS_ENABLE_ENDPOINT_DISCOVERY" - awsS3UseARNRegionEnvVar = "AWS_S3_USE_ARN_REGION" + awsS3UseARNRegionEnv = "AWS_S3_USE_ARN_REGION" - awsEc2MetadataServiceEndpointModeEnvVar = "AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE" + awsEc2MetadataServiceEndpointModeEnv = "AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE" - awsEc2MetadataServiceEndpointEnvVar = "AWS_EC2_METADATA_SERVICE_ENDPOINT" + awsEc2MetadataServiceEndpointEnv = "AWS_EC2_METADATA_SERVICE_ENDPOINT" - awsEc2MetadataDisabled = "AWS_EC2_METADATA_DISABLED" - awsEc2MetadataV1DisabledEnvVar = "AWS_EC2_METADATA_V1_DISABLED" + awsEc2MetadataDisabledEnv = "AWS_EC2_METADATA_DISABLED" + awsEc2MetadataV1DisabledEnv = "AWS_EC2_METADATA_V1_DISABLED" - awsS3DisableMultiRegionAccessPointEnvVar = "AWS_S3_DISABLE_MULTIREGION_ACCESS_POINTS" + awsS3DisableMultiRegionAccessPointsEnv = "AWS_S3_DISABLE_MULTIREGION_ACCESS_POINTS" - awsUseDualStackEndpoint = "AWS_USE_DUALSTACK_ENDPOINT" + awsUseDualStackEndpointEnv = "AWS_USE_DUALSTACK_ENDPOINT" - awsUseFIPSEndpoint = "AWS_USE_FIPS_ENDPOINT" + awsUseFIPSEndpointEnv = "AWS_USE_FIPS_ENDPOINT" - awsDefaultMode = "AWS_DEFAULTS_MODE" + awsDefaultsModeEnv = "AWS_DEFAULTS_MODE" - awsRetryMaxAttempts = "AWS_MAX_ATTEMPTS" - awsRetryMode = "AWS_RETRY_MODE" - awsSdkAppID = "AWS_SDK_UA_APP_ID" + awsMaxAttemptsEnv = "AWS_MAX_ATTEMPTS" + awsRetryModeEnv = "AWS_RETRY_MODE" + awsSdkUaAppIDEnv = "AWS_SDK_UA_APP_ID" - awsIgnoreConfiguredEndpoints = "AWS_IGNORE_CONFIGURED_ENDPOINT_URLS" - awsEndpointURL = "AWS_ENDPOINT_URL" + awsIgnoreConfiguredEndpointURLEnv = "AWS_IGNORE_CONFIGURED_ENDPOINT_URLS" + awsEndpointURLEnv = "AWS_ENDPOINT_URL" - awsDisableRequestCompression = "AWS_DISABLE_REQUEST_COMPRESSION" - awsRequestMinCompressionSizeBytes = "AWS_REQUEST_MIN_COMPRESSION_SIZE_BYTES" + awsDisableRequestCompressionEnv = "AWS_DISABLE_REQUEST_COMPRESSION" + awsRequestMinCompressionSizeBytesEnv = "AWS_REQUEST_MIN_COMPRESSION_SIZE_BYTES" awsS3DisableExpressSessionAuthEnv = "AWS_S3_DISABLE_EXPRESS_SESSION_AUTH" + + awsAccountIDEnv = "AWS_ACCOUNT_ID" + awsAccountIDEndpointModeEnv = "AWS_ACCOUNT_ID_ENDPOINT_MODE" + + awsRequestChecksumCalculation = "AWS_REQUEST_CHECKSUM_CALCULATION" + awsResponseChecksumValidation = "AWS_RESPONSE_CHECKSUM_VALIDATION" ) var ( credAccessEnvKeys = []string{ - awsAccessKeyIDEnvVar, - awsAccessKeyEnvVar, + awsAccessKeyIDEnv, + awsAccessKeyEnv, } credSecretEnvKeys = []string{ - awsSecretAccessKeyEnvVar, - awsSecretKeyEnvVar, + awsSecretAccessKeyEnv, + awsSecretKeyEnv, } regionEnvKeys = []string{ - awsRegionEnvVar, - awsDefaultRegionEnvVar, + awsRegionEnv, + awsDefaultRegionEnv, } profileEnvKeys = []string{ - awsProfileEnvVar, - awsDefaultProfileEnvVar, + awsProfileEnv, + awsDefaultProfileEnv, } ) @@ -290,6 +295,15 @@ type EnvConfig struct { // will only bypass the modified endpoint routing and signing behaviors // associated with the feature. S3DisableExpressAuth *bool + + // Indicates whether account ID will be required/ignored in endpoint2.0 routing + AccountIDEndpointMode aws.AccountIDEndpointMode + + // Indicates whether request checksum should be calculated + RequestChecksumCalculation aws.RequestChecksumCalculation + + // Indicates whether response checksum should be validated + ResponseChecksumValidation aws.ResponseChecksumValidation } // loadEnvConfig reads configuration values from the OS's environment variables. @@ -309,79 +323,80 @@ func NewEnvConfig() (EnvConfig, error) { setStringFromEnvVal(&creds.AccessKeyID, credAccessEnvKeys) setStringFromEnvVal(&creds.SecretAccessKey, credSecretEnvKeys) if creds.HasKeys() { - creds.SessionToken = os.Getenv(awsSessionTokenEnvVar) + creds.AccountID = os.Getenv(awsAccountIDEnv) + creds.SessionToken = os.Getenv(awsSessionTokenEnv) cfg.Credentials = creds } - cfg.ContainerCredentialsEndpoint = os.Getenv(awsContainerCredentialsEndpointEnvVar) - cfg.ContainerCredentialsRelativePath = os.Getenv(awsContainerCredentialsRelativePathEnvVar) - cfg.ContainerAuthorizationToken = os.Getenv(awsContainerPProviderAuthorizationEnvVar) + cfg.ContainerCredentialsEndpoint = os.Getenv(awsContainerCredentialsFullURIEnv) + cfg.ContainerCredentialsRelativePath = os.Getenv(awsContainerCredentialsRelativeURIEnv) + cfg.ContainerAuthorizationToken = os.Getenv(awsContainerAuthorizationTokenEnv) setStringFromEnvVal(&cfg.Region, regionEnvKeys) setStringFromEnvVal(&cfg.SharedConfigProfile, profileEnvKeys) - cfg.SharedCredentialsFile = os.Getenv(awsSharedCredentialsFileEnvVar) - cfg.SharedConfigFile = os.Getenv(awsConfigFileEnvVar) + cfg.SharedCredentialsFile = os.Getenv(awsSharedCredentialsFileEnv) + cfg.SharedConfigFile = os.Getenv(awsConfigFileEnv) - cfg.CustomCABundle = os.Getenv(awsCustomCABundleEnvVar) + cfg.CustomCABundle = os.Getenv(awsCABundleEnv) - cfg.WebIdentityTokenFilePath = os.Getenv(awsWebIdentityTokenFilePathEnvVar) + cfg.WebIdentityTokenFilePath = os.Getenv(awsWebIdentityTokenFileEnv) - cfg.RoleARN = os.Getenv(awsRoleARNEnvVar) - cfg.RoleSessionName = os.Getenv(awsRoleSessionNameEnvVar) + cfg.RoleARN = os.Getenv(awsRoleARNEnv) + cfg.RoleSessionName = os.Getenv(awsRoleSessionNameEnv) - cfg.AppID = os.Getenv(awsSdkAppID) + cfg.AppID = os.Getenv(awsSdkUaAppIDEnv) - if err := setBoolPtrFromEnvVal(&cfg.DisableRequestCompression, []string{awsDisableRequestCompression}); err != nil { + if err := setBoolPtrFromEnvVal(&cfg.DisableRequestCompression, []string{awsDisableRequestCompressionEnv}); err != nil { return cfg, err } - if err := setInt64PtrFromEnvVal(&cfg.RequestMinCompressSizeBytes, []string{awsRequestMinCompressionSizeBytes}, smithyrequestcompression.MaxRequestMinCompressSizeBytes); err != nil { + if err := setInt64PtrFromEnvVal(&cfg.RequestMinCompressSizeBytes, []string{awsRequestMinCompressionSizeBytesEnv}, smithyrequestcompression.MaxRequestMinCompressSizeBytes); err != nil { return cfg, err } - if err := setEndpointDiscoveryTypeFromEnvVal(&cfg.EnableEndpointDiscovery, []string{awsEnableEndpointDiscoveryEnvVar}); err != nil { + if err := setEndpointDiscoveryTypeFromEnvVal(&cfg.EnableEndpointDiscovery, []string{awsEnableEndpointDiscoveryEnv}); err != nil { return cfg, err } - if err := setBoolPtrFromEnvVal(&cfg.S3UseARNRegion, []string{awsS3UseARNRegionEnvVar}); err != nil { + if err := setBoolPtrFromEnvVal(&cfg.S3UseARNRegion, []string{awsS3UseARNRegionEnv}); err != nil { return cfg, err } - setEC2IMDSClientEnableState(&cfg.EC2IMDSClientEnableState, []string{awsEc2MetadataDisabled}) - if err := setEC2IMDSEndpointMode(&cfg.EC2IMDSEndpointMode, []string{awsEc2MetadataServiceEndpointModeEnvVar}); err != nil { + setEC2IMDSClientEnableState(&cfg.EC2IMDSClientEnableState, []string{awsEc2MetadataDisabledEnv}) + if err := setEC2IMDSEndpointMode(&cfg.EC2IMDSEndpointMode, []string{awsEc2MetadataServiceEndpointModeEnv}); err != nil { return cfg, err } - cfg.EC2IMDSEndpoint = os.Getenv(awsEc2MetadataServiceEndpointEnvVar) - if err := setBoolPtrFromEnvVal(&cfg.EC2IMDSv1Disabled, []string{awsEc2MetadataV1DisabledEnvVar}); err != nil { + cfg.EC2IMDSEndpoint = os.Getenv(awsEc2MetadataServiceEndpointEnv) + if err := setBoolPtrFromEnvVal(&cfg.EC2IMDSv1Disabled, []string{awsEc2MetadataV1DisabledEnv}); err != nil { return cfg, err } - if err := setBoolPtrFromEnvVal(&cfg.S3DisableMultiRegionAccessPoints, []string{awsS3DisableMultiRegionAccessPointEnvVar}); err != nil { + if err := setBoolPtrFromEnvVal(&cfg.S3DisableMultiRegionAccessPoints, []string{awsS3DisableMultiRegionAccessPointsEnv}); err != nil { return cfg, err } - if err := setUseDualStackEndpointFromEnvVal(&cfg.UseDualStackEndpoint, []string{awsUseDualStackEndpoint}); err != nil { + if err := setUseDualStackEndpointFromEnvVal(&cfg.UseDualStackEndpoint, []string{awsUseDualStackEndpointEnv}); err != nil { return cfg, err } - if err := setUseFIPSEndpointFromEnvVal(&cfg.UseFIPSEndpoint, []string{awsUseFIPSEndpoint}); err != nil { + if err := setUseFIPSEndpointFromEnvVal(&cfg.UseFIPSEndpoint, []string{awsUseFIPSEndpointEnv}); err != nil { return cfg, err } - if err := setDefaultsModeFromEnvVal(&cfg.DefaultsMode, []string{awsDefaultMode}); err != nil { + if err := setDefaultsModeFromEnvVal(&cfg.DefaultsMode, []string{awsDefaultsModeEnv}); err != nil { return cfg, err } - if err := setIntFromEnvVal(&cfg.RetryMaxAttempts, []string{awsRetryMaxAttempts}); err != nil { + if err := setIntFromEnvVal(&cfg.RetryMaxAttempts, []string{awsMaxAttemptsEnv}); err != nil { return cfg, err } - if err := setRetryModeFromEnvVal(&cfg.RetryMode, []string{awsRetryMode}); err != nil { + if err := setRetryModeFromEnvVal(&cfg.RetryMode, []string{awsRetryModeEnv}); err != nil { return cfg, err } - setStringFromEnvVal(&cfg.BaseEndpoint, []string{awsEndpointURL}) + setStringFromEnvVal(&cfg.BaseEndpoint, []string{awsEndpointURLEnv}) - if err := setBoolPtrFromEnvVal(&cfg.IgnoreConfiguredEndpoints, []string{awsIgnoreConfiguredEndpoints}); err != nil { + if err := setBoolPtrFromEnvVal(&cfg.IgnoreConfiguredEndpoints, []string{awsIgnoreConfiguredEndpointURLEnv}); err != nil { return cfg, err } @@ -389,6 +404,17 @@ func NewEnvConfig() (EnvConfig, error) { return cfg, err } + if err := setAIDEndPointModeFromEnvVal(&cfg.AccountIDEndpointMode, []string{awsAccountIDEndpointModeEnv}); err != nil { + return cfg, err + } + + if err := setRequestChecksumCalculationFromEnvVal(&cfg.RequestChecksumCalculation, []string{awsRequestChecksumCalculation}); err != nil { + return cfg, err + } + if err := setResponseChecksumValidationFromEnvVal(&cfg.ResponseChecksumValidation, []string{awsResponseChecksumValidation}); err != nil { + return cfg, err + } + return cfg, nil } @@ -417,6 +443,18 @@ func (c EnvConfig) getRequestMinCompressSizeBytes(context.Context) (int64, bool, return *c.RequestMinCompressSizeBytes, true, nil } +func (c EnvConfig) getAccountIDEndpointMode(context.Context) (aws.AccountIDEndpointMode, bool, error) { + return c.AccountIDEndpointMode, len(c.AccountIDEndpointMode) > 0, nil +} + +func (c EnvConfig) getRequestChecksumCalculation(context.Context) (aws.RequestChecksumCalculation, bool, error) { + return c.RequestChecksumCalculation, c.RequestChecksumCalculation > 0, nil +} + +func (c EnvConfig) getResponseChecksumValidation(context.Context) (aws.ResponseChecksumValidation, bool, error) { + return c.ResponseChecksumValidation, c.ResponseChecksumValidation > 0, nil +} + // GetRetryMaxAttempts returns the value of AWS_MAX_ATTEMPTS if was specified, // and not 0. func (c EnvConfig) GetRetryMaxAttempts(ctx context.Context) (int, bool, error) { @@ -491,6 +529,67 @@ func setEC2IMDSEndpointMode(mode *imds.EndpointModeState, keys []string) error { return nil } +func setAIDEndPointModeFromEnvVal(m *aws.AccountIDEndpointMode, keys []string) error { + for _, k := range keys { + value := os.Getenv(k) + if len(value) == 0 { + continue + } + + switch value { + case "preferred": + *m = aws.AccountIDEndpointModePreferred + case "required": + *m = aws.AccountIDEndpointModeRequired + case "disabled": + *m = aws.AccountIDEndpointModeDisabled + default: + return fmt.Errorf("invalid value for environment variable, %s=%s, must be preferred/required/disabled", k, value) + } + break + } + return nil +} + +func setRequestChecksumCalculationFromEnvVal(m *aws.RequestChecksumCalculation, keys []string) error { + for _, k := range keys { + value := os.Getenv(k) + if len(value) == 0 { + continue + } + + switch strings.ToLower(value) { + case checksumWhenSupported: + *m = aws.RequestChecksumCalculationWhenSupported + case checksumWhenRequired: + *m = aws.RequestChecksumCalculationWhenRequired + default: + return fmt.Errorf("invalid value for environment variable, %s=%s, must be when_supported/when_required", k, value) + } + } + return nil +} + +func setResponseChecksumValidationFromEnvVal(m *aws.ResponseChecksumValidation, keys []string) error { + for _, k := range keys { + value := os.Getenv(k) + if len(value) == 0 { + continue + } + + switch strings.ToLower(value) { + case checksumWhenSupported: + *m = aws.ResponseChecksumValidationWhenSupported + case checksumWhenRequired: + *m = aws.ResponseChecksumValidationWhenRequired + default: + return fmt.Errorf("invalid value for environment variable, %s=%s, must be when_supported/when_required", k, value) + } + + } + return nil +} + // GetRegion returns the AWS Region if set in the environment. Returns an empty // string if not set. func (c EnvConfig) getRegion(ctx context.Context) (string, bool, error) { @@ -547,7 +646,7 @@ func (c EnvConfig) getCustomCABundle(context.Context) (io.Reader, bool, error) { return nil, false, nil } - b, err := ioutil.ReadFile(c.CustomCABundle) + b, err := os.ReadFile(c.CustomCABundle) if err != nil { return nil, false, err } @@ -571,7 +670,7 @@ func (c EnvConfig) getBaseEndpoint(context.Context) (string, bool, error) { // GetServiceBaseEndpoint is used to retrieve a normalized SDK ID for use // with configured endpoints. func (c EnvConfig) GetServiceBaseEndpoint(ctx context.Context, sdkID string) (string, bool, error) { - if endpt := os.Getenv(fmt.Sprintf("%s_%s", awsEndpointURL, normalizeEnv(sdkID))); endpt != "" { + if endpt := os.Getenv(fmt.Sprintf("%s_%s", awsEndpointURLEnv, normalizeEnv(sdkID))); endpt != "" { return endpt, true, nil } return "", false, nil diff --git a/vendor/github.com/aws/aws-sdk-go-v2/config/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/config/go_module_metadata.go index 6fc8acb..089369e 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/config/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/config/go_module_metadata.go @@ -3,4 +3,4 @@ package config // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.26.5" +const goModuleVersion = "1.29.5" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/config/load_options.go b/vendor/github.com/aws/aws-sdk-go-v2/config/load_options.go index 06596c1..0810ecf 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/config/load_options.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/config/load_options.go @@ -215,6 +215,19 @@ type LoadOptions struct { // Whether S3 Express auth is disabled. S3DisableExpressAuth *bool + + // Whether account id should be built into endpoint resolution + AccountIDEndpointMode aws.AccountIDEndpointMode + + // Specify if request checksum should be calculated + RequestChecksumCalculation aws.RequestChecksumCalculation + + // Specifies if response checksum should be validated + ResponseChecksumValidation aws.ResponseChecksumValidation + + // Service endpoint override. This value is not necessarily final and is + // passed to the service's EndpointResolverV2 for further delegation. + BaseEndpoint string } func (o LoadOptions) getDefaultsMode(ctx context.Context) (aws.DefaultsMode, bool, error) { @@ -278,6 +291,31 @@ func (o LoadOptions) getRequestMinCompressSizeBytes(ctx context.Context) (int64, return *o.RequestMinCompressSizeBytes, true, nil } +func (o LoadOptions) getAccountIDEndpointMode(ctx context.Context) (aws.AccountIDEndpointMode, bool, error) { + return o.AccountIDEndpointMode, len(o.AccountIDEndpointMode) > 0, nil +} + +func (o LoadOptions) getRequestChecksumCalculation(ctx context.Context) (aws.RequestChecksumCalculation, bool, error) { + return o.RequestChecksumCalculation, o.RequestChecksumCalculation > 0, nil +} + +func (o LoadOptions) getResponseChecksumValidation(ctx context.Context) (aws.ResponseChecksumValidation, bool, error) { + return o.ResponseChecksumValidation, o.ResponseChecksumValidation > 0, nil +} + +func (o LoadOptions) getBaseEndpoint(context.Context) (string, bool, error) { + return o.BaseEndpoint, o.BaseEndpoint != "", nil +} + +// GetServiceBaseEndpoint satisfies (internal/configsources).ServiceBaseEndpointProvider. +// +// The sdkID value is unused because LoadOptions only supports setting a GLOBAL +// endpoint override. In-code, per-service endpoint overrides are performed via +// functional options in service client space. +func (o LoadOptions) GetServiceBaseEndpoint(context.Context, string) (string, bool, error) { + return o.BaseEndpoint, o.BaseEndpoint != "", nil +} + // WithRegion is a helper function to construct functional options // that sets Region on config's LoadOptions. Setting the region to // an empty string, will result in the region value being ignored. @@ -323,6 +361,37 @@ func WithRequestMinCompressSizeBytes(RequestMinCompressSizeBytes *int64) LoadOpt } } +// WithAccountIDEndpointMode is a helper function to construct functional options +// that sets AccountIDEndpointMode on config's LoadOptions +func WithAccountIDEndpointMode(m aws.AccountIDEndpointMode) LoadOptionsFunc { + return func(o *LoadOptions) error { + if m != "" { + o.AccountIDEndpointMode = m + } + return nil + } +} + +// WithRequestChecksumCalculation is a helper function to construct functional options +// that sets RequestChecksumCalculation on config's LoadOptions +func WithRequestChecksumCalculation(c aws.RequestChecksumCalculation) LoadOptionsFunc { + return func(o *LoadOptions) error { + if c > 0 { + o.RequestChecksumCalculation = c + } + return nil + } +} + +// WithResponseChecksumValidation is a helper function to construct functional options +// that sets ResponseChecksumValidation on config's LoadOptions +func WithResponseChecksumValidation(v aws.ResponseChecksumValidation) LoadOptionsFunc { + return func(o *LoadOptions) error { + o.ResponseChecksumValidation = v + return nil + } +} + // getDefaultRegion returns DefaultRegion from config's LoadOptions func (o LoadOptions) getDefaultRegion(ctx context.Context) (string, bool, error) { if len(o.DefaultRegion) == 0 { @@ -824,7 +893,14 @@ func (o LoadOptions) getEndpointResolver(ctx context.Context) (aws.EndpointResol // the EndpointResolver value is ignored. If multiple WithEndpointResolver calls // are made, the last call overrides the previous call values. // -// Deprecated: See WithEndpointResolverWithOptions +// Deprecated: The global endpoint resolution interface is deprecated. The API +// for endpoint resolution is now unique to each service and is set via the +// EndpointResolverV2 field on service client options. Use of +// WithEndpointResolver or WithEndpointResolverWithOptions will prevent you +// from using any endpoint-related service features released after the +// introduction of EndpointResolverV2. You may also encounter broken or +// unexpected behavior when using the old global interface with services that +// use many endpoint-related customizations such as S3. func WithEndpointResolver(v aws.EndpointResolver) LoadOptionsFunc { return func(o *LoadOptions) error { o.EndpointResolver = v @@ -844,6 +920,9 @@ func (o LoadOptions) getEndpointResolverWithOptions(ctx context.Context) (aws.En // that sets the EndpointResolverWithOptions on LoadOptions. If the EndpointResolverWithOptions is set to nil, // the EndpointResolver value is ignored. If multiple WithEndpointResolver calls // are made, the last call overrides the previous call values. +// +// Deprecated: The global endpoint resolution interface is deprecated. See +// deprecation docs on [WithEndpointResolver]. func WithEndpointResolverWithOptions(v aws.EndpointResolverWithOptions) LoadOptionsFunc { return func(o *LoadOptions) error { o.EndpointResolverWithOptions = v @@ -1112,3 +1191,19 @@ func WithS3DisableExpressAuth(v bool) LoadOptionsFunc { return nil } } + +// WithBaseEndpoint is a helper function to construct functional options that +// sets BaseEndpoint on config's LoadOptions. Empty values have no effect, and +// subsequent calls to this API override previous ones. +// +// This is an in-code setting, therefore, any value set using this hook takes +// precedence over and will override ALL environment and shared config +// directives that set endpoint URLs. Functional options on service clients +// have higher specificity, and functional options that modify the value of +// BaseEndpoint on a client will take precedence over this setting. +func WithBaseEndpoint(v string) LoadOptionsFunc { + return func(o *LoadOptions) error { + o.BaseEndpoint = v + return nil + } +} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/config/provider.go b/vendor/github.com/aws/aws-sdk-go-v2/config/provider.go index 13745fc..a8ff40d 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/config/provider.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/config/provider.go @@ -225,6 +225,57 @@ func getRequestMinCompressSizeBytes(ctx context.Context, configs configs) (value return } +// accountIDEndpointModeProvider provides access to the AccountIDEndpointMode +type accountIDEndpointModeProvider interface { + getAccountIDEndpointMode(context.Context) (aws.AccountIDEndpointMode, bool, error) +} + +func getAccountIDEndpointMode(ctx context.Context, configs configs) (value aws.AccountIDEndpointMode, found bool, err error) { + for _, cfg := range configs { + if p, ok := cfg.(accountIDEndpointModeProvider); ok { + value, found, err = p.getAccountIDEndpointMode(ctx) + if err != nil || found { + break + } + } + } + return +} + +// requestChecksumCalculationProvider provides access to the RequestChecksumCalculation +type requestChecksumCalculationProvider interface { + getRequestChecksumCalculation(context.Context) (aws.RequestChecksumCalculation, bool, error) +} + +func getRequestChecksumCalculation(ctx context.Context, configs configs) (value aws.RequestChecksumCalculation, found bool, err error) { + for _, cfg := range configs { + if p, ok := cfg.(requestChecksumCalculationProvider); ok { + value, found, err = p.getRequestChecksumCalculation(ctx) + if err != nil || found { + break + } + } + } + return +} + +// responseChecksumValidationProvider provides access to the ResponseChecksumValidation +type responseChecksumValidationProvider interface { + getResponseChecksumValidation(context.Context) (aws.ResponseChecksumValidation, bool, error) +} + +func getResponseChecksumValidation(ctx context.Context, configs configs) (value aws.ResponseChecksumValidation, found bool, err error) { + for _, cfg := range configs { + if p, ok := cfg.(responseChecksumValidationProvider); ok { + value, found, err = p.getResponseChecksumValidation(ctx) + if err != nil || found { + break + } + } + } + return +} + // ec2IMDSRegionProvider provides access to the ec2 imds region // configuration value type ec2IMDSRegionProvider interface { diff --git a/vendor/github.com/aws/aws-sdk-go-v2/config/resolve.go b/vendor/github.com/aws/aws-sdk-go-v2/config/resolve.go index fde2e39..a68bd09 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/config/resolve.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/config/resolve.go @@ -166,6 +166,52 @@ func resolveRequestMinCompressSizeBytes(ctx context.Context, cfg *aws.Config, co return nil } +// resolveAccountIDEndpointMode extracts the AccountIDEndpointMode from the configs slice's +// SharedConfig or EnvConfig +func resolveAccountIDEndpointMode(ctx context.Context, cfg *aws.Config, configs configs) error { + m, found, err := getAccountIDEndpointMode(ctx, configs) + if err != nil { + return err + } + + if !found { + m = aws.AccountIDEndpointModePreferred + } + + cfg.AccountIDEndpointMode = m + return nil +} + +// resolveRequestChecksumCalculation extracts the RequestChecksumCalculation from the configs slice's +// SharedConfig or EnvConfig +func resolveRequestChecksumCalculation(ctx context.Context, cfg *aws.Config, configs configs) error { + c, found, err := getRequestChecksumCalculation(ctx, configs) + if err != nil { + return err + } + + if !found { + c = aws.RequestChecksumCalculationWhenSupported + } + cfg.RequestChecksumCalculation = c + return nil +} + +// resolveResponseValidation extracts the ResponseChecksumValidation from the configs slice's +// SharedConfig or EnvConfig +func resolveResponseChecksumValidation(ctx context.Context, cfg *aws.Config, configs configs) error { + c, found, err := getResponseChecksumValidation(ctx, configs) + if err != nil { + return err + } + + if !found { + c = aws.ResponseChecksumValidationWhenSupported + } + cfg.ResponseChecksumValidation = c + return nil +} + // resolveDefaultRegion extracts the first instance of a default region and sets `aws.Config.Region` to the default // region if region had not been resolved from other sources. func resolveDefaultRegion(ctx context.Context, cfg *aws.Config, configs configs) error { diff --git a/vendor/github.com/aws/aws-sdk-go-v2/config/resolve_credentials.go b/vendor/github.com/aws/aws-sdk-go-v2/config/resolve_credentials.go index 8936852..7ae252e 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/config/resolve_credentials.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/config/resolve_credentials.go @@ -162,12 +162,12 @@ func resolveCredsFromProfile(ctx context.Context, cfg *aws.Config, envConfig *En // Get credentials from CredentialProcess err = processCredentials(ctx, cfg, sharedConfig, configs) - case len(envConfig.ContainerCredentialsEndpoint) != 0: - err = resolveLocalHTTPCredProvider(ctx, cfg, envConfig.ContainerCredentialsEndpoint, envConfig.ContainerAuthorizationToken, configs) - case len(envConfig.ContainerCredentialsRelativePath) != 0: err = resolveHTTPCredProvider(ctx, cfg, ecsContainerURI(envConfig.ContainerCredentialsRelativePath), envConfig.ContainerAuthorizationToken, configs) + case len(envConfig.ContainerCredentialsEndpoint) != 0: + err = resolveLocalHTTPCredProvider(ctx, cfg, envConfig.ContainerCredentialsEndpoint, envConfig.ContainerAuthorizationToken, configs) + default: err = resolveEC2RoleCredentials(ctx, cfg, configs) } @@ -355,10 +355,13 @@ func resolveCredsFromSource(ctx context.Context, cfg *aws.Config, envConfig *Env cfg.Credentials = credentials.StaticCredentialsProvider{Value: envConfig.Credentials} case credSourceECSContainer: - if len(envConfig.ContainerCredentialsRelativePath) == 0 { - return fmt.Errorf("EcsContainer was specified as the credential_source, but 'AWS_CONTAINER_CREDENTIALS_RELATIVE_URI' was not set") + if len(envConfig.ContainerCredentialsRelativePath) != 0 { + return resolveHTTPCredProvider(ctx, cfg, ecsContainerURI(envConfig.ContainerCredentialsRelativePath), envConfig.ContainerAuthorizationToken, configs) } - return resolveHTTPCredProvider(ctx, cfg, ecsContainerURI(envConfig.ContainerCredentialsRelativePath), envConfig.ContainerAuthorizationToken, configs) + if len(envConfig.ContainerCredentialsEndpoint) != 0 { + return resolveLocalHTTPCredProvider(ctx, cfg, envConfig.ContainerCredentialsEndpoint, envConfig.ContainerAuthorizationToken, configs) + } + return fmt.Errorf("EcsContainer was specified as the credential_source, but neither 'AWS_CONTAINER_CREDENTIALS_RELATIVE_URI' or AWS_CONTAINER_CREDENTIALS_FULL_URI' was set") default: return fmt.Errorf("credential_source values must be EcsContainer, Ec2InstanceMetadata, or Environment") diff --git a/vendor/github.com/aws/aws-sdk-go-v2/config/shared_config.go b/vendor/github.com/aws/aws-sdk-go-v2/config/shared_config.go index c546cb7..00b071f 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/config/shared_config.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/config/shared_config.go @@ -115,6 +115,14 @@ const ( requestMinCompressionSizeBytes = "request_min_compression_size_bytes" s3DisableExpressSessionAuthKey = "s3_disable_express_session_auth" + + accountIDKey = "aws_account_id" + accountIDEndpointMode = "account_id_endpoint_mode" + + requestChecksumCalculationKey = "request_checksum_calculation" + responseChecksumValidationKey = "response_checksum_validation" + checksumWhenSupported = "when_supported" + checksumWhenRequired = "when_required" ) // defaultSharedConfigProfile allows for swapping the default profile for testing @@ -341,6 +349,14 @@ type SharedConfig struct { // will only bypass the modified endpoint routing and signing behaviors // associated with the feature. S3DisableExpressAuth *bool + + AccountIDEndpointMode aws.AccountIDEndpointMode + + // RequestChecksumCalculation indicates if the request checksum should be calculated + RequestChecksumCalculation aws.RequestChecksumCalculation + + // ResponseChecksumValidation indicates if the response checksum should be validated + ResponseChecksumValidation aws.ResponseChecksumValidation } func (c SharedConfig) getDefaultsMode(ctx context.Context) (value aws.DefaultsMode, ok bool, err error) { @@ -1124,12 +1140,24 @@ func (c *SharedConfig) setFromIniSection(profile string, section ini.Section) er return fmt.Errorf("failed to load %s from shared config, %w", requestMinCompressionSizeBytes, err) } + if err := updateAIDEndpointMode(&c.AccountIDEndpointMode, section, accountIDEndpointMode); err != nil { + return fmt.Errorf("failed to load %s from shared config, %w", accountIDEndpointMode, err) + } + + if err := updateRequestChecksumCalculation(&c.RequestChecksumCalculation, section, requestChecksumCalculationKey); err != nil { + return fmt.Errorf("failed to load %s from shared config, %w", requestChecksumCalculationKey, err) + } + if err := updateResponseChecksumValidation(&c.ResponseChecksumValidation, section, responseChecksumValidationKey); err != nil { + return fmt.Errorf("failed to load %s from shared config, %w", responseChecksumValidationKey, err) + } + // Shared Credentials creds := aws.Credentials{ AccessKeyID: section.String(accessKeyIDKey), SecretAccessKey: section.String(secretAccessKey), SessionToken: section.String(sessionTokenKey), Source: fmt.Sprintf("SharedConfigCredentials: %s", section.SourceFile[accessKeyIDKey]), + AccountID: section.String(accountIDKey), } if creds.HasKeys() { @@ -1177,6 +1205,62 @@ func updateDisableRequestCompression(disable **bool, sec ini.Section, key string return nil } +func updateAIDEndpointMode(m *aws.AccountIDEndpointMode, sec ini.Section, key string) error { + if !sec.Has(key) { + return nil + } + + v := sec.String(key) + switch v { + case "preferred": + *m = aws.AccountIDEndpointModePreferred + case "required": + *m = aws.AccountIDEndpointModeRequired + case "disabled": + *m = aws.AccountIDEndpointModeDisabled + default: + return fmt.Errorf("invalid value for shared config profile field, %s=%s, must be preferred/required/disabled", key, v) + } + + return nil +} + +func updateRequestChecksumCalculation(m *aws.RequestChecksumCalculation, sec ini.Section, key string) error { + if !sec.Has(key) { + return nil + } + + v := sec.String(key) + switch strings.ToLower(v) { + case checksumWhenSupported: + *m = aws.RequestChecksumCalculationWhenSupported + case checksumWhenRequired: + *m = aws.RequestChecksumCalculationWhenRequired + default: + return fmt.Errorf("invalid value for shared config profile field, %s=%s, must be when_supported/when_required", key, v) + } + + return nil +} + +func updateResponseChecksumValidation(m *aws.ResponseChecksumValidation, sec ini.Section, key string) error { + if !sec.Has(key) { + return nil + } + + v := sec.String(key) + switch strings.ToLower(v) { + case checksumWhenSupported: + *m = aws.ResponseChecksumValidationWhenSupported + case checksumWhenRequired: + *m = aws.ResponseChecksumValidationWhenRequired + default: + return fmt.Errorf("invalid value for shared config profile field, %s=%s, must be when_supported/when_required", key, v) + } + + return nil +} + func (c SharedConfig) getRequestMinCompressSizeBytes(ctx context.Context) (int64, bool, error) { if c.RequestMinCompressSizeBytes == nil { return 0, false, nil @@ -1191,6 +1275,18 @@ func (c SharedConfig) getDisableRequestCompression(ctx context.Context) (bool, b return *c.DisableRequestCompression, true, nil } +func (c SharedConfig) getAccountIDEndpointMode(ctx context.Context) (aws.AccountIDEndpointMode, bool, error) { + return c.AccountIDEndpointMode, len(c.AccountIDEndpointMode) > 0, nil +} + +func (c SharedConfig) getRequestChecksumCalculation(ctx context.Context) (aws.RequestChecksumCalculation, bool, error) { + return c.RequestChecksumCalculation, c.RequestChecksumCalculation > 0, nil +} + +func (c SharedConfig) getResponseChecksumValidation(ctx context.Context) (aws.ResponseChecksumValidation, bool, error) { + return c.ResponseChecksumValidation, c.ResponseChecksumValidation > 0, nil +} + func updateDefaultsMode(mode *aws.DefaultsMode, section ini.Section, key string) error { if !section.Has(key) { return nil diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/credentials/CHANGELOG.md index 989c4ea..5a0ef6f 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/credentials/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/CHANGELOG.md @@ -1,3 +1,245 @@ +# v1.17.58 (2025-02-04) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.57 (2025-01-31) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.56 (2025-01-30) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.55 (2025-01-24) + +* **Dependency Update**: Updated to the latest SDK module versions +* **Dependency Update**: Upgrade to smithy-go v1.22.2. + +# v1.17.54 (2025-01-17) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.53 (2025-01-15) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.52 (2025-01-14) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.51 (2025-01-10) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.50 (2025-01-09) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.49 (2025-01-08) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.48 (2024-12-19) + +* **Bug Fix**: Fix improper use of printf-style functions. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.47 (2024-12-02) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.46 (2024-11-18) + +* **Dependency Update**: Update to smithy-go v1.22.1. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.45 (2024-11-14) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.44 (2024-11-07) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.43 (2024-11-06) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.42 (2024-10-28) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.41 (2024-10-08) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.40 (2024-10-07) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.39 (2024-10-04) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.38 (2024-10-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.37 (2024-09-27) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.36 (2024-09-25) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.35 (2024-09-23) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.34 (2024-09-20) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.33 (2024-09-17) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.32 (2024-09-04) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.31 (2024-09-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.30 (2024-08-26) + +* **Bug Fix**: Save SSO cached token expiry in UTC to ensure cross-SDK compatibility. + +# v1.17.29 (2024-08-22) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.28 (2024-08-15) + +* **Dependency Update**: Bump minimum Go version to 1.21. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.27 (2024-07-18) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.26 (2024-07-10.2) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.25 (2024-07-10) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.24 (2024-07-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.23 (2024-06-28) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.22 (2024-06-26) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.21 (2024-06-19) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.20 (2024-06-18) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.19 (2024-06-17) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.18 (2024-06-07) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.17 (2024-06-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.16 (2024-05-23) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.15 (2024-05-16) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.14 (2024-05-15) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.13 (2024-05-10) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.12 (2024-05-08) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.11 (2024-04-05) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.10 (2024-03-29) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.9 (2024-03-21) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.8 (2024-03-18) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.7 (2024-03-07) + +* **Bug Fix**: Remove dependency on go-cmp. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.6 (2024-03-05) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.5 (2024-03-04) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.4 (2024-02-23) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.3 (2024-02-22) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.2 (2024-02-21) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.1 (2024-02-20) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.17.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. +* **Dependency Update**: Updated to the latest SDK module versions + # v1.16.16 (2024-01-18) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/client.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/client.go index 9a869f8..dc291c9 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/client.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/internal/client/client.go @@ -128,6 +128,7 @@ type GetCredentialsOutput struct { AccessKeyID string SecretAccessKey string Token string + AccountID string } // EndpointError is an error returned from the endpoint service diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/provider.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/provider.go index 0c3c4d6..2386153 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/provider.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/endpointcreds/provider.go @@ -152,6 +152,7 @@ func (p *Provider) Retrieve(ctx context.Context) (aws.Credentials, error) { SecretAccessKey: resp.SecretAccessKey, SessionToken: resp.Token, Source: ProviderName, + AccountID: resp.AccountID, } if resp.Expiration != nil { diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/go_module_metadata.go index fe92184..20eaebc 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/credentials/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/go_module_metadata.go @@ -3,4 +3,4 @@ package credentials // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.16.16" +const goModuleVersion = "1.17.58" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/processcreds/provider.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/processcreds/provider.go index fe9345e..911fcc3 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/credentials/processcreds/provider.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/processcreds/provider.go @@ -167,6 +167,9 @@ type CredentialProcessResponse struct { // The date on which the current credentials expire. Expiration *time.Time + + // The ID of the account for credentials + AccountID string `json:"AccountId"` } // Retrieve executes the credential process command and returns the @@ -208,6 +211,7 @@ func (p *Provider) Retrieve(ctx context.Context) (aws.Credentials, error) { AccessKeyID: resp.AccessKeyID, SecretAccessKey: resp.SecretAccessKey, SessionToken: resp.SessionToken, + AccountID: resp.AccountID, } // Handle expiration diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_cached_token.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_cached_token.go index 3b97e6d..46ae2f9 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_cached_token.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_cached_token.go @@ -225,7 +225,7 @@ func (r *rfc3339) UnmarshalJSON(bytes []byte) (err error) { } func (r *rfc3339) MarshalJSON() ([]byte, error) { - value := time.Time(*r).Format(time.RFC3339) + value := time.Time(*r).UTC().Format(time.RFC3339) // Use JSON unmarshal to unescape the quoted value making use of JSON's // quoting rules. diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_credentials_provider.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_credentials_provider.go index b3cf785..8c230be 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_credentials_provider.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/ssocreds/sso_credentials_provider.go @@ -129,6 +129,7 @@ func (p *Provider) Retrieve(ctx context.Context) (aws.Credentials, error) { CanExpire: true, Expires: time.Unix(0, output.RoleCredentials.Expiration*int64(time.Millisecond)).UTC(), Source: ProviderName, + AccountID: p.options.AccountID, }, nil } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/stscreds/assume_role_provider.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/stscreds/assume_role_provider.go index 289707b..4c7f799 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/credentials/stscreds/assume_role_provider.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/stscreds/assume_role_provider.go @@ -308,6 +308,11 @@ func (p *AssumeRoleProvider) Retrieve(ctx context.Context) (aws.Credentials, err return aws.Credentials{Source: ProviderName}, err } + var accountID string + if resp.AssumedRoleUser != nil { + accountID = getAccountID(resp.AssumedRoleUser) + } + return aws.Credentials{ AccessKeyID: *resp.Credentials.AccessKeyId, SecretAccessKey: *resp.Credentials.SecretAccessKey, @@ -316,5 +321,6 @@ func (p *AssumeRoleProvider) Retrieve(ctx context.Context) (aws.Credentials, err CanExpire: true, Expires: *resp.Credentials.Expiration, + AccountID: accountID, }, nil } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/credentials/stscreds/web_identity_provider.go b/vendor/github.com/aws/aws-sdk-go-v2/credentials/stscreds/web_identity_provider.go index ddaf6df..b4b7197 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/credentials/stscreds/web_identity_provider.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/credentials/stscreds/web_identity_provider.go @@ -5,6 +5,7 @@ import ( "fmt" "io/ioutil" "strconv" + "strings" "time" "github.com/aws/aws-sdk-go-v2/aws" @@ -135,6 +136,11 @@ func (p *WebIdentityRoleProvider) Retrieve(ctx context.Context) (aws.Credentials return aws.Credentials{}, fmt.Errorf("failed to retrieve credentials, %w", err) } + var accountID string + if resp.AssumedRoleUser != nil { + accountID = getAccountID(resp.AssumedRoleUser) + } + // InvalidIdentityToken error is a temporary error that can occur // when assuming an Role with a JWT web identity token. @@ -145,6 +151,19 @@ func (p *WebIdentityRoleProvider) Retrieve(ctx context.Context) (aws.Credentials Source: WebIdentityProviderName, CanExpire: true, Expires: *resp.Credentials.Expiration, + AccountID: accountID, } return value, nil } + +// extract accountID from arn with format "arn:partition:service:region:account-id:[resource-section]" +func getAccountID(u *types.AssumedRoleUser) string { + if u.Arn == nil { + return "" + } + parts := strings.Split(*u.Arn, ":") + if len(parts) < 5 { + return "" + } + return parts[4] +} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/CHANGELOG.md index 40c317a..d90cc27 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/CHANGELOG.md @@ -1,3 +1,140 @@ +# v1.16.27 (2025-01-31) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.26 (2025-01-30) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.25 (2025-01-24) + +* **Dependency Update**: Updated to the latest SDK module versions +* **Dependency Update**: Upgrade to smithy-go v1.22.2. + +# v1.16.24 (2025-01-15) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.23 (2025-01-09) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.22 (2024-12-19) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.21 (2024-12-02) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.20 (2024-11-18) + +* **Dependency Update**: Update to smithy-go v1.22.1. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.19 (2024-11-06) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.18 (2024-10-28) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.17 (2024-10-08) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.16 (2024-10-07) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.15 (2024-10-04) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.14 (2024-09-20) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.13 (2024-09-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.12 (2024-08-15) + +* **Dependency Update**: Bump minimum Go version to 1.21. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.11 (2024-07-10.2) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.10 (2024-07-10) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.9 (2024-06-28) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.8 (2024-06-19) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.7 (2024-06-18) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.6 (2024-06-17) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.5 (2024-06-07) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.4 (2024-06-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.3 (2024-05-16) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.2 (2024-05-15) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.1 (2024-03-29) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.16.0 (2024-03-21) + +* **Feature**: Add config switch `DisableDefaultTimeout` that allows you to disable the default operation timeout (5 seconds) for IMDS calls. + +# v1.15.4 (2024-03-18) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.15.3 (2024-03-07) + +* **Bug Fix**: Remove dependency on go-cmp. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.15.2 (2024-02-23) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.15.1 (2024-02-21) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.15.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. +* **Dependency Update**: Updated to the latest SDK module versions + # v1.14.11 (2024-01-04) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/api_client.go b/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/api_client.go index 46e144d..3f4a10e 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/api_client.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/api_client.go @@ -185,6 +185,10 @@ type Options struct { // [configuring IMDS]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html EnableFallback aws.Ternary + // By default, all IMDS client operations enforce a 5-second timeout. You + // can disable that behavior with this setting. + DisableDefaultTimeout bool + // provides the caching of API tokens used for operation calls. If unset, // the API token will not be retrieved for the operation. tokenProvider *tokenProvider diff --git a/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/doc.go b/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/doc.go index bacdb5d..d5765c3 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/doc.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/doc.go @@ -3,8 +3,9 @@ // // All Client operation calls have a default timeout. If the operation is not // completed before this timeout expires, the operation will be canceled. This -// timeout can be overridden by providing Context with a timeout or deadline -// with calling the client's operations. +// timeout can be overridden through the following: +// - Set the options flag DisableDefaultTimeout +// - Provide a Context with a timeout or deadline with calling the client's operations. // // See the EC2 IMDS user guide for more information on using the API. // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html diff --git a/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/go_module_metadata.go index 0d747b2..94f576a 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/go_module_metadata.go @@ -3,4 +3,4 @@ package imds // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.14.11" +const goModuleVersion = "1.16.27" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/request_middleware.go b/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/request_middleware.go index fc948c2..90cf4ae 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/request_middleware.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/feature/ec2/imds/request_middleware.go @@ -56,6 +56,7 @@ func addRequestMiddleware(stack *middleware.Stack, // Operation timeout err = stack.Initialize.Add(&operationTimeout{ + Disabled: options.DisableDefaultTimeout, DefaultTimeout: defaultOperationTimeout, }, middleware.Before) if err != nil { @@ -260,6 +261,7 @@ const ( // Otherwise the timeout cleanup will race the resource being consumed // upstream. type operationTimeout struct { + Disabled bool DefaultTimeout time.Duration } @@ -270,6 +272,10 @@ func (m *operationTimeout) HandleInitialize( ) ( output middleware.InitializeOutput, metadata middleware.Metadata, err error, ) { + if m.Disabled { + return next.HandleInitialize(ctx, input) + } + if _, ok := ctx.Deadline(); !ok && m.DefaultTimeout != 0 { var cancelFn func() ctx, cancelFn = context.WithTimeout(ctx, m.DefaultTimeout) diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/auth/smithy/v4signer_adapter.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/auth/smithy/v4signer_adapter.go index 0c5a2d4..24db8e1 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/auth/smithy/v4signer_adapter.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/auth/smithy/v4signer_adapter.go @@ -5,6 +5,7 @@ import ( "fmt" v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + internalcontext "github.com/aws/aws-sdk-go-v2/internal/context" "github.com/aws/aws-sdk-go-v2/internal/sdk" "github.com/aws/smithy-go" "github.com/aws/smithy-go/auth" @@ -39,7 +40,10 @@ func (v *V4SignerAdapter) SignRequest(ctx context.Context, r *smithyhttp.Request } hash := v4.GetPayloadHash(ctx) - err := v.Signer.SignHTTP(ctx, ca.Credentials, r.Request, hash, name, region, sdk.NowTime(), func(o *v4.SignerOptions) { + signingTime := sdk.NowTime() + skew := internalcontext.GetAttemptSkewContext(ctx) + signingTime = signingTime.Add(skew) + err := v.Signer.SignHTTP(ctx, ca.Credentials, r.Request, hash, name, region, signingTime, func(o *v4.SignerOptions) { o.DisableURIPathEscaping, _ = smithyhttp.GetDisableDoubleEncoding(&props) o.Logger = v.Logger diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/CHANGELOG.md index dc87ec4..113b1da 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/CHANGELOG.md @@ -1,3 +1,135 @@ +# v1.3.31 (2025-01-31) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.30 (2025-01-30) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.29 (2025-01-24) + +* **Dependency Update**: Updated to the latest SDK module versions +* **Dependency Update**: Upgrade to smithy-go v1.22.2. + +# v1.3.28 (2025-01-15) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.27 (2025-01-09) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.26 (2024-12-19) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.25 (2024-12-02) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.24 (2024-11-18) + +* **Dependency Update**: Update to smithy-go v1.22.1. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.23 (2024-11-06) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.22 (2024-10-28) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.21 (2024-10-08) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.20 (2024-10-07) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.19 (2024-10-04) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.18 (2024-09-20) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.17 (2024-09-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.16 (2024-08-15) + +* **Dependency Update**: Bump minimum Go version to 1.21. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.15 (2024-07-10.2) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.14 (2024-07-10) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.13 (2024-06-28) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.12 (2024-06-19) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.11 (2024-06-18) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.10 (2024-06-17) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.9 (2024-06-07) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.8 (2024-06-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.7 (2024-05-16) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.6 (2024-05-15) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.5 (2024-03-29) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.4 (2024-03-18) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.3 (2024-03-07) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.2 (2024-02-23) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.1 (2024-02-21) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.3.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. +* **Dependency Update**: Updated to the latest SDK module versions + # v1.2.10 (2024-01-04) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/go_module_metadata.go index 41ee0bf..28c635d 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/configsources/go_module_metadata.go @@ -3,4 +3,4 @@ package configsources // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.2.10" +const goModuleVersion = "1.3.31" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/context/context.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/context/context.go new file mode 100644 index 0000000..f0c283d --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/context/context.go @@ -0,0 +1,52 @@ +package context + +import ( + "context" + "time" + + "github.com/aws/smithy-go/middleware" +) + +type s3BackendKey struct{} +type checksumInputAlgorithmKey struct{} +type clockSkew struct{} + +const ( + // S3BackendS3Express identifies the S3Express backend + S3BackendS3Express = "S3Express" +) + +// SetS3Backend stores the resolved endpoint backend within the request +// context, which is required for a variety of custom S3 behaviors. +func SetS3Backend(ctx context.Context, typ string) context.Context { + return middleware.WithStackValue(ctx, s3BackendKey{}, typ) +} + +// GetS3Backend retrieves the stored endpoint backend within the context. +func GetS3Backend(ctx context.Context) string { + v, _ := middleware.GetStackValue(ctx, s3BackendKey{}).(string) + return v +} + +// SetChecksumInputAlgorithm sets the request checksum algorithm on the +// context. +func SetChecksumInputAlgorithm(ctx context.Context, value string) context.Context { + return middleware.WithStackValue(ctx, checksumInputAlgorithmKey{}, value) +} + +// GetChecksumInputAlgorithm returns the checksum algorithm from the context. +func GetChecksumInputAlgorithm(ctx context.Context) string { + v, _ := middleware.GetStackValue(ctx, checksumInputAlgorithmKey{}).(string) + return v +} + +// SetAttemptSkewContext sets the clock skew value on the context +func SetAttemptSkewContext(ctx context.Context, v time.Duration) context.Context { + return middleware.WithStackValue(ctx, clockSkew{}, v) +} + +// GetAttemptSkewContext gets the clock skew value from the context +func GetAttemptSkewContext(ctx context.Context) time.Duration { + x, _ := middleware.GetStackValue(ctx, clockSkew{}).(time.Duration) + return x +} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partition.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partition.go index ba60327..91414af 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partition.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partition.go @@ -12,11 +12,12 @@ type Partition struct { // PartitionConfig provides the endpoint metadata for an AWS region or partition. type PartitionConfig struct { - Name string `json:"name"` - DnsSuffix string `json:"dnsSuffix"` - DualStackDnsSuffix string `json:"dualStackDnsSuffix"` - SupportsFIPS bool `json:"supportsFIPS"` - SupportsDualStack bool `json:"supportsDualStack"` + Name string `json:"name"` + DnsSuffix string `json:"dnsSuffix"` + DualStackDnsSuffix string `json:"dualStackDnsSuffix"` + SupportsFIPS bool `json:"supportsFIPS"` + SupportsDualStack bool `json:"supportsDualStack"` + ImplicitGlobalRegion string `json:"implicitGlobalRegion"` } type RegionOverrides struct { diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.go index 849beff..5f07799 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.go @@ -13,11 +13,12 @@ var partitions = []Partition{ ID: "aws", RegionRegex: "^(us|eu|ap|sa|ca|me|af|il)\\-\\w+\\-\\d+$", DefaultConfig: PartitionConfig{ - Name: "aws", - DnsSuffix: "amazonaws.com", - DualStackDnsSuffix: "api.aws", - SupportsFIPS: true, - SupportsDualStack: true, + Name: "aws", + DnsSuffix: "amazonaws.com", + DualStackDnsSuffix: "api.aws", + SupportsFIPS: true, + SupportsDualStack: true, + ImplicitGlobalRegion: "us-east-1", }, Regions: map[string]RegionOverrides{ "af-south-1": { @@ -111,6 +112,13 @@ var partitions = []Partition{ SupportsFIPS: nil, SupportsDualStack: nil, }, + "ca-west-1": { + Name: nil, + DnsSuffix: nil, + DualStackDnsSuffix: nil, + SupportsFIPS: nil, + SupportsDualStack: nil, + }, "eu-central-1": { Name: nil, DnsSuffix: nil, @@ -229,11 +237,12 @@ var partitions = []Partition{ ID: "aws-cn", RegionRegex: "^cn\\-\\w+\\-\\d+$", DefaultConfig: PartitionConfig{ - Name: "aws-cn", - DnsSuffix: "amazonaws.com.cn", - DualStackDnsSuffix: "api.amazonwebservices.com.cn", - SupportsFIPS: true, - SupportsDualStack: true, + Name: "aws-cn", + DnsSuffix: "amazonaws.com.cn", + DualStackDnsSuffix: "api.amazonwebservices.com.cn", + SupportsFIPS: true, + SupportsDualStack: true, + ImplicitGlobalRegion: "cn-northwest-1", }, Regions: map[string]RegionOverrides{ "aws-cn-global": { @@ -263,11 +272,12 @@ var partitions = []Partition{ ID: "aws-us-gov", RegionRegex: "^us\\-gov\\-\\w+\\-\\d+$", DefaultConfig: PartitionConfig{ - Name: "aws-us-gov", - DnsSuffix: "amazonaws.com", - DualStackDnsSuffix: "api.aws", - SupportsFIPS: true, - SupportsDualStack: true, + Name: "aws-us-gov", + DnsSuffix: "amazonaws.com", + DualStackDnsSuffix: "api.aws", + SupportsFIPS: true, + SupportsDualStack: true, + ImplicitGlobalRegion: "us-gov-west-1", }, Regions: map[string]RegionOverrides{ "aws-us-gov-global": { @@ -297,11 +307,12 @@ var partitions = []Partition{ ID: "aws-iso", RegionRegex: "^us\\-iso\\-\\w+\\-\\d+$", DefaultConfig: PartitionConfig{ - Name: "aws-iso", - DnsSuffix: "c2s.ic.gov", - DualStackDnsSuffix: "c2s.ic.gov", - SupportsFIPS: true, - SupportsDualStack: false, + Name: "aws-iso", + DnsSuffix: "c2s.ic.gov", + DualStackDnsSuffix: "c2s.ic.gov", + SupportsFIPS: true, + SupportsDualStack: false, + ImplicitGlobalRegion: "us-iso-east-1", }, Regions: map[string]RegionOverrides{ "aws-iso-global": { @@ -331,11 +342,12 @@ var partitions = []Partition{ ID: "aws-iso-b", RegionRegex: "^us\\-isob\\-\\w+\\-\\d+$", DefaultConfig: PartitionConfig{ - Name: "aws-iso-b", - DnsSuffix: "sc2s.sgov.gov", - DualStackDnsSuffix: "sc2s.sgov.gov", - SupportsFIPS: true, - SupportsDualStack: false, + Name: "aws-iso-b", + DnsSuffix: "sc2s.sgov.gov", + DualStackDnsSuffix: "sc2s.sgov.gov", + SupportsFIPS: true, + SupportsDualStack: false, + ImplicitGlobalRegion: "us-isob-east-1", }, Regions: map[string]RegionOverrides{ "aws-iso-b-global": { @@ -358,23 +370,33 @@ var partitions = []Partition{ ID: "aws-iso-e", RegionRegex: "^eu\\-isoe\\-\\w+\\-\\d+$", DefaultConfig: PartitionConfig{ - Name: "aws-iso-e", - DnsSuffix: "cloud.adc-e.uk", - DualStackDnsSuffix: "cloud.adc-e.uk", - SupportsFIPS: true, - SupportsDualStack: false, + Name: "aws-iso-e", + DnsSuffix: "cloud.adc-e.uk", + DualStackDnsSuffix: "cloud.adc-e.uk", + SupportsFIPS: true, + SupportsDualStack: false, + ImplicitGlobalRegion: "eu-isoe-west-1", + }, + Regions: map[string]RegionOverrides{ + "eu-isoe-west-1": { + Name: nil, + DnsSuffix: nil, + DualStackDnsSuffix: nil, + SupportsFIPS: nil, + SupportsDualStack: nil, + }, }, - Regions: map[string]RegionOverrides{}, }, { ID: "aws-iso-f", RegionRegex: "^us\\-isof\\-\\w+\\-\\d+$", DefaultConfig: PartitionConfig{ - Name: "aws-iso-f", - DnsSuffix: "csp.hci.ic.gov", - DualStackDnsSuffix: "csp.hci.ic.gov", - SupportsFIPS: true, - SupportsDualStack: false, + Name: "aws-iso-f", + DnsSuffix: "csp.hci.ic.gov", + DualStackDnsSuffix: "csp.hci.ic.gov", + SupportsFIPS: true, + SupportsDualStack: false, + ImplicitGlobalRegion: "us-isof-south-1", }, Regions: map[string]RegionOverrides{}, }, diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.json b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.json index f376f69..43f6449 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.json +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn/partitions.json @@ -9,7 +9,7 @@ "supportsDualStack" : true, "supportsFIPS" : true }, - "regionRegex" : "^(us|eu|ap|sa|ca|me|af|il)\\-\\w+\\-\\d+$", + "regionRegex" : "^(us|eu|ap|sa|ca|me|af|il|mx)\\-\\w+\\-\\d+$", "regions" : { "af-south-1" : { "description" : "Africa (Cape Town)" @@ -44,6 +44,12 @@ "ap-southeast-4" : { "description" : "Asia Pacific (Melbourne)" }, + "ap-southeast-5" : { + "description" : "Asia Pacific (Malaysia)" + }, + "ap-southeast-7" : { + "description" : "Asia Pacific (Thailand)" + }, "aws-global" : { "description" : "AWS Standard global region" }, @@ -86,6 +92,9 @@ "me-south-1" : { "description" : "Middle East (Bahrain)" }, + "mx-central-1" : { + "description" : "Mexico (Central)" + }, "sa-east-1" : { "description" : "South America (Sao Paulo)" }, @@ -198,7 +207,11 @@ "supportsFIPS" : true }, "regionRegex" : "^eu\\-isoe\\-\\w+\\-\\d+$", - "regions" : { } + "regions" : { + "eu-isoe-west-1" : { + "description" : "EU ISOE West" + } + } }, { "id" : "aws-iso-f", "outputs" : { diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/CHANGELOG.md index e026547..1cab71d 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/CHANGELOG.md @@ -1,3 +1,137 @@ +# v2.6.31 (2025-01-31) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.30 (2025-01-30) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.29 (2025-01-24) + +* **Dependency Update**: Updated to the latest SDK module versions +* **Dependency Update**: Upgrade to smithy-go v1.22.2. + +# v2.6.28 (2025-01-15) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.27 (2025-01-09) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.26 (2024-12-19) + +* **Bug Fix**: Fix improper use of printf-style functions. +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.25 (2024-12-02) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.24 (2024-11-18) + +* **Dependency Update**: Update to smithy-go v1.22.1. +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.23 (2024-11-06) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.22 (2024-10-28) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.21 (2024-10-08) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.20 (2024-10-07) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.19 (2024-10-04) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.18 (2024-09-20) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.17 (2024-09-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.16 (2024-08-15) + +* **Dependency Update**: Bump minimum Go version to 1.21. +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.15 (2024-07-10.2) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.14 (2024-07-10) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.13 (2024-06-28) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.12 (2024-06-19) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.11 (2024-06-18) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.10 (2024-06-17) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.9 (2024-06-07) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.8 (2024-06-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.7 (2024-05-16) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.6 (2024-05-15) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.5 (2024-03-29) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.4 (2024-03-18) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.3 (2024-03-07) + +* **Bug Fix**: Remove dependency on go-cmp. +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.2 (2024-02-23) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.1 (2024-02-21) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v2.6.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. +* **Dependency Update**: Updated to the latest SDK module versions + # v2.5.10 (2024-01-04) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/go_module_metadata.go index bec2c6a..589a4a7 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/go_module_metadata.go @@ -3,4 +3,4 @@ package endpoints // goModuleVersion is the tagged release for this module -const goModuleVersion = "2.5.10" +const goModuleVersion = "2.6.31" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/CHANGELOG.md index adbbf4a..1d23b9b 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/CHANGELOG.md @@ -1,3 +1,19 @@ +# v1.8.2 (2025-01-24) + +* **Bug Fix**: Refactor filepath.Walk to filepath.WalkDir + +# v1.8.1 (2024-08-15) + +* **Dependency Update**: Bump minimum Go version to 1.21. + +# v1.8.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. + +# v1.7.3 (2024-01-22) + +* **Bug Fix**: Remove invalid escaping of shared config values. All values in the shared config file will now be interpreted literally, save for fully-quoted strings which are unwrapped for legacy reasons. + # v1.7.2 (2023-12-08) * **Bug Fix**: Correct loading of [services *] sections into shared config. diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/go_module_metadata.go index f0673f3..355ed39 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/go_module_metadata.go @@ -3,4 +3,4 @@ package ini // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.7.2" +const goModuleVersion = "1.8.2" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/strings.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/strings.go index 661588c..ed77d08 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/strings.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/ini/strings.go @@ -67,12 +67,8 @@ func unquote(s string) string { // applies various legacy conversions to property values: // - remote wrapping single/doublequotes -// - expand escaped quote and newline sequences func legacyStrconv(s string) string { s = unquote(s) - s = strings.ReplaceAll(s, `\"`, `"`) - s = strings.ReplaceAll(s, `\'`, `'`) - s = strings.ReplaceAll(s, `\n`, "\n") return s } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/internal/middleware/middleware.go b/vendor/github.com/aws/aws-sdk-go-v2/internal/middleware/middleware.go new file mode 100644 index 0000000..8e24a3f --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/internal/middleware/middleware.go @@ -0,0 +1,42 @@ +package middleware + +import ( + "context" + "sync/atomic" + "time" + + internalcontext "github.com/aws/aws-sdk-go-v2/internal/context" + "github.com/aws/smithy-go/middleware" +) + +// AddTimeOffsetMiddleware sets a value representing clock skew on the request context. +// This can be read by other operations (such as signing) to correct the date value they send +// on the request +type AddTimeOffsetMiddleware struct { + Offset *atomic.Int64 +} + +// ID the identifier for AddTimeOffsetMiddleware +func (m *AddTimeOffsetMiddleware) ID() string { return "AddTimeOffsetMiddleware" } + +// HandleBuild sets a value for attemptSkew on the request context if one is set on the client. +func (m AddTimeOffsetMiddleware) HandleBuild(ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler) ( + out middleware.BuildOutput, metadata middleware.Metadata, err error, +) { + if m.Offset != nil { + offset := time.Duration(m.Offset.Load()) + ctx = internalcontext.SetAttemptSkewContext(ctx, offset) + } + return next.HandleBuild(ctx, in) +} + +// HandleDeserialize gets the clock skew context from the context, and if set, sets it on the pointer +// held by AddTimeOffsetMiddleware +func (m *AddTimeOffsetMiddleware) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + if v := internalcontext.GetAttemptSkewContext(ctx); v != 0 { + m.Offset.Store(v.Nanoseconds()) + } + return next.HandleDeserialize(ctx, in) +} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/CHANGELOG.md index c3525fd..ef78753 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/CHANGELOG.md @@ -1,3 +1,39 @@ +# v1.12.2 (2025-01-24) + +* **Dependency Update**: Upgrade to smithy-go v1.22.2. + +# v1.12.1 (2024-11-18) + +* **Dependency Update**: Update to smithy-go v1.22.1. + +# v1.12.0 (2024-10-04) + +* **Feature**: Add support for HTTP client metrics. + +# v1.11.5 (2024-09-20) + +* No change notes available for this release. + +# v1.11.4 (2024-08-15) + +* **Dependency Update**: Bump minimum Go version to 1.21. + +# v1.11.3 (2024-06-28) + +* No change notes available for this release. + +# v1.11.2 (2024-03-29) + +* No change notes available for this release. + +# v1.11.1 (2024-02-21) + +* No change notes available for this release. + +# v1.11.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. + # v1.10.4 (2023-12-07) * No change notes available for this release. diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/go_module_metadata.go index cc63840..cbf79b4 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding/go_module_metadata.go @@ -3,4 +3,4 @@ package acceptencoding // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.10.4" +const goModuleVersion = "1.12.2" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/CHANGELOG.md index a65890b..04186fd 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/CHANGELOG.md @@ -1,3 +1,145 @@ +# v1.12.12 (2025-01-31) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.12.11 (2025-01-30) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.12.10 (2025-01-24) + +* **Dependency Update**: Updated to the latest SDK module versions +* **Dependency Update**: Upgrade to smithy-go v1.22.2. + +# v1.12.9 (2025-01-15) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.12.8 (2025-01-09) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.12.7 (2024-12-19) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.12.6 (2024-12-02) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.12.5 (2024-11-18) + +* **Dependency Update**: Update to smithy-go v1.22.1. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.12.4 (2024-11-06) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.12.3 (2024-10-28) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.12.2 (2024-10-08) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.12.1 (2024-10-07) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.12.0 (2024-10-04) + +* **Feature**: Add support for HTTP client metrics. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.20 (2024-09-20) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.19 (2024-09-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.18 (2024-08-15) + +* **Dependency Update**: Bump minimum Go version to 1.21. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.17 (2024-07-10.2) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.16 (2024-07-10) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.15 (2024-06-28) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.14 (2024-06-19) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.13 (2024-06-18) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.12 (2024-06-17) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.11 (2024-06-07) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.10 (2024-06-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.9 (2024-05-16) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.8 (2024-05-15) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.7 (2024-03-29) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.6 (2024-03-18) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.5 (2024-03-07) + +* **Bug Fix**: Remove dependency on go-cmp. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.4 (2024-03-05) + +* **Bug Fix**: Restore typo'd API `AddAsIsInternalPresigingMiddleware` as an alias for backwards compatibility. + +# v1.11.3 (2024-03-04) + +* **Bug Fix**: Correct a typo in internal AddAsIsPresigningMiddleware API. + +# v1.11.2 (2024-02-23) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.1 (2024-02-21) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.11.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. +* **Dependency Update**: Updated to the latest SDK module versions + # v1.10.10 (2024-01-04) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/context.go b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/context.go index cc91970..5d5286f 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/context.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/context.go @@ -27,13 +27,21 @@ func GetIsPresigning(ctx context.Context) bool { type isPresigningKey struct{} -// AddAsIsPresigingMiddleware adds a middleware to the head of the stack that +// AddAsIsPresigningMiddleware adds a middleware to the head of the stack that // will update the stack's context to be flagged as being invoked for the // purpose of presigning. -func AddAsIsPresigingMiddleware(stack *middleware.Stack) error { +func AddAsIsPresigningMiddleware(stack *middleware.Stack) error { return stack.Initialize.Add(asIsPresigningMiddleware{}, middleware.Before) } +// AddAsIsPresigingMiddleware is an alias for backwards compatibility. +// +// Deprecated: This API was released with a typo. Use +// [AddAsIsPresigningMiddleware] instead. +func AddAsIsPresigingMiddleware(stack *middleware.Stack) error { + return AddAsIsPresigningMiddleware(stack) +} + type asIsPresigningMiddleware struct{} func (asIsPresigningMiddleware) ID() string { return "AsIsPresigningMiddleware" } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/go_module_metadata.go index 073e886..66771d9 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/internal/presigned-url/go_module_metadata.go @@ -3,4 +3,4 @@ package presignedurl // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.10.10" +const goModuleVersion = "1.12.12" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/CHANGELOG.md index 46dea1b..8a05d96 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/CHANGELOG.md @@ -1,3 +1,201 @@ +# v1.24.14 (2025-01-31) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.24.13 (2025-01-30) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.24.12 (2025-01-24) + +* **Dependency Update**: Updated to the latest SDK module versions +* **Dependency Update**: Upgrade to smithy-go v1.22.2. + +# v1.24.11 (2025-01-17) + +* **Bug Fix**: Fix bug where credentials weren't refreshed during retry loop. + +# v1.24.10 (2025-01-15) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.24.9 (2025-01-09) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.24.8 (2024-12-19) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.24.7 (2024-12-02) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.24.6 (2024-11-18) + +* **Dependency Update**: Update to smithy-go v1.22.1. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.24.5 (2024-11-07) + +* **Bug Fix**: Adds case-insensitive handling of error message fields in service responses + +# v1.24.4 (2024-11-06) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.24.3 (2024-10-28) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.24.2 (2024-10-08) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.24.1 (2024-10-07) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.24.0 (2024-10-04) + +* **Feature**: Add support for HTTP client metrics. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.23.4 (2024-10-03) + +* No change notes available for this release. + +# v1.23.3 (2024-09-27) + +* No change notes available for this release. + +# v1.23.2 (2024-09-25) + +* No change notes available for this release. + +# v1.23.1 (2024-09-23) + +* No change notes available for this release. + +# v1.23.0 (2024-09-20) + +* **Feature**: Add tracing and metrics support to service clients. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.22.8 (2024-09-17) + +* **Bug Fix**: **BREAKFIX**: Only generate AccountIDEndpointMode config for services that use it. This is a compiler break, but removes no actual functionality, as no services currently use the account ID in endpoint resolution. + +# v1.22.7 (2024-09-04) + +* No change notes available for this release. + +# v1.22.6 (2024-09-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.22.5 (2024-08-15) + +* **Dependency Update**: Bump minimum Go version to 1.21. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.22.4 (2024-07-18) + +* No change notes available for this release. + +# v1.22.3 (2024-07-10.2) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.22.2 (2024-07-10) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.22.1 (2024-06-28) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.22.0 (2024-06-26) + +* **Feature**: Support list-of-string endpoint parameter. + +# v1.21.1 (2024-06-19) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.21.0 (2024-06-18) + +* **Feature**: Track usage of various AWS SDK features in user-agent string. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.20.12 (2024-06-17) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.20.11 (2024-06-07) + +* **Bug Fix**: Add clock skew correction on all service clients +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.20.10 (2024-06-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.20.9 (2024-05-23) + +* No change notes available for this release. + +# v1.20.8 (2024-05-16) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.20.7 (2024-05-15) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.20.6 (2024-05-08) + +* **Bug Fix**: GoDoc improvement + +# v1.20.5 (2024-04-05) + +* No change notes available for this release. + +# v1.20.4 (2024-03-29) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.20.3 (2024-03-18) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.20.2 (2024-03-07) + +* **Bug Fix**: Remove dependency on go-cmp. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.20.1 (2024-02-23) + +* **Bug Fix**: Move all common, SDK-side middleware stack ops into the service client module to prevent cross-module compatibility issues in the future. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.20.0 (2024-02-22) + +* **Feature**: Add middleware stack snapshot tests. + +# v1.19.2 (2024-02-21) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.19.1 (2024-02-20) + +* **Bug Fix**: When sourcing values for a service's `EndpointParameters`, the lack of a configured region (i.e. `options.Region == ""`) will now translate to a `nil` value for `EndpointParameters.Region` instead of a pointer to the empty string `""`. This will result in a much more explicit error when calling an operation instead of an obscure hostname lookup failure. + +# v1.19.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. +* **Dependency Update**: Updated to the latest SDK module versions + # v1.18.7 (2024-01-18) * No change notes available for this release. diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_client.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_client.go index e439699..0b244f1 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_client.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_client.go @@ -4,6 +4,7 @@ package sso import ( "context" + "errors" "fmt" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/defaults" @@ -14,22 +15,157 @@ import ( internalauth "github.com/aws/aws-sdk-go-v2/internal/auth" internalauthsmithy "github.com/aws/aws-sdk-go-v2/internal/auth/smithy" internalConfig "github.com/aws/aws-sdk-go-v2/internal/configsources" + internalmiddleware "github.com/aws/aws-sdk-go-v2/internal/middleware" smithy "github.com/aws/smithy-go" + smithyauth "github.com/aws/smithy-go/auth" smithydocument "github.com/aws/smithy-go/document" "github.com/aws/smithy-go/logging" + "github.com/aws/smithy-go/metrics" "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" "net" "net/http" + "sync/atomic" "time" ) const ServiceID = "SSO" const ServiceAPIVersion = "2019-06-10" +type operationMetrics struct { + Duration metrics.Float64Histogram + SerializeDuration metrics.Float64Histogram + ResolveIdentityDuration metrics.Float64Histogram + ResolveEndpointDuration metrics.Float64Histogram + SignRequestDuration metrics.Float64Histogram + DeserializeDuration metrics.Float64Histogram +} + +func (m *operationMetrics) histogramFor(name string) metrics.Float64Histogram { + switch name { + case "client.call.duration": + return m.Duration + case "client.call.serialization_duration": + return m.SerializeDuration + case "client.call.resolve_identity_duration": + return m.ResolveIdentityDuration + case "client.call.resolve_endpoint_duration": + return m.ResolveEndpointDuration + case "client.call.signing_duration": + return m.SignRequestDuration + case "client.call.deserialization_duration": + return m.DeserializeDuration + default: + panic("unrecognized operation metric") + } +} + +func timeOperationMetric[T any]( + ctx context.Context, metric string, fn func() (T, error), + opts ...metrics.RecordMetricOption, +) (T, error) { + instr := getOperationMetrics(ctx).histogramFor(metric) + opts = append([]metrics.RecordMetricOption{withOperationMetadata(ctx)}, opts...) + + start := time.Now() + v, err := fn() + end := time.Now() + + elapsed := end.Sub(start) + instr.Record(ctx, float64(elapsed)/1e9, opts...) + return v, err +} + +func startMetricTimer(ctx context.Context, metric string, opts ...metrics.RecordMetricOption) func() { + instr := getOperationMetrics(ctx).histogramFor(metric) + opts = append([]metrics.RecordMetricOption{withOperationMetadata(ctx)}, opts...) + + var ended bool + start := time.Now() + return func() { + if ended { + return + } + ended = true + + end := time.Now() + + elapsed := end.Sub(start) + instr.Record(ctx, float64(elapsed)/1e9, opts...) + } +} + +func withOperationMetadata(ctx context.Context) metrics.RecordMetricOption { + return func(o *metrics.RecordMetricOptions) { + o.Properties.Set("rpc.service", middleware.GetServiceID(ctx)) + o.Properties.Set("rpc.method", middleware.GetOperationName(ctx)) + } +} + +type operationMetricsKey struct{} + +func withOperationMetrics(parent context.Context, mp metrics.MeterProvider) (context.Context, error) { + meter := mp.Meter("github.com/aws/aws-sdk-go-v2/service/sso") + om := &operationMetrics{} + + var err error + + om.Duration, err = operationMetricTimer(meter, "client.call.duration", + "Overall call duration (including retries and time to send or receive request and response body)") + if err != nil { + return nil, err + } + om.SerializeDuration, err = operationMetricTimer(meter, "client.call.serialization_duration", + "The time it takes to serialize a message body") + if err != nil { + return nil, err + } + om.ResolveIdentityDuration, err = operationMetricTimer(meter, "client.call.auth.resolve_identity_duration", + "The time taken to acquire an identity (AWS credentials, bearer token, etc) from an Identity Provider") + if err != nil { + return nil, err + } + om.ResolveEndpointDuration, err = operationMetricTimer(meter, "client.call.resolve_endpoint_duration", + "The time it takes to resolve an endpoint (endpoint resolver, not DNS) for the request") + if err != nil { + return nil, err + } + om.SignRequestDuration, err = operationMetricTimer(meter, "client.call.auth.signing_duration", + "The time it takes to sign a request") + if err != nil { + return nil, err + } + om.DeserializeDuration, err = operationMetricTimer(meter, "client.call.deserialization_duration", + "The time it takes to deserialize a message body") + if err != nil { + return nil, err + } + + return context.WithValue(parent, operationMetricsKey{}, om), nil +} + +func operationMetricTimer(m metrics.Meter, name, desc string) (metrics.Float64Histogram, error) { + return m.Float64Histogram(name, func(o *metrics.InstrumentOptions) { + o.UnitLabel = "s" + o.Description = desc + }) +} + +func getOperationMetrics(ctx context.Context) *operationMetrics { + return ctx.Value(operationMetricsKey{}).(*operationMetrics) +} + +func operationTracer(p tracing.TracerProvider) tracing.Tracer { + return p.Tracer("github.com/aws/aws-sdk-go-v2/service/sso") +} + // Client provides the API client to make operations call for AWS Single Sign-On. type Client struct { options Options + + // Difference between the time reported by the server and the client + timeOffset *atomic.Int64 } // New returns an initialized Client based on the functional options. Provide @@ -50,6 +186,10 @@ func New(options Options, optFns ...func(*Options)) *Client { resolveEndpointResolverV2(&options) + resolveTracerProvider(&options) + + resolveMeterProvider(&options) + resolveAuthSchemeResolver(&options) for _, fn := range optFns { @@ -68,6 +208,8 @@ func New(options Options, optFns ...func(*Options)) *Client { options: options, } + initializeTimeOffsetResolver(client) + return client } @@ -80,8 +222,15 @@ func (c *Client) Options() Options { return c.options.Copy() } -func (c *Client) invokeOperation(ctx context.Context, opID string, params interface{}, optFns []func(*Options), stackFns ...func(*middleware.Stack, Options) error) (result interface{}, metadata middleware.Metadata, err error) { +func (c *Client) invokeOperation( + ctx context.Context, opID string, params interface{}, optFns []func(*Options), stackFns ...func(*middleware.Stack, Options) error, +) ( + result interface{}, metadata middleware.Metadata, err error, +) { ctx = middleware.ClearStackValues(ctx) + ctx = middleware.WithServiceID(ctx, ServiceID) + ctx = middleware.WithOperationName(ctx, opID) + stack := middleware.NewStack(opID, smithyhttp.NewStackRequest) options := c.options.Copy() @@ -105,15 +254,56 @@ func (c *Client) invokeOperation(ctx context.Context, opID string, params interf } } - handler := middleware.DecorateHandler(smithyhttp.NewClientHandler(options.HTTPClient), stack) - result, metadata, err = handler.Handle(ctx, params) + ctx, err = withOperationMetrics(ctx, options.MeterProvider) if err != nil { + return nil, metadata, err + } + + tracer := operationTracer(options.TracerProvider) + spanName := fmt.Sprintf("%s.%s", ServiceID, opID) + + ctx = tracing.WithOperationTracer(ctx, tracer) + + ctx, span := tracer.StartSpan(ctx, spanName, func(o *tracing.SpanOptions) { + o.Kind = tracing.SpanKindClient + o.Properties.Set("rpc.system", "aws-api") + o.Properties.Set("rpc.method", opID) + o.Properties.Set("rpc.service", ServiceID) + }) + endTimer := startMetricTimer(ctx, "client.call.duration") + defer endTimer() + defer span.End() + + handler := smithyhttp.NewClientHandlerWithOptions(options.HTTPClient, func(o *smithyhttp.ClientHandler) { + o.Meter = options.MeterProvider.Meter("github.com/aws/aws-sdk-go-v2/service/sso") + }) + decorated := middleware.DecorateHandler(handler, stack) + result, metadata, err = decorated.Handle(ctx, params) + if err != nil { + span.SetProperty("exception.type", fmt.Sprintf("%T", err)) + span.SetProperty("exception.message", err.Error()) + + var aerr smithy.APIError + if errors.As(err, &aerr) { + span.SetProperty("api.error_code", aerr.ErrorCode()) + span.SetProperty("api.error_message", aerr.ErrorMessage()) + span.SetProperty("api.error_fault", aerr.ErrorFault().String()) + } + err = &smithy.OperationError{ ServiceID: ServiceID, OperationName: opID, Err: err, } } + + span.SetProperty("error", err != nil) + if err == nil { + span.SetStatus(tracing.SpanStatusOK) + } else { + span.SetStatus(tracing.SpanStatusError) + } + return result, metadata, err } @@ -151,7 +341,7 @@ func addProtocolFinalizerMiddlewares(stack *middleware.Stack, options Options, o if err := stack.Finalize.Insert(&resolveEndpointV2Middleware{options: options}, "GetIdentity", middleware.After); err != nil { return fmt.Errorf("add ResolveEndpointV2: %v", err) } - if err := stack.Finalize.Insert(&signRequestMiddleware{}, "ResolveEndpointV2", middleware.After); err != nil { + if err := stack.Finalize.Insert(&signRequestMiddleware{options: options}, "ResolveEndpointV2", middleware.After); err != nil { return fmt.Errorf("add Signing: %w", err) } return nil @@ -361,17 +551,37 @@ func resolveAWSEndpointResolver(cfg aws.Config, o *Options) { } func addClientUserAgent(stack *middleware.Stack, options Options) error { - if err := awsmiddleware.AddSDKAgentKeyValue(awsmiddleware.APIMetadata, "sso", goModuleVersion)(stack); err != nil { + ua, err := getOrAddRequestUserAgent(stack) + if err != nil { return err } + ua.AddSDKAgentKeyValue(awsmiddleware.APIMetadata, "sso", goModuleVersion) if len(options.AppID) > 0 { - return awsmiddleware.AddSDKAgentKey(awsmiddleware.ApplicationIdentifier, options.AppID)(stack) + ua.AddSDKAgentKey(awsmiddleware.ApplicationIdentifier, options.AppID) } return nil } +func getOrAddRequestUserAgent(stack *middleware.Stack) (*awsmiddleware.RequestUserAgent, error) { + id := (*awsmiddleware.RequestUserAgent)(nil).ID() + mw, ok := stack.Build.Get(id) + if !ok { + mw = awsmiddleware.NewRequestUserAgent() + if err := stack.Build.Add(mw, middleware.After); err != nil { + return nil, err + } + } + + ua, ok := mw.(*awsmiddleware.RequestUserAgent) + if !ok { + return nil, fmt.Errorf("%T for %s middleware did not match expected type", mw, id) + } + + return ua, nil +} + type HTTPSignerV4 interface { SignHTTP(ctx context.Context, credentials aws.Credentials, r *http.Request, payloadHash string, service string, region string, signingTime time.Time, optFns ...func(*v4.SignerOptions)) error } @@ -390,12 +600,97 @@ func newDefaultV4Signer(o Options) *v4.Signer { }) } -func addRetryMiddlewares(stack *middleware.Stack, o Options) error { - mo := retry.AddRetryMiddlewaresOptions{ - Retryer: o.Retryer, - LogRetryAttempts: o.ClientLogMode.IsRetries(), +func addClientRequestID(stack *middleware.Stack) error { + return stack.Build.Add(&awsmiddleware.ClientRequestID{}, middleware.After) +} + +func addComputeContentLength(stack *middleware.Stack) error { + return stack.Build.Add(&smithyhttp.ComputeContentLength{}, middleware.After) +} + +func addRawResponseToMetadata(stack *middleware.Stack) error { + return stack.Deserialize.Add(&awsmiddleware.AddRawResponse{}, middleware.Before) +} + +func addRecordResponseTiming(stack *middleware.Stack) error { + return stack.Deserialize.Add(&awsmiddleware.RecordResponseTiming{}, middleware.After) +} + +func addSpanRetryLoop(stack *middleware.Stack, options Options) error { + return stack.Finalize.Insert(&spanRetryLoop{options: options}, "Retry", middleware.Before) +} + +type spanRetryLoop struct { + options Options +} + +func (*spanRetryLoop) ID() string { + return "spanRetryLoop" +} + +func (m *spanRetryLoop) HandleFinalize( + ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler, +) ( + middleware.FinalizeOutput, middleware.Metadata, error, +) { + tracer := operationTracer(m.options.TracerProvider) + ctx, span := tracer.StartSpan(ctx, "RetryLoop") + defer span.End() + + return next.HandleFinalize(ctx, in) +} +func addStreamingEventsPayload(stack *middleware.Stack) error { + return stack.Finalize.Add(&v4.StreamingEventsPayload{}, middleware.Before) +} + +func addUnsignedPayload(stack *middleware.Stack) error { + return stack.Finalize.Insert(&v4.UnsignedPayload{}, "ResolveEndpointV2", middleware.After) +} + +func addComputePayloadSHA256(stack *middleware.Stack) error { + return stack.Finalize.Insert(&v4.ComputePayloadSHA256{}, "ResolveEndpointV2", middleware.After) +} + +func addContentSHA256Header(stack *middleware.Stack) error { + return stack.Finalize.Insert(&v4.ContentSHA256Header{}, (*v4.ComputePayloadSHA256)(nil).ID(), middleware.After) +} + +func addIsWaiterUserAgent(o *Options) { + o.APIOptions = append(o.APIOptions, func(stack *middleware.Stack) error { + ua, err := getOrAddRequestUserAgent(stack) + if err != nil { + return err + } + + ua.AddUserAgentFeature(awsmiddleware.UserAgentFeatureWaiter) + return nil + }) +} + +func addIsPaginatorUserAgent(o *Options) { + o.APIOptions = append(o.APIOptions, func(stack *middleware.Stack) error { + ua, err := getOrAddRequestUserAgent(stack) + if err != nil { + return err + } + + ua.AddUserAgentFeature(awsmiddleware.UserAgentFeaturePaginator) + return nil + }) +} + +func addRetry(stack *middleware.Stack, o Options) error { + attempt := retry.NewAttemptMiddleware(o.Retryer, smithyhttp.RequestCloner, func(m *retry.Attempt) { + m.LogAttempts = o.ClientLogMode.IsRetries() + m.OperationMeter = o.MeterProvider.Meter("github.com/aws/aws-sdk-go-v2/service/sso") + }) + if err := stack.Finalize.Insert(attempt, "ResolveAuthScheme", middleware.Before); err != nil { + return err } - return retry.AddRetryMiddlewares(stack, mo) + if err := stack.Finalize.Insert(&retry.MetricsHeader{}, attempt.ID(), middleware.After); err != nil { + return err + } + return nil } // resolves dual-stack endpoint configuration @@ -428,12 +723,68 @@ func resolveUseFIPSEndpoint(cfg aws.Config, o *Options) error { return nil } +func resolveAccountID(identity smithyauth.Identity, mode aws.AccountIDEndpointMode) *string { + if mode == aws.AccountIDEndpointModeDisabled { + return nil + } + + if ca, ok := identity.(*internalauthsmithy.CredentialsAdapter); ok && ca.Credentials.AccountID != "" { + return aws.String(ca.Credentials.AccountID) + } + + return nil +} + +func addTimeOffsetBuild(stack *middleware.Stack, c *Client) error { + mw := internalmiddleware.AddTimeOffsetMiddleware{Offset: c.timeOffset} + if err := stack.Build.Add(&mw, middleware.After); err != nil { + return err + } + return stack.Deserialize.Insert(&mw, "RecordResponseTiming", middleware.Before) +} +func initializeTimeOffsetResolver(c *Client) { + c.timeOffset = new(atomic.Int64) +} + +func addUserAgentRetryMode(stack *middleware.Stack, options Options) error { + ua, err := getOrAddRequestUserAgent(stack) + if err != nil { + return err + } + + switch options.Retryer.(type) { + case *retry.Standard: + ua.AddUserAgentFeature(awsmiddleware.UserAgentFeatureRetryModeStandard) + case *retry.AdaptiveMode: + ua.AddUserAgentFeature(awsmiddleware.UserAgentFeatureRetryModeAdaptive) + } + return nil +} + +func resolveTracerProvider(options *Options) { + if options.TracerProvider == nil { + options.TracerProvider = &tracing.NopTracerProvider{} + } +} + +func resolveMeterProvider(options *Options) { + if options.MeterProvider == nil { + options.MeterProvider = metrics.NopMeterProvider{} + } +} + +func addRecursionDetection(stack *middleware.Stack) error { + return stack.Build.Add(&awsmiddleware.RecursionDetection{}, middleware.After) +} + func addRequestIDRetrieverMiddleware(stack *middleware.Stack) error { - return awsmiddleware.AddRequestIDRetrieverMiddleware(stack) + return stack.Deserialize.Insert(&awsmiddleware.RequestIDRetriever{}, "OperationDeserializer", middleware.Before) + } func addResponseErrorMiddleware(stack *middleware.Stack) error { - return awshttp.AddResponseErrorMiddleware(stack) + return stack.Deserialize.Insert(&awshttp.ResponseErrorWrapper{}, "RequestIDRetriever", middleware.Before) + } func addRequestResponseLogging(stack *middleware.Stack, o Options) error { @@ -473,3 +824,89 @@ func addDisableHTTPSMiddleware(stack *middleware.Stack, o Options) error { DisableHTTPS: o.EndpointOptions.DisableHTTPS, }, "ResolveEndpointV2", middleware.After) } + +type spanInitializeStart struct { +} + +func (*spanInitializeStart) ID() string { + return "spanInitializeStart" +} + +func (m *spanInitializeStart) HandleInitialize( + ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler, +) ( + middleware.InitializeOutput, middleware.Metadata, error, +) { + ctx, _ = tracing.StartSpan(ctx, "Initialize") + + return next.HandleInitialize(ctx, in) +} + +type spanInitializeEnd struct { +} + +func (*spanInitializeEnd) ID() string { + return "spanInitializeEnd" +} + +func (m *spanInitializeEnd) HandleInitialize( + ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler, +) ( + middleware.InitializeOutput, middleware.Metadata, error, +) { + ctx, span := tracing.PopSpan(ctx) + span.End() + + return next.HandleInitialize(ctx, in) +} + +type spanBuildRequestStart struct { +} + +func (*spanBuildRequestStart) ID() string { + return "spanBuildRequestStart" +} + +func (m *spanBuildRequestStart) HandleSerialize( + ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler, +) ( + middleware.SerializeOutput, middleware.Metadata, error, +) { + ctx, _ = tracing.StartSpan(ctx, "BuildRequest") + + return next.HandleSerialize(ctx, in) +} + +type spanBuildRequestEnd struct { +} + +func (*spanBuildRequestEnd) ID() string { + return "spanBuildRequestEnd" +} + +func (m *spanBuildRequestEnd) HandleBuild( + ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler, +) ( + middleware.BuildOutput, middleware.Metadata, error, +) { + ctx, span := tracing.PopSpan(ctx) + span.End() + + return next.HandleBuild(ctx, in) +} + +func addSpanInitializeStart(stack *middleware.Stack) error { + return stack.Initialize.Add(&spanInitializeStart{}, middleware.Before) +} + +func addSpanInitializeEnd(stack *middleware.Stack) error { + return stack.Initialize.Add(&spanInitializeEnd{}, middleware.After) +} + +func addSpanBuildRequestStart(stack *middleware.Stack) error { + return stack.Serialize.Add(&spanBuildRequestStart{}, middleware.Before) +} + +func addSpanBuildRequestEnd(stack *middleware.Stack) error { + return stack.Build.Add(&spanBuildRequestEnd{}, middleware.After) +} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_GetRoleCredentials.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_GetRoleCredentials.go index 436eadc..a656020 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_GetRoleCredentials.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_GetRoleCredentials.go @@ -30,9 +30,10 @@ func (c *Client) GetRoleCredentials(ctx context.Context, params *GetRoleCredenti type GetRoleCredentialsInput struct { - // The token issued by the CreateToken API call. For more information, see - // CreateToken (https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/API_CreateToken.html) - // in the IAM Identity Center OIDC API Reference Guide. + // The token issued by the CreateToken API call. For more information, see [CreateToken] in the + // IAM Identity Center OIDC API Reference Guide. + // + // [CreateToken]: https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/API_CreateToken.html // // This member is required. AccessToken *string @@ -83,22 +84,25 @@ func (c *Client) addOperationGetRoleCredentialsMiddlewares(stack *middleware.Sta if err = addSetLoggerMiddleware(stack, options); err != nil { return err } - if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + if err = addClientRequestID(stack); err != nil { return err } - if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + if err = addComputeContentLength(stack); err != nil { return err } if err = addResolveEndpointMiddleware(stack, options); err != nil { return err } - if err = addRetryMiddlewares(stack, options); err != nil { + if err = addRetry(stack, options); err != nil { return err } - if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + if err = addRawResponseToMetadata(stack); err != nil { return err } - if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + if err = addRecordResponseTiming(stack); err != nil { + return err + } + if err = addSpanRetryLoop(stack, options); err != nil { return err } if err = addClientUserAgent(stack, options); err != nil { @@ -113,13 +117,19 @@ func (c *Client) addOperationGetRoleCredentialsMiddlewares(stack *middleware.Sta if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil { return err } + if err = addTimeOffsetBuild(stack, c); err != nil { + return err + } + if err = addUserAgentRetryMode(stack, options); err != nil { + return err + } if err = addOpGetRoleCredentialsValidationMiddleware(stack); err != nil { return err } if err = stack.Initialize.Add(newServiceMetadataMiddleware_opGetRoleCredentials(options.Region), middleware.Before); err != nil { return err } - if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + if err = addRecursionDetection(stack); err != nil { return err } if err = addRequestIDRetrieverMiddleware(stack); err != nil { @@ -134,6 +144,18 @@ func (c *Client) addOperationGetRoleCredentialsMiddlewares(stack *middleware.Sta if err = addDisableHTTPSMiddleware(stack, options); err != nil { return err } + if err = addSpanInitializeStart(stack); err != nil { + return err + } + if err = addSpanInitializeEnd(stack); err != nil { + return err + } + if err = addSpanBuildRequestStart(stack); err != nil { + return err + } + if err = addSpanBuildRequestEnd(stack); err != nil { + return err + } return nil } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_ListAccountRoles.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_ListAccountRoles.go index d81b067..315526e 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_ListAccountRoles.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_ListAccountRoles.go @@ -29,9 +29,10 @@ func (c *Client) ListAccountRoles(ctx context.Context, params *ListAccountRolesI type ListAccountRolesInput struct { - // The token issued by the CreateToken API call. For more information, see - // CreateToken (https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/API_CreateToken.html) - // in the IAM Identity Center OIDC API Reference Guide. + // The token issued by the CreateToken API call. For more information, see [CreateToken] in the + // IAM Identity Center OIDC API Reference Guide. + // + // [CreateToken]: https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/API_CreateToken.html // // This member is required. AccessToken *string @@ -88,22 +89,25 @@ func (c *Client) addOperationListAccountRolesMiddlewares(stack *middleware.Stack if err = addSetLoggerMiddleware(stack, options); err != nil { return err } - if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + if err = addClientRequestID(stack); err != nil { return err } - if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + if err = addComputeContentLength(stack); err != nil { return err } if err = addResolveEndpointMiddleware(stack, options); err != nil { return err } - if err = addRetryMiddlewares(stack, options); err != nil { + if err = addRetry(stack, options); err != nil { return err } - if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + if err = addRawResponseToMetadata(stack); err != nil { return err } - if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + if err = addRecordResponseTiming(stack); err != nil { + return err + } + if err = addSpanRetryLoop(stack, options); err != nil { return err } if err = addClientUserAgent(stack, options); err != nil { @@ -118,13 +122,19 @@ func (c *Client) addOperationListAccountRolesMiddlewares(stack *middleware.Stack if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil { return err } + if err = addTimeOffsetBuild(stack, c); err != nil { + return err + } + if err = addUserAgentRetryMode(stack, options); err != nil { + return err + } if err = addOpListAccountRolesValidationMiddleware(stack); err != nil { return err } if err = stack.Initialize.Add(newServiceMetadataMiddleware_opListAccountRoles(options.Region), middleware.Before); err != nil { return err } - if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + if err = addRecursionDetection(stack); err != nil { return err } if err = addRequestIDRetrieverMiddleware(stack); err != nil { @@ -139,17 +149,21 @@ func (c *Client) addOperationListAccountRolesMiddlewares(stack *middleware.Stack if err = addDisableHTTPSMiddleware(stack, options); err != nil { return err } + if err = addSpanInitializeStart(stack); err != nil { + return err + } + if err = addSpanInitializeEnd(stack); err != nil { + return err + } + if err = addSpanBuildRequestStart(stack); err != nil { + return err + } + if err = addSpanBuildRequestEnd(stack); err != nil { + return err + } return nil } -// ListAccountRolesAPIClient is a client that implements the ListAccountRoles -// operation. -type ListAccountRolesAPIClient interface { - ListAccountRoles(context.Context, *ListAccountRolesInput, ...func(*Options)) (*ListAccountRolesOutput, error) -} - -var _ ListAccountRolesAPIClient = (*Client)(nil) - // ListAccountRolesPaginatorOptions is the paginator options for ListAccountRoles type ListAccountRolesPaginatorOptions struct { // The number of items that clients can request per page. @@ -213,6 +227,9 @@ func (p *ListAccountRolesPaginator) NextPage(ctx context.Context, optFns ...func } params.MaxResults = limit + optFns = append([]func(*Options){ + addIsPaginatorUserAgent, + }, optFns...) result, err := p.client.ListAccountRoles(ctx, ¶ms, optFns...) if err != nil { return nil, err @@ -232,6 +249,14 @@ func (p *ListAccountRolesPaginator) NextPage(ctx context.Context, optFns ...func return result, nil } +// ListAccountRolesAPIClient is a client that implements the ListAccountRoles +// operation. +type ListAccountRolesAPIClient interface { + ListAccountRoles(context.Context, *ListAccountRolesInput, ...func(*Options)) (*ListAccountRolesOutput, error) +} + +var _ ListAccountRolesAPIClient = (*Client)(nil) + func newServiceMetadataMiddleware_opListAccountRoles(region string) *awsmiddleware.RegisterServiceMetadata { return &awsmiddleware.RegisterServiceMetadata{ Region: region, diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_ListAccounts.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_ListAccounts.go index 38f8472..d867b78 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_ListAccounts.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_ListAccounts.go @@ -12,9 +12,10 @@ import ( ) // Lists all AWS accounts assigned to the user. These AWS accounts are assigned by -// the administrator of the account. For more information, see Assign User Access (https://docs.aws.amazon.com/singlesignon/latest/userguide/useraccess.html#assignusers) -// in the IAM Identity Center User Guide. This operation returns a paginated -// response. +// the administrator of the account. For more information, see [Assign User Access]in the IAM Identity +// Center User Guide. This operation returns a paginated response. +// +// [Assign User Access]: https://docs.aws.amazon.com/singlesignon/latest/userguide/useraccess.html#assignusers func (c *Client) ListAccounts(ctx context.Context, params *ListAccountsInput, optFns ...func(*Options)) (*ListAccountsOutput, error) { if params == nil { params = &ListAccountsInput{} @@ -32,9 +33,10 @@ func (c *Client) ListAccounts(ctx context.Context, params *ListAccountsInput, op type ListAccountsInput struct { - // The token issued by the CreateToken API call. For more information, see - // CreateToken (https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/API_CreateToken.html) - // in the IAM Identity Center OIDC API Reference Guide. + // The token issued by the CreateToken API call. For more information, see [CreateToken] in the + // IAM Identity Center OIDC API Reference Guide. + // + // [CreateToken]: https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/API_CreateToken.html // // This member is required. AccessToken *string @@ -86,22 +88,25 @@ func (c *Client) addOperationListAccountsMiddlewares(stack *middleware.Stack, op if err = addSetLoggerMiddleware(stack, options); err != nil { return err } - if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + if err = addClientRequestID(stack); err != nil { return err } - if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + if err = addComputeContentLength(stack); err != nil { return err } if err = addResolveEndpointMiddleware(stack, options); err != nil { return err } - if err = addRetryMiddlewares(stack, options); err != nil { + if err = addRetry(stack, options); err != nil { return err } - if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + if err = addRawResponseToMetadata(stack); err != nil { return err } - if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + if err = addRecordResponseTiming(stack); err != nil { + return err + } + if err = addSpanRetryLoop(stack, options); err != nil { return err } if err = addClientUserAgent(stack, options); err != nil { @@ -116,13 +121,19 @@ func (c *Client) addOperationListAccountsMiddlewares(stack *middleware.Stack, op if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil { return err } + if err = addTimeOffsetBuild(stack, c); err != nil { + return err + } + if err = addUserAgentRetryMode(stack, options); err != nil { + return err + } if err = addOpListAccountsValidationMiddleware(stack); err != nil { return err } if err = stack.Initialize.Add(newServiceMetadataMiddleware_opListAccounts(options.Region), middleware.Before); err != nil { return err } - if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + if err = addRecursionDetection(stack); err != nil { return err } if err = addRequestIDRetrieverMiddleware(stack); err != nil { @@ -137,16 +148,21 @@ func (c *Client) addOperationListAccountsMiddlewares(stack *middleware.Stack, op if err = addDisableHTTPSMiddleware(stack, options); err != nil { return err } + if err = addSpanInitializeStart(stack); err != nil { + return err + } + if err = addSpanInitializeEnd(stack); err != nil { + return err + } + if err = addSpanBuildRequestStart(stack); err != nil { + return err + } + if err = addSpanBuildRequestEnd(stack); err != nil { + return err + } return nil } -// ListAccountsAPIClient is a client that implements the ListAccounts operation. -type ListAccountsAPIClient interface { - ListAccounts(context.Context, *ListAccountsInput, ...func(*Options)) (*ListAccountsOutput, error) -} - -var _ ListAccountsAPIClient = (*Client)(nil) - // ListAccountsPaginatorOptions is the paginator options for ListAccounts type ListAccountsPaginatorOptions struct { // This is the number of items clients can request per page. @@ -210,6 +226,9 @@ func (p *ListAccountsPaginator) NextPage(ctx context.Context, optFns ...func(*Op } params.MaxResults = limit + optFns = append([]func(*Options){ + addIsPaginatorUserAgent, + }, optFns...) result, err := p.client.ListAccounts(ctx, ¶ms, optFns...) if err != nil { return nil, err @@ -229,6 +248,13 @@ func (p *ListAccountsPaginator) NextPage(ctx context.Context, optFns ...func(*Op return result, nil } +// ListAccountsAPIClient is a client that implements the ListAccounts operation. +type ListAccountsAPIClient interface { + ListAccounts(context.Context, *ListAccountsInput, ...func(*Options)) (*ListAccountsOutput, error) +} + +var _ ListAccountsAPIClient = (*Client)(nil) + func newServiceMetadataMiddleware_opListAccounts(region string) *awsmiddleware.RegisterServiceMetadata { return &awsmiddleware.RegisterServiceMetadata{ Region: region, diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_Logout.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_Logout.go index 82e98a8..434b430 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_Logout.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/api_op_Logout.go @@ -12,16 +12,20 @@ import ( // Removes the locally stored SSO tokens from the client-side cache and sends an // API call to the IAM Identity Center service to invalidate the corresponding -// server-side IAM Identity Center sign in session. If a user uses IAM Identity -// Center to access the AWS CLI, the user’s IAM Identity Center sign in session is -// used to obtain an IAM session, as specified in the corresponding IAM Identity -// Center permission set. More specifically, IAM Identity Center assumes an IAM -// role in the target account on behalf of the user, and the corresponding -// temporary AWS credentials are returned to the client. After user logout, any -// existing IAM role sessions that were created by using IAM Identity Center -// permission sets continue based on the duration configured in the permission set. -// For more information, see User authentications (https://docs.aws.amazon.com/singlesignon/latest/userguide/authconcept.html) -// in the IAM Identity Center User Guide. +// server-side IAM Identity Center sign in session. +// +// If a user uses IAM Identity Center to access the AWS CLI, the user’s IAM +// Identity Center sign in session is used to obtain an IAM session, as specified +// in the corresponding IAM Identity Center permission set. More specifically, IAM +// Identity Center assumes an IAM role in the target account on behalf of the user, +// and the corresponding temporary AWS credentials are returned to the client. +// +// After user logout, any existing IAM role sessions that were created by using +// IAM Identity Center permission sets continue based on the duration configured in +// the permission set. For more information, see [User authentications]in the IAM Identity Center User +// Guide. +// +// [User authentications]: https://docs.aws.amazon.com/singlesignon/latest/userguide/authconcept.html func (c *Client) Logout(ctx context.Context, params *LogoutInput, optFns ...func(*Options)) (*LogoutOutput, error) { if params == nil { params = &LogoutInput{} @@ -39,9 +43,10 @@ func (c *Client) Logout(ctx context.Context, params *LogoutInput, optFns ...func type LogoutInput struct { - // The token issued by the CreateToken API call. For more information, see - // CreateToken (https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/API_CreateToken.html) - // in the IAM Identity Center OIDC API Reference Guide. + // The token issued by the CreateToken API call. For more information, see [CreateToken] in the + // IAM Identity Center OIDC API Reference Guide. + // + // [CreateToken]: https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/API_CreateToken.html // // This member is required. AccessToken *string @@ -78,22 +83,25 @@ func (c *Client) addOperationLogoutMiddlewares(stack *middleware.Stack, options if err = addSetLoggerMiddleware(stack, options); err != nil { return err } - if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + if err = addClientRequestID(stack); err != nil { return err } - if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + if err = addComputeContentLength(stack); err != nil { return err } if err = addResolveEndpointMiddleware(stack, options); err != nil { return err } - if err = addRetryMiddlewares(stack, options); err != nil { + if err = addRetry(stack, options); err != nil { return err } - if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + if err = addRawResponseToMetadata(stack); err != nil { return err } - if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + if err = addRecordResponseTiming(stack); err != nil { + return err + } + if err = addSpanRetryLoop(stack, options); err != nil { return err } if err = addClientUserAgent(stack, options); err != nil { @@ -108,13 +116,19 @@ func (c *Client) addOperationLogoutMiddlewares(stack *middleware.Stack, options if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil { return err } + if err = addTimeOffsetBuild(stack, c); err != nil { + return err + } + if err = addUserAgentRetryMode(stack, options); err != nil { + return err + } if err = addOpLogoutValidationMiddleware(stack); err != nil { return err } if err = stack.Initialize.Add(newServiceMetadataMiddleware_opLogout(options.Region), middleware.Before); err != nil { return err } - if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + if err = addRecursionDetection(stack); err != nil { return err } if err = addRequestIDRetrieverMiddleware(stack); err != nil { @@ -129,6 +143,18 @@ func (c *Client) addOperationLogoutMiddlewares(stack *middleware.Stack, options if err = addDisableHTTPSMiddleware(stack, options); err != nil { return err } + if err = addSpanInitializeStart(stack); err != nil { + return err + } + if err = addSpanInitializeEnd(stack); err != nil { + return err + } + if err = addSpanBuildRequestStart(stack); err != nil { + return err + } + if err = addSpanBuildRequestEnd(stack); err != nil { + return err + } return nil } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/auth.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/auth.go index 3b28e82..366963b 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/auth.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/auth.go @@ -8,11 +8,13 @@ import ( awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" smithy "github.com/aws/smithy-go" smithyauth "github.com/aws/smithy-go/auth" + "github.com/aws/smithy-go/metrics" "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" ) -func bindAuthParamsRegion(params *AuthResolverParameters, _ interface{}, options Options) { +func bindAuthParamsRegion(_ interface{}, params *AuthResolverParameters, _ interface{}, options Options) { params.Region = options.Region } @@ -90,12 +92,12 @@ type AuthResolverParameters struct { Region string } -func bindAuthResolverParams(operation string, input interface{}, options Options) *AuthResolverParameters { +func bindAuthResolverParams(ctx context.Context, operation string, input interface{}, options Options) *AuthResolverParameters { params := &AuthResolverParameters{ Operation: operation, } - bindAuthParamsRegion(params, input, options) + bindAuthParamsRegion(ctx, params, input, options) return params } @@ -169,7 +171,10 @@ func (*resolveAuthSchemeMiddleware) ID() string { func (m *resolveAuthSchemeMiddleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) ( out middleware.FinalizeOutput, metadata middleware.Metadata, err error, ) { - params := bindAuthResolverParams(m.operation, getOperationInput(ctx), m.options) + _, span := tracing.StartSpan(ctx, "ResolveAuthScheme") + defer span.End() + + params := bindAuthResolverParams(ctx, m.operation, getOperationInput(ctx), m.options) options, err := m.options.AuthSchemeResolver.ResolveAuthSchemes(ctx, params) if err != nil { return out, metadata, fmt.Errorf("resolve auth scheme: %w", err) @@ -181,6 +186,9 @@ func (m *resolveAuthSchemeMiddleware) HandleFinalize(ctx context.Context, in mid } ctx = setResolvedAuthScheme(ctx, scheme) + + span.SetProperty("auth.scheme_id", scheme.Scheme.SchemeID()) + span.End() return next.HandleFinalize(ctx, in) } @@ -240,7 +248,10 @@ func (*getIdentityMiddleware) ID() string { func (m *getIdentityMiddleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) ( out middleware.FinalizeOutput, metadata middleware.Metadata, err error, ) { - rscheme := getResolvedAuthScheme(ctx) + innerCtx, span := tracing.StartSpan(ctx, "GetIdentity") + defer span.End() + + rscheme := getResolvedAuthScheme(innerCtx) if rscheme == nil { return out, metadata, fmt.Errorf("no resolved auth scheme") } @@ -250,12 +261,20 @@ func (m *getIdentityMiddleware) HandleFinalize(ctx context.Context, in middlewar return out, metadata, fmt.Errorf("no identity resolver") } - identity, err := resolver.GetIdentity(ctx, rscheme.IdentityProperties) + identity, err := timeOperationMetric(ctx, "client.call.resolve_identity_duration", + func() (smithyauth.Identity, error) { + return resolver.GetIdentity(innerCtx, rscheme.IdentityProperties) + }, + func(o *metrics.RecordMetricOptions) { + o.Properties.Set("auth.scheme_id", rscheme.Scheme.SchemeID()) + }) if err != nil { return out, metadata, fmt.Errorf("get identity: %w", err) } ctx = setIdentity(ctx, identity) + + span.End() return next.HandleFinalize(ctx, in) } @@ -271,6 +290,7 @@ func getIdentity(ctx context.Context) smithyauth.Identity { } type signRequestMiddleware struct { + options Options } func (*signRequestMiddleware) ID() string { @@ -280,6 +300,9 @@ func (*signRequestMiddleware) ID() string { func (m *signRequestMiddleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) ( out middleware.FinalizeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "SignRequest") + defer span.End() + req, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, fmt.Errorf("unexpected transport type %T", in.Request) @@ -300,9 +323,15 @@ func (m *signRequestMiddleware) HandleFinalize(ctx context.Context, in middlewar return out, metadata, fmt.Errorf("no signer") } - if err := signer.SignRequest(ctx, req, identity, rscheme.SignerProperties); err != nil { + _, err = timeOperationMetric(ctx, "client.call.signing_duration", func() (any, error) { + return nil, signer.SignRequest(ctx, req, identity, rscheme.SignerProperties) + }, func(o *metrics.RecordMetricOptions) { + o.Properties.Set("auth.scheme_id", rscheme.Scheme.SchemeID()) + }) + if err != nil { return out, metadata, fmt.Errorf("sign request: %w", err) } + span.End() return next.HandleFinalize(ctx, in) } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/deserializers.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/deserializers.go index 8bba205..ec23c36 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/deserializers.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/deserializers.go @@ -13,12 +13,23 @@ import ( smithyio "github.com/aws/smithy-go/io" "github.com/aws/smithy-go/middleware" "github.com/aws/smithy-go/ptr" + smithytime "github.com/aws/smithy-go/time" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" "io" "io/ioutil" "strings" + "time" ) +func deserializeS3Expires(v string) (*time.Time, error) { + t, err := smithytime.ParseHTTPDate(v) + if err != nil { + return nil, nil + } + return &t, nil +} + type awsRestjson1_deserializeOpGetRoleCredentials struct { } @@ -34,6 +45,10 @@ func (m *awsRestjson1_deserializeOpGetRoleCredentials) HandleDeserialize(ctx con return out, metadata, err } + _, span := tracing.StartSpan(ctx, "OperationDeserializer") + endTimer := startMetricTimer(ctx, "client.call.deserialization_duration") + defer endTimer() + defer span.End() response, ok := out.RawResponse.(*smithyhttp.Response) if !ok { return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} @@ -73,6 +88,7 @@ func (m *awsRestjson1_deserializeOpGetRoleCredentials) HandleDeserialize(ctx con } } + span.End() return out, metadata, err } @@ -190,6 +206,10 @@ func (m *awsRestjson1_deserializeOpListAccountRoles) HandleDeserialize(ctx conte return out, metadata, err } + _, span := tracing.StartSpan(ctx, "OperationDeserializer") + endTimer := startMetricTimer(ctx, "client.call.deserialization_duration") + defer endTimer() + defer span.End() response, ok := out.RawResponse.(*smithyhttp.Response) if !ok { return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} @@ -229,6 +249,7 @@ func (m *awsRestjson1_deserializeOpListAccountRoles) HandleDeserialize(ctx conte } } + span.End() return out, metadata, err } @@ -355,6 +376,10 @@ func (m *awsRestjson1_deserializeOpListAccounts) HandleDeserialize(ctx context.C return out, metadata, err } + _, span := tracing.StartSpan(ctx, "OperationDeserializer") + endTimer := startMetricTimer(ctx, "client.call.deserialization_duration") + defer endTimer() + defer span.End() response, ok := out.RawResponse.(*smithyhttp.Response) if !ok { return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} @@ -394,6 +419,7 @@ func (m *awsRestjson1_deserializeOpListAccounts) HandleDeserialize(ctx context.C } } + span.End() return out, metadata, err } @@ -520,6 +546,10 @@ func (m *awsRestjson1_deserializeOpLogout) HandleDeserialize(ctx context.Context return out, metadata, err } + _, span := tracing.StartSpan(ctx, "OperationDeserializer") + endTimer := startMetricTimer(ctx, "client.call.deserialization_duration") + defer endTimer() + defer span.End() response, ok := out.RawResponse.(*smithyhttp.Response) if !ok { return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} @@ -537,6 +567,7 @@ func (m *awsRestjson1_deserializeOpLogout) HandleDeserialize(ctx context.Context } } + span.End() return out, metadata, err } @@ -858,7 +889,7 @@ func awsRestjson1_deserializeDocumentInvalidRequestException(v **types.InvalidRe for key, value := range shape { switch key { - case "message": + case "message", "Message": if value != nil { jtv, ok := value.(string) if !ok { @@ -898,7 +929,7 @@ func awsRestjson1_deserializeDocumentResourceNotFoundException(v **types.Resourc for key, value := range shape { switch key { - case "message": + case "message", "Message": if value != nil { jtv, ok := value.(string) if !ok { @@ -1092,7 +1123,7 @@ func awsRestjson1_deserializeDocumentTooManyRequestsException(v **types.TooManyR for key, value := range shape { switch key { - case "message": + case "message", "Message": if value != nil { jtv, ok := value.(string) if !ok { @@ -1132,7 +1163,7 @@ func awsRestjson1_deserializeDocumentUnauthorizedException(v **types.Unauthorize for key, value := range shape { switch key { - case "message": + case "message", "Message": if value != nil { jtv, ok := value.(string) if !ok { diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/doc.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/doc.go index 59456d5..7f6e429 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/doc.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/doc.go @@ -6,16 +6,22 @@ // AWS IAM Identity Center (successor to AWS Single Sign-On) Portal is a web // service that makes it easy for you to assign user access to IAM Identity Center // resources such as the AWS access portal. Users can get AWS account applications -// and roles assigned to them and get federated into the application. Although AWS -// Single Sign-On was renamed, the sso and identitystore API namespaces will -// continue to retain their original name for backward compatibility purposes. For -// more information, see IAM Identity Center rename (https://docs.aws.amazon.com/singlesignon/latest/userguide/what-is.html#renamed) -// . This reference guide describes the IAM Identity Center Portal operations that +// and roles assigned to them and get federated into the application. +// +// Although AWS Single Sign-On was renamed, the sso and identitystore API +// namespaces will continue to retain their original name for backward +// compatibility purposes. For more information, see [IAM Identity Center rename]. +// +// This reference guide describes the IAM Identity Center Portal operations that // you can call programatically and includes detailed information on data types and -// errors. AWS provides SDKs that consist of libraries and sample code for various +// errors. +// +// AWS provides SDKs that consist of libraries and sample code for various // programming languages and platforms, such as Java, Ruby, .Net, iOS, or Android. // The SDKs provide a convenient way to create programmatic access to IAM Identity // Center and other AWS services. For more information about the AWS SDKs, -// including how to download and install them, see Tools for Amazon Web Services (http://aws.amazon.com/tools/) -// . +// including how to download and install them, see [Tools for Amazon Web Services]. +// +// [Tools for Amazon Web Services]: http://aws.amazon.com/tools/ +// [IAM Identity Center rename]: https://docs.aws.amazon.com/singlesignon/latest/userguide/what-is.html#renamed package sso diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/endpoints.go index d31380c..53c6bc7 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/endpoints.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/endpoints.go @@ -16,6 +16,7 @@ import ( smithyendpoints "github.com/aws/smithy-go/endpoints" "github.com/aws/smithy-go/middleware" "github.com/aws/smithy-go/ptr" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" "net/http" "net/url" @@ -216,6 +217,13 @@ func resolveBaseEndpoint(cfg aws.Config, o *Options) { } } +func bindRegion(region string) *string { + if region == "" { + return nil + } + return aws.String(endpoints.MapFIPSRegion(region)) +} + // EndpointParameters provides the parameters that influence how endpoints are // resolved. type EndpointParameters struct { @@ -281,6 +289,17 @@ func (p EndpointParameters) WithDefaults() EndpointParameters { return p } +type stringSlice []string + +func (s stringSlice) Get(i int) *string { + if i < 0 || i >= len(s) { + return nil + } + + v := s[i] + return &v +} + // EndpointResolverV2 provides the interface for resolving service endpoints. type EndpointResolverV2 interface { // ResolveEndpoint attempts to resolve the endpoint with the provided options, @@ -458,10 +477,10 @@ type endpointParamsBinder interface { bindEndpointParams(*EndpointParameters) } -func bindEndpointParams(input interface{}, options Options) *EndpointParameters { +func bindEndpointParams(ctx context.Context, input interface{}, options Options) *EndpointParameters { params := &EndpointParameters{} - params.Region = aws.String(endpoints.MapFIPSRegion(options.Region)) + params.Region = bindRegion(options.Region) params.UseDualStack = aws.Bool(options.EndpointOptions.UseDualStackEndpoint == aws.DualStackEndpointStateEnabled) params.UseFIPS = aws.Bool(options.EndpointOptions.UseFIPSEndpoint == aws.FIPSEndpointStateEnabled) params.Endpoint = options.BaseEndpoint @@ -484,6 +503,9 @@ func (*resolveEndpointV2Middleware) ID() string { func (m *resolveEndpointV2Middleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) ( out middleware.FinalizeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "ResolveEndpoint") + defer span.End() + if awsmiddleware.GetRequiresLegacyEndpoints(ctx) { return next.HandleFinalize(ctx, in) } @@ -497,12 +519,17 @@ func (m *resolveEndpointV2Middleware) HandleFinalize(ctx context.Context, in mid return out, metadata, fmt.Errorf("expected endpoint resolver to not be nil") } - params := bindEndpointParams(getOperationInput(ctx), m.options) - endpt, err := m.options.EndpointResolverV2.ResolveEndpoint(ctx, *params) + params := bindEndpointParams(ctx, getOperationInput(ctx), m.options) + endpt, err := timeOperationMetric(ctx, "client.call.resolve_endpoint_duration", + func() (smithyendpoints.Endpoint, error) { + return m.options.EndpointResolverV2.ResolveEndpoint(ctx, *params) + }) if err != nil { return out, metadata, fmt.Errorf("failed to resolve service endpoint, %w", err) } + span.SetProperty("client.call.resolved_endpoint", endpt.URI.String()) + if endpt.URI.RawPath == "" && req.URL.RawPath != "" { endpt.URI.RawPath = endpt.URI.Path } @@ -524,5 +551,6 @@ func (m *resolveEndpointV2Middleware) HandleFinalize(ctx context.Context, in mid rscheme.SignerProperties.SetAll(&o.SignerProperties) } + span.End() return next.HandleFinalize(ctx, in) } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/generated.json b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/generated.json index 53060bc..936253d 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/generated.json +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/generated.json @@ -3,8 +3,7 @@ "github.com/aws/aws-sdk-go-v2": "v1.4.0", "github.com/aws/aws-sdk-go-v2/internal/configsources": "v0.0.0-00010101000000-000000000000", "github.com/aws/aws-sdk-go-v2/internal/endpoints/v2": "v2.0.0-00010101000000-000000000000", - "github.com/aws/smithy-go": "v1.4.0", - "github.com/google/go-cmp": "v0.5.4" + "github.com/aws/smithy-go": "v1.4.0" }, "files": [ "api_client.go", @@ -25,6 +24,7 @@ "options.go", "protocol_test.go", "serializers.go", + "snapshot_test.go", "types/errors.go", "types/types.go", "validators.go" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/go_module_metadata.go index 857a6af..43c6740 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/go_module_metadata.go @@ -3,4 +3,4 @@ package sso // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.18.7" +const goModuleVersion = "1.24.14" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/internal/endpoints/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/internal/endpoints/endpoints.go index c8f7c09..081867b 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/internal/endpoints/endpoints.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/internal/endpoints/endpoints.go @@ -94,7 +94,7 @@ var partitionRegexp = struct { AwsUsGov *regexp.Regexp }{ - Aws: regexp.MustCompile("^(us|eu|ap|sa|ca|me|af|il)\\-\\w+\\-\\d+$"), + Aws: regexp.MustCompile("^(us|eu|ap|sa|ca|me|af|il|mx)\\-\\w+\\-\\d+$"), AwsCn: regexp.MustCompile("^cn\\-\\w+\\-\\d+$"), AwsIso: regexp.MustCompile("^us\\-iso\\-\\w+\\-\\d+$"), AwsIsoB: regexp.MustCompile("^us\\-isob\\-\\w+\\-\\d+$"), @@ -187,6 +187,14 @@ var defaultPartitions = endpoints.Partitions{ Region: "ap-south-1", }, }, + endpoints.EndpointKey{ + Region: "ap-south-2", + }: endpoints.Endpoint{ + Hostname: "portal.sso.ap-south-2.amazonaws.com", + CredentialScope: endpoints.CredentialScope{ + Region: "ap-south-2", + }, + }, endpoints.EndpointKey{ Region: "ap-southeast-1", }: endpoints.Endpoint{ @@ -211,6 +219,14 @@ var defaultPartitions = endpoints.Partitions{ Region: "ap-southeast-3", }, }, + endpoints.EndpointKey{ + Region: "ap-southeast-4", + }: endpoints.Endpoint{ + Hostname: "portal.sso.ap-southeast-4.amazonaws.com", + CredentialScope: endpoints.CredentialScope{ + Region: "ap-southeast-4", + }, + }, endpoints.EndpointKey{ Region: "ca-central-1", }: endpoints.Endpoint{ @@ -219,6 +235,14 @@ var defaultPartitions = endpoints.Partitions{ Region: "ca-central-1", }, }, + endpoints.EndpointKey{ + Region: "ca-west-1", + }: endpoints.Endpoint{ + Hostname: "portal.sso.ca-west-1.amazonaws.com", + CredentialScope: endpoints.CredentialScope{ + Region: "ca-west-1", + }, + }, endpoints.EndpointKey{ Region: "eu-central-1", }: endpoints.Endpoint{ @@ -251,6 +275,14 @@ var defaultPartitions = endpoints.Partitions{ Region: "eu-south-1", }, }, + endpoints.EndpointKey{ + Region: "eu-south-2", + }: endpoints.Endpoint{ + Hostname: "portal.sso.eu-south-2.amazonaws.com", + CredentialScope: endpoints.CredentialScope{ + Region: "eu-south-2", + }, + }, endpoints.EndpointKey{ Region: "eu-west-1", }: endpoints.Endpoint{ diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/options.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/options.go index 5dee7e5..aa744f1 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/options.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/options.go @@ -9,7 +9,9 @@ import ( internalauthsmithy "github.com/aws/aws-sdk-go-v2/internal/auth/smithy" smithyauth "github.com/aws/smithy-go/auth" "github.com/aws/smithy-go/logging" + "github.com/aws/smithy-go/metrics" "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" "net/http" ) @@ -50,8 +52,10 @@ type Options struct { // Deprecated: Deprecated: EndpointResolver and WithEndpointResolver. Providing a // value for this field will likely prevent you from using any endpoint-related // service features released after the introduction of EndpointResolverV2 and - // BaseEndpoint. To migrate an EndpointResolver implementation that uses a custom - // endpoint, set the client option BaseEndpoint instead. + // BaseEndpoint. + // + // To migrate an EndpointResolver implementation that uses a custom endpoint, set + // the client option BaseEndpoint instead. EndpointResolver EndpointResolver // Resolves the endpoint used for a particular service operation. This should be @@ -64,23 +68,29 @@ type Options struct { // The logger writer interface to write logging messages to. Logger logging.Logger + // The client meter provider. + MeterProvider metrics.MeterProvider + // The region to send requests to. (Required) Region string // RetryMaxAttempts specifies the maximum number attempts an API client will call // an operation that fails with a retryable error. A value of 0 is ignored, and // will not be used to configure the API client created default retryer, or modify - // per operation call's retry max attempts. If specified in an operation call's - // functional options with a value that is different than the constructed client's - // Options, the Client's Retryer will be wrapped to use the operation's specific - // RetryMaxAttempts value. + // per operation call's retry max attempts. + // + // If specified in an operation call's functional options with a value that is + // different than the constructed client's Options, the Client's Retryer will be + // wrapped to use the operation's specific RetryMaxAttempts value. RetryMaxAttempts int // RetryMode specifies the retry mode the API client will be created with, if - // Retryer option is not also specified. When creating a new API Clients this - // member will only be used if the Retryer Options member is nil. This value will - // be ignored if Retryer is not nil. Currently does not support per operation call - // overrides, may in the future. + // Retryer option is not also specified. + // + // When creating a new API Clients this member will only be used if the Retryer + // Options member is nil. This value will be ignored if Retryer is not nil. + // + // Currently does not support per operation call overrides, may in the future. RetryMode aws.RetryMode // Retryer guides how HTTP requests should be retried in case of recoverable @@ -95,10 +105,14 @@ type Options struct { // within your applications. RuntimeEnvironment aws.RuntimeEnvironment + // The client tracer provider. + TracerProvider tracing.TracerProvider + // The initial DefaultsMode used when the client options were constructed. If the // DefaultsMode was set to aws.DefaultsModeAuto this will store what the resolved - // value was at that point in time. Currently does not support per operation call - // overrides, may in the future. + // value was at that point in time. + // + // Currently does not support per operation call overrides, may in the future. resolvedDefaultsMode aws.DefaultsMode // The HTTP client to invoke API calls with. Defaults to client's default HTTP @@ -143,6 +157,7 @@ func WithAPIOptions(optFns ...func(*middleware.Stack) error) func(*Options) { // Deprecated: EndpointResolver and WithEndpointResolver. Providing a value for // this field will likely prevent you from using any endpoint-related service // features released after the introduction of EndpointResolverV2 and BaseEndpoint. +// // To migrate an EndpointResolver implementation that uses a custom endpoint, set // the client option BaseEndpoint instead. func WithEndpointResolver(v EndpointResolver) func(*Options) { diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/serializers.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/serializers.go index 02e3141..a7a5b57 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/serializers.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/serializers.go @@ -8,6 +8,7 @@ import ( smithy "github.com/aws/smithy-go" "github.com/aws/smithy-go/encoding/httpbinding" "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" ) @@ -21,6 +22,10 @@ func (*awsRestjson1_serializeOpGetRoleCredentials) ID() string { func (m *awsRestjson1_serializeOpGetRoleCredentials) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( out middleware.SerializeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "OperationSerializer") + endTimer := startMetricTimer(ctx, "client.call.serialization_duration") + defer endTimer() + defer span.End() request, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} @@ -57,6 +62,8 @@ func (m *awsRestjson1_serializeOpGetRoleCredentials) HandleSerialize(ctx context } in.Request = request + endTimer() + span.End() return next.HandleSerialize(ctx, in) } func awsRestjson1_serializeOpHttpBindingsGetRoleCredentialsInput(v *GetRoleCredentialsInput, encoder *httpbinding.Encoder) error { @@ -64,7 +71,7 @@ func awsRestjson1_serializeOpHttpBindingsGetRoleCredentialsInput(v *GetRoleCrede return fmt.Errorf("unsupported serialization of nil %T", v) } - if v.AccessToken != nil && len(*v.AccessToken) > 0 { + if v.AccessToken != nil { locationName := "X-Amz-Sso_bearer_token" encoder.SetHeader(locationName).String(*v.AccessToken) } @@ -90,6 +97,10 @@ func (*awsRestjson1_serializeOpListAccountRoles) ID() string { func (m *awsRestjson1_serializeOpListAccountRoles) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( out middleware.SerializeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "OperationSerializer") + endTimer := startMetricTimer(ctx, "client.call.serialization_duration") + defer endTimer() + defer span.End() request, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} @@ -126,6 +137,8 @@ func (m *awsRestjson1_serializeOpListAccountRoles) HandleSerialize(ctx context.C } in.Request = request + endTimer() + span.End() return next.HandleSerialize(ctx, in) } func awsRestjson1_serializeOpHttpBindingsListAccountRolesInput(v *ListAccountRolesInput, encoder *httpbinding.Encoder) error { @@ -133,7 +146,7 @@ func awsRestjson1_serializeOpHttpBindingsListAccountRolesInput(v *ListAccountRol return fmt.Errorf("unsupported serialization of nil %T", v) } - if v.AccessToken != nil && len(*v.AccessToken) > 0 { + if v.AccessToken != nil { locationName := "X-Amz-Sso_bearer_token" encoder.SetHeader(locationName).String(*v.AccessToken) } @@ -163,6 +176,10 @@ func (*awsRestjson1_serializeOpListAccounts) ID() string { func (m *awsRestjson1_serializeOpListAccounts) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( out middleware.SerializeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "OperationSerializer") + endTimer := startMetricTimer(ctx, "client.call.serialization_duration") + defer endTimer() + defer span.End() request, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} @@ -199,6 +216,8 @@ func (m *awsRestjson1_serializeOpListAccounts) HandleSerialize(ctx context.Conte } in.Request = request + endTimer() + span.End() return next.HandleSerialize(ctx, in) } func awsRestjson1_serializeOpHttpBindingsListAccountsInput(v *ListAccountsInput, encoder *httpbinding.Encoder) error { @@ -206,7 +225,7 @@ func awsRestjson1_serializeOpHttpBindingsListAccountsInput(v *ListAccountsInput, return fmt.Errorf("unsupported serialization of nil %T", v) } - if v.AccessToken != nil && len(*v.AccessToken) > 0 { + if v.AccessToken != nil { locationName := "X-Amz-Sso_bearer_token" encoder.SetHeader(locationName).String(*v.AccessToken) } @@ -232,6 +251,10 @@ func (*awsRestjson1_serializeOpLogout) ID() string { func (m *awsRestjson1_serializeOpLogout) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( out middleware.SerializeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "OperationSerializer") + endTimer := startMetricTimer(ctx, "client.call.serialization_duration") + defer endTimer() + defer span.End() request, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} @@ -268,6 +291,8 @@ func (m *awsRestjson1_serializeOpLogout) HandleSerialize(ctx context.Context, in } in.Request = request + endTimer() + span.End() return next.HandleSerialize(ctx, in) } func awsRestjson1_serializeOpHttpBindingsLogoutInput(v *LogoutInput, encoder *httpbinding.Encoder) error { @@ -275,7 +300,7 @@ func awsRestjson1_serializeOpHttpBindingsLogoutInput(v *LogoutInput, encoder *ht return fmt.Errorf("unsupported serialization of nil %T", v) } - if v.AccessToken != nil && len(*v.AccessToken) > 0 { + if v.AccessToken != nil { locationName := "X-Amz-Sso_bearer_token" encoder.SetHeader(locationName).String(*v.AccessToken) } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/types/types.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/types/types.go index 8dc0229..07ac468 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sso/types/types.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sso/types/types.go @@ -25,22 +25,24 @@ type AccountInfo struct { type RoleCredentials struct { // The identifier used for the temporary security credentials. For more - // information, see Using Temporary Security Credentials to Request Access to AWS - // Resources (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html) - // in the AWS IAM User Guide. + // information, see [Using Temporary Security Credentials to Request Access to AWS Resources]in the AWS IAM User Guide. + // + // [Using Temporary Security Credentials to Request Access to AWS Resources]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html AccessKeyId *string // The date on which temporary security credentials expire. Expiration int64 - // The key that is used to sign the request. For more information, see Using - // Temporary Security Credentials to Request Access to AWS Resources (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html) - // in the AWS IAM User Guide. + // The key that is used to sign the request. For more information, see [Using Temporary Security Credentials to Request Access to AWS Resources] in the AWS + // IAM User Guide. + // + // [Using Temporary Security Credentials to Request Access to AWS Resources]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html SecretAccessKey *string - // The token used for temporary credentials. For more information, see Using - // Temporary Security Credentials to Request Access to AWS Resources (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html) - // in the AWS IAM User Guide. + // The token used for temporary credentials. For more information, see [Using Temporary Security Credentials to Request Access to AWS Resources] in the AWS + // IAM User Guide. + // + // [Using Temporary Security Credentials to Request Access to AWS Resources]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html SessionToken *string noSmithyDocumentSerde diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/CHANGELOG.md index f77c478..29bce60 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/CHANGELOG.md @@ -1,3 +1,198 @@ +# v1.28.13 (2025-01-31) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.12 (2025-01-30) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.11 (2025-01-24) + +* **Documentation**: Fixed typos in the descriptions. +* **Dependency Update**: Updated to the latest SDK module versions +* **Dependency Update**: Upgrade to smithy-go v1.22.2. + +# v1.28.10 (2025-01-17) + +* **Bug Fix**: Fix bug where credentials weren't refreshed during retry loop. + +# v1.28.9 (2025-01-15) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.8 (2025-01-09) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.7 (2024-12-19) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.6 (2024-12-02) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.5 (2024-11-18) + +* **Dependency Update**: Update to smithy-go v1.22.1. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.4 (2024-11-06) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.3 (2024-10-28) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.2 (2024-10-08) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.1 (2024-10-07) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.0 (2024-10-04) + +* **Feature**: Add support for HTTP client metrics. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.4 (2024-10-03) + +* No change notes available for this release. + +# v1.27.3 (2024-09-27) + +* No change notes available for this release. + +# v1.27.2 (2024-09-25) + +* No change notes available for this release. + +# v1.27.1 (2024-09-23) + +* No change notes available for this release. + +# v1.27.0 (2024-09-20) + +* **Feature**: Add tracing and metrics support to service clients. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.26.8 (2024-09-17) + +* **Bug Fix**: **BREAKFIX**: Only generate AccountIDEndpointMode config for services that use it. This is a compiler break, but removes no actual functionality, as no services currently use the account ID in endpoint resolution. + +# v1.26.7 (2024-09-04) + +* No change notes available for this release. + +# v1.26.6 (2024-09-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.26.5 (2024-08-15) + +* **Dependency Update**: Bump minimum Go version to 1.21. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.26.4 (2024-07-10.2) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.26.3 (2024-07-10) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.26.2 (2024-07-03) + +* No change notes available for this release. + +# v1.26.1 (2024-06-28) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.26.0 (2024-06-26) + +* **Feature**: Support list-of-string endpoint parameter. + +# v1.25.1 (2024-06-19) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.25.0 (2024-06-18) + +* **Feature**: Track usage of various AWS SDK features in user-agent string. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.24.6 (2024-06-17) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.24.5 (2024-06-07) + +* **Bug Fix**: Add clock skew correction on all service clients +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.24.4 (2024-06-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.24.3 (2024-05-23) + +* No change notes available for this release. + +# v1.24.2 (2024-05-16) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.24.1 (2024-05-15) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.24.0 (2024-05-10) + +* **Feature**: Updated request parameters for PKCE support. + +# v1.23.5 (2024-05-08) + +* **Bug Fix**: GoDoc improvement + +# v1.23.4 (2024-03-29) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.23.3 (2024-03-18) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.23.2 (2024-03-07) + +* **Bug Fix**: Remove dependency on go-cmp. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.23.1 (2024-02-23) + +* **Bug Fix**: Move all common, SDK-side middleware stack ops into the service client module to prevent cross-module compatibility issues in the future. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.23.0 (2024-02-22) + +* **Feature**: Add middleware stack snapshot tests. + +# v1.22.2 (2024-02-21) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.22.1 (2024-02-20) + +* **Bug Fix**: When sourcing values for a service's `EndpointParameters`, the lack of a configured region (i.e. `options.Region == ""`) will now translate to a `nil` value for `EndpointParameters.Region` instead of a pointer to the empty string `""`. This will result in a much more explicit error when calling an operation instead of an obscure hostname lookup failure. + +# v1.22.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. +* **Dependency Update**: Updated to the latest SDK module versions + # v1.21.7 (2024-01-16) * No change notes available for this release. diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_client.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_client.go index fed0897..9b7f4ac 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_client.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_client.go @@ -4,6 +4,7 @@ package ssooidc import ( "context" + "errors" "fmt" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/defaults" @@ -14,22 +15,157 @@ import ( internalauth "github.com/aws/aws-sdk-go-v2/internal/auth" internalauthsmithy "github.com/aws/aws-sdk-go-v2/internal/auth/smithy" internalConfig "github.com/aws/aws-sdk-go-v2/internal/configsources" + internalmiddleware "github.com/aws/aws-sdk-go-v2/internal/middleware" smithy "github.com/aws/smithy-go" + smithyauth "github.com/aws/smithy-go/auth" smithydocument "github.com/aws/smithy-go/document" "github.com/aws/smithy-go/logging" + "github.com/aws/smithy-go/metrics" "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" "net" "net/http" + "sync/atomic" "time" ) const ServiceID = "SSO OIDC" const ServiceAPIVersion = "2019-06-10" +type operationMetrics struct { + Duration metrics.Float64Histogram + SerializeDuration metrics.Float64Histogram + ResolveIdentityDuration metrics.Float64Histogram + ResolveEndpointDuration metrics.Float64Histogram + SignRequestDuration metrics.Float64Histogram + DeserializeDuration metrics.Float64Histogram +} + +func (m *operationMetrics) histogramFor(name string) metrics.Float64Histogram { + switch name { + case "client.call.duration": + return m.Duration + case "client.call.serialization_duration": + return m.SerializeDuration + case "client.call.resolve_identity_duration": + return m.ResolveIdentityDuration + case "client.call.resolve_endpoint_duration": + return m.ResolveEndpointDuration + case "client.call.signing_duration": + return m.SignRequestDuration + case "client.call.deserialization_duration": + return m.DeserializeDuration + default: + panic("unrecognized operation metric") + } +} + +func timeOperationMetric[T any]( + ctx context.Context, metric string, fn func() (T, error), + opts ...metrics.RecordMetricOption, +) (T, error) { + instr := getOperationMetrics(ctx).histogramFor(metric) + opts = append([]metrics.RecordMetricOption{withOperationMetadata(ctx)}, opts...) + + start := time.Now() + v, err := fn() + end := time.Now() + + elapsed := end.Sub(start) + instr.Record(ctx, float64(elapsed)/1e9, opts...) + return v, err +} + +func startMetricTimer(ctx context.Context, metric string, opts ...metrics.RecordMetricOption) func() { + instr := getOperationMetrics(ctx).histogramFor(metric) + opts = append([]metrics.RecordMetricOption{withOperationMetadata(ctx)}, opts...) + + var ended bool + start := time.Now() + return func() { + if ended { + return + } + ended = true + + end := time.Now() + + elapsed := end.Sub(start) + instr.Record(ctx, float64(elapsed)/1e9, opts...) + } +} + +func withOperationMetadata(ctx context.Context) metrics.RecordMetricOption { + return func(o *metrics.RecordMetricOptions) { + o.Properties.Set("rpc.service", middleware.GetServiceID(ctx)) + o.Properties.Set("rpc.method", middleware.GetOperationName(ctx)) + } +} + +type operationMetricsKey struct{} + +func withOperationMetrics(parent context.Context, mp metrics.MeterProvider) (context.Context, error) { + meter := mp.Meter("github.com/aws/aws-sdk-go-v2/service/ssooidc") + om := &operationMetrics{} + + var err error + + om.Duration, err = operationMetricTimer(meter, "client.call.duration", + "Overall call duration (including retries and time to send or receive request and response body)") + if err != nil { + return nil, err + } + om.SerializeDuration, err = operationMetricTimer(meter, "client.call.serialization_duration", + "The time it takes to serialize a message body") + if err != nil { + return nil, err + } + om.ResolveIdentityDuration, err = operationMetricTimer(meter, "client.call.auth.resolve_identity_duration", + "The time taken to acquire an identity (AWS credentials, bearer token, etc) from an Identity Provider") + if err != nil { + return nil, err + } + om.ResolveEndpointDuration, err = operationMetricTimer(meter, "client.call.resolve_endpoint_duration", + "The time it takes to resolve an endpoint (endpoint resolver, not DNS) for the request") + if err != nil { + return nil, err + } + om.SignRequestDuration, err = operationMetricTimer(meter, "client.call.auth.signing_duration", + "The time it takes to sign a request") + if err != nil { + return nil, err + } + om.DeserializeDuration, err = operationMetricTimer(meter, "client.call.deserialization_duration", + "The time it takes to deserialize a message body") + if err != nil { + return nil, err + } + + return context.WithValue(parent, operationMetricsKey{}, om), nil +} + +func operationMetricTimer(m metrics.Meter, name, desc string) (metrics.Float64Histogram, error) { + return m.Float64Histogram(name, func(o *metrics.InstrumentOptions) { + o.UnitLabel = "s" + o.Description = desc + }) +} + +func getOperationMetrics(ctx context.Context) *operationMetrics { + return ctx.Value(operationMetricsKey{}).(*operationMetrics) +} + +func operationTracer(p tracing.TracerProvider) tracing.Tracer { + return p.Tracer("github.com/aws/aws-sdk-go-v2/service/ssooidc") +} + // Client provides the API client to make operations call for AWS SSO OIDC. type Client struct { options Options + + // Difference between the time reported by the server and the client + timeOffset *atomic.Int64 } // New returns an initialized Client based on the functional options. Provide @@ -50,6 +186,10 @@ func New(options Options, optFns ...func(*Options)) *Client { resolveEndpointResolverV2(&options) + resolveTracerProvider(&options) + + resolveMeterProvider(&options) + resolveAuthSchemeResolver(&options) for _, fn := range optFns { @@ -68,6 +208,8 @@ func New(options Options, optFns ...func(*Options)) *Client { options: options, } + initializeTimeOffsetResolver(client) + return client } @@ -80,8 +222,15 @@ func (c *Client) Options() Options { return c.options.Copy() } -func (c *Client) invokeOperation(ctx context.Context, opID string, params interface{}, optFns []func(*Options), stackFns ...func(*middleware.Stack, Options) error) (result interface{}, metadata middleware.Metadata, err error) { +func (c *Client) invokeOperation( + ctx context.Context, opID string, params interface{}, optFns []func(*Options), stackFns ...func(*middleware.Stack, Options) error, +) ( + result interface{}, metadata middleware.Metadata, err error, +) { ctx = middleware.ClearStackValues(ctx) + ctx = middleware.WithServiceID(ctx, ServiceID) + ctx = middleware.WithOperationName(ctx, opID) + stack := middleware.NewStack(opID, smithyhttp.NewStackRequest) options := c.options.Copy() @@ -105,15 +254,56 @@ func (c *Client) invokeOperation(ctx context.Context, opID string, params interf } } - handler := middleware.DecorateHandler(smithyhttp.NewClientHandler(options.HTTPClient), stack) - result, metadata, err = handler.Handle(ctx, params) + ctx, err = withOperationMetrics(ctx, options.MeterProvider) if err != nil { + return nil, metadata, err + } + + tracer := operationTracer(options.TracerProvider) + spanName := fmt.Sprintf("%s.%s", ServiceID, opID) + + ctx = tracing.WithOperationTracer(ctx, tracer) + + ctx, span := tracer.StartSpan(ctx, spanName, func(o *tracing.SpanOptions) { + o.Kind = tracing.SpanKindClient + o.Properties.Set("rpc.system", "aws-api") + o.Properties.Set("rpc.method", opID) + o.Properties.Set("rpc.service", ServiceID) + }) + endTimer := startMetricTimer(ctx, "client.call.duration") + defer endTimer() + defer span.End() + + handler := smithyhttp.NewClientHandlerWithOptions(options.HTTPClient, func(o *smithyhttp.ClientHandler) { + o.Meter = options.MeterProvider.Meter("github.com/aws/aws-sdk-go-v2/service/ssooidc") + }) + decorated := middleware.DecorateHandler(handler, stack) + result, metadata, err = decorated.Handle(ctx, params) + if err != nil { + span.SetProperty("exception.type", fmt.Sprintf("%T", err)) + span.SetProperty("exception.message", err.Error()) + + var aerr smithy.APIError + if errors.As(err, &aerr) { + span.SetProperty("api.error_code", aerr.ErrorCode()) + span.SetProperty("api.error_message", aerr.ErrorMessage()) + span.SetProperty("api.error_fault", aerr.ErrorFault().String()) + } + err = &smithy.OperationError{ ServiceID: ServiceID, OperationName: opID, Err: err, } } + + span.SetProperty("error", err != nil) + if err == nil { + span.SetStatus(tracing.SpanStatusOK) + } else { + span.SetStatus(tracing.SpanStatusError) + } + return result, metadata, err } @@ -151,7 +341,7 @@ func addProtocolFinalizerMiddlewares(stack *middleware.Stack, options Options, o if err := stack.Finalize.Insert(&resolveEndpointV2Middleware{options: options}, "GetIdentity", middleware.After); err != nil { return fmt.Errorf("add ResolveEndpointV2: %v", err) } - if err := stack.Finalize.Insert(&signRequestMiddleware{}, "ResolveEndpointV2", middleware.After); err != nil { + if err := stack.Finalize.Insert(&signRequestMiddleware{options: options}, "ResolveEndpointV2", middleware.After); err != nil { return fmt.Errorf("add Signing: %w", err) } return nil @@ -361,17 +551,37 @@ func resolveAWSEndpointResolver(cfg aws.Config, o *Options) { } func addClientUserAgent(stack *middleware.Stack, options Options) error { - if err := awsmiddleware.AddSDKAgentKeyValue(awsmiddleware.APIMetadata, "ssooidc", goModuleVersion)(stack); err != nil { + ua, err := getOrAddRequestUserAgent(stack) + if err != nil { return err } + ua.AddSDKAgentKeyValue(awsmiddleware.APIMetadata, "ssooidc", goModuleVersion) if len(options.AppID) > 0 { - return awsmiddleware.AddSDKAgentKey(awsmiddleware.ApplicationIdentifier, options.AppID)(stack) + ua.AddSDKAgentKey(awsmiddleware.ApplicationIdentifier, options.AppID) } return nil } +func getOrAddRequestUserAgent(stack *middleware.Stack) (*awsmiddleware.RequestUserAgent, error) { + id := (*awsmiddleware.RequestUserAgent)(nil).ID() + mw, ok := stack.Build.Get(id) + if !ok { + mw = awsmiddleware.NewRequestUserAgent() + if err := stack.Build.Add(mw, middleware.After); err != nil { + return nil, err + } + } + + ua, ok := mw.(*awsmiddleware.RequestUserAgent) + if !ok { + return nil, fmt.Errorf("%T for %s middleware did not match expected type", mw, id) + } + + return ua, nil +} + type HTTPSignerV4 interface { SignHTTP(ctx context.Context, credentials aws.Credentials, r *http.Request, payloadHash string, service string, region string, signingTime time.Time, optFns ...func(*v4.SignerOptions)) error } @@ -390,12 +600,97 @@ func newDefaultV4Signer(o Options) *v4.Signer { }) } -func addRetryMiddlewares(stack *middleware.Stack, o Options) error { - mo := retry.AddRetryMiddlewaresOptions{ - Retryer: o.Retryer, - LogRetryAttempts: o.ClientLogMode.IsRetries(), +func addClientRequestID(stack *middleware.Stack) error { + return stack.Build.Add(&awsmiddleware.ClientRequestID{}, middleware.After) +} + +func addComputeContentLength(stack *middleware.Stack) error { + return stack.Build.Add(&smithyhttp.ComputeContentLength{}, middleware.After) +} + +func addRawResponseToMetadata(stack *middleware.Stack) error { + return stack.Deserialize.Add(&awsmiddleware.AddRawResponse{}, middleware.Before) +} + +func addRecordResponseTiming(stack *middleware.Stack) error { + return stack.Deserialize.Add(&awsmiddleware.RecordResponseTiming{}, middleware.After) +} + +func addSpanRetryLoop(stack *middleware.Stack, options Options) error { + return stack.Finalize.Insert(&spanRetryLoop{options: options}, "Retry", middleware.Before) +} + +type spanRetryLoop struct { + options Options +} + +func (*spanRetryLoop) ID() string { + return "spanRetryLoop" +} + +func (m *spanRetryLoop) HandleFinalize( + ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler, +) ( + middleware.FinalizeOutput, middleware.Metadata, error, +) { + tracer := operationTracer(m.options.TracerProvider) + ctx, span := tracer.StartSpan(ctx, "RetryLoop") + defer span.End() + + return next.HandleFinalize(ctx, in) +} +func addStreamingEventsPayload(stack *middleware.Stack) error { + return stack.Finalize.Add(&v4.StreamingEventsPayload{}, middleware.Before) +} + +func addUnsignedPayload(stack *middleware.Stack) error { + return stack.Finalize.Insert(&v4.UnsignedPayload{}, "ResolveEndpointV2", middleware.After) +} + +func addComputePayloadSHA256(stack *middleware.Stack) error { + return stack.Finalize.Insert(&v4.ComputePayloadSHA256{}, "ResolveEndpointV2", middleware.After) +} + +func addContentSHA256Header(stack *middleware.Stack) error { + return stack.Finalize.Insert(&v4.ContentSHA256Header{}, (*v4.ComputePayloadSHA256)(nil).ID(), middleware.After) +} + +func addIsWaiterUserAgent(o *Options) { + o.APIOptions = append(o.APIOptions, func(stack *middleware.Stack) error { + ua, err := getOrAddRequestUserAgent(stack) + if err != nil { + return err + } + + ua.AddUserAgentFeature(awsmiddleware.UserAgentFeatureWaiter) + return nil + }) +} + +func addIsPaginatorUserAgent(o *Options) { + o.APIOptions = append(o.APIOptions, func(stack *middleware.Stack) error { + ua, err := getOrAddRequestUserAgent(stack) + if err != nil { + return err + } + + ua.AddUserAgentFeature(awsmiddleware.UserAgentFeaturePaginator) + return nil + }) +} + +func addRetry(stack *middleware.Stack, o Options) error { + attempt := retry.NewAttemptMiddleware(o.Retryer, smithyhttp.RequestCloner, func(m *retry.Attempt) { + m.LogAttempts = o.ClientLogMode.IsRetries() + m.OperationMeter = o.MeterProvider.Meter("github.com/aws/aws-sdk-go-v2/service/ssooidc") + }) + if err := stack.Finalize.Insert(attempt, "ResolveAuthScheme", middleware.Before); err != nil { + return err } - return retry.AddRetryMiddlewares(stack, mo) + if err := stack.Finalize.Insert(&retry.MetricsHeader{}, attempt.ID(), middleware.After); err != nil { + return err + } + return nil } // resolves dual-stack endpoint configuration @@ -428,12 +723,68 @@ func resolveUseFIPSEndpoint(cfg aws.Config, o *Options) error { return nil } +func resolveAccountID(identity smithyauth.Identity, mode aws.AccountIDEndpointMode) *string { + if mode == aws.AccountIDEndpointModeDisabled { + return nil + } + + if ca, ok := identity.(*internalauthsmithy.CredentialsAdapter); ok && ca.Credentials.AccountID != "" { + return aws.String(ca.Credentials.AccountID) + } + + return nil +} + +func addTimeOffsetBuild(stack *middleware.Stack, c *Client) error { + mw := internalmiddleware.AddTimeOffsetMiddleware{Offset: c.timeOffset} + if err := stack.Build.Add(&mw, middleware.After); err != nil { + return err + } + return stack.Deserialize.Insert(&mw, "RecordResponseTiming", middleware.Before) +} +func initializeTimeOffsetResolver(c *Client) { + c.timeOffset = new(atomic.Int64) +} + +func addUserAgentRetryMode(stack *middleware.Stack, options Options) error { + ua, err := getOrAddRequestUserAgent(stack) + if err != nil { + return err + } + + switch options.Retryer.(type) { + case *retry.Standard: + ua.AddUserAgentFeature(awsmiddleware.UserAgentFeatureRetryModeStandard) + case *retry.AdaptiveMode: + ua.AddUserAgentFeature(awsmiddleware.UserAgentFeatureRetryModeAdaptive) + } + return nil +} + +func resolveTracerProvider(options *Options) { + if options.TracerProvider == nil { + options.TracerProvider = &tracing.NopTracerProvider{} + } +} + +func resolveMeterProvider(options *Options) { + if options.MeterProvider == nil { + options.MeterProvider = metrics.NopMeterProvider{} + } +} + +func addRecursionDetection(stack *middleware.Stack) error { + return stack.Build.Add(&awsmiddleware.RecursionDetection{}, middleware.After) +} + func addRequestIDRetrieverMiddleware(stack *middleware.Stack) error { - return awsmiddleware.AddRequestIDRetrieverMiddleware(stack) + return stack.Deserialize.Insert(&awsmiddleware.RequestIDRetriever{}, "OperationDeserializer", middleware.Before) + } func addResponseErrorMiddleware(stack *middleware.Stack) error { - return awshttp.AddResponseErrorMiddleware(stack) + return stack.Deserialize.Insert(&awshttp.ResponseErrorWrapper{}, "RequestIDRetriever", middleware.Before) + } func addRequestResponseLogging(stack *middleware.Stack, o Options) error { @@ -473,3 +824,89 @@ func addDisableHTTPSMiddleware(stack *middleware.Stack, o Options) error { DisableHTTPS: o.EndpointOptions.DisableHTTPS, }, "ResolveEndpointV2", middleware.After) } + +type spanInitializeStart struct { +} + +func (*spanInitializeStart) ID() string { + return "spanInitializeStart" +} + +func (m *spanInitializeStart) HandleInitialize( + ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler, +) ( + middleware.InitializeOutput, middleware.Metadata, error, +) { + ctx, _ = tracing.StartSpan(ctx, "Initialize") + + return next.HandleInitialize(ctx, in) +} + +type spanInitializeEnd struct { +} + +func (*spanInitializeEnd) ID() string { + return "spanInitializeEnd" +} + +func (m *spanInitializeEnd) HandleInitialize( + ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler, +) ( + middleware.InitializeOutput, middleware.Metadata, error, +) { + ctx, span := tracing.PopSpan(ctx) + span.End() + + return next.HandleInitialize(ctx, in) +} + +type spanBuildRequestStart struct { +} + +func (*spanBuildRequestStart) ID() string { + return "spanBuildRequestStart" +} + +func (m *spanBuildRequestStart) HandleSerialize( + ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler, +) ( + middleware.SerializeOutput, middleware.Metadata, error, +) { + ctx, _ = tracing.StartSpan(ctx, "BuildRequest") + + return next.HandleSerialize(ctx, in) +} + +type spanBuildRequestEnd struct { +} + +func (*spanBuildRequestEnd) ID() string { + return "spanBuildRequestEnd" +} + +func (m *spanBuildRequestEnd) HandleBuild( + ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler, +) ( + middleware.BuildOutput, middleware.Metadata, error, +) { + ctx, span := tracing.PopSpan(ctx) + span.End() + + return next.HandleBuild(ctx, in) +} + +func addSpanInitializeStart(stack *middleware.Stack) error { + return stack.Initialize.Add(&spanInitializeStart{}, middleware.Before) +} + +func addSpanInitializeEnd(stack *middleware.Stack) error { + return stack.Initialize.Add(&spanInitializeEnd{}, middleware.After) +} + +func addSpanBuildRequestStart(stack *middleware.Stack) error { + return stack.Serialize.Add(&spanBuildRequestStart{}, middleware.Before) +} + +func addSpanBuildRequestEnd(stack *middleware.Stack) error { + return stack.Build.Add(&spanBuildRequestEnd{}, middleware.After) +} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_CreateToken.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_CreateToken.go index 4246429..2ab3524 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_CreateToken.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_CreateToken.go @@ -12,7 +12,7 @@ import ( // Creates and returns access and refresh tokens for clients that are // authenticated using client secrets. The access token can be used to fetch -// short-term credentials for the assigned AWS accounts or to access application +// short-lived credentials for the assigned AWS accounts or to access application // APIs using bearer authentication. func (c *Client) CreateToken(ctx context.Context, params *CreateTokenInput, optFns ...func(*Options)) (*CreateTokenOutput, error) { if params == nil { @@ -32,34 +32,42 @@ func (c *Client) CreateToken(ctx context.Context, params *CreateTokenInput, optF type CreateTokenInput struct { // The unique identifier string for the client or application. This value comes - // from the result of the RegisterClient API. + // from the result of the RegisterClientAPI. // // This member is required. ClientId *string // A secret string generated for the client. This value should come from the - // persisted result of the RegisterClient API. + // persisted result of the RegisterClientAPI. // // This member is required. ClientSecret *string - // Supports the following OAuth grant types: Device Code and Refresh Token. - // Specify either of the following values, depending on the grant type that you - // want: * Device Code - urn:ietf:params:oauth:grant-type:device_code * Refresh - // Token - refresh_token For information about how to obtain the device code, see - // the StartDeviceAuthorization topic. + // Supports the following OAuth grant types: Authorization Code, Device Code, and + // Refresh Token. Specify one of the following values, depending on the grant type + // that you want: + // + // * Authorization Code - authorization_code + // + // * Device Code - urn:ietf:params:oauth:grant-type:device_code + // + // * Refresh Token - refresh_token // // This member is required. GrantType *string // Used only when calling this API for the Authorization Code grant type. The - // short-term code is used to identify this authorization request. This grant type - // is currently unsupported for the CreateToken API. + // short-lived code is used to identify this authorization request. Code *string - // Used only when calling this API for the Device Code grant type. This short-term - // code is used to identify this authorization request. This comes from the result - // of the StartDeviceAuthorization API. + // Used only when calling this API for the Authorization Code grant type. This + // value is generated by the client and presented to validate the original code + // challenge value the client passed at authorization time. + CodeVerifier *string + + // Used only when calling this API for the Device Code grant type. This + // short-lived code is used to identify this authorization request. This comes from + // the result of the StartDeviceAuthorizationAPI. DeviceCode *string // Used only when calling this API for the Authorization Code grant type. This @@ -68,17 +76,19 @@ type CreateTokenInput struct { RedirectUri *string // Used only when calling this API for the Refresh Token grant type. This token is - // used to refresh short-term tokens, such as the access token, that might expire. + // used to refresh short-lived tokens, such as the access token, that might expire. + // // For more information about the features and limitations of the current IAM // Identity Center OIDC implementation, see Considerations for Using this Guide in - // the IAM Identity Center OIDC API Reference (https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/Welcome.html) - // . + // the [IAM Identity Center OIDC API Reference]. + // + // [IAM Identity Center OIDC API Reference]: https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/Welcome.html RefreshToken *string // The list of scopes for which authorization is requested. The access token that // is issued is limited to the scopes that are granted. If this value is not // specified, IAM Identity Center authorizes all scopes that are configured for the - // client during the call to RegisterClient . + // client during the call to RegisterClient. Scope []string noSmithyDocumentSerde @@ -86,7 +96,8 @@ type CreateTokenInput struct { type CreateTokenOutput struct { - // A bearer token to access AWS accounts and applications assigned to a user. + // A bearer token to access Amazon Web Services accounts and applications assigned + // to a user. AccessToken *string // Indicates the time in seconds when an access token will expire. @@ -94,18 +105,22 @@ type CreateTokenOutput struct { // The idToken is not implemented or supported. For more information about the // features and limitations of the current IAM Identity Center OIDC implementation, - // see Considerations for Using this Guide in the IAM Identity Center OIDC API - // Reference (https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/Welcome.html) - // . A JSON Web Token (JWT) that identifies who is associated with the issued - // access token. + // see Considerations for Using this Guide in the [IAM Identity Center OIDC API Reference]. + // + // A JSON Web Token (JWT) that identifies who is associated with the issued access + // token. + // + // [IAM Identity Center OIDC API Reference]: https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/Welcome.html IdToken *string // A token that, if present, can be used to refresh a previously issued access - // token that might have expired. For more information about the features and - // limitations of the current IAM Identity Center OIDC implementation, see - // Considerations for Using this Guide in the IAM Identity Center OIDC API - // Reference (https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/Welcome.html) - // . + // token that might have expired. + // + // For more information about the features and limitations of the current IAM + // Identity Center OIDC implementation, see Considerations for Using this Guide in + // the [IAM Identity Center OIDC API Reference]. + // + // [IAM Identity Center OIDC API Reference]: https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/Welcome.html RefreshToken *string // Used to notify the client that the returned token is an access token. The @@ -140,22 +155,25 @@ func (c *Client) addOperationCreateTokenMiddlewares(stack *middleware.Stack, opt if err = addSetLoggerMiddleware(stack, options); err != nil { return err } - if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + if err = addClientRequestID(stack); err != nil { return err } - if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + if err = addComputeContentLength(stack); err != nil { return err } if err = addResolveEndpointMiddleware(stack, options); err != nil { return err } - if err = addRetryMiddlewares(stack, options); err != nil { + if err = addRetry(stack, options); err != nil { return err } - if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + if err = addRawResponseToMetadata(stack); err != nil { return err } - if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + if err = addRecordResponseTiming(stack); err != nil { + return err + } + if err = addSpanRetryLoop(stack, options); err != nil { return err } if err = addClientUserAgent(stack, options); err != nil { @@ -170,13 +188,19 @@ func (c *Client) addOperationCreateTokenMiddlewares(stack *middleware.Stack, opt if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil { return err } + if err = addTimeOffsetBuild(stack, c); err != nil { + return err + } + if err = addUserAgentRetryMode(stack, options); err != nil { + return err + } if err = addOpCreateTokenValidationMiddleware(stack); err != nil { return err } if err = stack.Initialize.Add(newServiceMetadataMiddleware_opCreateToken(options.Region), middleware.Before); err != nil { return err } - if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + if err = addRecursionDetection(stack); err != nil { return err } if err = addRequestIDRetrieverMiddleware(stack); err != nil { @@ -191,6 +215,18 @@ func (c *Client) addOperationCreateTokenMiddlewares(stack *middleware.Stack, opt if err = addDisableHTTPSMiddleware(stack, options); err != nil { return err } + if err = addSpanInitializeStart(stack); err != nil { + return err + } + if err = addSpanInitializeEnd(stack); err != nil { + return err + } + if err = addSpanBuildRequestStart(stack); err != nil { + return err + } + if err = addSpanBuildRequestEnd(stack); err != nil { + return err + } return nil } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_CreateTokenWithIAM.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_CreateTokenWithIAM.go index ed4b98f..e5253ce 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_CreateTokenWithIAM.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_CreateTokenWithIAM.go @@ -6,15 +6,14 @@ import ( "context" "fmt" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" - "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/smithy-go/middleware" smithyhttp "github.com/aws/smithy-go/transport/http" ) // Creates and returns access and refresh tokens for clients and applications that // are authenticated using IAM entities. The access token can be used to fetch -// short-term credentials for the assigned AWS accounts or to access application -// APIs using bearer authentication. +// short-lived credentials for the assigned Amazon Web Services accounts or to +// access application APIs using bearer authentication. func (c *Client) CreateTokenWithIAM(ctx context.Context, params *CreateTokenWithIAMInput, optFns ...func(*Options)) (*CreateTokenWithIAMOutput, error) { if params == nil { params = &CreateTokenWithIAMInput{} @@ -40,10 +39,15 @@ type CreateTokenWithIAMInput struct { // Supports the following OAuth grant types: Authorization Code, Refresh Token, // JWT Bearer, and Token Exchange. Specify one of the following values, depending - // on the grant type that you want: * Authorization Code - authorization_code * - // Refresh Token - refresh_token * JWT Bearer - - // urn:ietf:params:oauth:grant-type:jwt-bearer * Token Exchange - - // urn:ietf:params:oauth:grant-type:token-exchange + // on the grant type that you want: + // + // * Authorization Code - authorization_code + // + // * Refresh Token - refresh_token + // + // * JWT Bearer - urn:ietf:params:oauth:grant-type:jwt-bearer + // + // * Token Exchange - urn:ietf:params:oauth:grant-type:token-exchange // // This member is required. GrantType *string @@ -55,28 +59,38 @@ type CreateTokenWithIAMInput struct { Assertion *string // Used only when calling this API for the Authorization Code grant type. This - // short-term code is used to identify this authorization request. The code is + // short-lived code is used to identify this authorization request. The code is // obtained through a redirect from IAM Identity Center to a redirect URI persisted // in the Authorization Code GrantOptions for the application. Code *string + // Used only when calling this API for the Authorization Code grant type. This + // value is generated by the client and presented to validate the original code + // challenge value the client passed at authorization time. + CodeVerifier *string + // Used only when calling this API for the Authorization Code grant type. This // value specifies the location of the client or application that has registered to // receive the authorization code. RedirectUri *string // Used only when calling this API for the Refresh Token grant type. This token is - // used to refresh short-term tokens, such as the access token, that might expire. + // used to refresh short-lived tokens, such as the access token, that might expire. + // // For more information about the features and limitations of the current IAM // Identity Center OIDC implementation, see Considerations for Using this Guide in - // the IAM Identity Center OIDC API Reference (https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/Welcome.html) - // . + // the [IAM Identity Center OIDC API Reference]. + // + // [IAM Identity Center OIDC API Reference]: https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/Welcome.html RefreshToken *string // Used only when calling this API for the Token Exchange grant type. This value // specifies the type of token that the requester can receive. The following values - // are supported: * Access Token - urn:ietf:params:oauth:token-type:access_token * - // Refresh Token - urn:ietf:params:oauth:token-type:refresh_token + // are supported: + // + // * Access Token - urn:ietf:params:oauth:token-type:access_token + // + // * Refresh Token - urn:ietf:params:oauth:token-type:refresh_token RequestedTokenType *string // The list of scopes for which authorization is requested. The access token that @@ -95,8 +109,9 @@ type CreateTokenWithIAMInput struct { // Used only when calling this API for the Token Exchange grant type. This value // specifies the type of token that is passed as the subject of the exchange. The - // following value is supported: * Access Token - - // urn:ietf:params:oauth:token-type:access_token + // following value is supported: + // + // * Access Token - urn:ietf:params:oauth:token-type:access_token SubjectTokenType *string noSmithyDocumentSerde @@ -104,7 +119,8 @@ type CreateTokenWithIAMInput struct { type CreateTokenWithIAMOutput struct { - // A bearer token to access AWS accounts and applications assigned to a user. + // A bearer token to access Amazon Web Services accounts and applications assigned + // to a user. AccessToken *string // Indicates the time in seconds when an access token will expire. @@ -115,17 +131,21 @@ type CreateTokenWithIAMOutput struct { IdToken *string // Indicates the type of tokens that are issued by IAM Identity Center. The - // following values are supported: * Access Token - - // urn:ietf:params:oauth:token-type:access_token * Refresh Token - - // urn:ietf:params:oauth:token-type:refresh_token + // following values are supported: + // + // * Access Token - urn:ietf:params:oauth:token-type:access_token + // + // * Refresh Token - urn:ietf:params:oauth:token-type:refresh_token IssuedTokenType *string // A token that, if present, can be used to refresh a previously issued access - // token that might have expired. For more information about the features and - // limitations of the current IAM Identity Center OIDC implementation, see - // Considerations for Using this Guide in the IAM Identity Center OIDC API - // Reference (https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/Welcome.html) - // . + // token that might have expired. + // + // For more information about the features and limitations of the current IAM + // Identity Center OIDC implementation, see Considerations for Using this Guide in + // the [IAM Identity Center OIDC API Reference]. + // + // [IAM Identity Center OIDC API Reference]: https://docs.aws.amazon.com/singlesignon/latest/OIDCAPIReference/Welcome.html RefreshToken *string // The list of scopes for which authorization is granted. The access token that is @@ -164,25 +184,28 @@ func (c *Client) addOperationCreateTokenWithIAMMiddlewares(stack *middleware.Sta if err = addSetLoggerMiddleware(stack, options); err != nil { return err } - if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + if err = addClientRequestID(stack); err != nil { return err } - if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + if err = addComputeContentLength(stack); err != nil { return err } if err = addResolveEndpointMiddleware(stack, options); err != nil { return err } - if err = v4.AddComputePayloadSHA256Middleware(stack); err != nil { + if err = addComputePayloadSHA256(stack); err != nil { return err } - if err = addRetryMiddlewares(stack, options); err != nil { + if err = addRetry(stack, options); err != nil { return err } - if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + if err = addRawResponseToMetadata(stack); err != nil { return err } - if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + if err = addRecordResponseTiming(stack); err != nil { + return err + } + if err = addSpanRetryLoop(stack, options); err != nil { return err } if err = addClientUserAgent(stack, options); err != nil { @@ -197,13 +220,19 @@ func (c *Client) addOperationCreateTokenWithIAMMiddlewares(stack *middleware.Sta if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil { return err } + if err = addTimeOffsetBuild(stack, c); err != nil { + return err + } + if err = addUserAgentRetryMode(stack, options); err != nil { + return err + } if err = addOpCreateTokenWithIAMValidationMiddleware(stack); err != nil { return err } if err = stack.Initialize.Add(newServiceMetadataMiddleware_opCreateTokenWithIAM(options.Region), middleware.Before); err != nil { return err } - if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + if err = addRecursionDetection(stack); err != nil { return err } if err = addRequestIDRetrieverMiddleware(stack); err != nil { @@ -218,6 +247,18 @@ func (c *Client) addOperationCreateTokenWithIAMMiddlewares(stack *middleware.Sta if err = addDisableHTTPSMiddleware(stack, options); err != nil { return err } + if err = addSpanInitializeStart(stack); err != nil { + return err + } + if err = addSpanInitializeEnd(stack); err != nil { + return err + } + if err = addSpanBuildRequestStart(stack); err != nil { + return err + } + if err = addSpanBuildRequestEnd(stack); err != nil { + return err + } return nil } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_RegisterClient.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_RegisterClient.go index 7aee904..2022270 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_RegisterClient.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_RegisterClient.go @@ -10,9 +10,9 @@ import ( smithyhttp "github.com/aws/smithy-go/transport/http" ) -// Registers a client with IAM Identity Center. This allows clients to initiate -// device authorization. The output should be persisted for reuse through many -// authentication requests. +// Registers a public client with IAM Identity Center. This allows clients to +// perform authorization using the authorization code grant with Proof Key for Code +// Exchange (PKCE) or the device code grant. func (c *Client) RegisterClient(ctx context.Context, params *RegisterClientInput, optFns ...func(*Options)) (*RegisterClientOutput, error) { if params == nil { params = &RegisterClientInput{} @@ -41,6 +41,33 @@ type RegisterClientInput struct { // This member is required. ClientType *string + // This IAM Identity Center application ARN is used to define + // administrator-managed configuration for public client access to resources. At + // authorization, the scopes, grants, and redirect URI available to this client + // will be restricted by this application resource. + EntitledApplicationArn *string + + // The list of OAuth 2.0 grant types that are defined by the client. This list is + // used to restrict the token granting flows available to the client. Supports the + // following OAuth 2.0 grant types: Authorization Code, Device Code, and Refresh + // Token. + // + // * Authorization Code - authorization_code + // + // * Device Code - urn:ietf:params:oauth:grant-type:device_code + // + // * Refresh Token - refresh_token + GrantTypes []string + + // The IAM Identity Center Issuer URL associated with an instance of IAM Identity + // Center. This value is needed for user access to resources through the client. + IssuerUrl *string + + // The list of redirect URI that are defined by the client. At completion of + // authorization, this list is used to restrict what locations the user agent can + // be redirected back to. + RedirectUris []string + // The list of scopes that are defined by the client. Upon authorization, this // list is used to restrict permissions when granting an access token. Scopes []string @@ -98,22 +125,25 @@ func (c *Client) addOperationRegisterClientMiddlewares(stack *middleware.Stack, if err = addSetLoggerMiddleware(stack, options); err != nil { return err } - if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + if err = addClientRequestID(stack); err != nil { return err } - if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + if err = addComputeContentLength(stack); err != nil { return err } if err = addResolveEndpointMiddleware(stack, options); err != nil { return err } - if err = addRetryMiddlewares(stack, options); err != nil { + if err = addRetry(stack, options); err != nil { return err } - if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + if err = addRawResponseToMetadata(stack); err != nil { return err } - if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + if err = addRecordResponseTiming(stack); err != nil { + return err + } + if err = addSpanRetryLoop(stack, options); err != nil { return err } if err = addClientUserAgent(stack, options); err != nil { @@ -128,13 +158,19 @@ func (c *Client) addOperationRegisterClientMiddlewares(stack *middleware.Stack, if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil { return err } + if err = addTimeOffsetBuild(stack, c); err != nil { + return err + } + if err = addUserAgentRetryMode(stack, options); err != nil { + return err + } if err = addOpRegisterClientValidationMiddleware(stack); err != nil { return err } if err = stack.Initialize.Add(newServiceMetadataMiddleware_opRegisterClient(options.Region), middleware.Before); err != nil { return err } - if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + if err = addRecursionDetection(stack); err != nil { return err } if err = addRequestIDRetrieverMiddleware(stack); err != nil { @@ -149,6 +185,18 @@ func (c *Client) addOperationRegisterClientMiddlewares(stack *middleware.Stack, if err = addDisableHTTPSMiddleware(stack, options); err != nil { return err } + if err = addSpanInitializeStart(stack); err != nil { + return err + } + if err = addSpanInitializeEnd(stack); err != nil { + return err + } + if err = addSpanBuildRequestStart(stack); err != nil { + return err + } + if err = addSpanBuildRequestEnd(stack); err != nil { + return err + } return nil } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_StartDeviceAuthorization.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_StartDeviceAuthorization.go index d30349e..203ca5e 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_StartDeviceAuthorization.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/api_op_StartDeviceAuthorization.go @@ -30,22 +30,23 @@ func (c *Client) StartDeviceAuthorization(ctx context.Context, params *StartDevi type StartDeviceAuthorizationInput struct { // The unique identifier string for the client that is registered with IAM - // Identity Center. This value should come from the persisted result of the - // RegisterClient API operation. + // Identity Center. This value should come from the persisted result of the RegisterClientAPI + // operation. // // This member is required. ClientId *string // A secret string that is generated for the client. This value should come from - // the persisted result of the RegisterClient API operation. + // the persisted result of the RegisterClientAPI operation. // // This member is required. ClientSecret *string - // The URL for the Amazon Web Services access portal. For more information, see - // Using the Amazon Web Services access portal (https://docs.aws.amazon.com/singlesignon/latest/userguide/using-the-portal.html) + // The URL for the Amazon Web Services access portal. For more information, see [Using the Amazon Web Services access portal] // in the IAM Identity Center User Guide. // + // [Using the Amazon Web Services access portal]: https://docs.aws.amazon.com/singlesignon/latest/userguide/using-the-portal.html + // // This member is required. StartUrl *string @@ -106,22 +107,25 @@ func (c *Client) addOperationStartDeviceAuthorizationMiddlewares(stack *middlewa if err = addSetLoggerMiddleware(stack, options); err != nil { return err } - if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + if err = addClientRequestID(stack); err != nil { return err } - if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + if err = addComputeContentLength(stack); err != nil { return err } if err = addResolveEndpointMiddleware(stack, options); err != nil { return err } - if err = addRetryMiddlewares(stack, options); err != nil { + if err = addRetry(stack, options); err != nil { return err } - if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + if err = addRawResponseToMetadata(stack); err != nil { return err } - if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + if err = addRecordResponseTiming(stack); err != nil { + return err + } + if err = addSpanRetryLoop(stack, options); err != nil { return err } if err = addClientUserAgent(stack, options); err != nil { @@ -136,13 +140,19 @@ func (c *Client) addOperationStartDeviceAuthorizationMiddlewares(stack *middlewa if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil { return err } + if err = addTimeOffsetBuild(stack, c); err != nil { + return err + } + if err = addUserAgentRetryMode(stack, options); err != nil { + return err + } if err = addOpStartDeviceAuthorizationValidationMiddleware(stack); err != nil { return err } if err = stack.Initialize.Add(newServiceMetadataMiddleware_opStartDeviceAuthorization(options.Region), middleware.Before); err != nil { return err } - if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + if err = addRecursionDetection(stack); err != nil { return err } if err = addRequestIDRetrieverMiddleware(stack); err != nil { @@ -157,6 +167,18 @@ func (c *Client) addOperationStartDeviceAuthorizationMiddlewares(stack *middlewa if err = addDisableHTTPSMiddleware(stack, options); err != nil { return err } + if err = addSpanInitializeStart(stack); err != nil { + return err + } + if err = addSpanInitializeEnd(stack); err != nil { + return err + } + if err = addSpanBuildRequestStart(stack); err != nil { + return err + } + if err = addSpanBuildRequestEnd(stack); err != nil { + return err + } return nil } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/auth.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/auth.go index 40b3bec..e4b87f5 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/auth.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/auth.go @@ -8,11 +8,13 @@ import ( awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" smithy "github.com/aws/smithy-go" smithyauth "github.com/aws/smithy-go/auth" + "github.com/aws/smithy-go/metrics" "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" ) -func bindAuthParamsRegion(params *AuthResolverParameters, _ interface{}, options Options) { +func bindAuthParamsRegion(_ interface{}, params *AuthResolverParameters, _ interface{}, options Options) { params.Region = options.Region } @@ -90,12 +92,12 @@ type AuthResolverParameters struct { Region string } -func bindAuthResolverParams(operation string, input interface{}, options Options) *AuthResolverParameters { +func bindAuthResolverParams(ctx context.Context, operation string, input interface{}, options Options) *AuthResolverParameters { params := &AuthResolverParameters{ Operation: operation, } - bindAuthParamsRegion(params, input, options) + bindAuthParamsRegion(ctx, params, input, options) return params } @@ -163,7 +165,10 @@ func (*resolveAuthSchemeMiddleware) ID() string { func (m *resolveAuthSchemeMiddleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) ( out middleware.FinalizeOutput, metadata middleware.Metadata, err error, ) { - params := bindAuthResolverParams(m.operation, getOperationInput(ctx), m.options) + _, span := tracing.StartSpan(ctx, "ResolveAuthScheme") + defer span.End() + + params := bindAuthResolverParams(ctx, m.operation, getOperationInput(ctx), m.options) options, err := m.options.AuthSchemeResolver.ResolveAuthSchemes(ctx, params) if err != nil { return out, metadata, fmt.Errorf("resolve auth scheme: %w", err) @@ -175,6 +180,9 @@ func (m *resolveAuthSchemeMiddleware) HandleFinalize(ctx context.Context, in mid } ctx = setResolvedAuthScheme(ctx, scheme) + + span.SetProperty("auth.scheme_id", scheme.Scheme.SchemeID()) + span.End() return next.HandleFinalize(ctx, in) } @@ -234,7 +242,10 @@ func (*getIdentityMiddleware) ID() string { func (m *getIdentityMiddleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) ( out middleware.FinalizeOutput, metadata middleware.Metadata, err error, ) { - rscheme := getResolvedAuthScheme(ctx) + innerCtx, span := tracing.StartSpan(ctx, "GetIdentity") + defer span.End() + + rscheme := getResolvedAuthScheme(innerCtx) if rscheme == nil { return out, metadata, fmt.Errorf("no resolved auth scheme") } @@ -244,12 +255,20 @@ func (m *getIdentityMiddleware) HandleFinalize(ctx context.Context, in middlewar return out, metadata, fmt.Errorf("no identity resolver") } - identity, err := resolver.GetIdentity(ctx, rscheme.IdentityProperties) + identity, err := timeOperationMetric(ctx, "client.call.resolve_identity_duration", + func() (smithyauth.Identity, error) { + return resolver.GetIdentity(innerCtx, rscheme.IdentityProperties) + }, + func(o *metrics.RecordMetricOptions) { + o.Properties.Set("auth.scheme_id", rscheme.Scheme.SchemeID()) + }) if err != nil { return out, metadata, fmt.Errorf("get identity: %w", err) } ctx = setIdentity(ctx, identity) + + span.End() return next.HandleFinalize(ctx, in) } @@ -265,6 +284,7 @@ func getIdentity(ctx context.Context) smithyauth.Identity { } type signRequestMiddleware struct { + options Options } func (*signRequestMiddleware) ID() string { @@ -274,6 +294,9 @@ func (*signRequestMiddleware) ID() string { func (m *signRequestMiddleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) ( out middleware.FinalizeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "SignRequest") + defer span.End() + req, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, fmt.Errorf("unexpected transport type %T", in.Request) @@ -294,9 +317,15 @@ func (m *signRequestMiddleware) HandleFinalize(ctx context.Context, in middlewar return out, metadata, fmt.Errorf("no signer") } - if err := signer.SignRequest(ctx, req, identity, rscheme.SignerProperties); err != nil { + _, err = timeOperationMetric(ctx, "client.call.signing_duration", func() (any, error) { + return nil, signer.SignRequest(ctx, req, identity, rscheme.SignerProperties) + }, func(o *metrics.RecordMetricOptions) { + o.Properties.Set("auth.scheme_id", rscheme.Scheme.SchemeID()) + }) + if err != nil { return out, metadata, fmt.Errorf("sign request: %w", err) } + span.End() return next.HandleFinalize(ctx, in) } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/deserializers.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/deserializers.go index 76a1160..ae9f145 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/deserializers.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/deserializers.go @@ -13,11 +13,22 @@ import ( smithyio "github.com/aws/smithy-go/io" "github.com/aws/smithy-go/middleware" "github.com/aws/smithy-go/ptr" + smithytime "github.com/aws/smithy-go/time" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" "io" "strings" + "time" ) +func deserializeS3Expires(v string) (*time.Time, error) { + t, err := smithytime.ParseHTTPDate(v) + if err != nil { + return nil, nil + } + return &t, nil +} + type awsRestjson1_deserializeOpCreateToken struct { } @@ -33,6 +44,10 @@ func (m *awsRestjson1_deserializeOpCreateToken) HandleDeserialize(ctx context.Co return out, metadata, err } + _, span := tracing.StartSpan(ctx, "OperationDeserializer") + endTimer := startMetricTimer(ctx, "client.call.deserialization_duration") + defer endTimer() + defer span.End() response, ok := out.RawResponse.(*smithyhttp.Response) if !ok { return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} @@ -72,6 +87,7 @@ func (m *awsRestjson1_deserializeOpCreateToken) HandleDeserialize(ctx context.Co } } + span.End() return out, metadata, err } @@ -254,6 +270,10 @@ func (m *awsRestjson1_deserializeOpCreateTokenWithIAM) HandleDeserialize(ctx con return out, metadata, err } + _, span := tracing.StartSpan(ctx, "OperationDeserializer") + endTimer := startMetricTimer(ctx, "client.call.deserialization_duration") + defer endTimer() + defer span.End() response, ok := out.RawResponse.(*smithyhttp.Response) if !ok { return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} @@ -293,6 +313,7 @@ func (m *awsRestjson1_deserializeOpCreateTokenWithIAM) HandleDeserialize(ctx con } } + span.End() return out, metadata, err } @@ -492,6 +513,10 @@ func (m *awsRestjson1_deserializeOpRegisterClient) HandleDeserialize(ctx context return out, metadata, err } + _, span := tracing.StartSpan(ctx, "OperationDeserializer") + endTimer := startMetricTimer(ctx, "client.call.deserialization_duration") + defer endTimer() + defer span.End() response, ok := out.RawResponse.(*smithyhttp.Response) if !ok { return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} @@ -531,6 +556,7 @@ func (m *awsRestjson1_deserializeOpRegisterClient) HandleDeserialize(ctx context } } + span.End() return out, metadata, err } @@ -581,12 +607,18 @@ func awsRestjson1_deserializeOpErrorRegisterClient(response *smithyhttp.Response case strings.EqualFold("InvalidClientMetadataException", errorCode): return awsRestjson1_deserializeErrorInvalidClientMetadataException(response, errorBody) + case strings.EqualFold("InvalidRedirectUriException", errorCode): + return awsRestjson1_deserializeErrorInvalidRedirectUriException(response, errorBody) + case strings.EqualFold("InvalidRequestException", errorCode): return awsRestjson1_deserializeErrorInvalidRequestException(response, errorBody) case strings.EqualFold("InvalidScopeException", errorCode): return awsRestjson1_deserializeErrorInvalidScopeException(response, errorBody) + case strings.EqualFold("UnsupportedGrantTypeException", errorCode): + return awsRestjson1_deserializeErrorUnsupportedGrantTypeException(response, errorBody) + default: genericError := &smithy.GenericAPIError{ Code: errorCode, @@ -705,6 +737,10 @@ func (m *awsRestjson1_deserializeOpStartDeviceAuthorization) HandleDeserialize(c return out, metadata, err } + _, span := tracing.StartSpan(ctx, "OperationDeserializer") + endTimer := startMetricTimer(ctx, "client.call.deserialization_duration") + defer endTimer() + defer span.End() response, ok := out.RawResponse.(*smithyhttp.Response) if !ok { return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} @@ -744,6 +780,7 @@ func (m *awsRestjson1_deserializeOpStartDeviceAuthorization) HandleDeserialize(c } } + span.End() return out, metadata, err } @@ -1158,6 +1195,42 @@ func awsRestjson1_deserializeErrorInvalidGrantException(response *smithyhttp.Res return output } +func awsRestjson1_deserializeErrorInvalidRedirectUriException(response *smithyhttp.Response, errorBody *bytes.Reader) error { + output := &types.InvalidRedirectUriException{} + var buff [1024]byte + ringBuffer := smithyio.NewRingBuffer(buff[:]) + + body := io.TeeReader(errorBody, ringBuffer) + decoder := json.NewDecoder(body) + decoder.UseNumber() + var shape interface{} + if err := decoder.Decode(&shape); err != nil && err != io.EOF { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + err = &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + return err + } + + err := awsRestjson1_deserializeDocumentInvalidRedirectUriException(&output, shape) + + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + err = &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + return err + } + + errorBody.Seek(0, io.SeekStart) + + return output +} + func awsRestjson1_deserializeErrorInvalidRequestException(response *smithyhttp.Response, errorBody *bytes.Reader) error { output := &types.InvalidRequestException{} var buff [1024]byte @@ -1717,6 +1790,55 @@ func awsRestjson1_deserializeDocumentInvalidGrantException(v **types.InvalidGran return nil } +func awsRestjson1_deserializeDocumentInvalidRedirectUriException(v **types.InvalidRedirectUriException, value interface{}) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + if value == nil { + return nil + } + + shape, ok := value.(map[string]interface{}) + if !ok { + return fmt.Errorf("unexpected JSON type %v", value) + } + + var sv *types.InvalidRedirectUriException + if *v == nil { + sv = &types.InvalidRedirectUriException{} + } else { + sv = *v + } + + for key, value := range shape { + switch key { + case "error": + if value != nil { + jtv, ok := value.(string) + if !ok { + return fmt.Errorf("expected Error to be of type string, got %T instead", value) + } + sv.Error_ = ptr.String(jtv) + } + + case "error_description": + if value != nil { + jtv, ok := value.(string) + if !ok { + return fmt.Errorf("expected ErrorDescription to be of type string, got %T instead", value) + } + sv.Error_description = ptr.String(jtv) + } + + default: + _, _ = key, value + + } + } + *v = sv + return nil +} + func awsRestjson1_deserializeDocumentInvalidRequestException(v **types.InvalidRequestException, value interface{}) error { if v == nil { return fmt.Errorf("unexpected nil of type %T", v) diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/doc.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/doc.go index 53cd4f5..f3510b1 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/doc.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/doc.go @@ -6,33 +6,44 @@ // IAM Identity Center OpenID Connect (OIDC) is a web service that enables a // client (such as CLI or a native application) to register with IAM Identity // Center. The service also enables the client to fetch the user’s access token -// upon successful authentication and authorization with IAM Identity Center. IAM -// Identity Center uses the sso and identitystore API namespaces. Considerations -// for Using This Guide Before you begin using this guide, we recommend that you -// first review the following important information about how the IAM Identity -// Center OIDC service works. +// upon successful authentication and authorization with IAM Identity Center. +// +// # API namespaces +// +// IAM Identity Center uses the sso and identitystore API namespaces. IAM Identity +// Center OpenID Connect uses the sso-oidc namespace. +// +// # Considerations for using this guide +// +// Before you begin using this guide, we recommend that you first review the +// following important information about how the IAM Identity Center OIDC service +// works. +// // - The IAM Identity Center OIDC service currently implements only the portions -// of the OAuth 2.0 Device Authorization Grant standard ( -// https://tools.ietf.org/html/rfc8628 (https://tools.ietf.org/html/rfc8628) ) -// that are necessary to enable single sign-on authentication with the CLI. +// of the OAuth 2.0 Device Authorization Grant standard ([https://tools.ietf.org/html/rfc8628] ) that are necessary to +// enable single sign-on authentication with the CLI. +// // - With older versions of the CLI, the service only emits OIDC access tokens, // so to obtain a new token, users must explicitly re-authenticate. To access the // OIDC flow that supports token refresh and doesn’t require re-authentication, // update to the latest CLI version (1.27.10 for CLI V1 and 2.9.0 for CLI V2) with // support for OIDC token refresh and configurable IAM Identity Center session -// durations. For more information, see Configure Amazon Web Services access -// portal session duration (https://docs.aws.amazon.com/singlesignon/latest/userguide/configure-user-session.html) -// . +// durations. For more information, see [Configure Amazon Web Services access portal session duration]. +// // - The access tokens provided by this service grant access to all Amazon Web // Services account entitlements assigned to an IAM Identity Center user, not just // a particular application. +// // - The documentation in this guide does not describe the mechanism to convert // the access token into Amazon Web Services Auth (“sigv4”) credentials for use // with IAM-protected Amazon Web Services service endpoints. For more information, -// see GetRoleCredentials (https://docs.aws.amazon.com/singlesignon/latest/PortalAPIReference/API_GetRoleCredentials.html) -// in the IAM Identity Center Portal API Reference Guide. +// see [GetRoleCredentials]in the IAM Identity Center Portal API Reference Guide. // -// For general information about IAM Identity Center, see What is IAM Identity -// Center? (https://docs.aws.amazon.com/singlesignon/latest/userguide/what-is.html) -// in the IAM Identity Center User Guide. +// For general information about IAM Identity Center, see [What is IAM Identity Center?] in the IAM Identity +// Center User Guide. +// +// [Configure Amazon Web Services access portal session duration]: https://docs.aws.amazon.com/singlesignon/latest/userguide/configure-user-session.html +// [GetRoleCredentials]: https://docs.aws.amazon.com/singlesignon/latest/PortalAPIReference/API_GetRoleCredentials.html +// [https://tools.ietf.org/html/rfc8628]: https://tools.ietf.org/html/rfc8628 +// [What is IAM Identity Center?]: https://docs.aws.amazon.com/singlesignon/latest/userguide/what-is.html package ssooidc diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/endpoints.go index 85b8708..6feea0c 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/endpoints.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/endpoints.go @@ -16,6 +16,7 @@ import ( smithyendpoints "github.com/aws/smithy-go/endpoints" "github.com/aws/smithy-go/middleware" "github.com/aws/smithy-go/ptr" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" "net/http" "net/url" @@ -216,6 +217,13 @@ func resolveBaseEndpoint(cfg aws.Config, o *Options) { } } +func bindRegion(region string) *string { + if region == "" { + return nil + } + return aws.String(endpoints.MapFIPSRegion(region)) +} + // EndpointParameters provides the parameters that influence how endpoints are // resolved. type EndpointParameters struct { @@ -281,6 +289,17 @@ func (p EndpointParameters) WithDefaults() EndpointParameters { return p } +type stringSlice []string + +func (s stringSlice) Get(i int) *string { + if i < 0 || i >= len(s) { + return nil + } + + v := s[i] + return &v +} + // EndpointResolverV2 provides the interface for resolving service endpoints. type EndpointResolverV2 interface { // ResolveEndpoint attempts to resolve the endpoint with the provided options, @@ -458,10 +477,10 @@ type endpointParamsBinder interface { bindEndpointParams(*EndpointParameters) } -func bindEndpointParams(input interface{}, options Options) *EndpointParameters { +func bindEndpointParams(ctx context.Context, input interface{}, options Options) *EndpointParameters { params := &EndpointParameters{} - params.Region = aws.String(endpoints.MapFIPSRegion(options.Region)) + params.Region = bindRegion(options.Region) params.UseDualStack = aws.Bool(options.EndpointOptions.UseDualStackEndpoint == aws.DualStackEndpointStateEnabled) params.UseFIPS = aws.Bool(options.EndpointOptions.UseFIPSEndpoint == aws.FIPSEndpointStateEnabled) params.Endpoint = options.BaseEndpoint @@ -484,6 +503,9 @@ func (*resolveEndpointV2Middleware) ID() string { func (m *resolveEndpointV2Middleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) ( out middleware.FinalizeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "ResolveEndpoint") + defer span.End() + if awsmiddleware.GetRequiresLegacyEndpoints(ctx) { return next.HandleFinalize(ctx, in) } @@ -497,12 +519,17 @@ func (m *resolveEndpointV2Middleware) HandleFinalize(ctx context.Context, in mid return out, metadata, fmt.Errorf("expected endpoint resolver to not be nil") } - params := bindEndpointParams(getOperationInput(ctx), m.options) - endpt, err := m.options.EndpointResolverV2.ResolveEndpoint(ctx, *params) + params := bindEndpointParams(ctx, getOperationInput(ctx), m.options) + endpt, err := timeOperationMetric(ctx, "client.call.resolve_endpoint_duration", + func() (smithyendpoints.Endpoint, error) { + return m.options.EndpointResolverV2.ResolveEndpoint(ctx, *params) + }) if err != nil { return out, metadata, fmt.Errorf("failed to resolve service endpoint, %w", err) } + span.SetProperty("client.call.resolved_endpoint", endpt.URI.String()) + if endpt.URI.RawPath == "" && req.URL.RawPath != "" { endpt.URI.RawPath = endpt.URI.Path } @@ -524,5 +551,6 @@ func (m *resolveEndpointV2Middleware) HandleFinalize(ctx context.Context, in mid rscheme.SignerProperties.SetAll(&o.SignerProperties) } + span.End() return next.HandleFinalize(ctx, in) } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/generated.json b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/generated.json index 0a6b349..b2a5263 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/generated.json +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/generated.json @@ -3,8 +3,7 @@ "github.com/aws/aws-sdk-go-v2": "v1.4.0", "github.com/aws/aws-sdk-go-v2/internal/configsources": "v0.0.0-00010101000000-000000000000", "github.com/aws/aws-sdk-go-v2/internal/endpoints/v2": "v2.0.0-00010101000000-000000000000", - "github.com/aws/smithy-go": "v1.4.0", - "github.com/google/go-cmp": "v0.5.4" + "github.com/aws/smithy-go": "v1.4.0" }, "files": [ "api_client.go", @@ -25,6 +24,7 @@ "options.go", "protocol_test.go", "serializers.go", + "snapshot_test.go", "types/errors.go", "types/types.go", "validators.go" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/go_module_metadata.go index 474a574..b338cba 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/go_module_metadata.go @@ -3,4 +3,4 @@ package ssooidc // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.21.7" +const goModuleVersion = "1.28.13" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/internal/endpoints/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/internal/endpoints/endpoints.go index cbd77fd..b4c61eb 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/internal/endpoints/endpoints.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/internal/endpoints/endpoints.go @@ -94,7 +94,7 @@ var partitionRegexp = struct { AwsUsGov *regexp.Regexp }{ - Aws: regexp.MustCompile("^(us|eu|ap|sa|ca|me|af|il)\\-\\w+\\-\\d+$"), + Aws: regexp.MustCompile("^(us|eu|ap|sa|ca|me|af|il|mx)\\-\\w+\\-\\d+$"), AwsCn: regexp.MustCompile("^cn\\-\\w+\\-\\d+$"), AwsIso: regexp.MustCompile("^us\\-iso\\-\\w+\\-\\d+$"), AwsIsoB: regexp.MustCompile("^us\\-isob\\-\\w+\\-\\d+$"), @@ -187,6 +187,14 @@ var defaultPartitions = endpoints.Partitions{ Region: "ap-south-1", }, }, + endpoints.EndpointKey{ + Region: "ap-south-2", + }: endpoints.Endpoint{ + Hostname: "oidc.ap-south-2.amazonaws.com", + CredentialScope: endpoints.CredentialScope{ + Region: "ap-south-2", + }, + }, endpoints.EndpointKey{ Region: "ap-southeast-1", }: endpoints.Endpoint{ @@ -211,6 +219,14 @@ var defaultPartitions = endpoints.Partitions{ Region: "ap-southeast-3", }, }, + endpoints.EndpointKey{ + Region: "ap-southeast-4", + }: endpoints.Endpoint{ + Hostname: "oidc.ap-southeast-4.amazonaws.com", + CredentialScope: endpoints.CredentialScope{ + Region: "ap-southeast-4", + }, + }, endpoints.EndpointKey{ Region: "ca-central-1", }: endpoints.Endpoint{ @@ -219,6 +235,14 @@ var defaultPartitions = endpoints.Partitions{ Region: "ca-central-1", }, }, + endpoints.EndpointKey{ + Region: "ca-west-1", + }: endpoints.Endpoint{ + Hostname: "oidc.ca-west-1.amazonaws.com", + CredentialScope: endpoints.CredentialScope{ + Region: "ca-west-1", + }, + }, endpoints.EndpointKey{ Region: "eu-central-1", }: endpoints.Endpoint{ @@ -251,6 +275,14 @@ var defaultPartitions = endpoints.Partitions{ Region: "eu-south-1", }, }, + endpoints.EndpointKey{ + Region: "eu-south-2", + }: endpoints.Endpoint{ + Hostname: "oidc.eu-south-2.amazonaws.com", + CredentialScope: endpoints.CredentialScope{ + Region: "eu-south-2", + }, + }, endpoints.EndpointKey{ Region: "eu-west-1", }: endpoints.Endpoint{ diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/options.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/options.go index b964e7e..55dd80d 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/options.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/options.go @@ -9,7 +9,9 @@ import ( internalauthsmithy "github.com/aws/aws-sdk-go-v2/internal/auth/smithy" smithyauth "github.com/aws/smithy-go/auth" "github.com/aws/smithy-go/logging" + "github.com/aws/smithy-go/metrics" "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" "net/http" ) @@ -50,8 +52,10 @@ type Options struct { // Deprecated: Deprecated: EndpointResolver and WithEndpointResolver. Providing a // value for this field will likely prevent you from using any endpoint-related // service features released after the introduction of EndpointResolverV2 and - // BaseEndpoint. To migrate an EndpointResolver implementation that uses a custom - // endpoint, set the client option BaseEndpoint instead. + // BaseEndpoint. + // + // To migrate an EndpointResolver implementation that uses a custom endpoint, set + // the client option BaseEndpoint instead. EndpointResolver EndpointResolver // Resolves the endpoint used for a particular service operation. This should be @@ -64,23 +68,29 @@ type Options struct { // The logger writer interface to write logging messages to. Logger logging.Logger + // The client meter provider. + MeterProvider metrics.MeterProvider + // The region to send requests to. (Required) Region string // RetryMaxAttempts specifies the maximum number attempts an API client will call // an operation that fails with a retryable error. A value of 0 is ignored, and // will not be used to configure the API client created default retryer, or modify - // per operation call's retry max attempts. If specified in an operation call's - // functional options with a value that is different than the constructed client's - // Options, the Client's Retryer will be wrapped to use the operation's specific - // RetryMaxAttempts value. + // per operation call's retry max attempts. + // + // If specified in an operation call's functional options with a value that is + // different than the constructed client's Options, the Client's Retryer will be + // wrapped to use the operation's specific RetryMaxAttempts value. RetryMaxAttempts int // RetryMode specifies the retry mode the API client will be created with, if - // Retryer option is not also specified. When creating a new API Clients this - // member will only be used if the Retryer Options member is nil. This value will - // be ignored if Retryer is not nil. Currently does not support per operation call - // overrides, may in the future. + // Retryer option is not also specified. + // + // When creating a new API Clients this member will only be used if the Retryer + // Options member is nil. This value will be ignored if Retryer is not nil. + // + // Currently does not support per operation call overrides, may in the future. RetryMode aws.RetryMode // Retryer guides how HTTP requests should be retried in case of recoverable @@ -95,10 +105,14 @@ type Options struct { // within your applications. RuntimeEnvironment aws.RuntimeEnvironment + // The client tracer provider. + TracerProvider tracing.TracerProvider + // The initial DefaultsMode used when the client options were constructed. If the // DefaultsMode was set to aws.DefaultsModeAuto this will store what the resolved - // value was at that point in time. Currently does not support per operation call - // overrides, may in the future. + // value was at that point in time. + // + // Currently does not support per operation call overrides, may in the future. resolvedDefaultsMode aws.DefaultsMode // The HTTP client to invoke API calls with. Defaults to client's default HTTP @@ -143,6 +157,7 @@ func WithAPIOptions(optFns ...func(*middleware.Stack) error) func(*Options) { // Deprecated: EndpointResolver and WithEndpointResolver. Providing a value for // this field will likely prevent you from using any endpoint-related service // features released after the introduction of EndpointResolverV2 and BaseEndpoint. +// // To migrate an EndpointResolver implementation that uses a custom endpoint, set // the client option BaseEndpoint instead. func WithEndpointResolver(v EndpointResolver) func(*Options) { diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/serializers.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/serializers.go index 754218b..1ad103d 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/serializers.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/serializers.go @@ -10,6 +10,7 @@ import ( "github.com/aws/smithy-go/encoding/httpbinding" smithyjson "github.com/aws/smithy-go/encoding/json" "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" ) @@ -23,6 +24,10 @@ func (*awsRestjson1_serializeOpCreateToken) ID() string { func (m *awsRestjson1_serializeOpCreateToken) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( out middleware.SerializeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "OperationSerializer") + endTimer := startMetricTimer(ctx, "client.call.serialization_duration") + defer endTimer() + defer span.End() request, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} @@ -66,6 +71,8 @@ func (m *awsRestjson1_serializeOpCreateToken) HandleSerialize(ctx context.Contex } in.Request = request + endTimer() + span.End() return next.HandleSerialize(ctx, in) } func awsRestjson1_serializeOpHttpBindingsCreateTokenInput(v *CreateTokenInput, encoder *httpbinding.Encoder) error { @@ -95,6 +102,11 @@ func awsRestjson1_serializeOpDocumentCreateTokenInput(v *CreateTokenInput, value ok.String(*v.Code) } + if v.CodeVerifier != nil { + ok := object.Key("codeVerifier") + ok.String(*v.CodeVerifier) + } + if v.DeviceCode != nil { ok := object.Key("deviceCode") ok.String(*v.DeviceCode) @@ -135,6 +147,10 @@ func (*awsRestjson1_serializeOpCreateTokenWithIAM) ID() string { func (m *awsRestjson1_serializeOpCreateTokenWithIAM) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( out middleware.SerializeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "OperationSerializer") + endTimer := startMetricTimer(ctx, "client.call.serialization_duration") + defer endTimer() + defer span.End() request, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} @@ -178,6 +194,8 @@ func (m *awsRestjson1_serializeOpCreateTokenWithIAM) HandleSerialize(ctx context } in.Request = request + endTimer() + span.End() return next.HandleSerialize(ctx, in) } func awsRestjson1_serializeOpHttpBindingsCreateTokenWithIAMInput(v *CreateTokenWithIAMInput, encoder *httpbinding.Encoder) error { @@ -207,6 +225,11 @@ func awsRestjson1_serializeOpDocumentCreateTokenWithIAMInput(v *CreateTokenWithI ok.String(*v.Code) } + if v.CodeVerifier != nil { + ok := object.Key("codeVerifier") + ok.String(*v.CodeVerifier) + } + if v.GrantType != nil { ok := object.Key("grantType") ok.String(*v.GrantType) @@ -257,6 +280,10 @@ func (*awsRestjson1_serializeOpRegisterClient) ID() string { func (m *awsRestjson1_serializeOpRegisterClient) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( out middleware.SerializeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "OperationSerializer") + endTimer := startMetricTimer(ctx, "client.call.serialization_duration") + defer endTimer() + defer span.End() request, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} @@ -300,6 +327,8 @@ func (m *awsRestjson1_serializeOpRegisterClient) HandleSerialize(ctx context.Con } in.Request = request + endTimer() + span.End() return next.HandleSerialize(ctx, in) } func awsRestjson1_serializeOpHttpBindingsRegisterClientInput(v *RegisterClientInput, encoder *httpbinding.Encoder) error { @@ -324,6 +353,30 @@ func awsRestjson1_serializeOpDocumentRegisterClientInput(v *RegisterClientInput, ok.String(*v.ClientType) } + if v.EntitledApplicationArn != nil { + ok := object.Key("entitledApplicationArn") + ok.String(*v.EntitledApplicationArn) + } + + if v.GrantTypes != nil { + ok := object.Key("grantTypes") + if err := awsRestjson1_serializeDocumentGrantTypes(v.GrantTypes, ok); err != nil { + return err + } + } + + if v.IssuerUrl != nil { + ok := object.Key("issuerUrl") + ok.String(*v.IssuerUrl) + } + + if v.RedirectUris != nil { + ok := object.Key("redirectUris") + if err := awsRestjson1_serializeDocumentRedirectUris(v.RedirectUris, ok); err != nil { + return err + } + } + if v.Scopes != nil { ok := object.Key("scopes") if err := awsRestjson1_serializeDocumentScopes(v.Scopes, ok); err != nil { @@ -344,6 +397,10 @@ func (*awsRestjson1_serializeOpStartDeviceAuthorization) ID() string { func (m *awsRestjson1_serializeOpStartDeviceAuthorization) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( out middleware.SerializeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "OperationSerializer") + endTimer := startMetricTimer(ctx, "client.call.serialization_duration") + defer endTimer() + defer span.End() request, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} @@ -387,6 +444,8 @@ func (m *awsRestjson1_serializeOpStartDeviceAuthorization) HandleSerialize(ctx c } in.Request = request + endTimer() + span.End() return next.HandleSerialize(ctx, in) } func awsRestjson1_serializeOpHttpBindingsStartDeviceAuthorizationInput(v *StartDeviceAuthorizationInput, encoder *httpbinding.Encoder) error { @@ -419,6 +478,28 @@ func awsRestjson1_serializeOpDocumentStartDeviceAuthorizationInput(v *StartDevic return nil } +func awsRestjson1_serializeDocumentGrantTypes(v []string, value smithyjson.Value) error { + array := value.Array() + defer array.Close() + + for i := range v { + av := array.Value() + av.String(v[i]) + } + return nil +} + +func awsRestjson1_serializeDocumentRedirectUris(v []string, value smithyjson.Value) error { + array := value.Array() + defer array.Close() + + for i := range v { + av := array.Value() + av.String(v[i]) + } + return nil +} + func awsRestjson1_serializeDocumentScopes(v []string, value smithyjson.Value) error { array := value.Array() defer array.Close() diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/types/errors.go b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/types/errors.go index 86b6204..2cfe7b4 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/types/errors.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/ssooidc/types/errors.go @@ -188,7 +188,7 @@ func (e *InvalidClientMetadataException) ErrorCode() string { func (e *InvalidClientMetadataException) ErrorFault() smithy.ErrorFault { return smithy.FaultClient } // Indicates that a request contains an invalid grant. This can occur if a client -// makes a CreateToken request with an invalid grant type. +// makes a CreateTokenrequest with an invalid grant type. type InvalidGrantException struct { Message *string @@ -217,6 +217,36 @@ func (e *InvalidGrantException) ErrorCode() string { } func (e *InvalidGrantException) ErrorFault() smithy.ErrorFault { return smithy.FaultClient } +// Indicates that one or more redirect URI in the request is not supported for +// this operation. +type InvalidRedirectUriException struct { + Message *string + + ErrorCodeOverride *string + + Error_ *string + Error_description *string + + noSmithyDocumentSerde +} + +func (e *InvalidRedirectUriException) Error() string { + return fmt.Sprintf("%s: %s", e.ErrorCode(), e.ErrorMessage()) +} +func (e *InvalidRedirectUriException) ErrorMessage() string { + if e.Message == nil { + return "" + } + return *e.Message +} +func (e *InvalidRedirectUriException) ErrorCode() string { + if e == nil || e.ErrorCodeOverride == nil { + return "InvalidRedirectUriException" + } + return *e.ErrorCodeOverride +} +func (e *InvalidRedirectUriException) ErrorFault() smithy.ErrorFault { return smithy.FaultClient } + // Indicates that something is wrong with the input to the request. For example, a // required parameter might be missing or out of range. type InvalidRequestException struct { diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/CHANGELOG.md index f9b6404..4a1d033 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/CHANGELOG.md +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/CHANGELOG.md @@ -1,3 +1,222 @@ +# v1.33.13 (2025-02-04) + +* No change notes available for this release. + +# v1.33.12 (2025-01-31) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.33.11 (2025-01-30) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.33.10 (2025-01-24) + +* **Dependency Update**: Updated to the latest SDK module versions +* **Dependency Update**: Upgrade to smithy-go v1.22.2. + +# v1.33.9 (2025-01-17) + +* **Bug Fix**: Fix bug where credentials weren't refreshed during retry loop. + +# v1.33.8 (2025-01-15) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.33.7 (2025-01-14) + +* No change notes available for this release. + +# v1.33.6 (2025-01-10) + +* **Documentation**: Fixed typos in the descriptions. + +# v1.33.5 (2025-01-09) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.33.4 (2025-01-08) + +* No change notes available for this release. + +# v1.33.3 (2024-12-19) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.33.2 (2024-12-02) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.33.1 (2024-11-18) + +* **Dependency Update**: Update to smithy-go v1.22.1. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.33.0 (2024-11-14) + +* **Feature**: This release introduces the new API 'AssumeRoot', which returns short-term credentials that you can use to perform privileged tasks. + +# v1.32.4 (2024-11-06) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.32.3 (2024-10-28) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.32.2 (2024-10-08) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.32.1 (2024-10-07) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.32.0 (2024-10-04) + +* **Feature**: Add support for HTTP client metrics. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.31.4 (2024-10-03) + +* No change notes available for this release. + +# v1.31.3 (2024-09-27) + +* No change notes available for this release. + +# v1.31.2 (2024-09-25) + +* No change notes available for this release. + +# v1.31.1 (2024-09-23) + +* No change notes available for this release. + +# v1.31.0 (2024-09-20) + +* **Feature**: Add tracing and metrics support to service clients. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.30.8 (2024-09-17) + +* **Bug Fix**: **BREAKFIX**: Only generate AccountIDEndpointMode config for services that use it. This is a compiler break, but removes no actual functionality, as no services currently use the account ID in endpoint resolution. + +# v1.30.7 (2024-09-04) + +* No change notes available for this release. + +# v1.30.6 (2024-09-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.30.5 (2024-08-22) + +* No change notes available for this release. + +# v1.30.4 (2024-08-15) + +* **Dependency Update**: Bump minimum Go version to 1.21. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.30.3 (2024-07-10.2) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.30.2 (2024-07-10) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.30.1 (2024-06-28) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.30.0 (2024-06-26) + +* **Feature**: Support list-of-string endpoint parameter. + +# v1.29.1 (2024-06-19) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.29.0 (2024-06-18) + +* **Feature**: Track usage of various AWS SDK features in user-agent string. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.13 (2024-06-17) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.12 (2024-06-07) + +* **Bug Fix**: Add clock skew correction on all service clients +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.11 (2024-06-03) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.10 (2024-05-23) + +* No change notes available for this release. + +# v1.28.9 (2024-05-16) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.8 (2024-05-15) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.7 (2024-05-08) + +* **Bug Fix**: GoDoc improvement + +# v1.28.6 (2024-03-29) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.5 (2024-03-18) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.4 (2024-03-07) + +* **Bug Fix**: Remove dependency on go-cmp. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.3 (2024-03-05) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.2 (2024-03-04) + +* **Bug Fix**: Update internal/presigned-url dependency for corrected API name. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.1 (2024-02-23) + +* **Bug Fix**: Move all common, SDK-side middleware stack ops into the service client module to prevent cross-module compatibility issues in the future. +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.28.0 (2024-02-22) + +* **Feature**: Add middleware stack snapshot tests. + +# v1.27.2 (2024-02-21) + +* **Dependency Update**: Updated to the latest SDK module versions + +# v1.27.1 (2024-02-20) + +* **Bug Fix**: When sourcing values for a service's `EndpointParameters`, the lack of a configured region (i.e. `options.Region == ""`) will now translate to a `nil` value for `EndpointParameters.Region` instead of a pointer to the empty string `""`. This will result in a much more explicit error when calling an operation instead of an obscure hostname lookup failure. + +# v1.27.0 (2024-02-13) + +* **Feature**: Bump minimum Go version to 1.20 per our language support policy. +* **Dependency Update**: Updated to the latest SDK module versions + # v1.26.7 (2024-01-04) * **Dependency Update**: Updated to the latest SDK module versions diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_client.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_client.go index 369de83..2578732 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_client.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_client.go @@ -4,6 +4,7 @@ package sts import ( "context" + "errors" "fmt" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/defaults" @@ -15,25 +16,160 @@ import ( internalauth "github.com/aws/aws-sdk-go-v2/internal/auth" internalauthsmithy "github.com/aws/aws-sdk-go-v2/internal/auth/smithy" internalConfig "github.com/aws/aws-sdk-go-v2/internal/configsources" + internalmiddleware "github.com/aws/aws-sdk-go-v2/internal/middleware" acceptencodingcust "github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding" presignedurlcust "github.com/aws/aws-sdk-go-v2/service/internal/presigned-url" smithy "github.com/aws/smithy-go" + smithyauth "github.com/aws/smithy-go/auth" smithydocument "github.com/aws/smithy-go/document" "github.com/aws/smithy-go/logging" + "github.com/aws/smithy-go/metrics" "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" "net" "net/http" + "sync/atomic" "time" ) const ServiceID = "STS" const ServiceAPIVersion = "2011-06-15" +type operationMetrics struct { + Duration metrics.Float64Histogram + SerializeDuration metrics.Float64Histogram + ResolveIdentityDuration metrics.Float64Histogram + ResolveEndpointDuration metrics.Float64Histogram + SignRequestDuration metrics.Float64Histogram + DeserializeDuration metrics.Float64Histogram +} + +func (m *operationMetrics) histogramFor(name string) metrics.Float64Histogram { + switch name { + case "client.call.duration": + return m.Duration + case "client.call.serialization_duration": + return m.SerializeDuration + case "client.call.resolve_identity_duration": + return m.ResolveIdentityDuration + case "client.call.resolve_endpoint_duration": + return m.ResolveEndpointDuration + case "client.call.signing_duration": + return m.SignRequestDuration + case "client.call.deserialization_duration": + return m.DeserializeDuration + default: + panic("unrecognized operation metric") + } +} + +func timeOperationMetric[T any]( + ctx context.Context, metric string, fn func() (T, error), + opts ...metrics.RecordMetricOption, +) (T, error) { + instr := getOperationMetrics(ctx).histogramFor(metric) + opts = append([]metrics.RecordMetricOption{withOperationMetadata(ctx)}, opts...) + + start := time.Now() + v, err := fn() + end := time.Now() + + elapsed := end.Sub(start) + instr.Record(ctx, float64(elapsed)/1e9, opts...) + return v, err +} + +func startMetricTimer(ctx context.Context, metric string, opts ...metrics.RecordMetricOption) func() { + instr := getOperationMetrics(ctx).histogramFor(metric) + opts = append([]metrics.RecordMetricOption{withOperationMetadata(ctx)}, opts...) + + var ended bool + start := time.Now() + return func() { + if ended { + return + } + ended = true + + end := time.Now() + + elapsed := end.Sub(start) + instr.Record(ctx, float64(elapsed)/1e9, opts...) + } +} + +func withOperationMetadata(ctx context.Context) metrics.RecordMetricOption { + return func(o *metrics.RecordMetricOptions) { + o.Properties.Set("rpc.service", middleware.GetServiceID(ctx)) + o.Properties.Set("rpc.method", middleware.GetOperationName(ctx)) + } +} + +type operationMetricsKey struct{} + +func withOperationMetrics(parent context.Context, mp metrics.MeterProvider) (context.Context, error) { + meter := mp.Meter("github.com/aws/aws-sdk-go-v2/service/sts") + om := &operationMetrics{} + + var err error + + om.Duration, err = operationMetricTimer(meter, "client.call.duration", + "Overall call duration (including retries and time to send or receive request and response body)") + if err != nil { + return nil, err + } + om.SerializeDuration, err = operationMetricTimer(meter, "client.call.serialization_duration", + "The time it takes to serialize a message body") + if err != nil { + return nil, err + } + om.ResolveIdentityDuration, err = operationMetricTimer(meter, "client.call.auth.resolve_identity_duration", + "The time taken to acquire an identity (AWS credentials, bearer token, etc) from an Identity Provider") + if err != nil { + return nil, err + } + om.ResolveEndpointDuration, err = operationMetricTimer(meter, "client.call.resolve_endpoint_duration", + "The time it takes to resolve an endpoint (endpoint resolver, not DNS) for the request") + if err != nil { + return nil, err + } + om.SignRequestDuration, err = operationMetricTimer(meter, "client.call.auth.signing_duration", + "The time it takes to sign a request") + if err != nil { + return nil, err + } + om.DeserializeDuration, err = operationMetricTimer(meter, "client.call.deserialization_duration", + "The time it takes to deserialize a message body") + if err != nil { + return nil, err + } + + return context.WithValue(parent, operationMetricsKey{}, om), nil +} + +func operationMetricTimer(m metrics.Meter, name, desc string) (metrics.Float64Histogram, error) { + return m.Float64Histogram(name, func(o *metrics.InstrumentOptions) { + o.UnitLabel = "s" + o.Description = desc + }) +} + +func getOperationMetrics(ctx context.Context) *operationMetrics { + return ctx.Value(operationMetricsKey{}).(*operationMetrics) +} + +func operationTracer(p tracing.TracerProvider) tracing.Tracer { + return p.Tracer("github.com/aws/aws-sdk-go-v2/service/sts") +} + // Client provides the API client to make operations call for AWS Security Token // Service. type Client struct { options Options + + // Difference between the time reported by the server and the client + timeOffset *atomic.Int64 } // New returns an initialized Client based on the functional options. Provide @@ -54,6 +190,10 @@ func New(options Options, optFns ...func(*Options)) *Client { resolveEndpointResolverV2(&options) + resolveTracerProvider(&options) + + resolveMeterProvider(&options) + resolveAuthSchemeResolver(&options) for _, fn := range optFns { @@ -72,6 +212,8 @@ func New(options Options, optFns ...func(*Options)) *Client { options: options, } + initializeTimeOffsetResolver(client) + return client } @@ -84,8 +226,15 @@ func (c *Client) Options() Options { return c.options.Copy() } -func (c *Client) invokeOperation(ctx context.Context, opID string, params interface{}, optFns []func(*Options), stackFns ...func(*middleware.Stack, Options) error) (result interface{}, metadata middleware.Metadata, err error) { +func (c *Client) invokeOperation( + ctx context.Context, opID string, params interface{}, optFns []func(*Options), stackFns ...func(*middleware.Stack, Options) error, +) ( + result interface{}, metadata middleware.Metadata, err error, +) { ctx = middleware.ClearStackValues(ctx) + ctx = middleware.WithServiceID(ctx, ServiceID) + ctx = middleware.WithOperationName(ctx, opID) + stack := middleware.NewStack(opID, smithyhttp.NewStackRequest) options := c.options.Copy() @@ -109,15 +258,56 @@ func (c *Client) invokeOperation(ctx context.Context, opID string, params interf } } - handler := middleware.DecorateHandler(smithyhttp.NewClientHandler(options.HTTPClient), stack) - result, metadata, err = handler.Handle(ctx, params) + ctx, err = withOperationMetrics(ctx, options.MeterProvider) if err != nil { + return nil, metadata, err + } + + tracer := operationTracer(options.TracerProvider) + spanName := fmt.Sprintf("%s.%s", ServiceID, opID) + + ctx = tracing.WithOperationTracer(ctx, tracer) + + ctx, span := tracer.StartSpan(ctx, spanName, func(o *tracing.SpanOptions) { + o.Kind = tracing.SpanKindClient + o.Properties.Set("rpc.system", "aws-api") + o.Properties.Set("rpc.method", opID) + o.Properties.Set("rpc.service", ServiceID) + }) + endTimer := startMetricTimer(ctx, "client.call.duration") + defer endTimer() + defer span.End() + + handler := smithyhttp.NewClientHandlerWithOptions(options.HTTPClient, func(o *smithyhttp.ClientHandler) { + o.Meter = options.MeterProvider.Meter("github.com/aws/aws-sdk-go-v2/service/sts") + }) + decorated := middleware.DecorateHandler(handler, stack) + result, metadata, err = decorated.Handle(ctx, params) + if err != nil { + span.SetProperty("exception.type", fmt.Sprintf("%T", err)) + span.SetProperty("exception.message", err.Error()) + + var aerr smithy.APIError + if errors.As(err, &aerr) { + span.SetProperty("api.error_code", aerr.ErrorCode()) + span.SetProperty("api.error_message", aerr.ErrorMessage()) + span.SetProperty("api.error_fault", aerr.ErrorFault().String()) + } + err = &smithy.OperationError{ ServiceID: ServiceID, OperationName: opID, Err: err, } } + + span.SetProperty("error", err != nil) + if err == nil { + span.SetStatus(tracing.SpanStatusOK) + } else { + span.SetStatus(tracing.SpanStatusError) + } + return result, metadata, err } @@ -155,7 +345,7 @@ func addProtocolFinalizerMiddlewares(stack *middleware.Stack, options Options, o if err := stack.Finalize.Insert(&resolveEndpointV2Middleware{options: options}, "GetIdentity", middleware.After); err != nil { return fmt.Errorf("add ResolveEndpointV2: %v", err) } - if err := stack.Finalize.Insert(&signRequestMiddleware{}, "ResolveEndpointV2", middleware.After); err != nil { + if err := stack.Finalize.Insert(&signRequestMiddleware{options: options}, "ResolveEndpointV2", middleware.After); err != nil { return fmt.Errorf("add Signing: %w", err) } return nil @@ -365,17 +555,37 @@ func resolveAWSEndpointResolver(cfg aws.Config, o *Options) { } func addClientUserAgent(stack *middleware.Stack, options Options) error { - if err := awsmiddleware.AddSDKAgentKeyValue(awsmiddleware.APIMetadata, "sts", goModuleVersion)(stack); err != nil { + ua, err := getOrAddRequestUserAgent(stack) + if err != nil { return err } + ua.AddSDKAgentKeyValue(awsmiddleware.APIMetadata, "sts", goModuleVersion) if len(options.AppID) > 0 { - return awsmiddleware.AddSDKAgentKey(awsmiddleware.ApplicationIdentifier, options.AppID)(stack) + ua.AddSDKAgentKey(awsmiddleware.ApplicationIdentifier, options.AppID) } return nil } +func getOrAddRequestUserAgent(stack *middleware.Stack) (*awsmiddleware.RequestUserAgent, error) { + id := (*awsmiddleware.RequestUserAgent)(nil).ID() + mw, ok := stack.Build.Get(id) + if !ok { + mw = awsmiddleware.NewRequestUserAgent() + if err := stack.Build.Add(mw, middleware.After); err != nil { + return nil, err + } + } + + ua, ok := mw.(*awsmiddleware.RequestUserAgent) + if !ok { + return nil, fmt.Errorf("%T for %s middleware did not match expected type", mw, id) + } + + return ua, nil +} + type HTTPSignerV4 interface { SignHTTP(ctx context.Context, credentials aws.Credentials, r *http.Request, payloadHash string, service string, region string, signingTime time.Time, optFns ...func(*v4.SignerOptions)) error } @@ -394,12 +604,97 @@ func newDefaultV4Signer(o Options) *v4.Signer { }) } -func addRetryMiddlewares(stack *middleware.Stack, o Options) error { - mo := retry.AddRetryMiddlewaresOptions{ - Retryer: o.Retryer, - LogRetryAttempts: o.ClientLogMode.IsRetries(), +func addClientRequestID(stack *middleware.Stack) error { + return stack.Build.Add(&awsmiddleware.ClientRequestID{}, middleware.After) +} + +func addComputeContentLength(stack *middleware.Stack) error { + return stack.Build.Add(&smithyhttp.ComputeContentLength{}, middleware.After) +} + +func addRawResponseToMetadata(stack *middleware.Stack) error { + return stack.Deserialize.Add(&awsmiddleware.AddRawResponse{}, middleware.Before) +} + +func addRecordResponseTiming(stack *middleware.Stack) error { + return stack.Deserialize.Add(&awsmiddleware.RecordResponseTiming{}, middleware.After) +} + +func addSpanRetryLoop(stack *middleware.Stack, options Options) error { + return stack.Finalize.Insert(&spanRetryLoop{options: options}, "Retry", middleware.Before) +} + +type spanRetryLoop struct { + options Options +} + +func (*spanRetryLoop) ID() string { + return "spanRetryLoop" +} + +func (m *spanRetryLoop) HandleFinalize( + ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler, +) ( + middleware.FinalizeOutput, middleware.Metadata, error, +) { + tracer := operationTracer(m.options.TracerProvider) + ctx, span := tracer.StartSpan(ctx, "RetryLoop") + defer span.End() + + return next.HandleFinalize(ctx, in) +} +func addStreamingEventsPayload(stack *middleware.Stack) error { + return stack.Finalize.Add(&v4.StreamingEventsPayload{}, middleware.Before) +} + +func addUnsignedPayload(stack *middleware.Stack) error { + return stack.Finalize.Insert(&v4.UnsignedPayload{}, "ResolveEndpointV2", middleware.After) +} + +func addComputePayloadSHA256(stack *middleware.Stack) error { + return stack.Finalize.Insert(&v4.ComputePayloadSHA256{}, "ResolveEndpointV2", middleware.After) +} + +func addContentSHA256Header(stack *middleware.Stack) error { + return stack.Finalize.Insert(&v4.ContentSHA256Header{}, (*v4.ComputePayloadSHA256)(nil).ID(), middleware.After) +} + +func addIsWaiterUserAgent(o *Options) { + o.APIOptions = append(o.APIOptions, func(stack *middleware.Stack) error { + ua, err := getOrAddRequestUserAgent(stack) + if err != nil { + return err + } + + ua.AddUserAgentFeature(awsmiddleware.UserAgentFeatureWaiter) + return nil + }) +} + +func addIsPaginatorUserAgent(o *Options) { + o.APIOptions = append(o.APIOptions, func(stack *middleware.Stack) error { + ua, err := getOrAddRequestUserAgent(stack) + if err != nil { + return err + } + + ua.AddUserAgentFeature(awsmiddleware.UserAgentFeaturePaginator) + return nil + }) +} + +func addRetry(stack *middleware.Stack, o Options) error { + attempt := retry.NewAttemptMiddleware(o.Retryer, smithyhttp.RequestCloner, func(m *retry.Attempt) { + m.LogAttempts = o.ClientLogMode.IsRetries() + m.OperationMeter = o.MeterProvider.Meter("github.com/aws/aws-sdk-go-v2/service/sts") + }) + if err := stack.Finalize.Insert(attempt, "ResolveAuthScheme", middleware.Before); err != nil { + return err } - return retry.AddRetryMiddlewares(stack, mo) + if err := stack.Finalize.Insert(&retry.MetricsHeader{}, attempt.ID(), middleware.After); err != nil { + return err + } + return nil } // resolves dual-stack endpoint configuration @@ -432,12 +727,68 @@ func resolveUseFIPSEndpoint(cfg aws.Config, o *Options) error { return nil } +func resolveAccountID(identity smithyauth.Identity, mode aws.AccountIDEndpointMode) *string { + if mode == aws.AccountIDEndpointModeDisabled { + return nil + } + + if ca, ok := identity.(*internalauthsmithy.CredentialsAdapter); ok && ca.Credentials.AccountID != "" { + return aws.String(ca.Credentials.AccountID) + } + + return nil +} + +func addTimeOffsetBuild(stack *middleware.Stack, c *Client) error { + mw := internalmiddleware.AddTimeOffsetMiddleware{Offset: c.timeOffset} + if err := stack.Build.Add(&mw, middleware.After); err != nil { + return err + } + return stack.Deserialize.Insert(&mw, "RecordResponseTiming", middleware.Before) +} +func initializeTimeOffsetResolver(c *Client) { + c.timeOffset = new(atomic.Int64) +} + +func addUserAgentRetryMode(stack *middleware.Stack, options Options) error { + ua, err := getOrAddRequestUserAgent(stack) + if err != nil { + return err + } + + switch options.Retryer.(type) { + case *retry.Standard: + ua.AddUserAgentFeature(awsmiddleware.UserAgentFeatureRetryModeStandard) + case *retry.AdaptiveMode: + ua.AddUserAgentFeature(awsmiddleware.UserAgentFeatureRetryModeAdaptive) + } + return nil +} + +func resolveTracerProvider(options *Options) { + if options.TracerProvider == nil { + options.TracerProvider = &tracing.NopTracerProvider{} + } +} + +func resolveMeterProvider(options *Options) { + if options.MeterProvider == nil { + options.MeterProvider = metrics.NopMeterProvider{} + } +} + +func addRecursionDetection(stack *middleware.Stack) error { + return stack.Build.Add(&awsmiddleware.RecursionDetection{}, middleware.After) +} + func addRequestIDRetrieverMiddleware(stack *middleware.Stack) error { - return awsmiddleware.AddRequestIDRetrieverMiddleware(stack) + return stack.Deserialize.Insert(&awsmiddleware.RequestIDRetriever{}, "OperationDeserializer", middleware.Before) + } func addResponseErrorMiddleware(stack *middleware.Stack) error { - return awshttp.AddResponseErrorMiddleware(stack) + return stack.Deserialize.Insert(&awshttp.ResponseErrorWrapper{}, "RequestIDRetriever", middleware.Before) + } // HTTPPresignerV4 represents presigner interface used by presign url client @@ -581,7 +932,7 @@ func (c presignConverter) convertToPresignMiddleware(stack *middleware.Stack, op if err != nil { return err } - err = presignedurlcust.AddAsIsPresigingMiddleware(stack) + err = presignedurlcust.AddAsIsPresigningMiddleware(stack) if err != nil { return err } @@ -625,3 +976,89 @@ func addDisableHTTPSMiddleware(stack *middleware.Stack, o Options) error { DisableHTTPS: o.EndpointOptions.DisableHTTPS, }, "ResolveEndpointV2", middleware.After) } + +type spanInitializeStart struct { +} + +func (*spanInitializeStart) ID() string { + return "spanInitializeStart" +} + +func (m *spanInitializeStart) HandleInitialize( + ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler, +) ( + middleware.InitializeOutput, middleware.Metadata, error, +) { + ctx, _ = tracing.StartSpan(ctx, "Initialize") + + return next.HandleInitialize(ctx, in) +} + +type spanInitializeEnd struct { +} + +func (*spanInitializeEnd) ID() string { + return "spanInitializeEnd" +} + +func (m *spanInitializeEnd) HandleInitialize( + ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler, +) ( + middleware.InitializeOutput, middleware.Metadata, error, +) { + ctx, span := tracing.PopSpan(ctx) + span.End() + + return next.HandleInitialize(ctx, in) +} + +type spanBuildRequestStart struct { +} + +func (*spanBuildRequestStart) ID() string { + return "spanBuildRequestStart" +} + +func (m *spanBuildRequestStart) HandleSerialize( + ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler, +) ( + middleware.SerializeOutput, middleware.Metadata, error, +) { + ctx, _ = tracing.StartSpan(ctx, "BuildRequest") + + return next.HandleSerialize(ctx, in) +} + +type spanBuildRequestEnd struct { +} + +func (*spanBuildRequestEnd) ID() string { + return "spanBuildRequestEnd" +} + +func (m *spanBuildRequestEnd) HandleBuild( + ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler, +) ( + middleware.BuildOutput, middleware.Metadata, error, +) { + ctx, span := tracing.PopSpan(ctx) + span.End() + + return next.HandleBuild(ctx, in) +} + +func addSpanInitializeStart(stack *middleware.Stack) error { + return stack.Initialize.Add(&spanInitializeStart{}, middleware.Before) +} + +func addSpanInitializeEnd(stack *middleware.Stack) error { + return stack.Initialize.Add(&spanInitializeEnd{}, middleware.After) +} + +func addSpanBuildRequestStart(stack *middleware.Stack) error { + return stack.Serialize.Add(&spanBuildRequestStart{}, middleware.Before) +} + +func addSpanBuildRequestEnd(stack *middleware.Stack) error { + return stack.Build.Add(&spanBuildRequestEnd{}, middleware.After) +} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRole.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRole.go index 2938dac..d056327 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRole.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRole.go @@ -16,69 +16,98 @@ import ( // Amazon Web Services resources. These temporary credentials consist of an access // key ID, a secret access key, and a security token. Typically, you use AssumeRole // within your account or for cross-account access. For a comparison of AssumeRole -// with other API operations that produce temporary credentials, see Requesting -// Temporary Security Credentials (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) -// and Comparing the Amazon Web Services STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) -// in the IAM User Guide. Permissions The temporary security credentials created by -// AssumeRole can be used to make API calls to any Amazon Web Services service -// with the following exception: You cannot call the Amazon Web Services STS -// GetFederationToken or GetSessionToken API operations. (Optional) You can pass -// inline or managed session policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) -// to this operation. You can pass a single JSON policy document to use as an -// inline session policy. You can also specify up to 10 managed policy Amazon -// Resource Names (ARNs) to use as managed session policies. The plaintext that you -// use for both inline and managed session policies can't exceed 2,048 characters. -// Passing policies to this operation returns new temporary credentials. The -// resulting session's permissions are the intersection of the role's -// identity-based policy and the session policies. You can use the role's temporary -// credentials in subsequent Amazon Web Services API calls to access resources in -// the account that owns the role. You cannot use session policies to grant more -// permissions than those allowed by the identity-based policy of the role that is -// being assumed. For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) -// in the IAM User Guide. When you create a role, you create two policies: a role -// trust policy that specifies who can assume the role, and a permissions policy -// that specifies what can be done with the role. You specify the trusted principal -// that is allowed to assume the role in the role trust policy. To assume a role -// from a different account, your Amazon Web Services account must be trusted by -// the role. The trust relationship is defined in the role's trust policy when the -// role is created. That trust policy states which accounts are allowed to delegate -// that access to users in the account. A user who wants to access a role in a -// different account must also have permissions that are delegated from the account -// administrator. The administrator must attach a policy that allows the user to -// call AssumeRole for the ARN of the role in the other account. To allow a user -// to assume a role in the same account, you can do either of the following: +// with other API operations that produce temporary credentials, see [Requesting Temporary Security Credentials]and [Compare STS credentials] in the +// IAM User Guide. +// +// # Permissions +// +// The temporary security credentials created by AssumeRole can be used to make +// API calls to any Amazon Web Services service with the following exception: You +// cannot call the Amazon Web Services STS GetFederationToken or GetSessionToken +// API operations. +// +// (Optional) You can pass inline or managed session policies to this operation. +// You can pass a single JSON policy document to use as an inline session policy. +// You can also specify up to 10 managed policy Amazon Resource Names (ARNs) to use +// as managed session policies. The plaintext that you use for both inline and +// managed session policies can't exceed 2,048 characters. Passing policies to this +// operation returns new temporary credentials. The resulting session's permissions +// are the intersection of the role's identity-based policy and the session +// policies. You can use the role's temporary credentials in subsequent Amazon Web +// Services API calls to access resources in the account that owns the role. You +// cannot use session policies to grant more permissions than those allowed by the +// identity-based policy of the role that is being assumed. For more information, +// see [Session Policies]in the IAM User Guide. +// +// When you create a role, you create two policies: a role trust policy that +// specifies who can assume the role, and a permissions policy that specifies what +// can be done with the role. You specify the trusted principal that is allowed to +// assume the role in the role trust policy. +// +// To assume a role from a different account, your Amazon Web Services account +// must be trusted by the role. The trust relationship is defined in the role's +// trust policy when the role is created. That trust policy states which accounts +// are allowed to delegate that access to users in the account. +// +// A user who wants to access a role in a different account must also have +// permissions that are delegated from the account administrator. The administrator +// must attach a policy that allows the user to call AssumeRole for the ARN of the +// role in the other account. +// +// To allow a user to assume a role in the same account, you can do either of the +// following: +// // - Attach a policy to the user that allows the user to call AssumeRole (as long // as the role's trust policy trusts the account). +// // - Add the user as a principal directly in the role's trust policy. // // You can do either because the role’s trust policy acts as an IAM resource-based // policy. When a resource-based policy grants access to a principal in the same // account, no additional identity-based policy is required. For more information -// about trust policies and resource-based policies, see IAM Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html) -// in the IAM User Guide. Tags (Optional) You can pass tag key-value pairs to your -// session. These tags are called session tags. For more information about session -// tags, see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) -// in the IAM User Guide. An administrator must grant you the permissions necessary -// to pass session tags. The administrator can also create granular permissions to -// allow you to pass only specific session tags. For more information, see -// Tutorial: Using Tags for Attribute-Based Access Control (https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html) -// in the IAM User Guide. You can set the session tags as transitive. Transitive -// tags persist during role chaining. For more information, see Chaining Roles -// with Session Tags (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining) -// in the IAM User Guide. Using MFA with AssumeRole (Optional) You can include -// multi-factor authentication (MFA) information when you call AssumeRole . This is -// useful for cross-account scenarios to ensure that the user that assumes the role -// has been authenticated with an Amazon Web Services MFA device. In that scenario, -// the trust policy of the role being assumed includes a condition that tests for -// MFA authentication. If the caller does not include valid MFA information, the -// request to assume the role is denied. The condition in a trust policy that tests -// for MFA authentication might look like the following example. "Condition": -// {"Bool": {"aws:MultiFactorAuthPresent": true}} For more information, see -// Configuring MFA-Protected API Access (https://docs.aws.amazon.com/IAM/latest/UserGuide/MFAProtectedAPI.html) -// in the IAM User Guide guide. To use MFA with AssumeRole , you pass values for -// the SerialNumber and TokenCode parameters. The SerialNumber value identifies -// the user's hardware or virtual MFA device. The TokenCode is the time-based -// one-time password (TOTP) that the MFA device produces. +// about trust policies and resource-based policies, see [IAM Policies]in the IAM User Guide. +// +// # Tags +// +// (Optional) You can pass tag key-value pairs to your session. These tags are +// called session tags. For more information about session tags, see [Passing Session Tags in STS]in the IAM +// User Guide. +// +// An administrator must grant you the permissions necessary to pass session tags. +// The administrator can also create granular permissions to allow you to pass only +// specific session tags. For more information, see [Tutorial: Using Tags for Attribute-Based Access Control]in the IAM User Guide. +// +// You can set the session tags as transitive. Transitive tags persist during role +// chaining. For more information, see [Chaining Roles with Session Tags]in the IAM User Guide. +// +// # Using MFA with AssumeRole +// +// (Optional) You can include multi-factor authentication (MFA) information when +// you call AssumeRole . This is useful for cross-account scenarios to ensure that +// the user that assumes the role has been authenticated with an Amazon Web +// Services MFA device. In that scenario, the trust policy of the role being +// assumed includes a condition that tests for MFA authentication. If the caller +// does not include valid MFA information, the request to assume the role is +// denied. The condition in a trust policy that tests for MFA authentication might +// look like the following example. +// +// "Condition": {"Bool": {"aws:MultiFactorAuthPresent": true}} +// +// For more information, see [Configuring MFA-Protected API Access] in the IAM User Guide guide. +// +// To use MFA with AssumeRole , you pass values for the SerialNumber and TokenCode +// parameters. The SerialNumber value identifies the user's hardware or virtual +// MFA device. The TokenCode is the time-based one-time password (TOTP) that the +// MFA device produces. +// +// [Configuring MFA-Protected API Access]: https://docs.aws.amazon.com/IAM/latest/UserGuide/MFAProtectedAPI.html +// [Session Policies]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session +// [Passing Session Tags in STS]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html +// [Chaining Roles with Session Tags]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining +// [IAM Policies]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html +// [Requesting Temporary Security Credentials]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html +// [Compare STS credentials]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_sts-comparison.html +// [Tutorial: Using Tags for Attribute-Based Access Control]: https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html func (c *Client) AssumeRole(ctx context.Context, params *AssumeRoleInput, optFns ...func(*Options)) (*AssumeRoleOutput, error) { if params == nil { params = &AssumeRoleInput{} @@ -101,17 +130,27 @@ type AssumeRoleInput struct { // This member is required. RoleArn *string - // An identifier for the assumed role session. Use the role session name to - // uniquely identify a session when the same role is assumed by different - // principals or for different reasons. In cross-account scenarios, the role - // session name is visible to, and can be logged by the account that owns the role. - // The role session name is also used in the ARN of the assumed role principal. - // This means that subsequent cross-account API requests that use the temporary - // security credentials will expose the role session name to the external account - // in their CloudTrail logs. The regex used to validate this parameter is a string - // of characters consisting of upper- and lower-case alphanumeric characters with - // no spaces. You can also include underscores or any of the following characters: - // =,.@- + // An identifier for the assumed role session. + // + // Use the role session name to uniquely identify a session when the same role is + // assumed by different principals or for different reasons. In cross-account + // scenarios, the role session name is visible to, and can be logged by the account + // that owns the role. The role session name is also used in the ARN of the assumed + // role principal. This means that subsequent cross-account API requests that use + // the temporary security credentials will expose the role session name to the + // external account in their CloudTrail logs. + // + // For security purposes, administrators can view this field in [CloudTrail logs] to help identify + // who performed an action in Amazon Web Services. Your administrator might require + // that you specify your user name as the session name when you assume the role. + // For more information, see [sts:RoleSessionName]sts:RoleSessionName . + // + // The regex used to validate this parameter is a string of characters consisting + // of upper- and lower-case alphanumeric characters with no spaces. You can also + // include underscores or any of the following characters: =,.@- + // + // [CloudTrail logs]: https://docs.aws.amazon.com/IAM/latest/UserGuide/cloudtrail-integration.html#cloudtrail-integration_signin-tempcreds + // [sts:RoleSessionName]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_iam-condition-keys.html#ck_rolesessionname // // This member is required. RoleSessionName *string @@ -122,23 +161,27 @@ type AssumeRoleInput struct { // hours. If you specify a value higher than this setting or the administrator // setting (whichever is lower), the operation fails. For example, if you specify a // session duration of 12 hours, but your administrator set the maximum session - // duration to 6 hours, your operation fails. Role chaining limits your Amazon Web - // Services CLI or Amazon Web Services API role session to a maximum of one hour. - // When you use the AssumeRole API operation to assume a role, you can specify the - // duration of your role session with the DurationSeconds parameter. You can - // specify a parameter value of up to 43200 seconds (12 hours), depending on the - // maximum session duration setting for your role. However, if you assume a role - // using role chaining and provide a DurationSeconds parameter value greater than - // one hour, the operation fails. To learn how to view the maximum value for your - // role, see View the Maximum Session Duration Setting for a Role (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session) - // in the IAM User Guide. By default, the value is set to 3600 seconds. The - // DurationSeconds parameter is separate from the duration of a console session - // that you might request using the returned credentials. The request to the - // federation endpoint for a console sign-in token takes a SessionDuration + // duration to 6 hours, your operation fails. + // + // Role chaining limits your Amazon Web Services CLI or Amazon Web Services API + // role session to a maximum of one hour. When you use the AssumeRole API + // operation to assume a role, you can specify the duration of your role session + // with the DurationSeconds parameter. You can specify a parameter value of up to + // 43200 seconds (12 hours), depending on the maximum session duration setting for + // your role. However, if you assume a role using role chaining and provide a + // DurationSeconds parameter value greater than one hour, the operation fails. To + // learn how to view the maximum value for your role, see [Update the maximum session duration for a role]. + // + // By default, the value is set to 3600 seconds. + // + // The DurationSeconds parameter is separate from the duration of a console + // session that you might request using the returned credentials. The request to + // the federation endpoint for a console sign-in token takes a SessionDuration // parameter that specifies the maximum length of the console session. For more - // information, see Creating a URL that Enables Federated Users to Access the - // Amazon Web Services Management Console (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html) - // in the IAM User Guide. + // information, see [Creating a URL that Enables Federated Users to Access the Amazon Web Services Management Console]in the IAM User Guide. + // + // [Update the maximum session duration for a role]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_update-role-settings.html#id_roles_update-session-duration + // [Creating a URL that Enables Federated Users to Access the Amazon Web Services Management Console]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html DurationSeconds *int32 // A unique identifier that might be required when you assume a role in another @@ -149,63 +192,82 @@ type AssumeRoleInput struct { // the administrator of the trusting account might send an external ID to the // administrator of the trusted account. That way, only someone with the ID can // assume the role, rather than everyone in the account. For more information about - // the external ID, see How to Use an External ID When Granting Access to Your - // Amazon Web Services Resources to a Third Party (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html) - // in the IAM User Guide. The regex used to validate this parameter is a string of - // characters consisting of upper- and lower-case alphanumeric characters with no - // spaces. You can also include underscores or any of the following characters: - // =,.@:/- + // the external ID, see [How to Use an External ID When Granting Access to Your Amazon Web Services Resources to a Third Party]in the IAM User Guide. + // + // The regex used to validate this parameter is a string of characters consisting + // of upper- and lower-case alphanumeric characters with no spaces. You can also + // include underscores or any of the following characters: =,.@:/- + // + // [How to Use an External ID When Granting Access to Your Amazon Web Services Resources to a Third Party]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html ExternalId *string // An IAM policy in JSON format that you want to use as an inline session policy. + // // This parameter is optional. Passing policies to this operation returns new // temporary credentials. The resulting session's permissions are the intersection // of the role's identity-based policy and the session policies. You can use the // role's temporary credentials in subsequent Amazon Web Services API calls to // access resources in the account that owns the role. You cannot use session // policies to grant more permissions than those allowed by the identity-based - // policy of the role that is being assumed. For more information, see Session - // Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) - // in the IAM User Guide. The plaintext that you use for both inline and managed - // session policies can't exceed 2,048 characters. The JSON policy characters can - // be any ASCII character from the space character to the end of the valid - // character list (\u0020 through \u00FF). It can also include the tab (\u0009), - // linefeed (\u000A), and carriage return (\u000D) characters. An Amazon Web - // Services conversion compresses the passed inline session policy, managed policy - // ARNs, and session tags into a packed binary format that has a separate limit. - // Your request can fail for this limit even if your plaintext meets the other - // requirements. The PackedPolicySize response element indicates by percentage how - // close the policies and tags for your request are to the upper size limit. + // policy of the role that is being assumed. For more information, see [Session Policies]in the IAM + // User Guide. + // + // The plaintext that you use for both inline and managed session policies can't + // exceed 2,048 characters. The JSON policy characters can be any ASCII character + // from the space character to the end of the valid character list (\u0020 through + // \u00FF). It can also include the tab (\u0009), linefeed (\u000A), and carriage + // return (\u000D) characters. + // + // An Amazon Web Services conversion compresses the passed inline session policy, + // managed policy ARNs, and session tags into a packed binary format that has a + // separate limit. Your request can fail for this limit even if your plaintext + // meets the other requirements. The PackedPolicySize response element indicates + // by percentage how close the policies and tags for your request are to the upper + // size limit. + // + // For more information about role session permissions, see [Session policies]. + // + // [Session Policies]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session + // [Session policies]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session Policy *string // The Amazon Resource Names (ARNs) of the IAM managed policies that you want to // use as managed session policies. The policies must exist in the same account as - // the role. This parameter is optional. You can provide up to 10 managed policy - // ARNs. However, the plaintext that you use for both inline and managed session - // policies can't exceed 2,048 characters. For more information about ARNs, see - // Amazon Resource Names (ARNs) and Amazon Web Services Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) - // in the Amazon Web Services General Reference. An Amazon Web Services conversion - // compresses the passed inline session policy, managed policy ARNs, and session - // tags into a packed binary format that has a separate limit. Your request can - // fail for this limit even if your plaintext meets the other requirements. The - // PackedPolicySize response element indicates by percentage how close the policies - // and tags for your request are to the upper size limit. Passing policies to this - // operation returns new temporary credentials. The resulting session's permissions - // are the intersection of the role's identity-based policy and the session - // policies. You can use the role's temporary credentials in subsequent Amazon Web - // Services API calls to access resources in the account that owns the role. You - // cannot use session policies to grant more permissions than those allowed by the - // identity-based policy of the role that is being assumed. For more information, - // see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) - // in the IAM User Guide. + // the role. + // + // This parameter is optional. You can provide up to 10 managed policy ARNs. + // However, the plaintext that you use for both inline and managed session policies + // can't exceed 2,048 characters. For more information about ARNs, see [Amazon Resource Names (ARNs) and Amazon Web Services Service Namespaces]in the + // Amazon Web Services General Reference. + // + // An Amazon Web Services conversion compresses the passed inline session policy, + // managed policy ARNs, and session tags into a packed binary format that has a + // separate limit. Your request can fail for this limit even if your plaintext + // meets the other requirements. The PackedPolicySize response element indicates + // by percentage how close the policies and tags for your request are to the upper + // size limit. + // + // Passing policies to this operation returns new temporary credentials. The + // resulting session's permissions are the intersection of the role's + // identity-based policy and the session policies. You can use the role's temporary + // credentials in subsequent Amazon Web Services API calls to access resources in + // the account that owns the role. You cannot use session policies to grant more + // permissions than those allowed by the identity-based policy of the role that is + // being assumed. For more information, see [Session Policies]in the IAM User Guide. + // + // [Session Policies]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session + // [Amazon Resource Names (ARNs) and Amazon Web Services Service Namespaces]: https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html PolicyArns []types.PolicyDescriptorType // A list of previously acquired trusted context assertions in the format of a // JSON array. The trusted context assertion is signed and encrypted by Amazon Web - // Services STS. The following is an example of a ProvidedContext value that - // includes a single trusted context assertion and the ARN of the context provider - // from which the trusted context assertion was generated. - // [{"ProviderArn":"arn:aws:iam::aws:contextProvider/IdentityCenter","ContextAssertion":"trusted-context-assertion"}] + // Services STS. + // + // The following is an example of a ProvidedContext value that includes a single + // trusted context assertion and the ARN of the context provider from which the + // trusted context assertion was generated. + // + // [{"ProviderArn":"arn:aws:iam::aws:contextProvider/IdentityCenter","ContextAssertion":"trusted-context-assertion"}] ProvidedContexts []types.ProvidedContext // The identification number of the MFA device that is associated with the user @@ -213,79 +275,99 @@ type AssumeRoleInput struct { // the role being assumed includes a condition that requires MFA authentication. // The value is either the serial number for a hardware device (such as // GAHT12345678 ) or an Amazon Resource Name (ARN) for a virtual device (such as - // arn:aws:iam::123456789012:mfa/user ). The regex used to validate this parameter - // is a string of characters consisting of upper- and lower-case alphanumeric - // characters with no spaces. You can also include underscores or any of the - // following characters: =,.@- + // arn:aws:iam::123456789012:mfa/user ). + // + // The regex used to validate this parameter is a string of characters consisting + // of upper- and lower-case alphanumeric characters with no spaces. You can also + // include underscores or any of the following characters: =,.@- SerialNumber *string // The source identity specified by the principal that is calling the AssumeRole - // operation. You can require users to specify a source identity when they assume a - // role. You do this by using the sts:SourceIdentity condition key in a role trust - // policy. You can use source identity information in CloudTrail logs to determine - // who took actions with a role. You can use the aws:SourceIdentity condition key - // to further control access to Amazon Web Services resources based on the value of - // source identity. For more information about using source identity, see Monitor - // and control actions taken with assumed roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html) - // in the IAM User Guide. The regex used to validate this parameter is a string of - // characters consisting of upper- and lower-case alphanumeric characters with no - // spaces. You can also include underscores or any of the following characters: - // =,.@-. You cannot use a value that begins with the text aws: . This prefix is - // reserved for Amazon Web Services internal use. + // operation. The source identity value persists across [chained role]sessions. + // + // You can require users to specify a source identity when they assume a role. You + // do this by using the [sts:SourceIdentity]sts:SourceIdentity condition key in a role trust policy. + // You can use source identity information in CloudTrail logs to determine who took + // actions with a role. You can use the aws:SourceIdentity condition key to + // further control access to Amazon Web Services resources based on the value of + // source identity. For more information about using source identity, see [Monitor and control actions taken with assumed roles]in the + // IAM User Guide. + // + // The regex used to validate this parameter is a string of characters consisting + // of upper- and lower-case alphanumeric characters with no spaces. You can also + // include underscores or any of the following characters: +=,.@-. You cannot use a + // value that begins with the text aws: . This prefix is reserved for Amazon Web + // Services internal use. + // + // [chained role]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html#iam-term-role-chaining + // [Monitor and control actions taken with assumed roles]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html + // [sts:SourceIdentity]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-sourceidentity SourceIdentity *string // A list of session tags that you want to pass. Each session tag consists of a - // key name and an associated value. For more information about session tags, see - // Tagging Amazon Web Services STS Sessions (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) - // in the IAM User Guide. This parameter is optional. You can pass up to 50 session - // tags. The plaintext session tag keys can’t exceed 128 characters, and the values - // can’t exceed 256 characters. For these and additional limits, see IAM and STS - // Character Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length) - // in the IAM User Guide. An Amazon Web Services conversion compresses the passed - // inline session policy, managed policy ARNs, and session tags into a packed - // binary format that has a separate limit. Your request can fail for this limit - // even if your plaintext meets the other requirements. The PackedPolicySize - // response element indicates by percentage how close the policies and tags for - // your request are to the upper size limit. You can pass a session tag with the - // same key as a tag that is already attached to the role. When you do, session - // tags override a role tag with the same key. Tag key–value pairs are not case - // sensitive, but case is preserved. This means that you cannot have separate - // Department and department tag keys. Assume that the role has the Department = - // Marketing tag and you pass the department = engineering session tag. Department - // and department are not saved as separate tags, and the session tag passed in - // the request takes precedence over the role tag. Additionally, if you used - // temporary credentials to perform this operation, the new session inherits any - // transitive session tags from the calling session. If you pass a session tag with - // the same key as an inherited tag, the operation fails. To view the inherited - // tags for a session, see the CloudTrail logs. For more information, see Viewing - // Session Tags in CloudTrail (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_ctlogs) + // key name and an associated value. For more information about session tags, see [Tagging Amazon Web Services STS Sessions] // in the IAM User Guide. + // + // This parameter is optional. You can pass up to 50 session tags. The plaintext + // session tag keys can’t exceed 128 characters, and the values can’t exceed 256 + // characters. For these and additional limits, see [IAM and STS Character Limits]in the IAM User Guide. + // + // An Amazon Web Services conversion compresses the passed inline session policy, + // managed policy ARNs, and session tags into a packed binary format that has a + // separate limit. Your request can fail for this limit even if your plaintext + // meets the other requirements. The PackedPolicySize response element indicates + // by percentage how close the policies and tags for your request are to the upper + // size limit. + // + // You can pass a session tag with the same key as a tag that is already attached + // to the role. When you do, session tags override a role tag with the same key. + // + // Tag key–value pairs are not case sensitive, but case is preserved. This means + // that you cannot have separate Department and department tag keys. Assume that + // the role has the Department = Marketing tag and you pass the department = + // engineering session tag. Department and department are not saved as separate + // tags, and the session tag passed in the request takes precedence over the role + // tag. + // + // Additionally, if you used temporary credentials to perform this operation, the + // new session inherits any transitive session tags from the calling session. If + // you pass a session tag with the same key as an inherited tag, the operation + // fails. To view the inherited tags for a session, see the CloudTrail logs. For + // more information, see [Viewing Session Tags in CloudTrail]in the IAM User Guide. + // + // [Tagging Amazon Web Services STS Sessions]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html + // [IAM and STS Character Limits]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length + // [Viewing Session Tags in CloudTrail]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_ctlogs Tags []types.Tag // The value provided by the MFA device, if the trust policy of the role being // assumed requires MFA. (In other words, if the policy includes a condition that // tests for MFA). If the role being assumed requires MFA and if the TokenCode // value is missing or expired, the AssumeRole call returns an "access denied" - // error. The format for this parameter, as described by its regex pattern, is a - // sequence of six numeric digits. + // error. + // + // The format for this parameter, as described by its regex pattern, is a sequence + // of six numeric digits. TokenCode *string // A list of keys for session tags that you want to set as transitive. If you set // a tag key as transitive, the corresponding key and value passes to subsequent - // sessions in a role chain. For more information, see Chaining Roles with Session - // Tags (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining) - // in the IAM User Guide. This parameter is optional. When you set session tags as - // transitive, the session policy and session tags packed binary limit is not - // affected. If you choose not to specify a transitive tag key, then no tags are - // passed from this session to any subsequent sessions. + // sessions in a role chain. For more information, see [Chaining Roles with Session Tags]in the IAM User Guide. + // + // This parameter is optional. The transitive status of a session tag does not + // impact its packed binary size. + // + // If you choose not to specify a transitive tag key, then no tags are passed from + // this session to any subsequent sessions. + // + // [Chaining Roles with Session Tags]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining TransitiveTagKeys []string noSmithyDocumentSerde } -// Contains the response to a successful AssumeRole request, including temporary -// Amazon Web Services credentials that can be used to make Amazon Web Services -// requests. +// Contains the response to a successful AssumeRole request, including temporary Amazon Web +// Services credentials that can be used to make Amazon Web Services requests. type AssumeRoleOutput struct { // The Amazon Resource Name (ARN) and the assumed role ID, which are identifiers @@ -296,9 +378,10 @@ type AssumeRoleOutput struct { AssumedRoleUser *types.AssumedRoleUser // The temporary security credentials, which include an access key ID, a secret - // access key, and a security (or session) token. The size of the security token - // that STS API operations return is not fixed. We strongly recommend that you make - // no assumptions about the maximum size. + // access key, and a security (or session) token. + // + // The size of the security token that STS API operations return is not fixed. We + // strongly recommend that you make no assumptions about the maximum size. Credentials *types.Credentials // A percentage value that indicates the packed size of the session policies and @@ -308,17 +391,21 @@ type AssumeRoleOutput struct { PackedPolicySize *int32 // The source identity specified by the principal that is calling the AssumeRole - // operation. You can require users to specify a source identity when they assume a - // role. You do this by using the sts:SourceIdentity condition key in a role trust - // policy. You can use source identity information in CloudTrail logs to determine - // who took actions with a role. You can use the aws:SourceIdentity condition key - // to further control access to Amazon Web Services resources based on the value of - // source identity. For more information about using source identity, see Monitor - // and control actions taken with assumed roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html) - // in the IAM User Guide. The regex used to validate this parameter is a string of - // characters consisting of upper- and lower-case alphanumeric characters with no - // spaces. You can also include underscores or any of the following characters: - // =,.@- + // operation. + // + // You can require users to specify a source identity when they assume a role. You + // do this by using the sts:SourceIdentity condition key in a role trust policy. + // You can use source identity information in CloudTrail logs to determine who took + // actions with a role. You can use the aws:SourceIdentity condition key to + // further control access to Amazon Web Services resources based on the value of + // source identity. For more information about using source identity, see [Monitor and control actions taken with assumed roles]in the + // IAM User Guide. + // + // The regex used to validate this parameter is a string of characters consisting + // of upper- and lower-case alphanumeric characters with no spaces. You can also + // include underscores or any of the following characters: =,.@- + // + // [Monitor and control actions taken with assumed roles]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html SourceIdentity *string // Metadata pertaining to the operation's result. @@ -349,25 +436,28 @@ func (c *Client) addOperationAssumeRoleMiddlewares(stack *middleware.Stack, opti if err = addSetLoggerMiddleware(stack, options); err != nil { return err } - if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + if err = addClientRequestID(stack); err != nil { return err } - if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + if err = addComputeContentLength(stack); err != nil { return err } if err = addResolveEndpointMiddleware(stack, options); err != nil { return err } - if err = v4.AddComputePayloadSHA256Middleware(stack); err != nil { + if err = addComputePayloadSHA256(stack); err != nil { return err } - if err = addRetryMiddlewares(stack, options); err != nil { + if err = addRetry(stack, options); err != nil { return err } - if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + if err = addRawResponseToMetadata(stack); err != nil { return err } - if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + if err = addRecordResponseTiming(stack); err != nil { + return err + } + if err = addSpanRetryLoop(stack, options); err != nil { return err } if err = addClientUserAgent(stack, options); err != nil { @@ -382,13 +472,19 @@ func (c *Client) addOperationAssumeRoleMiddlewares(stack *middleware.Stack, opti if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil { return err } + if err = addTimeOffsetBuild(stack, c); err != nil { + return err + } + if err = addUserAgentRetryMode(stack, options); err != nil { + return err + } if err = addOpAssumeRoleValidationMiddleware(stack); err != nil { return err } if err = stack.Initialize.Add(newServiceMetadataMiddleware_opAssumeRole(options.Region), middleware.Before); err != nil { return err } - if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + if err = addRecursionDetection(stack); err != nil { return err } if err = addRequestIDRetrieverMiddleware(stack); err != nil { @@ -403,6 +499,18 @@ func (c *Client) addOperationAssumeRoleMiddlewares(stack *middleware.Stack, opti if err = addDisableHTTPSMiddleware(stack, options); err != nil { return err } + if err = addSpanInitializeStart(stack); err != nil { + return err + } + if err = addSpanInitializeEnd(stack); err != nil { + return err + } + if err = addSpanBuildRequestStart(stack); err != nil { + return err + } + if err = addSpanBuildRequestEnd(stack); err != nil { + return err + } return nil } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRoleWithSAML.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRoleWithSAML.go index ef576b6..d0e117a 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRoleWithSAML.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRoleWithSAML.go @@ -16,92 +16,132 @@ import ( // mechanism for tying an enterprise identity store or directory to role-based // Amazon Web Services access without user-specific credentials or configuration. // For a comparison of AssumeRoleWithSAML with the other API operations that -// produce temporary credentials, see Requesting Temporary Security Credentials (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) -// and Comparing the Amazon Web Services STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) -// in the IAM User Guide. The temporary security credentials returned by this -// operation consist of an access key ID, a secret access key, and a security -// token. Applications can use these temporary security credentials to sign calls -// to Amazon Web Services services. Session Duration By default, the temporary -// security credentials created by AssumeRoleWithSAML last for one hour. However, -// you can use the optional DurationSeconds parameter to specify the duration of -// your session. Your role session lasts for the duration that you specify, or -// until the time specified in the SAML authentication response's -// SessionNotOnOrAfter value, whichever is shorter. You can provide a -// DurationSeconds value from 900 seconds (15 minutes) up to the maximum session -// duration setting for the role. This setting can have a value from 1 hour to 12 -// hours. To learn how to view the maximum value for your role, see View the -// Maximum Session Duration Setting for a Role (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session) -// in the IAM User Guide. The maximum session duration limit applies when you use -// the AssumeRole* API operations or the assume-role* CLI commands. However the -// limit does not apply when you use those operations to create a console URL. For -// more information, see Using IAM Roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html) -// in the IAM User Guide. Role chaining (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#iam-term-role-chaining) -// limits your CLI or Amazon Web Services API role session to a maximum of one +// produce temporary credentials, see [Requesting Temporary Security Credentials]and [Compare STS credentials] in the IAM User Guide. +// +// The temporary security credentials returned by this operation consist of an +// access key ID, a secret access key, and a security token. Applications can use +// these temporary security credentials to sign calls to Amazon Web Services +// services. +// +// # Session Duration +// +// By default, the temporary security credentials created by AssumeRoleWithSAML +// last for one hour. However, you can use the optional DurationSeconds parameter +// to specify the duration of your session. Your role session lasts for the +// duration that you specify, or until the time specified in the SAML +// authentication response's SessionNotOnOrAfter value, whichever is shorter. You +// can provide a DurationSeconds value from 900 seconds (15 minutes) up to the +// maximum session duration setting for the role. This setting can have a value +// from 1 hour to 12 hours. To learn how to view the maximum value for your role, +// see [View the Maximum Session Duration Setting for a Role]in the IAM User Guide. The maximum session duration limit applies when you +// use the AssumeRole* API operations or the assume-role* CLI commands. However +// the limit does not apply when you use those operations to create a console URL. +// For more information, see [Using IAM Roles]in the IAM User Guide. +// +// [Role chaining]limits your CLI or Amazon Web Services API role session to a maximum of one // hour. When you use the AssumeRole API operation to assume a role, you can // specify the duration of your role session with the DurationSeconds parameter. // You can specify a parameter value of up to 43200 seconds (12 hours), depending // on the maximum session duration setting for your role. However, if you assume a // role using role chaining and provide a DurationSeconds parameter value greater -// than one hour, the operation fails. Permissions The temporary security -// credentials created by AssumeRoleWithSAML can be used to make API calls to any -// Amazon Web Services service with the following exception: you cannot call the -// STS GetFederationToken or GetSessionToken API operations. (Optional) You can -// pass inline or managed session policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) -// to this operation. You can pass a single JSON policy document to use as an -// inline session policy. You can also specify up to 10 managed policy Amazon -// Resource Names (ARNs) to use as managed session policies. The plaintext that you -// use for both inline and managed session policies can't exceed 2,048 characters. -// Passing policies to this operation returns new temporary credentials. The -// resulting session's permissions are the intersection of the role's -// identity-based policy and the session policies. You can use the role's temporary -// credentials in subsequent Amazon Web Services API calls to access resources in -// the account that owns the role. You cannot use session policies to grant more -// permissions than those allowed by the identity-based policy of the role that is -// being assumed. For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) -// in the IAM User Guide. Calling AssumeRoleWithSAML does not require the use of -// Amazon Web Services security credentials. The identity of the caller is -// validated by using keys in the metadata document that is uploaded for the SAML -// provider entity for your identity provider. Calling AssumeRoleWithSAML can -// result in an entry in your CloudTrail logs. The entry includes the value in the -// NameID element of the SAML assertion. We recommend that you use a NameIDType -// that is not associated with any personally identifiable information (PII). For -// example, you could instead use the persistent identifier ( -// urn:oasis:names:tc:SAML:2.0:nameid-format:persistent ). Tags (Optional) You can -// configure your IdP to pass attributes into your SAML assertion as session tags. -// Each session tag consists of a key name and an associated value. For more -// information about session tags, see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) -// in the IAM User Guide. You can pass up to 50 session tags. The plaintext session -// tag keys can’t exceed 128 characters and the values can’t exceed 256 characters. -// For these and additional limits, see IAM and STS Character Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length) -// in the IAM User Guide. An Amazon Web Services conversion compresses the passed -// inline session policy, managed policy ARNs, and session tags into a packed -// binary format that has a separate limit. Your request can fail for this limit -// even if your plaintext meets the other requirements. The PackedPolicySize -// response element indicates by percentage how close the policies and tags for -// your request are to the upper size limit. You can pass a session tag with the -// same key as a tag that is attached to the role. When you do, session tags -// override the role's tags with the same key. An administrator must grant you the -// permissions necessary to pass session tags. The administrator can also create -// granular permissions to allow you to pass only specific session tags. For more -// information, see Tutorial: Using Tags for Attribute-Based Access Control (https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html) -// in the IAM User Guide. You can set the session tags as transitive. Transitive -// tags persist during role chaining. For more information, see Chaining Roles -// with Session Tags (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining) -// in the IAM User Guide. SAML Configuration Before your application can call -// AssumeRoleWithSAML , you must configure your SAML identity provider (IdP) to -// issue the claims required by Amazon Web Services. Additionally, you must use -// Identity and Access Management (IAM) to create a SAML provider entity in your -// Amazon Web Services account that represents your identity provider. You must -// also create an IAM role that specifies this SAML provider in its trust policy. +// than one hour, the operation fails. +// +// # Permissions +// +// The temporary security credentials created by AssumeRoleWithSAML can be used to +// make API calls to any Amazon Web Services service with the following exception: +// you cannot call the STS GetFederationToken or GetSessionToken API operations. +// +// (Optional) You can pass inline or managed [session policies] to this operation. You can pass a +// single JSON policy document to use as an inline session policy. You can also +// specify up to 10 managed policy Amazon Resource Names (ARNs) to use as managed +// session policies. The plaintext that you use for both inline and managed session +// policies can't exceed 2,048 characters. Passing policies to this operation +// returns new temporary credentials. The resulting session's permissions are the +// intersection of the role's identity-based policy and the session policies. You +// can use the role's temporary credentials in subsequent Amazon Web Services API +// calls to access resources in the account that owns the role. You cannot use +// session policies to grant more permissions than those allowed by the +// identity-based policy of the role that is being assumed. For more information, +// see [Session Policies]in the IAM User Guide. +// +// Calling AssumeRoleWithSAML does not require the use of Amazon Web Services +// security credentials. The identity of the caller is validated by using keys in +// the metadata document that is uploaded for the SAML provider entity for your +// identity provider. +// +// Calling AssumeRoleWithSAML can result in an entry in your CloudTrail logs. The +// entry includes the value in the NameID element of the SAML assertion. We +// recommend that you use a NameIDType that is not associated with any personally +// identifiable information (PII). For example, you could instead use the +// persistent identifier ( urn:oasis:names:tc:SAML:2.0:nameid-format:persistent ). +// +// # Tags +// +// (Optional) You can configure your IdP to pass attributes into your SAML +// assertion as session tags. Each session tag consists of a key name and an +// associated value. For more information about session tags, see [Passing Session Tags in STS]in the IAM User +// Guide. +// +// You can pass up to 50 session tags. The plaintext session tag keys can’t exceed +// 128 characters and the values can’t exceed 256 characters. For these and +// additional limits, see [IAM and STS Character Limits]in the IAM User Guide. +// +// An Amazon Web Services conversion compresses the passed inline session policy, +// managed policy ARNs, and session tags into a packed binary format that has a +// separate limit. Your request can fail for this limit even if your plaintext +// meets the other requirements. The PackedPolicySize response element indicates +// by percentage how close the policies and tags for your request are to the upper +// size limit. +// +// You can pass a session tag with the same key as a tag that is attached to the +// role. When you do, session tags override the role's tags with the same key. +// +// An administrator must grant you the permissions necessary to pass session tags. +// The administrator can also create granular permissions to allow you to pass only +// specific session tags. For more information, see [Tutorial: Using Tags for Attribute-Based Access Control]in the IAM User Guide. +// +// You can set the session tags as transitive. Transitive tags persist during role +// chaining. For more information, see [Chaining Roles with Session Tags]in the IAM User Guide. +// +// # SAML Configuration +// +// Before your application can call AssumeRoleWithSAML , you must configure your +// SAML identity provider (IdP) to issue the claims required by Amazon Web +// Services. Additionally, you must use Identity and Access Management (IAM) to +// create a SAML provider entity in your Amazon Web Services account that +// represents your identity provider. You must also create an IAM role that +// specifies this SAML provider in its trust policy. +// // For more information, see the following resources: -// - About SAML 2.0-based Federation (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_saml.html) -// in the IAM User Guide. -// - Creating SAML Identity Providers (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_saml.html) -// in the IAM User Guide. -// - Configuring a Relying Party and Claims (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_saml_relying-party.html) -// in the IAM User Guide. -// - Creating a Role for SAML 2.0 Federation (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-idp_saml.html) -// in the IAM User Guide. +// +// [About SAML 2.0-based Federation] +// - in the IAM User Guide. +// +// [Creating SAML Identity Providers] +// - in the IAM User Guide. +// +// [Configuring a Relying Party and Claims] +// - in the IAM User Guide. +// +// [Creating a Role for SAML 2.0 Federation] +// - in the IAM User Guide. +// +// [View the Maximum Session Duration Setting for a Role]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session +// [Creating a Role for SAML 2.0 Federation]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-idp_saml.html +// [IAM and STS Character Limits]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length +// [Creating SAML Identity Providers]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_saml.html +// [session policies]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session +// [Requesting Temporary Security Credentials]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html +// [Compare STS credentials]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_sts-comparison.html +// [Tutorial: Using Tags for Attribute-Based Access Control]: https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html +// [Configuring a Relying Party and Claims]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_saml_relying-party.html +// [Role chaining]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#iam-term-role-chaining +// [Using IAM Roles]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html +// [Session Policies]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session +// [Passing Session Tags in STS]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html +// [About SAML 2.0-based Federation]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_saml.html +// [Chaining Roles with Session Tags]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining func (c *Client) AssumeRoleWithSAML(ctx context.Context, params *AssumeRoleWithSAMLInput, optFns ...func(*Options)) (*AssumeRoleWithSAMLOutput, error) { if params == nil { params = &AssumeRoleWithSAMLInput{} @@ -130,9 +170,11 @@ type AssumeRoleWithSAMLInput struct { // This member is required. RoleArn *string - // The base64 encoded SAML authentication response provided by the IdP. For more - // information, see Configuring a Relying Party and Adding Claims (https://docs.aws.amazon.com/IAM/latest/UserGuide/create-role-saml-IdP-tasks.html) - // in the IAM User Guide. + // The base64 encoded SAML authentication response provided by the IdP. + // + // For more information, see [Configuring a Relying Party and Adding Claims] in the IAM User Guide. + // + // [Configuring a Relying Party and Adding Claims]: https://docs.aws.amazon.com/IAM/latest/UserGuide/create-role-saml-IdP-tasks.html // // This member is required. SAMLAssertion *string @@ -146,92 +188,117 @@ type AssumeRoleWithSAMLInput struct { // than this setting, the operation fails. For example, if you specify a session // duration of 12 hours, but your administrator set the maximum session duration to // 6 hours, your operation fails. To learn how to view the maximum value for your - // role, see View the Maximum Session Duration Setting for a Role (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session) - // in the IAM User Guide. By default, the value is set to 3600 seconds. The - // DurationSeconds parameter is separate from the duration of a console session - // that you might request using the returned credentials. The request to the - // federation endpoint for a console sign-in token takes a SessionDuration + // role, see [View the Maximum Session Duration Setting for a Role]in the IAM User Guide. + // + // By default, the value is set to 3600 seconds. + // + // The DurationSeconds parameter is separate from the duration of a console + // session that you might request using the returned credentials. The request to + // the federation endpoint for a console sign-in token takes a SessionDuration // parameter that specifies the maximum length of the console session. For more - // information, see Creating a URL that Enables Federated Users to Access the - // Amazon Web Services Management Console (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html) - // in the IAM User Guide. + // information, see [Creating a URL that Enables Federated Users to Access the Amazon Web Services Management Console]in the IAM User Guide. + // + // [View the Maximum Session Duration Setting for a Role]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session + // [Creating a URL that Enables Federated Users to Access the Amazon Web Services Management Console]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html DurationSeconds *int32 // An IAM policy in JSON format that you want to use as an inline session policy. + // // This parameter is optional. Passing policies to this operation returns new // temporary credentials. The resulting session's permissions are the intersection // of the role's identity-based policy and the session policies. You can use the // role's temporary credentials in subsequent Amazon Web Services API calls to // access resources in the account that owns the role. You cannot use session // policies to grant more permissions than those allowed by the identity-based - // policy of the role that is being assumed. For more information, see Session - // Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) - // in the IAM User Guide. The plaintext that you use for both inline and managed - // session policies can't exceed 2,048 characters. The JSON policy characters can - // be any ASCII character from the space character to the end of the valid - // character list (\u0020 through \u00FF). It can also include the tab (\u0009), - // linefeed (\u000A), and carriage return (\u000D) characters. An Amazon Web - // Services conversion compresses the passed inline session policy, managed policy - // ARNs, and session tags into a packed binary format that has a separate limit. - // Your request can fail for this limit even if your plaintext meets the other - // requirements. The PackedPolicySize response element indicates by percentage how - // close the policies and tags for your request are to the upper size limit. + // policy of the role that is being assumed. For more information, see [Session Policies]in the IAM + // User Guide. + // + // The plaintext that you use for both inline and managed session policies can't + // exceed 2,048 characters. The JSON policy characters can be any ASCII character + // from the space character to the end of the valid character list (\u0020 through + // \u00FF). It can also include the tab (\u0009), linefeed (\u000A), and carriage + // return (\u000D) characters. + // + // For more information about role session permissions, see [Session policies]. + // + // An Amazon Web Services conversion compresses the passed inline session policy, + // managed policy ARNs, and session tags into a packed binary format that has a + // separate limit. Your request can fail for this limit even if your plaintext + // meets the other requirements. The PackedPolicySize response element indicates + // by percentage how close the policies and tags for your request are to the upper + // size limit. + // + // [Session Policies]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session + // [Session policies]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session Policy *string // The Amazon Resource Names (ARNs) of the IAM managed policies that you want to // use as managed session policies. The policies must exist in the same account as - // the role. This parameter is optional. You can provide up to 10 managed policy - // ARNs. However, the plaintext that you use for both inline and managed session - // policies can't exceed 2,048 characters. For more information about ARNs, see - // Amazon Resource Names (ARNs) and Amazon Web Services Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) - // in the Amazon Web Services General Reference. An Amazon Web Services conversion - // compresses the passed inline session policy, managed policy ARNs, and session - // tags into a packed binary format that has a separate limit. Your request can - // fail for this limit even if your plaintext meets the other requirements. The - // PackedPolicySize response element indicates by percentage how close the policies - // and tags for your request are to the upper size limit. Passing policies to this - // operation returns new temporary credentials. The resulting session's permissions - // are the intersection of the role's identity-based policy and the session - // policies. You can use the role's temporary credentials in subsequent Amazon Web - // Services API calls to access resources in the account that owns the role. You - // cannot use session policies to grant more permissions than those allowed by the - // identity-based policy of the role that is being assumed. For more information, - // see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) - // in the IAM User Guide. + // the role. + // + // This parameter is optional. You can provide up to 10 managed policy ARNs. + // However, the plaintext that you use for both inline and managed session policies + // can't exceed 2,048 characters. For more information about ARNs, see [Amazon Resource Names (ARNs) and Amazon Web Services Service Namespaces]in the + // Amazon Web Services General Reference. + // + // An Amazon Web Services conversion compresses the passed inline session policy, + // managed policy ARNs, and session tags into a packed binary format that has a + // separate limit. Your request can fail for this limit even if your plaintext + // meets the other requirements. The PackedPolicySize response element indicates + // by percentage how close the policies and tags for your request are to the upper + // size limit. + // + // Passing policies to this operation returns new temporary credentials. The + // resulting session's permissions are the intersection of the role's + // identity-based policy and the session policies. You can use the role's temporary + // credentials in subsequent Amazon Web Services API calls to access resources in + // the account that owns the role. You cannot use session policies to grant more + // permissions than those allowed by the identity-based policy of the role that is + // being assumed. For more information, see [Session Policies]in the IAM User Guide. + // + // [Session Policies]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session + // [Amazon Resource Names (ARNs) and Amazon Web Services Service Namespaces]: https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html PolicyArns []types.PolicyDescriptorType noSmithyDocumentSerde } -// Contains the response to a successful AssumeRoleWithSAML request, including -// temporary Amazon Web Services credentials that can be used to make Amazon Web -// Services requests. +// Contains the response to a successful AssumeRoleWithSAML request, including temporary Amazon Web +// Services credentials that can be used to make Amazon Web Services requests. type AssumeRoleWithSAMLOutput struct { // The identifiers for the temporary security credentials that the operation // returns. AssumedRoleUser *types.AssumedRoleUser - // The value of the Recipient attribute of the SubjectConfirmationData element of + // The value of the Recipient attribute of the SubjectConfirmationData element of // the SAML assertion. Audience *string // The temporary security credentials, which include an access key ID, a secret - // access key, and a security (or session) token. The size of the security token - // that STS API operations return is not fixed. We strongly recommend that you make - // no assumptions about the maximum size. + // access key, and a security (or session) token. + // + // The size of the security token that STS API operations return is not fixed. We + // strongly recommend that you make no assumptions about the maximum size. Credentials *types.Credentials // The value of the Issuer element of the SAML assertion. Issuer *string // A hash value based on the concatenation of the following: + // // - The Issuer response value. + // // - The Amazon Web Services account ID. + // // - The friendly name (the last part of the ARN) of the SAML provider in IAM. + // // The combination of NameQualifier and Subject can be used to uniquely identify a - // user. The following pseudocode shows how the hash value is calculated: BASE64 ( - // SHA1 ( "https://example.com/saml" + "123456789012" + "/MySAMLIdP" ) ) + // user. + // + // The following pseudocode shows how the hash value is calculated: + // + // BASE64 ( SHA1 ( "https://example.com/saml" + "123456789012" + "/MySAMLIdP" ) ) NameQualifier *string // A percentage value that indicates the packed size of the session policies and @@ -240,31 +307,37 @@ type AssumeRoleWithSAMLOutput struct { // allowed space. PackedPolicySize *int32 - // The value in the SourceIdentity attribute in the SAML assertion. You can - // require users to set a source identity value when they assume a role. You do - // this by using the sts:SourceIdentity condition key in a role trust policy. That - // way, actions that are taken with the role are associated with that user. After - // the source identity is set, the value cannot be changed. It is present in the - // request for all actions that are taken by the role and persists across chained - // role (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts#iam-term-role-chaining) - // sessions. You can configure your SAML identity provider to use an attribute - // associated with your users, like user name or email, as the source identity when - // calling AssumeRoleWithSAML . You do this by adding an attribute to the SAML - // assertion. For more information about using source identity, see Monitor and - // control actions taken with assumed roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html) - // in the IAM User Guide. The regex used to validate this parameter is a string of - // characters consisting of upper- and lower-case alphanumeric characters with no - // spaces. You can also include underscores or any of the following characters: - // =,.@- + // The value in the SourceIdentity attribute in the SAML assertion. The source + // identity value persists across [chained role]sessions. + // + // You can require users to set a source identity value when they assume a role. + // You do this by using the sts:SourceIdentity condition key in a role trust + // policy. That way, actions that are taken with the role are associated with that + // user. After the source identity is set, the value cannot be changed. It is + // present in the request for all actions that are taken by the role and persists + // across [chained role]sessions. You can configure your SAML identity provider to use an + // attribute associated with your users, like user name or email, as the source + // identity when calling AssumeRoleWithSAML . You do this by adding an attribute to + // the SAML assertion. For more information about using source identity, see [Monitor and control actions taken with assumed roles]in + // the IAM User Guide. + // + // The regex used to validate this parameter is a string of characters consisting + // of upper- and lower-case alphanumeric characters with no spaces. You can also + // include underscores or any of the following characters: =,.@- + // + // [chained role]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html#id_roles_terms-and-concepts + // [Monitor and control actions taken with assumed roles]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html SourceIdentity *string // The value of the NameID element in the Subject element of the SAML assertion. Subject *string - // The format of the name ID, as defined by the Format attribute in the NameID + // The format of the name ID, as defined by the Format attribute in the NameID // element of the SAML assertion. Typical examples of the format are transient or - // persistent . If the format includes the prefix - // urn:oasis:names:tc:SAML:2.0:nameid-format , that prefix is removed. For example, + // persistent . + // + // If the format includes the prefix urn:oasis:names:tc:SAML:2.0:nameid-format , + // that prefix is removed. For example, // urn:oasis:names:tc:SAML:2.0:nameid-format:transient is returned as transient . // If the format includes any other prefix, the format is returned with no // modifications. @@ -298,22 +371,25 @@ func (c *Client) addOperationAssumeRoleWithSAMLMiddlewares(stack *middleware.Sta if err = addSetLoggerMiddleware(stack, options); err != nil { return err } - if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + if err = addClientRequestID(stack); err != nil { return err } - if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + if err = addComputeContentLength(stack); err != nil { return err } if err = addResolveEndpointMiddleware(stack, options); err != nil { return err } - if err = addRetryMiddlewares(stack, options); err != nil { + if err = addRetry(stack, options); err != nil { return err } - if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + if err = addRawResponseToMetadata(stack); err != nil { return err } - if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + if err = addRecordResponseTiming(stack); err != nil { + return err + } + if err = addSpanRetryLoop(stack, options); err != nil { return err } if err = addClientUserAgent(stack, options); err != nil { @@ -328,13 +404,19 @@ func (c *Client) addOperationAssumeRoleWithSAMLMiddlewares(stack *middleware.Sta if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil { return err } + if err = addTimeOffsetBuild(stack, c); err != nil { + return err + } + if err = addUserAgentRetryMode(stack, options); err != nil { + return err + } if err = addOpAssumeRoleWithSAMLValidationMiddleware(stack); err != nil { return err } if err = stack.Initialize.Add(newServiceMetadataMiddleware_opAssumeRoleWithSAML(options.Region), middleware.Before); err != nil { return err } - if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + if err = addRecursionDetection(stack); err != nil { return err } if err = addRequestIDRetrieverMiddleware(stack); err != nil { @@ -349,6 +431,18 @@ func (c *Client) addOperationAssumeRoleWithSAMLMiddlewares(stack *middleware.Sta if err = addDisableHTTPSMiddleware(stack, options); err != nil { return err } + if err = addSpanInitializeStart(stack); err != nil { + return err + } + if err = addSpanInitializeEnd(stack); err != nil { + return err + } + if err = addSpanBuildRequestStart(stack); err != nil { + return err + } + if err = addSpanBuildRequestEnd(stack); err != nil { + return err + } return nil } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRoleWithWebIdentity.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRoleWithWebIdentity.go index b2f126b..0ae4bc1 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRoleWithWebIdentity.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRoleWithWebIdentity.go @@ -14,105 +14,132 @@ import ( // Returns a set of temporary security credentials for users who have been // authenticated in a mobile or web application with a web identity provider. // Example providers include the OAuth 2.0 providers Login with Amazon and -// Facebook, or any OpenID Connect-compatible identity provider such as Google or -// Amazon Cognito federated identities (https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-identity.html) -// . For mobile applications, we recommend that you use Amazon Cognito. You can use -// Amazon Cognito with the Amazon Web Services SDK for iOS Developer Guide (http://aws.amazon.com/sdkforios/) -// and the Amazon Web Services SDK for Android Developer Guide (http://aws.amazon.com/sdkforandroid/) -// to uniquely identify a user. You can also supply the user with a consistent -// identity throughout the lifetime of an application. To learn more about Amazon -// Cognito, see Amazon Cognito identity pools (https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-identity.html) -// in Amazon Cognito Developer Guide. Calling AssumeRoleWithWebIdentity does not -// require the use of Amazon Web Services security credentials. Therefore, you can -// distribute an application (for example, on mobile devices) that requests -// temporary security credentials without including long-term Amazon Web Services -// credentials in the application. You also don't need to deploy server-based proxy -// services that use long-term Amazon Web Services credentials. Instead, the -// identity of the caller is validated by using a token from the web identity -// provider. For a comparison of AssumeRoleWithWebIdentity with the other API -// operations that produce temporary credentials, see Requesting Temporary -// Security Credentials (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) -// and Comparing the Amazon Web Services STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) -// in the IAM User Guide. The temporary security credentials returned by this API -// consist of an access key ID, a secret access key, and a security token. -// Applications can use these temporary security credentials to sign calls to -// Amazon Web Services service API operations. Session Duration By default, the -// temporary security credentials created by AssumeRoleWithWebIdentity last for -// one hour. However, you can use the optional DurationSeconds parameter to -// specify the duration of your session. You can provide a value from 900 seconds -// (15 minutes) up to the maximum session duration setting for the role. This -// setting can have a value from 1 hour to 12 hours. To learn how to view the -// maximum value for your role, see View the Maximum Session Duration Setting for -// a Role (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session) -// in the IAM User Guide. The maximum session duration limit applies when you use -// the AssumeRole* API operations or the assume-role* CLI commands. However the -// limit does not apply when you use those operations to create a console URL. For -// more information, see Using IAM Roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html) -// in the IAM User Guide. Permissions The temporary security credentials created by -// AssumeRoleWithWebIdentity can be used to make API calls to any Amazon Web -// Services service with the following exception: you cannot call the STS -// GetFederationToken or GetSessionToken API operations. (Optional) You can pass -// inline or managed session policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) -// to this operation. You can pass a single JSON policy document to use as an -// inline session policy. You can also specify up to 10 managed policy Amazon -// Resource Names (ARNs) to use as managed session policies. The plaintext that you -// use for both inline and managed session policies can't exceed 2,048 characters. -// Passing policies to this operation returns new temporary credentials. The -// resulting session's permissions are the intersection of the role's -// identity-based policy and the session policies. You can use the role's temporary -// credentials in subsequent Amazon Web Services API calls to access resources in -// the account that owns the role. You cannot use session policies to grant more -// permissions than those allowed by the identity-based policy of the role that is -// being assumed. For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) -// in the IAM User Guide. Tags (Optional) You can configure your IdP to pass -// attributes into your web identity token as session tags. Each session tag -// consists of a key name and an associated value. For more information about -// session tags, see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) -// in the IAM User Guide. You can pass up to 50 session tags. The plaintext session -// tag keys can’t exceed 128 characters and the values can’t exceed 256 characters. -// For these and additional limits, see IAM and STS Character Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length) -// in the IAM User Guide. An Amazon Web Services conversion compresses the passed -// inline session policy, managed policy ARNs, and session tags into a packed -// binary format that has a separate limit. Your request can fail for this limit -// even if your plaintext meets the other requirements. The PackedPolicySize -// response element indicates by percentage how close the policies and tags for -// your request are to the upper size limit. You can pass a session tag with the -// same key as a tag that is attached to the role. When you do, the session tag -// overrides the role tag with the same key. An administrator must grant you the -// permissions necessary to pass session tags. The administrator can also create -// granular permissions to allow you to pass only specific session tags. For more -// information, see Tutorial: Using Tags for Attribute-Based Access Control (https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html) -// in the IAM User Guide. You can set the session tags as transitive. Transitive -// tags persist during role chaining. For more information, see Chaining Roles -// with Session Tags (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining) -// in the IAM User Guide. Identities Before your application can call -// AssumeRoleWithWebIdentity , you must have an identity token from a supported -// identity provider and create a role that the application can assume. The role -// that your application assumes must trust the identity provider that is -// associated with the identity token. In other words, the identity provider must -// be specified in the role's trust policy. Calling AssumeRoleWithWebIdentity can -// result in an entry in your CloudTrail logs. The entry includes the Subject (http://openid.net/specs/openid-connect-core-1_0.html#Claims) -// of the provided web identity token. We recommend that you avoid using any -// personally identifiable information (PII) in this field. For example, you could -// instead use a GUID or a pairwise identifier, as suggested in the OIDC -// specification (http://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes) -// . For more information about how to use web identity federation and the +// Facebook, or any OpenID Connect-compatible identity provider such as Google or [Amazon Cognito federated identities]. +// +// For mobile applications, we recommend that you use Amazon Cognito. You can use +// Amazon Cognito with the [Amazon Web Services SDK for iOS Developer Guide]and the [Amazon Web Services SDK for Android Developer Guide] to uniquely identify a user. You can also +// supply the user with a consistent identity throughout the lifetime of an +// application. +// +// To learn more about Amazon Cognito, see [Amazon Cognito identity pools] in Amazon Cognito Developer Guide. +// +// Calling AssumeRoleWithWebIdentity does not require the use of Amazon Web +// Services security credentials. Therefore, you can distribute an application (for +// example, on mobile devices) that requests temporary security credentials without +// including long-term Amazon Web Services credentials in the application. You also +// don't need to deploy server-based proxy services that use long-term Amazon Web +// Services credentials. Instead, the identity of the caller is validated by using +// a token from the web identity provider. For a comparison of +// AssumeRoleWithWebIdentity with the other API operations that produce temporary +// credentials, see [Requesting Temporary Security Credentials]and [Compare STS credentials] in the IAM User Guide. +// +// The temporary security credentials returned by this API consist of an access +// key ID, a secret access key, and a security token. Applications can use these +// temporary security credentials to sign calls to Amazon Web Services service API +// operations. +// +// # Session Duration +// +// By default, the temporary security credentials created by +// AssumeRoleWithWebIdentity last for one hour. However, you can use the optional +// DurationSeconds parameter to specify the duration of your session. You can +// provide a value from 900 seconds (15 minutes) up to the maximum session duration +// setting for the role. This setting can have a value from 1 hour to 12 hours. To +// learn how to view the maximum value for your role, see [Update the maximum session duration for a role]in the IAM User Guide. +// The maximum session duration limit applies when you use the AssumeRole* API +// operations or the assume-role* CLI commands. However the limit does not apply +// when you use those operations to create a console URL. For more information, see +// [Using IAM Roles]in the IAM User Guide. +// +// # Permissions +// +// The temporary security credentials created by AssumeRoleWithWebIdentity can be +// used to make API calls to any Amazon Web Services service with the following +// exception: you cannot call the STS GetFederationToken or GetSessionToken API +// operations. +// +// (Optional) You can pass inline or managed [session policies] to this operation. You can pass a +// single JSON policy document to use as an inline session policy. You can also +// specify up to 10 managed policy Amazon Resource Names (ARNs) to use as managed +// session policies. The plaintext that you use for both inline and managed session +// policies can't exceed 2,048 characters. Passing policies to this operation +// returns new temporary credentials. The resulting session's permissions are the +// intersection of the role's identity-based policy and the session policies. You +// can use the role's temporary credentials in subsequent Amazon Web Services API +// calls to access resources in the account that owns the role. You cannot use +// session policies to grant more permissions than those allowed by the +// identity-based policy of the role that is being assumed. For more information, +// see [Session Policies]in the IAM User Guide. +// +// # Tags +// +// (Optional) You can configure your IdP to pass attributes into your web identity +// token as session tags. Each session tag consists of a key name and an associated +// value. For more information about session tags, see [Passing Session Tags in STS]in the IAM User Guide. +// +// You can pass up to 50 session tags. The plaintext session tag keys can’t exceed +// 128 characters and the values can’t exceed 256 characters. For these and +// additional limits, see [IAM and STS Character Limits]in the IAM User Guide. +// +// An Amazon Web Services conversion compresses the passed inline session policy, +// managed policy ARNs, and session tags into a packed binary format that has a +// separate limit. Your request can fail for this limit even if your plaintext +// meets the other requirements. The PackedPolicySize response element indicates +// by percentage how close the policies and tags for your request are to the upper +// size limit. +// +// You can pass a session tag with the same key as a tag that is attached to the +// role. When you do, the session tag overrides the role tag with the same key. +// +// An administrator must grant you the permissions necessary to pass session tags. +// The administrator can also create granular permissions to allow you to pass only +// specific session tags. For more information, see [Tutorial: Using Tags for Attribute-Based Access Control]in the IAM User Guide. +// +// You can set the session tags as transitive. Transitive tags persist during role +// chaining. For more information, see [Chaining Roles with Session Tags]in the IAM User Guide. +// +// # Identities +// +// Before your application can call AssumeRoleWithWebIdentity , you must have an +// identity token from a supported identity provider and create a role that the +// application can assume. The role that your application assumes must trust the +// identity provider that is associated with the identity token. In other words, +// the identity provider must be specified in the role's trust policy. +// +// Calling AssumeRoleWithWebIdentity can result in an entry in your CloudTrail +// logs. The entry includes the [Subject]of the provided web identity token. We recommend +// that you avoid using any personally identifiable information (PII) in this +// field. For example, you could instead use a GUID or a pairwise identifier, as [suggested in the OIDC specification]. +// +// For more information about how to use OIDC federation and the // AssumeRoleWithWebIdentity API, see the following resources: -// - Using Web Identity Federation API Operations for Mobile Apps (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_oidc_manual.html) -// and Federation Through a Web-based Identity Provider (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_assumerolewithwebidentity) -// . -// - Web Identity Federation Playground (https://aws.amazon.com/blogs/aws/the-aws-web-identity-federation-playground/) -// . Walk through the process of authenticating through Login with Amazon, -// Facebook, or Google, getting temporary security credentials, and then using -// those credentials to make a request to Amazon Web Services. -// - Amazon Web Services SDK for iOS Developer Guide (http://aws.amazon.com/sdkforios/) -// and Amazon Web Services SDK for Android Developer Guide (http://aws.amazon.com/sdkforandroid/) -// . These toolkits contain sample apps that show how to invoke the identity -// providers. The toolkits then show how to use the information from these +// +// [Using Web Identity Federation API Operations for Mobile Apps] +// - and [Federation Through a Web-based Identity Provider]. +// +// [Amazon Web Services SDK for iOS Developer Guide] +// - and [Amazon Web Services SDK for Android Developer Guide]. These toolkits contain sample apps that show how to invoke the +// identity providers. The toolkits then show how to use the information from these // providers to get and use temporary security credentials. -// - Web Identity Federation with Mobile Applications (http://aws.amazon.com/articles/web-identity-federation-with-mobile-applications) -// . This article discusses web identity federation and shows an example of how to -// use web identity federation to get access to content in Amazon S3. +// +// [Amazon Web Services SDK for iOS Developer Guide]: http://aws.amazon.com/sdkforios/ +// [Amazon Web Services SDK for Android Developer Guide]: http://aws.amazon.com/sdkforandroid/ +// [IAM and STS Character Limits]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length +// [session policies]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session +// [Requesting Temporary Security Credentials]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html +// [Compare STS credentials]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_sts-comparison.html +// [Subject]: http://openid.net/specs/openid-connect-core-1_0.html#Claims +// [Tutorial: Using Tags for Attribute-Based Access Control]: https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html +// [Amazon Cognito identity pools]: https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-identity.html +// [Federation Through a Web-based Identity Provider]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_assumerolewithwebidentity +// [Using IAM Roles]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html +// [Session Policies]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session +// [Amazon Cognito federated identities]: https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-identity.html +// [Passing Session Tags in STS]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html +// [Chaining Roles with Session Tags]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining +// [Update the maximum session duration for a role]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_update-role-settings.html#id_roles_update-session-duration +// [Using Web Identity Federation API Operations for Mobile Apps]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_oidc_manual.html +// [suggested in the OIDC specification]: http://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes func (c *Client) AssumeRoleWithWebIdentity(ctx context.Context, params *AssumeRoleWithWebIdentityInput, optFns ...func(*Options)) (*AssumeRoleWithWebIdentityOutput, error) { if params == nil { params = &AssumeRoleWithWebIdentityInput{} @@ -132,6 +159,17 @@ type AssumeRoleWithWebIdentityInput struct { // The Amazon Resource Name (ARN) of the role that the caller is assuming. // + // Additional considerations apply to Amazon Cognito identity pools that assume [cross-account IAM roles]. + // The trust policies of these roles must accept the cognito-identity.amazonaws.com + // service principal and must contain the cognito-identity.amazonaws.com:aud + // condition key to restrict role assumption to users from your intended identity + // pools. A policy that trusts Amazon Cognito identity pools without this condition + // creates a risk that a user from an unintended identity pool can assume the role. + // For more information, see [Trust policies for IAM roles in Basic (Classic) authentication]in the Amazon Cognito Developer Guide. + // + // [cross-account IAM roles]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies-cross-account-resource-access.html + // [Trust policies for IAM roles in Basic (Classic) authentication]: https://docs.aws.amazon.com/cognito/latest/developerguide/iam-roles.html#trust-policies + // // This member is required. RoleArn *string @@ -139,10 +177,19 @@ type AssumeRoleWithWebIdentityInput struct { // identifier that is associated with the user who is using your application. That // way, the temporary security credentials that your application will use are // associated with that user. This session name is included as part of the ARN and - // assumed role ID in the AssumedRoleUser response element. The regex used to - // validate this parameter is a string of characters consisting of upper- and - // lower-case alphanumeric characters with no spaces. You can also include - // underscores or any of the following characters: =,.@- + // assumed role ID in the AssumedRoleUser response element. + // + // For security purposes, administrators can view this field in [CloudTrail logs] to help identify + // who performed an action in Amazon Web Services. Your administrator might require + // that you specify your user name as the session name when you assume the role. + // For more information, see [sts:RoleSessionName]sts:RoleSessionName . + // + // The regex used to validate this parameter is a string of characters consisting + // of upper- and lower-case alphanumeric characters with no spaces. You can also + // include underscores or any of the following characters: =,.@- + // + // [CloudTrail logs]: https://docs.aws.amazon.com/IAM/latest/UserGuide/cloudtrail-integration.html#cloudtrail-integration_signin-tempcreds + // [sts:RoleSessionName]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_iam-condition-keys.html#ck_rolesessionname // // This member is required. RoleSessionName *string @@ -150,8 +197,10 @@ type AssumeRoleWithWebIdentityInput struct { // The OAuth 2.0 access token or OpenID Connect ID token that is provided by the // identity provider. Your application must get this token by authenticating the // user who is using your application with a web identity provider before the - // application makes an AssumeRoleWithWebIdentity call. Only tokens with RSA - // algorithms (RS256) are supported. + // application makes an AssumeRoleWithWebIdentity call. Timestamps in the token + // must be formatted as either an integer or a long integer. Tokens must be signed + // using either RSA keys (RS256, RS384, or RS512) or ECDSA keys (ES256, ES384, or + // ES512). // // This member is required. WebIdentityToken *string @@ -162,73 +211,93 @@ type AssumeRoleWithWebIdentityInput struct { // higher than this setting, the operation fails. For example, if you specify a // session duration of 12 hours, but your administrator set the maximum session // duration to 6 hours, your operation fails. To learn how to view the maximum - // value for your role, see View the Maximum Session Duration Setting for a Role (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session) - // in the IAM User Guide. By default, the value is set to 3600 seconds. The - // DurationSeconds parameter is separate from the duration of a console session - // that you might request using the returned credentials. The request to the - // federation endpoint for a console sign-in token takes a SessionDuration + // value for your role, see [View the Maximum Session Duration Setting for a Role]in the IAM User Guide. + // + // By default, the value is set to 3600 seconds. + // + // The DurationSeconds parameter is separate from the duration of a console + // session that you might request using the returned credentials. The request to + // the federation endpoint for a console sign-in token takes a SessionDuration // parameter that specifies the maximum length of the console session. For more - // information, see Creating a URL that Enables Federated Users to Access the - // Amazon Web Services Management Console (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html) - // in the IAM User Guide. + // information, see [Creating a URL that Enables Federated Users to Access the Amazon Web Services Management Console]in the IAM User Guide. + // + // [View the Maximum Session Duration Setting for a Role]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session + // [Creating a URL that Enables Federated Users to Access the Amazon Web Services Management Console]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html DurationSeconds *int32 // An IAM policy in JSON format that you want to use as an inline session policy. + // // This parameter is optional. Passing policies to this operation returns new // temporary credentials. The resulting session's permissions are the intersection // of the role's identity-based policy and the session policies. You can use the // role's temporary credentials in subsequent Amazon Web Services API calls to // access resources in the account that owns the role. You cannot use session // policies to grant more permissions than those allowed by the identity-based - // policy of the role that is being assumed. For more information, see Session - // Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) - // in the IAM User Guide. The plaintext that you use for both inline and managed - // session policies can't exceed 2,048 characters. The JSON policy characters can - // be any ASCII character from the space character to the end of the valid - // character list (\u0020 through \u00FF). It can also include the tab (\u0009), - // linefeed (\u000A), and carriage return (\u000D) characters. An Amazon Web - // Services conversion compresses the passed inline session policy, managed policy - // ARNs, and session tags into a packed binary format that has a separate limit. - // Your request can fail for this limit even if your plaintext meets the other - // requirements. The PackedPolicySize response element indicates by percentage how - // close the policies and tags for your request are to the upper size limit. + // policy of the role that is being assumed. For more information, see [Session Policies]in the IAM + // User Guide. + // + // The plaintext that you use for both inline and managed session policies can't + // exceed 2,048 characters. The JSON policy characters can be any ASCII character + // from the space character to the end of the valid character list (\u0020 through + // \u00FF). It can also include the tab (\u0009), linefeed (\u000A), and carriage + // return (\u000D) characters. + // + // For more information about role session permissions, see [Session policies]. + // + // An Amazon Web Services conversion compresses the passed inline session policy, + // managed policy ARNs, and session tags into a packed binary format that has a + // separate limit. Your request can fail for this limit even if your plaintext + // meets the other requirements. The PackedPolicySize response element indicates + // by percentage how close the policies and tags for your request are to the upper + // size limit. + // + // [Session Policies]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session + // [Session policies]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session Policy *string // The Amazon Resource Names (ARNs) of the IAM managed policies that you want to // use as managed session policies. The policies must exist in the same account as - // the role. This parameter is optional. You can provide up to 10 managed policy - // ARNs. However, the plaintext that you use for both inline and managed session - // policies can't exceed 2,048 characters. For more information about ARNs, see - // Amazon Resource Names (ARNs) and Amazon Web Services Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) - // in the Amazon Web Services General Reference. An Amazon Web Services conversion - // compresses the passed inline session policy, managed policy ARNs, and session - // tags into a packed binary format that has a separate limit. Your request can - // fail for this limit even if your plaintext meets the other requirements. The - // PackedPolicySize response element indicates by percentage how close the policies - // and tags for your request are to the upper size limit. Passing policies to this - // operation returns new temporary credentials. The resulting session's permissions - // are the intersection of the role's identity-based policy and the session - // policies. You can use the role's temporary credentials in subsequent Amazon Web - // Services API calls to access resources in the account that owns the role. You - // cannot use session policies to grant more permissions than those allowed by the - // identity-based policy of the role that is being assumed. For more information, - // see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) - // in the IAM User Guide. + // the role. + // + // This parameter is optional. You can provide up to 10 managed policy ARNs. + // However, the plaintext that you use for both inline and managed session policies + // can't exceed 2,048 characters. For more information about ARNs, see [Amazon Resource Names (ARNs) and Amazon Web Services Service Namespaces]in the + // Amazon Web Services General Reference. + // + // An Amazon Web Services conversion compresses the passed inline session policy, + // managed policy ARNs, and session tags into a packed binary format that has a + // separate limit. Your request can fail for this limit even if your plaintext + // meets the other requirements. The PackedPolicySize response element indicates + // by percentage how close the policies and tags for your request are to the upper + // size limit. + // + // Passing policies to this operation returns new temporary credentials. The + // resulting session's permissions are the intersection of the role's + // identity-based policy and the session policies. You can use the role's temporary + // credentials in subsequent Amazon Web Services API calls to access resources in + // the account that owns the role. You cannot use session policies to grant more + // permissions than those allowed by the identity-based policy of the role that is + // being assumed. For more information, see [Session Policies]in the IAM User Guide. + // + // [Session Policies]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session + // [Amazon Resource Names (ARNs) and Amazon Web Services Service Namespaces]: https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html PolicyArns []types.PolicyDescriptorType // The fully qualified host component of the domain name of the OAuth 2.0 identity // provider. Do not specify this value for an OpenID Connect identity provider. + // // Currently www.amazon.com and graph.facebook.com are the only supported identity // providers for OAuth 2.0 access tokens. Do not include URL schemes and port - // numbers. Do not specify this value for OpenID Connect ID tokens. + // numbers. + // + // Do not specify this value for OpenID Connect ID tokens. ProviderId *string noSmithyDocumentSerde } -// Contains the response to a successful AssumeRoleWithWebIdentity request, -// including temporary Amazon Web Services credentials that can be used to make -// Amazon Web Services requests. +// Contains the response to a successful AssumeRoleWithWebIdentity request, including temporary Amazon Web +// Services credentials that can be used to make Amazon Web Services requests. type AssumeRoleWithWebIdentityOutput struct { // The Amazon Resource Name (ARN) and the assumed role ID, which are identifiers @@ -244,9 +313,10 @@ type AssumeRoleWithWebIdentityOutput struct { Audience *string // The temporary security credentials, which include an access key ID, a secret - // access key, and a security token. The size of the security token that STS API - // operations return is not fixed. We strongly recommend that you make no - // assumptions about the maximum size. + // access key, and a security token. + // + // The size of the security token that STS API operations return is not fixed. We + // strongly recommend that you make no assumptions about the maximum size. Credentials *types.Credentials // A percentage value that indicates the packed size of the session policies and @@ -255,30 +325,34 @@ type AssumeRoleWithWebIdentityOutput struct { // allowed space. PackedPolicySize *int32 - // The issuing authority of the web identity token presented. For OpenID Connect + // The issuing authority of the web identity token presented. For OpenID Connect // ID tokens, this contains the value of the iss field. For OAuth 2.0 access // tokens, this contains the value of the ProviderId parameter that was passed in // the AssumeRoleWithWebIdentity request. Provider *string // The value of the source identity that is returned in the JSON web token (JWT) - // from the identity provider. You can require users to set a source identity value - // when they assume a role. You do this by using the sts:SourceIdentity condition - // key in a role trust policy. That way, actions that are taken with the role are - // associated with that user. After the source identity is set, the value cannot be - // changed. It is present in the request for all actions that are taken by the role - // and persists across chained role (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts#iam-term-role-chaining) - // sessions. You can configure your identity provider to use an attribute + // from the identity provider. + // + // You can require users to set a source identity value when they assume a role. + // You do this by using the sts:SourceIdentity condition key in a role trust + // policy. That way, actions that are taken with the role are associated with that + // user. After the source identity is set, the value cannot be changed. It is + // present in the request for all actions that are taken by the role and persists + // across [chained role]sessions. You can configure your identity provider to use an attribute // associated with your users, like user name or email, as the source identity when // calling AssumeRoleWithWebIdentity . You do this by adding a claim to the JSON - // web token. To learn more about OIDC tokens and claims, see Using Tokens with - // User Pools (https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html) - // in the Amazon Cognito Developer Guide. For more information about using source - // identity, see Monitor and control actions taken with assumed roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html) - // in the IAM User Guide. The regex used to validate this parameter is a string of - // characters consisting of upper- and lower-case alphanumeric characters with no - // spaces. You can also include underscores or any of the following characters: - // =,.@- + // web token. To learn more about OIDC tokens and claims, see [Using Tokens with User Pools]in the Amazon + // Cognito Developer Guide. For more information about using source identity, see [Monitor and control actions taken with assumed roles] + // in the IAM User Guide. + // + // The regex used to validate this parameter is a string of characters consisting + // of upper- and lower-case alphanumeric characters with no spaces. You can also + // include underscores or any of the following characters: =,.@- + // + // [chained role]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html#id_roles_terms-and-concepts + // [Monitor and control actions taken with assumed roles]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html + // [Using Tokens with User Pools]: https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html SourceIdentity *string // The unique user identifier that is returned by the identity provider. This @@ -317,22 +391,25 @@ func (c *Client) addOperationAssumeRoleWithWebIdentityMiddlewares(stack *middlew if err = addSetLoggerMiddleware(stack, options); err != nil { return err } - if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + if err = addClientRequestID(stack); err != nil { return err } - if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + if err = addComputeContentLength(stack); err != nil { return err } if err = addResolveEndpointMiddleware(stack, options); err != nil { return err } - if err = addRetryMiddlewares(stack, options); err != nil { + if err = addRetry(stack, options); err != nil { return err } - if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + if err = addRawResponseToMetadata(stack); err != nil { return err } - if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + if err = addRecordResponseTiming(stack); err != nil { + return err + } + if err = addSpanRetryLoop(stack, options); err != nil { return err } if err = addClientUserAgent(stack, options); err != nil { @@ -347,13 +424,19 @@ func (c *Client) addOperationAssumeRoleWithWebIdentityMiddlewares(stack *middlew if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil { return err } + if err = addTimeOffsetBuild(stack, c); err != nil { + return err + } + if err = addUserAgentRetryMode(stack, options); err != nil { + return err + } if err = addOpAssumeRoleWithWebIdentityValidationMiddleware(stack); err != nil { return err } if err = stack.Initialize.Add(newServiceMetadataMiddleware_opAssumeRoleWithWebIdentity(options.Region), middleware.Before); err != nil { return err } - if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + if err = addRecursionDetection(stack); err != nil { return err } if err = addRequestIDRetrieverMiddleware(stack); err != nil { @@ -368,6 +451,18 @@ func (c *Client) addOperationAssumeRoleWithWebIdentityMiddlewares(stack *middlew if err = addDisableHTTPSMiddleware(stack, options); err != nil { return err } + if err = addSpanInitializeStart(stack); err != nil { + return err + } + if err = addSpanInitializeEnd(stack); err != nil { + return err + } + if err = addSpanBuildRequestStart(stack); err != nil { + return err + } + if err = addSpanBuildRequestEnd(stack); err != nil { + return err + } return nil } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRoot.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRoot.go new file mode 100644 index 0000000..cd976e5 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_AssumeRoot.go @@ -0,0 +1,220 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package sts + +import ( + "context" + "fmt" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + "github.com/aws/aws-sdk-go-v2/service/sts/types" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +// Returns a set of short term credentials you can use to perform privileged tasks +// on a member account in your organization. +// +// Before you can launch a privileged session, you must have centralized root +// access in your organization. For steps to enable this feature, see [Centralize root access for member accounts]in the IAM +// User Guide. +// +// The STS global endpoint is not supported for AssumeRoot. You must send this +// request to a Regional STS endpoint. For more information, see [Endpoints]. +// +// You can track AssumeRoot in CloudTrail logs to determine what actions were +// performed in a session. For more information, see [Track privileged tasks in CloudTrail]in the IAM User Guide. +// +// [Endpoints]: https://docs.aws.amazon.com/STS/latest/APIReference/welcome.html#sts-endpoints +// [Track privileged tasks in CloudTrail]: https://docs.aws.amazon.com/IAM/latest/UserGuide/cloudtrail-track-privileged-tasks.html +// [Centralize root access for member accounts]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-enable-root-access.html +func (c *Client) AssumeRoot(ctx context.Context, params *AssumeRootInput, optFns ...func(*Options)) (*AssumeRootOutput, error) { + if params == nil { + params = &AssumeRootInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "AssumeRoot", params, optFns, c.addOperationAssumeRootMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*AssumeRootOutput) + out.ResultMetadata = metadata + return out, nil +} + +type AssumeRootInput struct { + + // The member account principal ARN or account ID. + // + // This member is required. + TargetPrincipal *string + + // The identity based policy that scopes the session to the privileged tasks that + // can be performed. You can use one of following Amazon Web Services managed + // policies to scope root session actions. + // + // [IAMAuditRootUserCredentials] + // + // [IAMCreateRootUserPassword] + // + // [IAMDeleteRootUserCredentials] + // + // [S3UnlockBucketPolicy] + // + // [SQSUnlockQueuePolicy] + // + // [IAMDeleteRootUserCredentials]: https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-IAMDeleteRootUserCredentials + // [IAMCreateRootUserPassword]: https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-IAMCreateRootUserPassword + // [IAMAuditRootUserCredentials]: https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-IAMAuditRootUserCredentials + // [S3UnlockBucketPolicy]: https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-S3UnlockBucketPolicy + // [SQSUnlockQueuePolicy]: https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html#security-iam-awsmanpol-SQSUnlockQueuePolicy + // + // This member is required. + TaskPolicyArn *types.PolicyDescriptorType + + // The duration, in seconds, of the privileged session. The value can range from 0 + // seconds up to the maximum session duration of 900 seconds (15 minutes). If you + // specify a value higher than this setting, the operation fails. + // + // By default, the value is set to 900 seconds. + DurationSeconds *int32 + + noSmithyDocumentSerde +} + +type AssumeRootOutput struct { + + // The temporary security credentials, which include an access key ID, a secret + // access key, and a security token. + // + // The size of the security token that STS API operations return is not fixed. We + // strongly recommend that you make no assumptions about the maximum size. + Credentials *types.Credentials + + // The source identity specified by the principal that is calling the AssumeRoot + // operation. + // + // You can use the aws:SourceIdentity condition key to control access based on the + // value of source identity. For more information about using source identity, see [Monitor and control actions taken with assumed roles] + // in the IAM User Guide. + // + // The regex used to validate this parameter is a string of characters consisting + // of upper- and lower-case alphanumeric characters with no spaces. You can also + // include underscores or any of the following characters: =,.@- + // + // [Monitor and control actions taken with assumed roles]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html + SourceIdentity *string + + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata + + noSmithyDocumentSerde +} + +func (c *Client) addOperationAssumeRootMiddlewares(stack *middleware.Stack, options Options) (err error) { + if err := stack.Serialize.Add(&setOperationInputMiddleware{}, middleware.After); err != nil { + return err + } + err = stack.Serialize.Add(&awsAwsquery_serializeOpAssumeRoot{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsAwsquery_deserializeOpAssumeRoot{}, middleware.After) + if err != nil { + return err + } + if err := addProtocolFinalizerMiddlewares(stack, options, "AssumeRoot"); err != nil { + return fmt.Errorf("add protocol finalizers: %v", err) + } + + if err = addlegacyEndpointContextSetter(stack, options); err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = addClientRequestID(stack); err != nil { + return err + } + if err = addComputeContentLength(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = addComputePayloadSHA256(stack); err != nil { + return err + } + if err = addRetry(stack, options); err != nil { + return err + } + if err = addRawResponseToMetadata(stack); err != nil { + return err + } + if err = addRecordResponseTiming(stack); err != nil { + return err + } + if err = addSpanRetryLoop(stack, options); err != nil { + return err + } + if err = addClientUserAgent(stack, options); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil { + return err + } + if err = addTimeOffsetBuild(stack, c); err != nil { + return err + } + if err = addUserAgentRetryMode(stack, options); err != nil { + return err + } + if err = addOpAssumeRootValidationMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opAssumeRoot(options.Region), middleware.Before); err != nil { + return err + } + if err = addRecursionDetection(stack); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + if err = addDisableHTTPSMiddleware(stack, options); err != nil { + return err + } + if err = addSpanInitializeStart(stack); err != nil { + return err + } + if err = addSpanInitializeEnd(stack); err != nil { + return err + } + if err = addSpanBuildRequestStart(stack); err != nil { + return err + } + if err = addSpanBuildRequestEnd(stack); err != nil { + return err + } + return nil +} + +func newServiceMetadataMiddleware_opAssumeRoot(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + OperationName: "AssumeRoot", + } +} diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_DecodeAuthorizationMessage.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_DecodeAuthorizationMessage.go index 97a00b9..a56840e 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_DecodeAuthorizationMessage.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_DecodeAuthorizationMessage.go @@ -6,34 +6,44 @@ import ( "context" "fmt" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" - "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/smithy-go/middleware" smithyhttp "github.com/aws/smithy-go/transport/http" ) // Decodes additional information about the authorization status of a request from -// an encoded message returned in response to an Amazon Web Services request. For -// example, if a user is not authorized to perform an operation that he or she has -// requested, the request returns a Client.UnauthorizedOperation response (an HTTP -// 403 response). Some Amazon Web Services operations additionally return an -// encoded message that can provide details about this authorization failure. Only -// certain Amazon Web Services operations return an encoded authorization message. -// The documentation for an individual operation indicates whether that operation -// returns an encoded message in addition to returning an HTTP code. The message is -// encoded because the details of the authorization status can contain privileged -// information that the user who requested the operation should not see. To decode -// an authorization status message, a user must be granted permissions through an -// IAM policy (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html) -// to request the DecodeAuthorizationMessage ( sts:DecodeAuthorizationMessage ) -// action. The decoded message includes the following type of information: +// an encoded message returned in response to an Amazon Web Services request. +// +// For example, if a user is not authorized to perform an operation that he or she +// has requested, the request returns a Client.UnauthorizedOperation response (an +// HTTP 403 response). Some Amazon Web Services operations additionally return an +// encoded message that can provide details about this authorization failure. +// +// Only certain Amazon Web Services operations return an encoded authorization +// message. The documentation for an individual operation indicates whether that +// operation returns an encoded message in addition to returning an HTTP code. +// +// The message is encoded because the details of the authorization status can +// contain privileged information that the user who requested the operation should +// not see. To decode an authorization status message, a user must be granted +// permissions through an IAM [policy]to request the DecodeAuthorizationMessage ( +// sts:DecodeAuthorizationMessage ) action. +// +// The decoded message includes the following type of information: +// // - Whether the request was denied due to an explicit deny or due to the -// absence of an explicit allow. For more information, see Determining Whether a -// Request is Allowed or Denied (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic.html#policy-eval-denyallow) -// in the IAM User Guide. +// absence of an explicit allow. For more information, see [Determining Whether a Request is Allowed or Denied]in the IAM User +// Guide. +// // - The principal who made the request. +// // - The requested action. +// // - The requested resource. +// // - The values of condition keys in the context of the user's request. +// +// [Determining Whether a Request is Allowed or Denied]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic.html#policy-eval-denyallow +// [policy]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html func (c *Client) DecodeAuthorizationMessage(ctx context.Context, params *DecodeAuthorizationMessageInput, optFns ...func(*Options)) (*DecodeAuthorizationMessageOutput, error) { if params == nil { params = &DecodeAuthorizationMessageInput{} @@ -95,25 +105,28 @@ func (c *Client) addOperationDecodeAuthorizationMessageMiddlewares(stack *middle if err = addSetLoggerMiddleware(stack, options); err != nil { return err } - if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + if err = addClientRequestID(stack); err != nil { return err } - if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + if err = addComputeContentLength(stack); err != nil { return err } if err = addResolveEndpointMiddleware(stack, options); err != nil { return err } - if err = v4.AddComputePayloadSHA256Middleware(stack); err != nil { + if err = addComputePayloadSHA256(stack); err != nil { return err } - if err = addRetryMiddlewares(stack, options); err != nil { + if err = addRetry(stack, options); err != nil { return err } - if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + if err = addRawResponseToMetadata(stack); err != nil { return err } - if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + if err = addRecordResponseTiming(stack); err != nil { + return err + } + if err = addSpanRetryLoop(stack, options); err != nil { return err } if err = addClientUserAgent(stack, options); err != nil { @@ -128,13 +141,19 @@ func (c *Client) addOperationDecodeAuthorizationMessageMiddlewares(stack *middle if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil { return err } + if err = addTimeOffsetBuild(stack, c); err != nil { + return err + } + if err = addUserAgentRetryMode(stack, options); err != nil { + return err + } if err = addOpDecodeAuthorizationMessageValidationMiddleware(stack); err != nil { return err } if err = stack.Initialize.Add(newServiceMetadataMiddleware_opDecodeAuthorizationMessage(options.Region), middleware.Before); err != nil { return err } - if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + if err = addRecursionDetection(stack); err != nil { return err } if err = addRequestIDRetrieverMiddleware(stack); err != nil { @@ -149,6 +168,18 @@ func (c *Client) addOperationDecodeAuthorizationMessageMiddlewares(stack *middle if err = addDisableHTTPSMiddleware(stack, options); err != nil { return err } + if err = addSpanInitializeStart(stack); err != nil { + return err + } + if err = addSpanInitializeEnd(stack); err != nil { + return err + } + if err = addSpanBuildRequestStart(stack); err != nil { + return err + } + if err = addSpanBuildRequestEnd(stack); err != nil { + return err + } return nil } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetAccessKeyInfo.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetAccessKeyInfo.go index e01fceb..c80b055 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetAccessKeyInfo.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetAccessKeyInfo.go @@ -6,28 +6,35 @@ import ( "context" "fmt" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" - "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/smithy-go/middleware" smithyhttp "github.com/aws/smithy-go/transport/http" ) -// Returns the account identifier for the specified access key ID. Access keys -// consist of two parts: an access key ID (for example, AKIAIOSFODNN7EXAMPLE ) and -// a secret access key (for example, wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY ). -// For more information about access keys, see Managing Access Keys for IAM Users (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html) -// in the IAM User Guide. When you pass an access key ID to this operation, it -// returns the ID of the Amazon Web Services account to which the keys belong. -// Access key IDs beginning with AKIA are long-term credentials for an IAM user or -// the Amazon Web Services account root user. Access key IDs beginning with ASIA -// are temporary credentials that are created using STS operations. If the account -// in the response belongs to you, you can sign in as the root user and review your -// root user access keys. Then, you can pull a credentials report (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_getting-report.html) -// to learn which IAM user owns the keys. To learn who requested the temporary -// credentials for an ASIA access key, view the STS events in your CloudTrail logs (https://docs.aws.amazon.com/IAM/latest/UserGuide/cloudtrail-integration.html) -// in the IAM User Guide. This operation does not indicate the state of the access -// key. The key might be active, inactive, or deleted. Active keys might not have -// permissions to perform an operation. Providing a deleted access key might return -// an error that the key doesn't exist. +// Returns the account identifier for the specified access key ID. +// +// Access keys consist of two parts: an access key ID (for example, +// AKIAIOSFODNN7EXAMPLE ) and a secret access key (for example, +// wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY ). For more information about access +// keys, see [Managing Access Keys for IAM Users]in the IAM User Guide. +// +// When you pass an access key ID to this operation, it returns the ID of the +// Amazon Web Services account to which the keys belong. Access key IDs beginning +// with AKIA are long-term credentials for an IAM user or the Amazon Web Services +// account root user. Access key IDs beginning with ASIA are temporary credentials +// that are created using STS operations. If the account in the response belongs to +// you, you can sign in as the root user and review your root user access keys. +// Then, you can pull a [credentials report]to learn which IAM user owns the keys. To learn who +// requested the temporary credentials for an ASIA access key, view the STS events +// in your [CloudTrail logs]in the IAM User Guide. +// +// This operation does not indicate the state of the access key. The key might be +// active, inactive, or deleted. Active keys might not have permissions to perform +// an operation. Providing a deleted access key might return an error that the key +// doesn't exist. +// +// [credentials report]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_getting-report.html +// [CloudTrail logs]: https://docs.aws.amazon.com/IAM/latest/UserGuide/cloudtrail-integration.html +// [Managing Access Keys for IAM Users]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html func (c *Client) GetAccessKeyInfo(ctx context.Context, params *GetAccessKeyInfoInput, optFns ...func(*Options)) (*GetAccessKeyInfoOutput, error) { if params == nil { params = &GetAccessKeyInfoInput{} @@ -45,9 +52,10 @@ func (c *Client) GetAccessKeyInfo(ctx context.Context, params *GetAccessKeyInfoI type GetAccessKeyInfoInput struct { - // The identifier of an access key. This parameter allows (through its regex - // pattern) a string of characters that can consist of any upper- or lowercase - // letter or digit. + // The identifier of an access key. + // + // This parameter allows (through its regex pattern) a string of characters that + // can consist of any upper- or lowercase letter or digit. // // This member is required. AccessKeyId *string @@ -88,25 +96,28 @@ func (c *Client) addOperationGetAccessKeyInfoMiddlewares(stack *middleware.Stack if err = addSetLoggerMiddleware(stack, options); err != nil { return err } - if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + if err = addClientRequestID(stack); err != nil { return err } - if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + if err = addComputeContentLength(stack); err != nil { return err } if err = addResolveEndpointMiddleware(stack, options); err != nil { return err } - if err = v4.AddComputePayloadSHA256Middleware(stack); err != nil { + if err = addComputePayloadSHA256(stack); err != nil { return err } - if err = addRetryMiddlewares(stack, options); err != nil { + if err = addRetry(stack, options); err != nil { return err } - if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + if err = addRawResponseToMetadata(stack); err != nil { return err } - if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + if err = addRecordResponseTiming(stack); err != nil { + return err + } + if err = addSpanRetryLoop(stack, options); err != nil { return err } if err = addClientUserAgent(stack, options); err != nil { @@ -121,13 +132,19 @@ func (c *Client) addOperationGetAccessKeyInfoMiddlewares(stack *middleware.Stack if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil { return err } + if err = addTimeOffsetBuild(stack, c); err != nil { + return err + } + if err = addUserAgentRetryMode(stack, options); err != nil { + return err + } if err = addOpGetAccessKeyInfoValidationMiddleware(stack); err != nil { return err } if err = stack.Initialize.Add(newServiceMetadataMiddleware_opGetAccessKeyInfo(options.Region), middleware.Before); err != nil { return err } - if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + if err = addRecursionDetection(stack); err != nil { return err } if err = addRequestIDRetrieverMiddleware(stack); err != nil { @@ -142,6 +159,18 @@ func (c *Client) addOperationGetAccessKeyInfoMiddlewares(stack *middleware.Stack if err = addDisableHTTPSMiddleware(stack, options); err != nil { return err } + if err = addSpanInitializeStart(stack); err != nil { + return err + } + if err = addSpanInitializeEnd(stack); err != nil { + return err + } + if err = addSpanBuildRequestStart(stack); err != nil { + return err + } + if err = addSpanBuildRequestEnd(stack); err != nil { + return err + } return nil } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetCallerIdentity.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetCallerIdentity.go index 8029694..49304bd 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetCallerIdentity.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetCallerIdentity.go @@ -12,13 +12,15 @@ import ( ) // Returns details about the IAM user or role whose credentials are used to call -// the operation. No permissions are required to perform this operation. If an -// administrator attaches a policy to your identity that explicitly denies access -// to the sts:GetCallerIdentity action, you can still perform this operation. -// Permissions are not required because the same information is returned when -// access is denied. To view an example response, see I Am Not Authorized to -// Perform: iam:DeleteVirtualMFADevice (https://docs.aws.amazon.com/IAM/latest/UserGuide/troubleshoot_general.html#troubleshoot_general_access-denied-delete-mfa) -// in the IAM User Guide. +// the operation. +// +// No permissions are required to perform this operation. If an administrator +// attaches a policy to your identity that explicitly denies access to the +// sts:GetCallerIdentity action, you can still perform this operation. Permissions +// are not required because the same information is returned when access is denied. +// To view an example response, see [I Am Not Authorized to Perform: iam:DeleteVirtualMFADevice]in the IAM User Guide. +// +// [I Am Not Authorized to Perform: iam:DeleteVirtualMFADevice]: https://docs.aws.amazon.com/IAM/latest/UserGuide/troubleshoot_general.html#troubleshoot_general_access-denied-delete-mfa func (c *Client) GetCallerIdentity(ctx context.Context, params *GetCallerIdentityInput, optFns ...func(*Options)) (*GetCallerIdentityOutput, error) { if params == nil { params = &GetCallerIdentityInput{} @@ -38,8 +40,8 @@ type GetCallerIdentityInput struct { noSmithyDocumentSerde } -// Contains the response to a successful GetCallerIdentity request, including -// information about the entity making the request. +// Contains the response to a successful GetCallerIdentity request, including information about the +// entity making the request. type GetCallerIdentityOutput struct { // The Amazon Web Services account ID number of the account that owns or contains @@ -51,8 +53,10 @@ type GetCallerIdentityOutput struct { // The unique identifier of the calling entity. The exact value depends on the // type of entity that is making the call. The values returned are those listed in - // the aws:userid column in the Principal table (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_variables.html#principaltable) - // found on the Policy Variables reference page in the IAM User Guide. + // the aws:userid column in the [Principal table]found on the Policy Variables reference page in + // the IAM User Guide. + // + // [Principal table]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_variables.html#principaltable UserId *string // Metadata pertaining to the operation's result. @@ -83,25 +87,28 @@ func (c *Client) addOperationGetCallerIdentityMiddlewares(stack *middleware.Stac if err = addSetLoggerMiddleware(stack, options); err != nil { return err } - if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + if err = addClientRequestID(stack); err != nil { return err } - if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + if err = addComputeContentLength(stack); err != nil { return err } if err = addResolveEndpointMiddleware(stack, options); err != nil { return err } - if err = v4.AddComputePayloadSHA256Middleware(stack); err != nil { + if err = addComputePayloadSHA256(stack); err != nil { return err } - if err = addRetryMiddlewares(stack, options); err != nil { + if err = addRetry(stack, options); err != nil { return err } - if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + if err = addRawResponseToMetadata(stack); err != nil { return err } - if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + if err = addRecordResponseTiming(stack); err != nil { + return err + } + if err = addSpanRetryLoop(stack, options); err != nil { return err } if err = addClientUserAgent(stack, options); err != nil { @@ -116,10 +123,16 @@ func (c *Client) addOperationGetCallerIdentityMiddlewares(stack *middleware.Stac if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil { return err } + if err = addTimeOffsetBuild(stack, c); err != nil { + return err + } + if err = addUserAgentRetryMode(stack, options); err != nil { + return err + } if err = stack.Initialize.Add(newServiceMetadataMiddleware_opGetCallerIdentity(options.Region), middleware.Before); err != nil { return err } - if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + if err = addRecursionDetection(stack); err != nil { return err } if err = addRequestIDRetrieverMiddleware(stack); err != nil { @@ -134,6 +147,18 @@ func (c *Client) addOperationGetCallerIdentityMiddlewares(stack *middleware.Stac if err = addDisableHTTPSMiddleware(stack, options); err != nil { return err } + if err = addSpanInitializeStart(stack); err != nil { + return err + } + if err = addSpanInitializeEnd(stack); err != nil { + return err + } + if err = addSpanBuildRequestStart(stack); err != nil { + return err + } + if err = addSpanBuildRequestEnd(stack); err != nil { + return err + } return nil } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetFederationToken.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetFederationToken.go index efaba11..e2ecc79 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetFederationToken.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetFederationToken.go @@ -6,7 +6,6 @@ import ( "context" "fmt" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" - "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/service/sts/types" "github.com/aws/smithy-go/middleware" smithyhttp "github.com/aws/smithy-go/transport/http" @@ -15,74 +14,100 @@ import ( // Returns a set of temporary security credentials (consisting of an access key // ID, a secret access key, and a security token) for a user. A typical use is in a // proxy application that gets temporary security credentials on behalf of -// distributed applications inside a corporate network. You must call the -// GetFederationToken operation using the long-term security credentials of an IAM -// user. As a result, this call is appropriate in contexts where those credentials -// can be safeguarded, usually in a server-based application. For a comparison of -// GetFederationToken with the other API operations that produce temporary -// credentials, see Requesting Temporary Security Credentials (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) -// and Comparing the Amazon Web Services STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) -// in the IAM User Guide. Although it is possible to call GetFederationToken using -// the security credentials of an Amazon Web Services account root user rather than -// an IAM user that you create for the purpose of a proxy application, we do not -// recommend it. For more information, see Safeguard your root user credentials -// and don't use them for everyday tasks (https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#lock-away-credentials) -// in the IAM User Guide. You can create a mobile-based or browser-based app that -// can authenticate users using a web identity provider like Login with Amazon, -// Facebook, Google, or an OpenID Connect-compatible identity provider. In this -// case, we recommend that you use Amazon Cognito (http://aws.amazon.com/cognito/) -// or AssumeRoleWithWebIdentity . For more information, see Federation Through a -// Web-based Identity Provider (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_assumerolewithwebidentity) -// in the IAM User Guide. Session duration The temporary credentials are valid for -// the specified duration, from 900 seconds (15 minutes) up to a maximum of 129,600 -// seconds (36 hours). The default session duration is 43,200 seconds (12 hours). -// Temporary credentials obtained by using the root user credentials have a maximum -// duration of 3,600 seconds (1 hour). Permissions You can use the temporary -// credentials created by GetFederationToken in any Amazon Web Services service -// with the following exceptions: +// distributed applications inside a corporate network. +// +// You must call the GetFederationToken operation using the long-term security +// credentials of an IAM user. As a result, this call is appropriate in contexts +// where those credentials can be safeguarded, usually in a server-based +// application. For a comparison of GetFederationToken with the other API +// operations that produce temporary credentials, see [Requesting Temporary Security Credentials]and [Compare STS credentials] in the IAM User Guide. +// +// Although it is possible to call GetFederationToken using the security +// credentials of an Amazon Web Services account root user rather than an IAM user +// that you create for the purpose of a proxy application, we do not recommend it. +// For more information, see [Safeguard your root user credentials and don't use them for everyday tasks]in the IAM User Guide. +// +// You can create a mobile-based or browser-based app that can authenticate users +// using a web identity provider like Login with Amazon, Facebook, Google, or an +// OpenID Connect-compatible identity provider. In this case, we recommend that you +// use [Amazon Cognito]or AssumeRoleWithWebIdentity . For more information, see [Federation Through a Web-based Identity Provider] in the IAM User +// Guide. +// +// # Session duration +// +// The temporary credentials are valid for the specified duration, from 900 +// seconds (15 minutes) up to a maximum of 129,600 seconds (36 hours). The default +// session duration is 43,200 seconds (12 hours). Temporary credentials obtained by +// using the root user credentials have a maximum duration of 3,600 seconds (1 +// hour). +// +// # Permissions +// +// You can use the temporary credentials created by GetFederationToken in any +// Amazon Web Services service with the following exceptions: +// // - You cannot call any IAM operations using the CLI or the Amazon Web Services // API. This limitation does not apply to console sessions. +// // - You cannot call any STS operations except GetCallerIdentity . // -// You can use temporary credentials for single sign-on (SSO) to the console. You -// must pass an inline or managed session policy (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) -// to this operation. You can pass a single JSON policy document to use as an -// inline session policy. You can also specify up to 10 managed policy Amazon -// Resource Names (ARNs) to use as managed session policies. The plaintext that you -// use for both inline and managed session policies can't exceed 2,048 characters. +// You can use temporary credentials for single sign-on (SSO) to the console. +// +// You must pass an inline or managed [session policy] to this operation. You can pass a single +// JSON policy document to use as an inline session policy. You can also specify up +// to 10 managed policy Amazon Resource Names (ARNs) to use as managed session +// policies. The plaintext that you use for both inline and managed session +// policies can't exceed 2,048 characters. +// // Though the session policy parameters are optional, if you do not pass a policy, // then the resulting federated user session has no permissions. When you pass // session policies, the session permissions are the intersection of the IAM user // policies and the session policies that you pass. This gives you a way to further // restrict the permissions for a federated user. You cannot use session policies // to grant more permissions than those that are defined in the permissions policy -// of the IAM user. For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) -// in the IAM User Guide. For information about using GetFederationToken to create -// temporary security credentials, see GetFederationToken—Federation Through a -// Custom Identity Broker (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_getfederationtoken) -// . You can use the credentials to access a resource that has a resource-based +// of the IAM user. For more information, see [Session Policies]in the IAM User Guide. For +// information about using GetFederationToken to create temporary security +// credentials, see [GetFederationToken—Federation Through a Custom Identity Broker]. +// +// You can use the credentials to access a resource that has a resource-based // policy. If that policy specifically references the federated user session in the // Principal element of the policy, the session has the permissions allowed by the // policy. These permissions are granted in addition to the permissions granted by -// the session policies. Tags (Optional) You can pass tag key-value pairs to your -// session. These are called session tags. For more information about session tags, -// see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) -// in the IAM User Guide. You can create a mobile-based or browser-based app that -// can authenticate users using a web identity provider like Login with Amazon, -// Facebook, Google, or an OpenID Connect-compatible identity provider. In this -// case, we recommend that you use Amazon Cognito (http://aws.amazon.com/cognito/) -// or AssumeRoleWithWebIdentity . For more information, see Federation Through a -// Web-based Identity Provider (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_assumerolewithwebidentity) -// in the IAM User Guide. An administrator must grant you the permissions necessary -// to pass session tags. The administrator can also create granular permissions to -// allow you to pass only specific session tags. For more information, see -// Tutorial: Using Tags for Attribute-Based Access Control (https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html) -// in the IAM User Guide. Tag key–value pairs are not case sensitive, but case is -// preserved. This means that you cannot have separate Department and department -// tag keys. Assume that the user that you are federating has the Department = -// Marketing tag and you pass the department = engineering session tag. Department -// and department are not saved as separate tags, and the session tag passed in -// the request takes precedence over the user tag. +// the session policies. +// +// # Tags +// +// (Optional) You can pass tag key-value pairs to your session. These are called +// session tags. For more information about session tags, see [Passing Session Tags in STS]in the IAM User +// Guide. +// +// You can create a mobile-based or browser-based app that can authenticate users +// using a web identity provider like Login with Amazon, Facebook, Google, or an +// OpenID Connect-compatible identity provider. In this case, we recommend that you +// use [Amazon Cognito]or AssumeRoleWithWebIdentity . For more information, see [Federation Through a Web-based Identity Provider] in the IAM User +// Guide. +// +// An administrator must grant you the permissions necessary to pass session tags. +// The administrator can also create granular permissions to allow you to pass only +// specific session tags. For more information, see [Tutorial: Using Tags for Attribute-Based Access Control]in the IAM User Guide. +// +// Tag key–value pairs are not case sensitive, but case is preserved. This means +// that you cannot have separate Department and department tag keys. Assume that +// the user that you are federating has the Department = Marketing tag and you +// pass the department = engineering session tag. Department and department are +// not saved as separate tags, and the session tag passed in the request takes +// precedence over the user tag. +// +// [Federation Through a Web-based Identity Provider]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_assumerolewithwebidentity +// [session policy]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session +// [Amazon Cognito]: http://aws.amazon.com/cognito/ +// [Session Policies]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session +// [Passing Session Tags in STS]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html +// [GetFederationToken—Federation Through a Custom Identity Broker]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_getfederationtoken +// [Safeguard your root user credentials and don't use them for everyday tasks]: https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#lock-away-credentials +// [Requesting Temporary Security Credentials]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html +// [Compare STS credentials]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_sts-comparison.html +// [Tutorial: Using Tags for Attribute-Based Access Control]: https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html func (c *Client) GetFederationToken(ctx context.Context, params *GetFederationTokenInput, optFns ...func(*Options)) (*GetFederationTokenOutput, error) { if params == nil { params = &GetFederationTokenInput{} @@ -103,10 +128,11 @@ type GetFederationTokenInput struct { // The name of the federated user. The name is used as an identifier for the // temporary security credentials (such as Bob ). For example, you can reference // the federated user name in a resource-based policy, such as in an Amazon S3 - // bucket policy. The regex used to validate this parameter is a string of - // characters consisting of upper- and lower-case alphanumeric characters with no - // spaces. You can also include underscores or any of the following characters: - // =,.@- + // bucket policy. + // + // The regex used to validate this parameter is a string of characters consisting + // of upper- and lower-case alphanumeric characters with no spaces. You can also + // include underscores or any of the following characters: =,.@- // // This member is required. Name *string @@ -120,99 +146,127 @@ type GetFederationTokenInput struct { DurationSeconds *int32 // An IAM policy in JSON format that you want to use as an inline session policy. - // You must pass an inline or managed session policy (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) - // to this operation. You can pass a single JSON policy document to use as an - // inline session policy. You can also specify up to 10 managed policy Amazon - // Resource Names (ARNs) to use as managed session policies. This parameter is - // optional. However, if you do not pass any session policies, then the resulting - // federated user session has no permissions. When you pass session policies, the - // session permissions are the intersection of the IAM user policies and the - // session policies that you pass. This gives you a way to further restrict the - // permissions for a federated user. You cannot use session policies to grant more - // permissions than those that are defined in the permissions policy of the IAM - // user. For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) - // in the IAM User Guide. The resulting credentials can be used to access a - // resource that has a resource-based policy. If that policy specifically - // references the federated user session in the Principal element of the policy, - // the session has the permissions allowed by the policy. These permissions are - // granted in addition to the permissions that are granted by the session policies. + // + // You must pass an inline or managed [session policy] to this operation. You can pass a single + // JSON policy document to use as an inline session policy. You can also specify up + // to 10 managed policy Amazon Resource Names (ARNs) to use as managed session + // policies. + // + // This parameter is optional. However, if you do not pass any session policies, + // then the resulting federated user session has no permissions. + // + // When you pass session policies, the session permissions are the intersection of + // the IAM user policies and the session policies that you pass. This gives you a + // way to further restrict the permissions for a federated user. You cannot use + // session policies to grant more permissions than those that are defined in the + // permissions policy of the IAM user. For more information, see [Session Policies]in the IAM User + // Guide. + // + // The resulting credentials can be used to access a resource that has a + // resource-based policy. If that policy specifically references the federated user + // session in the Principal element of the policy, the session has the permissions + // allowed by the policy. These permissions are granted in addition to the + // permissions that are granted by the session policies. + // // The plaintext that you use for both inline and managed session policies can't // exceed 2,048 characters. The JSON policy characters can be any ASCII character // from the space character to the end of the valid character list (\u0020 through // \u00FF). It can also include the tab (\u0009), linefeed (\u000A), and carriage - // return (\u000D) characters. An Amazon Web Services conversion compresses the - // passed inline session policy, managed policy ARNs, and session tags into a - // packed binary format that has a separate limit. Your request can fail for this - // limit even if your plaintext meets the other requirements. The PackedPolicySize - // response element indicates by percentage how close the policies and tags for - // your request are to the upper size limit. - Policy *string - - // The Amazon Resource Names (ARNs) of the IAM managed policies that you want to - // use as a managed session policy. The policies must exist in the same account as - // the IAM user that is requesting federated access. You must pass an inline or - // managed session policy (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) - // to this operation. You can pass a single JSON policy document to use as an - // inline session policy. You can also specify up to 10 managed policy Amazon - // Resource Names (ARNs) to use as managed session policies. The plaintext that you - // use for both inline and managed session policies can't exceed 2,048 characters. - // You can provide up to 10 managed policy ARNs. For more information about ARNs, - // see Amazon Resource Names (ARNs) and Amazon Web Services Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) - // in the Amazon Web Services General Reference. This parameter is optional. - // However, if you do not pass any session policies, then the resulting federated - // user session has no permissions. When you pass session policies, the session - // permissions are the intersection of the IAM user policies and the session - // policies that you pass. This gives you a way to further restrict the permissions - // for a federated user. You cannot use session policies to grant more permissions - // than those that are defined in the permissions policy of the IAM user. For more - // information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session) - // in the IAM User Guide. The resulting credentials can be used to access a - // resource that has a resource-based policy. If that policy specifically - // references the federated user session in the Principal element of the policy, - // the session has the permissions allowed by the policy. These permissions are - // granted in addition to the permissions that are granted by the session policies. + // return (\u000D) characters. + // // An Amazon Web Services conversion compresses the passed inline session policy, // managed policy ARNs, and session tags into a packed binary format that has a // separate limit. Your request can fail for this limit even if your plaintext // meets the other requirements. The PackedPolicySize response element indicates // by percentage how close the policies and tags for your request are to the upper // size limit. + // + // [session policy]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session + // [Session Policies]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session + Policy *string + + // The Amazon Resource Names (ARNs) of the IAM managed policies that you want to + // use as a managed session policy. The policies must exist in the same account as + // the IAM user that is requesting federated access. + // + // You must pass an inline or managed [session policy] to this operation. You can pass a single + // JSON policy document to use as an inline session policy. You can also specify up + // to 10 managed policy Amazon Resource Names (ARNs) to use as managed session + // policies. The plaintext that you use for both inline and managed session + // policies can't exceed 2,048 characters. You can provide up to 10 managed policy + // ARNs. For more information about ARNs, see [Amazon Resource Names (ARNs) and Amazon Web Services Service Namespaces]in the Amazon Web Services General + // Reference. + // + // This parameter is optional. However, if you do not pass any session policies, + // then the resulting federated user session has no permissions. + // + // When you pass session policies, the session permissions are the intersection of + // the IAM user policies and the session policies that you pass. This gives you a + // way to further restrict the permissions for a federated user. You cannot use + // session policies to grant more permissions than those that are defined in the + // permissions policy of the IAM user. For more information, see [Session Policies]in the IAM User + // Guide. + // + // The resulting credentials can be used to access a resource that has a + // resource-based policy. If that policy specifically references the federated user + // session in the Principal element of the policy, the session has the permissions + // allowed by the policy. These permissions are granted in addition to the + // permissions that are granted by the session policies. + // + // An Amazon Web Services conversion compresses the passed inline session policy, + // managed policy ARNs, and session tags into a packed binary format that has a + // separate limit. Your request can fail for this limit even if your plaintext + // meets the other requirements. The PackedPolicySize response element indicates + // by percentage how close the policies and tags for your request are to the upper + // size limit. + // + // [session policy]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session + // [Session Policies]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session + // [Amazon Resource Names (ARNs) and Amazon Web Services Service Namespaces]: https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html PolicyArns []types.PolicyDescriptorType // A list of session tags. Each session tag consists of a key name and an - // associated value. For more information about session tags, see Passing Session - // Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) - // in the IAM User Guide. This parameter is optional. You can pass up to 50 session - // tags. The plaintext session tag keys can’t exceed 128 characters and the values - // can’t exceed 256 characters. For these and additional limits, see IAM and STS - // Character Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length) - // in the IAM User Guide. An Amazon Web Services conversion compresses the passed - // inline session policy, managed policy ARNs, and session tags into a packed - // binary format that has a separate limit. Your request can fail for this limit - // even if your plaintext meets the other requirements. The PackedPolicySize - // response element indicates by percentage how close the policies and tags for - // your request are to the upper size limit. You can pass a session tag with the - // same key as a tag that is already attached to the user you are federating. When - // you do, session tags override a user tag with the same key. Tag key–value pairs - // are not case sensitive, but case is preserved. This means that you cannot have - // separate Department and department tag keys. Assume that the role has the - // Department = Marketing tag and you pass the department = engineering session - // tag. Department and department are not saved as separate tags, and the session - // tag passed in the request takes precedence over the role tag. + // associated value. For more information about session tags, see [Passing Session Tags in STS]in the IAM User + // Guide. + // + // This parameter is optional. You can pass up to 50 session tags. The plaintext + // session tag keys can’t exceed 128 characters and the values can’t exceed 256 + // characters. For these and additional limits, see [IAM and STS Character Limits]in the IAM User Guide. + // + // An Amazon Web Services conversion compresses the passed inline session policy, + // managed policy ARNs, and session tags into a packed binary format that has a + // separate limit. Your request can fail for this limit even if your plaintext + // meets the other requirements. The PackedPolicySize response element indicates + // by percentage how close the policies and tags for your request are to the upper + // size limit. + // + // You can pass a session tag with the same key as a tag that is already attached + // to the user you are federating. When you do, session tags override a user tag + // with the same key. + // + // Tag key–value pairs are not case sensitive, but case is preserved. This means + // that you cannot have separate Department and department tag keys. Assume that + // the role has the Department = Marketing tag and you pass the department = + // engineering session tag. Department and department are not saved as separate + // tags, and the session tag passed in the request takes precedence over the role + // tag. + // + // [Passing Session Tags in STS]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html + // [IAM and STS Character Limits]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length Tags []types.Tag noSmithyDocumentSerde } -// Contains the response to a successful GetFederationToken request, including -// temporary Amazon Web Services credentials that can be used to make Amazon Web -// Services requests. +// Contains the response to a successful GetFederationToken request, including temporary Amazon Web +// Services credentials that can be used to make Amazon Web Services requests. type GetFederationTokenOutput struct { // The temporary security credentials, which include an access key ID, a secret - // access key, and a security (or session) token. The size of the security token - // that STS API operations return is not fixed. We strongly recommend that you make - // no assumptions about the maximum size. + // access key, and a security (or session) token. + // + // The size of the security token that STS API operations return is not fixed. We + // strongly recommend that you make no assumptions about the maximum size. Credentials *types.Credentials // Identifiers for the federated user associated with the credentials (such as @@ -255,25 +309,28 @@ func (c *Client) addOperationGetFederationTokenMiddlewares(stack *middleware.Sta if err = addSetLoggerMiddleware(stack, options); err != nil { return err } - if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + if err = addClientRequestID(stack); err != nil { return err } - if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + if err = addComputeContentLength(stack); err != nil { return err } if err = addResolveEndpointMiddleware(stack, options); err != nil { return err } - if err = v4.AddComputePayloadSHA256Middleware(stack); err != nil { + if err = addComputePayloadSHA256(stack); err != nil { return err } - if err = addRetryMiddlewares(stack, options); err != nil { + if err = addRetry(stack, options); err != nil { return err } - if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + if err = addRawResponseToMetadata(stack); err != nil { return err } - if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + if err = addRecordResponseTiming(stack); err != nil { + return err + } + if err = addSpanRetryLoop(stack, options); err != nil { return err } if err = addClientUserAgent(stack, options); err != nil { @@ -288,13 +345,19 @@ func (c *Client) addOperationGetFederationTokenMiddlewares(stack *middleware.Sta if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil { return err } + if err = addTimeOffsetBuild(stack, c); err != nil { + return err + } + if err = addUserAgentRetryMode(stack, options); err != nil { + return err + } if err = addOpGetFederationTokenValidationMiddleware(stack); err != nil { return err } if err = stack.Initialize.Add(newServiceMetadataMiddleware_opGetFederationToken(options.Region), middleware.Before); err != nil { return err } - if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + if err = addRecursionDetection(stack); err != nil { return err } if err = addRequestIDRetrieverMiddleware(stack); err != nil { @@ -309,6 +372,18 @@ func (c *Client) addOperationGetFederationTokenMiddlewares(stack *middleware.Sta if err = addDisableHTTPSMiddleware(stack, options); err != nil { return err } + if err = addSpanInitializeStart(stack); err != nil { + return err + } + if err = addSpanInitializeEnd(stack); err != nil { + return err + } + if err = addSpanBuildRequestStart(stack); err != nil { + return err + } + if err = addSpanBuildRequestEnd(stack); err != nil { + return err + } return nil } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetSessionToken.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetSessionToken.go index 7b07435..fdc4511 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetSessionToken.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/api_op_GetSessionToken.go @@ -6,7 +6,6 @@ import ( "context" "fmt" awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" - "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/service/sts/types" "github.com/aws/smithy-go/middleware" smithyhttp "github.com/aws/smithy-go/transport/http" @@ -16,43 +15,58 @@ import ( // IAM user. The credentials consist of an access key ID, a secret access key, and // a security token. Typically, you use GetSessionToken if you want to use MFA to // protect programmatic calls to specific Amazon Web Services API operations like -// Amazon EC2 StopInstances . MFA-enabled IAM users must call GetSessionToken and -// submit an MFA code that is associated with their MFA device. Using the temporary -// security credentials that the call returns, IAM users can then make programmatic -// calls to API operations that require MFA authentication. An incorrect MFA code -// causes the API to return an access denied error. For a comparison of -// GetSessionToken with the other API operations that produce temporary -// credentials, see Requesting Temporary Security Credentials (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html) -// and Comparing the Amazon Web Services STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison) -// in the IAM User Guide. No permissions are required for users to perform this -// operation. The purpose of the sts:GetSessionToken operation is to authenticate -// the user using MFA. You cannot use policies to control authentication -// operations. For more information, see Permissions for GetSessionToken (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_getsessiontoken.html) -// in the IAM User Guide. Session Duration The GetSessionToken operation must be -// called by using the long-term Amazon Web Services security credentials of an IAM -// user. Credentials that are created by IAM users are valid for the duration that -// you specify. This duration can range from 900 seconds (15 minutes) up to a -// maximum of 129,600 seconds (36 hours), with a default of 43,200 seconds (12 -// hours). Credentials based on account credentials can range from 900 seconds (15 -// minutes) up to 3,600 seconds (1 hour), with a default of 1 hour. Permissions The -// temporary security credentials created by GetSessionToken can be used to make -// API calls to any Amazon Web Services service with the following exceptions: +// Amazon EC2 StopInstances . +// +// MFA-enabled IAM users must call GetSessionToken and submit an MFA code that is +// associated with their MFA device. Using the temporary security credentials that +// the call returns, IAM users can then make programmatic calls to API operations +// that require MFA authentication. An incorrect MFA code causes the API to return +// an access denied error. For a comparison of GetSessionToken with the other API +// operations that produce temporary credentials, see [Requesting Temporary Security Credentials]and [Compare STS credentials] in the IAM User Guide. +// +// No permissions are required for users to perform this operation. The purpose of +// the sts:GetSessionToken operation is to authenticate the user using MFA. You +// cannot use policies to control authentication operations. For more information, +// see [Permissions for GetSessionToken]in the IAM User Guide. +// +// # Session Duration +// +// The GetSessionToken operation must be called by using the long-term Amazon Web +// Services security credentials of an IAM user. Credentials that are created by +// IAM users are valid for the duration that you specify. This duration can range +// from 900 seconds (15 minutes) up to a maximum of 129,600 seconds (36 hours), +// with a default of 43,200 seconds (12 hours). Credentials based on account +// credentials can range from 900 seconds (15 minutes) up to 3,600 seconds (1 +// hour), with a default of 1 hour. +// +// # Permissions +// +// The temporary security credentials created by GetSessionToken can be used to +// make API calls to any Amazon Web Services service with the following exceptions: +// // - You cannot call any IAM API operations unless MFA authentication // information is included in the request. +// // - You cannot call any STS API except AssumeRole or GetCallerIdentity . // // The credentials that GetSessionToken returns are based on permissions // associated with the IAM user whose credentials were used to call the operation. -// The temporary credentials have the same permissions as the IAM user. Although it -// is possible to call GetSessionToken using the security credentials of an Amazon -// Web Services account root user rather than an IAM user, we do not recommend it. -// If GetSessionToken is called using root user credentials, the temporary -// credentials have root user permissions. For more information, see Safeguard -// your root user credentials and don't use them for everyday tasks (https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#lock-away-credentials) -// in the IAM User Guide For more information about using GetSessionToken to -// create temporary credentials, see Temporary Credentials for Users in Untrusted -// Environments (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_getsessiontoken) -// in the IAM User Guide. +// The temporary credentials have the same permissions as the IAM user. +// +// Although it is possible to call GetSessionToken using the security credentials +// of an Amazon Web Services account root user rather than an IAM user, we do not +// recommend it. If GetSessionToken is called using root user credentials, the +// temporary credentials have root user permissions. For more information, see [Safeguard your root user credentials and don't use them for everyday tasks]in +// the IAM User Guide +// +// For more information about using GetSessionToken to create temporary +// credentials, see [Temporary Credentials for Users in Untrusted Environments]in the IAM User Guide. +// +// [Permissions for GetSessionToken]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_getsessiontoken.html +// [Temporary Credentials for Users in Untrusted Environments]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_getsessiontoken +// [Safeguard your root user credentials and don't use them for everyday tasks]: https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#lock-away-credentials +// [Requesting Temporary Security Credentials]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html +// [Compare STS credentials]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_sts-comparison.html func (c *Client) GetSessionToken(ctx context.Context, params *GetSessionTokenInput, optFns ...func(*Options)) (*GetSessionTokenOutput, error) { if params == nil { params = &GetSessionTokenInput{} @@ -84,10 +98,11 @@ type GetSessionTokenInput struct { // number for a hardware device (such as GAHT12345678 ) or an Amazon Resource Name // (ARN) for a virtual device (such as arn:aws:iam::123456789012:mfa/user ). You // can find the device for an IAM user by going to the Amazon Web Services - // Management Console and viewing the user's security credentials. The regex used - // to validate this parameter is a string of characters consisting of upper- and - // lower-case alphanumeric characters with no spaces. You can also include - // underscores or any of the following characters: =,.@:/- + // Management Console and viewing the user's security credentials. + // + // The regex used to validate this parameter is a string of characters consisting + // of upper- and lower-case alphanumeric characters with no spaces. You can also + // include underscores or any of the following characters: =,.@:/- SerialNumber *string // The value provided by the MFA device, if MFA is required. If any policy @@ -95,22 +110,24 @@ type GetSessionTokenInput struct { // authentication is required, the user must provide a code when requesting a set // of temporary security credentials. A user who fails to provide the code receives // an "access denied" response when requesting resources that require MFA - // authentication. The format for this parameter, as described by its regex - // pattern, is a sequence of six numeric digits. + // authentication. + // + // The format for this parameter, as described by its regex pattern, is a sequence + // of six numeric digits. TokenCode *string noSmithyDocumentSerde } -// Contains the response to a successful GetSessionToken request, including -// temporary Amazon Web Services credentials that can be used to make Amazon Web -// Services requests. +// Contains the response to a successful GetSessionToken request, including temporary Amazon Web +// Services credentials that can be used to make Amazon Web Services requests. type GetSessionTokenOutput struct { // The temporary security credentials, which include an access key ID, a secret - // access key, and a security (or session) token. The size of the security token - // that STS API operations return is not fixed. We strongly recommend that you make - // no assumptions about the maximum size. + // access key, and a security (or session) token. + // + // The size of the security token that STS API operations return is not fixed. We + // strongly recommend that you make no assumptions about the maximum size. Credentials *types.Credentials // Metadata pertaining to the operation's result. @@ -141,25 +158,28 @@ func (c *Client) addOperationGetSessionTokenMiddlewares(stack *middleware.Stack, if err = addSetLoggerMiddleware(stack, options); err != nil { return err } - if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + if err = addClientRequestID(stack); err != nil { return err } - if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + if err = addComputeContentLength(stack); err != nil { return err } if err = addResolveEndpointMiddleware(stack, options); err != nil { return err } - if err = v4.AddComputePayloadSHA256Middleware(stack); err != nil { + if err = addComputePayloadSHA256(stack); err != nil { return err } - if err = addRetryMiddlewares(stack, options); err != nil { + if err = addRetry(stack, options); err != nil { return err } - if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + if err = addRawResponseToMetadata(stack); err != nil { return err } - if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + if err = addRecordResponseTiming(stack); err != nil { + return err + } + if err = addSpanRetryLoop(stack, options); err != nil { return err } if err = addClientUserAgent(stack, options); err != nil { @@ -174,10 +194,16 @@ func (c *Client) addOperationGetSessionTokenMiddlewares(stack *middleware.Stack, if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil { return err } + if err = addTimeOffsetBuild(stack, c); err != nil { + return err + } + if err = addUserAgentRetryMode(stack, options); err != nil { + return err + } if err = stack.Initialize.Add(newServiceMetadataMiddleware_opGetSessionToken(options.Region), middleware.Before); err != nil { return err } - if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + if err = addRecursionDetection(stack); err != nil { return err } if err = addRequestIDRetrieverMiddleware(stack); err != nil { @@ -192,6 +218,18 @@ func (c *Client) addOperationGetSessionTokenMiddlewares(stack *middleware.Stack, if err = addDisableHTTPSMiddleware(stack, options); err != nil { return err } + if err = addSpanInitializeStart(stack); err != nil { + return err + } + if err = addSpanInitializeEnd(stack); err != nil { + return err + } + if err = addSpanBuildRequestStart(stack); err != nil { + return err + } + if err = addSpanBuildRequestEnd(stack); err != nil { + return err + } return nil } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/auth.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/auth.go index 9db5bfd..a90b2b7 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/auth.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/auth.go @@ -8,11 +8,13 @@ import ( awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" smithy "github.com/aws/smithy-go" smithyauth "github.com/aws/smithy-go/auth" + "github.com/aws/smithy-go/metrics" "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" ) -func bindAuthParamsRegion(params *AuthResolverParameters, _ interface{}, options Options) { +func bindAuthParamsRegion(_ interface{}, params *AuthResolverParameters, _ interface{}, options Options) { params.Region = options.Region } @@ -90,12 +92,12 @@ type AuthResolverParameters struct { Region string } -func bindAuthResolverParams(operation string, input interface{}, options Options) *AuthResolverParameters { +func bindAuthResolverParams(ctx context.Context, operation string, input interface{}, options Options) *AuthResolverParameters { params := &AuthResolverParameters{ Operation: operation, } - bindAuthParamsRegion(params, input, options) + bindAuthParamsRegion(ctx, params, input, options) return params } @@ -157,7 +159,10 @@ func (*resolveAuthSchemeMiddleware) ID() string { func (m *resolveAuthSchemeMiddleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) ( out middleware.FinalizeOutput, metadata middleware.Metadata, err error, ) { - params := bindAuthResolverParams(m.operation, getOperationInput(ctx), m.options) + _, span := tracing.StartSpan(ctx, "ResolveAuthScheme") + defer span.End() + + params := bindAuthResolverParams(ctx, m.operation, getOperationInput(ctx), m.options) options, err := m.options.AuthSchemeResolver.ResolveAuthSchemes(ctx, params) if err != nil { return out, metadata, fmt.Errorf("resolve auth scheme: %w", err) @@ -169,6 +174,9 @@ func (m *resolveAuthSchemeMiddleware) HandleFinalize(ctx context.Context, in mid } ctx = setResolvedAuthScheme(ctx, scheme) + + span.SetProperty("auth.scheme_id", scheme.Scheme.SchemeID()) + span.End() return next.HandleFinalize(ctx, in) } @@ -228,7 +236,10 @@ func (*getIdentityMiddleware) ID() string { func (m *getIdentityMiddleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) ( out middleware.FinalizeOutput, metadata middleware.Metadata, err error, ) { - rscheme := getResolvedAuthScheme(ctx) + innerCtx, span := tracing.StartSpan(ctx, "GetIdentity") + defer span.End() + + rscheme := getResolvedAuthScheme(innerCtx) if rscheme == nil { return out, metadata, fmt.Errorf("no resolved auth scheme") } @@ -238,12 +249,20 @@ func (m *getIdentityMiddleware) HandleFinalize(ctx context.Context, in middlewar return out, metadata, fmt.Errorf("no identity resolver") } - identity, err := resolver.GetIdentity(ctx, rscheme.IdentityProperties) + identity, err := timeOperationMetric(ctx, "client.call.resolve_identity_duration", + func() (smithyauth.Identity, error) { + return resolver.GetIdentity(innerCtx, rscheme.IdentityProperties) + }, + func(o *metrics.RecordMetricOptions) { + o.Properties.Set("auth.scheme_id", rscheme.Scheme.SchemeID()) + }) if err != nil { return out, metadata, fmt.Errorf("get identity: %w", err) } ctx = setIdentity(ctx, identity) + + span.End() return next.HandleFinalize(ctx, in) } @@ -259,6 +278,7 @@ func getIdentity(ctx context.Context) smithyauth.Identity { } type signRequestMiddleware struct { + options Options } func (*signRequestMiddleware) ID() string { @@ -268,6 +288,9 @@ func (*signRequestMiddleware) ID() string { func (m *signRequestMiddleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) ( out middleware.FinalizeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "SignRequest") + defer span.End() + req, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, fmt.Errorf("unexpected transport type %T", in.Request) @@ -288,9 +311,15 @@ func (m *signRequestMiddleware) HandleFinalize(ctx context.Context, in middlewar return out, metadata, fmt.Errorf("no signer") } - if err := signer.SignRequest(ctx, req, identity, rscheme.SignerProperties); err != nil { + _, err = timeOperationMetric(ctx, "client.call.signing_duration", func() (any, error) { + return nil, signer.SignRequest(ctx, req, identity, rscheme.SignerProperties) + }, func(o *metrics.RecordMetricOptions) { + o.Properties.Set("auth.scheme_id", rscheme.Scheme.SchemeID()) + }) + if err != nil { return out, metadata, fmt.Errorf("sign request: %w", err) } + span.End() return next.HandleFinalize(ctx, in) } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/deserializers.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/deserializers.go index 5d634ce..5934989 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/deserializers.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/deserializers.go @@ -16,12 +16,22 @@ import ( "github.com/aws/smithy-go/middleware" "github.com/aws/smithy-go/ptr" smithytime "github.com/aws/smithy-go/time" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" "io" "strconv" "strings" + "time" ) +func deserializeS3Expires(v string) (*time.Time, error) { + t, err := smithytime.ParseHTTPDate(v) + if err != nil { + return nil, nil + } + return &t, nil +} + type awsAwsquery_deserializeOpAssumeRole struct { } @@ -37,6 +47,10 @@ func (m *awsAwsquery_deserializeOpAssumeRole) HandleDeserialize(ctx context.Cont return out, metadata, err } + _, span := tracing.StartSpan(ctx, "OperationDeserializer") + endTimer := startMetricTimer(ctx, "client.call.deserialization_duration") + defer endTimer() + defer span.End() response, ok := out.RawResponse.(*smithyhttp.Response) if !ok { return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} @@ -154,6 +168,10 @@ func (m *awsAwsquery_deserializeOpAssumeRoleWithSAML) HandleDeserialize(ctx cont return out, metadata, err } + _, span := tracing.StartSpan(ctx, "OperationDeserializer") + endTimer := startMetricTimer(ctx, "client.call.deserialization_duration") + defer endTimer() + defer span.End() response, ok := out.RawResponse.(*smithyhttp.Response) if !ok { return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} @@ -277,6 +295,10 @@ func (m *awsAwsquery_deserializeOpAssumeRoleWithWebIdentity) HandleDeserialize(c return out, metadata, err } + _, span := tracing.StartSpan(ctx, "OperationDeserializer") + endTimer := startMetricTimer(ctx, "client.call.deserialization_duration") + defer endTimer() + defer span.End() response, ok := out.RawResponse.(*smithyhttp.Response) if !ok { return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} @@ -388,6 +410,121 @@ func awsAwsquery_deserializeOpErrorAssumeRoleWithWebIdentity(response *smithyhtt } } +type awsAwsquery_deserializeOpAssumeRoot struct { +} + +func (*awsAwsquery_deserializeOpAssumeRoot) ID() string { + return "OperationDeserializer" +} + +func (m *awsAwsquery_deserializeOpAssumeRoot) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + _, span := tracing.StartSpan(ctx, "OperationDeserializer") + endTimer := startMetricTimer(ctx, "client.call.deserialization_duration") + defer endTimer() + defer span.End() + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsAwsquery_deserializeOpErrorAssumeRoot(response, &metadata) + } + output := &AssumeRootOutput{} + out.Result = output + + var buff [1024]byte + ringBuffer := smithyio.NewRingBuffer(buff[:]) + body := io.TeeReader(response.Body, ringBuffer) + rootDecoder := xml.NewDecoder(body) + t, err := smithyxml.FetchRootElement(rootDecoder) + if err == io.EOF { + return out, metadata, nil + } + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + } + + decoder := smithyxml.WrapNodeDecoder(rootDecoder, t) + t, err = decoder.GetElement("AssumeRootResult") + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + err = &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + return out, metadata, err + } + + decoder = smithyxml.WrapNodeDecoder(decoder.Decoder, t) + err = awsAwsquery_deserializeOpDocumentAssumeRootOutput(&output, decoder) + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + err = &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + return out, metadata, err + } + + return out, metadata, err +} + +func awsAwsquery_deserializeOpErrorAssumeRoot(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + errorComponents, err := awsxml.GetErrorResponseComponents(errorBody, false) + if err != nil { + return err + } + if reqID := errorComponents.RequestID; len(reqID) != 0 { + awsmiddleware.SetRequestIDMetadata(metadata, reqID) + } + if len(errorComponents.Code) != 0 { + errorCode = errorComponents.Code + } + if len(errorComponents.Message) != 0 { + errorMessage = errorComponents.Message + } + errorBody.Seek(0, io.SeekStart) + switch { + case strings.EqualFold("ExpiredTokenException", errorCode): + return awsAwsquery_deserializeErrorExpiredTokenException(response, errorBody) + + case strings.EqualFold("RegionDisabledException", errorCode): + return awsAwsquery_deserializeErrorRegionDisabledException(response, errorBody) + + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + type awsAwsquery_deserializeOpDecodeAuthorizationMessage struct { } @@ -403,6 +540,10 @@ func (m *awsAwsquery_deserializeOpDecodeAuthorizationMessage) HandleDeserialize( return out, metadata, err } + _, span := tracing.StartSpan(ctx, "OperationDeserializer") + endTimer := startMetricTimer(ctx, "client.call.deserialization_duration") + defer endTimer() + defer span.End() response, ok := out.RawResponse.(*smithyhttp.Response) if !ok { return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} @@ -511,6 +652,10 @@ func (m *awsAwsquery_deserializeOpGetAccessKeyInfo) HandleDeserialize(ctx contex return out, metadata, err } + _, span := tracing.StartSpan(ctx, "OperationDeserializer") + endTimer := startMetricTimer(ctx, "client.call.deserialization_duration") + defer endTimer() + defer span.End() response, ok := out.RawResponse.(*smithyhttp.Response) if !ok { return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} @@ -616,6 +761,10 @@ func (m *awsAwsquery_deserializeOpGetCallerIdentity) HandleDeserialize(ctx conte return out, metadata, err } + _, span := tracing.StartSpan(ctx, "OperationDeserializer") + endTimer := startMetricTimer(ctx, "client.call.deserialization_duration") + defer endTimer() + defer span.End() response, ok := out.RawResponse.(*smithyhttp.Response) if !ok { return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} @@ -721,6 +870,10 @@ func (m *awsAwsquery_deserializeOpGetFederationToken) HandleDeserialize(ctx cont return out, metadata, err } + _, span := tracing.StartSpan(ctx, "OperationDeserializer") + endTimer := startMetricTimer(ctx, "client.call.deserialization_duration") + defer endTimer() + defer span.End() response, ok := out.RawResponse.(*smithyhttp.Response) if !ok { return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} @@ -835,6 +988,10 @@ func (m *awsAwsquery_deserializeOpGetSessionToken) HandleDeserialize(ctx context return out, metadata, err } + _, span := tracing.StartSpan(ctx, "OperationDeserializer") + endTimer := startMetricTimer(ctx, "client.call.deserialization_duration") + defer endTimer() + defer span.End() response, ok := out.RawResponse.(*smithyhttp.Response) if !ok { return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} @@ -2226,6 +2383,61 @@ func awsAwsquery_deserializeOpDocumentAssumeRoleWithWebIdentityOutput(v **Assume return nil } +func awsAwsquery_deserializeOpDocumentAssumeRootOutput(v **AssumeRootOutput, decoder smithyxml.NodeDecoder) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + var sv *AssumeRootOutput + if *v == nil { + sv = &AssumeRootOutput{} + } else { + sv = *v + } + + for { + t, done, err := decoder.Token() + if err != nil { + return err + } + if done { + break + } + originalDecoder := decoder + decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) + switch { + case strings.EqualFold("Credentials", t.Name.Local): + nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + if err := awsAwsquery_deserializeDocumentCredentials(&sv.Credentials, nodeDecoder); err != nil { + return err + } + + case strings.EqualFold("SourceIdentity", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + sv.SourceIdentity = ptr.String(xtv) + } + + default: + // Do nothing and ignore the unexpected tag element + err = decoder.Decoder.Skip() + if err != nil { + return err + } + + } + decoder = originalDecoder + } + *v = sv + return nil +} + func awsAwsquery_deserializeOpDocumentDecodeAuthorizationMessageOutput(v **DecodeAuthorizationMessageOutput, decoder smithyxml.NodeDecoder) error { if v == nil { return fmt.Errorf("unexpected nil of type %T", v) diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/doc.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/doc.go index d963fd8..cbb19c7 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/doc.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/doc.go @@ -3,9 +3,11 @@ // Package sts provides the API client, operations, and parameter types for AWS // Security Token Service. // -// Security Token Service Security Token Service (STS) enables you to request -// temporary, limited-privilege credentials for users. This guide provides -// descriptions of the STS API. For more information about using this service, see -// Temporary Security Credentials (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html) -// . +// # Security Token Service +// +// Security Token Service (STS) enables you to request temporary, +// limited-privilege credentials for users. This guide provides descriptions of the +// STS API. For more information about using this service, see [Temporary Security Credentials]. +// +// [Temporary Security Credentials]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html package sts diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/endpoints.go index 9f7932f..dca2ce3 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/endpoints.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/endpoints.go @@ -17,6 +17,7 @@ import ( smithyendpoints "github.com/aws/smithy-go/endpoints" "github.com/aws/smithy-go/middleware" "github.com/aws/smithy-go/ptr" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" "net/http" "net/url" @@ -217,6 +218,13 @@ func resolveBaseEndpoint(cfg aws.Config, o *Options) { } } +func bindRegion(region string) *string { + if region == "" { + return nil + } + return aws.String(endpoints.MapFIPSRegion(region)) +} + // EndpointParameters provides the parameters that influence how endpoints are // resolved. type EndpointParameters struct { @@ -299,6 +307,17 @@ func (p EndpointParameters) WithDefaults() EndpointParameters { return p } +type stringSlice []string + +func (s stringSlice) Get(i int) *string { + if i < 0 || i >= len(s) { + return nil + } + + v := s[i] + return &v +} + // EndpointResolverV2 provides the interface for resolving service endpoints. type EndpointResolverV2 interface { // ResolveEndpoint attempts to resolve the endpoint with the provided options, @@ -1038,10 +1057,10 @@ type endpointParamsBinder interface { bindEndpointParams(*EndpointParameters) } -func bindEndpointParams(input interface{}, options Options) *EndpointParameters { +func bindEndpointParams(ctx context.Context, input interface{}, options Options) *EndpointParameters { params := &EndpointParameters{} - params.Region = aws.String(endpoints.MapFIPSRegion(options.Region)) + params.Region = bindRegion(options.Region) params.UseDualStack = aws.Bool(options.EndpointOptions.UseDualStackEndpoint == aws.DualStackEndpointStateEnabled) params.UseFIPS = aws.Bool(options.EndpointOptions.UseFIPSEndpoint == aws.FIPSEndpointStateEnabled) params.Endpoint = options.BaseEndpoint @@ -1064,6 +1083,9 @@ func (*resolveEndpointV2Middleware) ID() string { func (m *resolveEndpointV2Middleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) ( out middleware.FinalizeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "ResolveEndpoint") + defer span.End() + if awsmiddleware.GetRequiresLegacyEndpoints(ctx) { return next.HandleFinalize(ctx, in) } @@ -1077,12 +1099,17 @@ func (m *resolveEndpointV2Middleware) HandleFinalize(ctx context.Context, in mid return out, metadata, fmt.Errorf("expected endpoint resolver to not be nil") } - params := bindEndpointParams(getOperationInput(ctx), m.options) - endpt, err := m.options.EndpointResolverV2.ResolveEndpoint(ctx, *params) + params := bindEndpointParams(ctx, getOperationInput(ctx), m.options) + endpt, err := timeOperationMetric(ctx, "client.call.resolve_endpoint_duration", + func() (smithyendpoints.Endpoint, error) { + return m.options.EndpointResolverV2.ResolveEndpoint(ctx, *params) + }) if err != nil { return out, metadata, fmt.Errorf("failed to resolve service endpoint, %w", err) } + span.SetProperty("client.call.resolved_endpoint", endpt.URI.String()) + if endpt.URI.RawPath == "" && req.URL.RawPath != "" { endpt.URI.RawPath = endpt.URI.Path } @@ -1104,5 +1131,6 @@ func (m *resolveEndpointV2Middleware) HandleFinalize(ctx context.Context, in mid rscheme.SignerProperties.SetAll(&o.SignerProperties) } + span.End() return next.HandleFinalize(ctx, in) } diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/generated.json b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/generated.json index d90b8bc..70a8845 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/generated.json +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/generated.json @@ -5,8 +5,7 @@ "github.com/aws/aws-sdk-go-v2/internal/endpoints/v2": "v2.0.0-00010101000000-000000000000", "github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding": "v1.0.5", "github.com/aws/aws-sdk-go-v2/service/internal/presigned-url": "v1.0.7", - "github.com/aws/smithy-go": "v1.4.0", - "github.com/google/go-cmp": "v0.5.4" + "github.com/aws/smithy-go": "v1.4.0" }, "files": [ "api_client.go", @@ -14,6 +13,7 @@ "api_op_AssumeRole.go", "api_op_AssumeRoleWithSAML.go", "api_op_AssumeRoleWithWebIdentity.go", + "api_op_AssumeRoot.go", "api_op_DecodeAuthorizationMessage.go", "api_op_GetAccessKeyInfo.go", "api_op_GetCallerIdentity.go", @@ -31,6 +31,7 @@ "options.go", "protocol_test.go", "serializers.go", + "snapshot_test.go", "types/errors.go", "types/types.go", "validators.go" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/go_module_metadata.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/go_module_metadata.go index 962c336..2827701 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/go_module_metadata.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/go_module_metadata.go @@ -3,4 +3,4 @@ package sts // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.26.7" +const goModuleVersion = "1.33.13" diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/internal/endpoints/endpoints.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/internal/endpoints/endpoints.go index 3dbd993..8fc2012 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/internal/endpoints/endpoints.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/internal/endpoints/endpoints.go @@ -94,7 +94,7 @@ var partitionRegexp = struct { AwsUsGov *regexp.Regexp }{ - Aws: regexp.MustCompile("^(us|eu|ap|sa|ca|me|af|il)\\-\\w+\\-\\d+$"), + Aws: regexp.MustCompile("^(us|eu|ap|sa|ca|me|af|il|mx)\\-\\w+\\-\\d+$"), AwsCn: regexp.MustCompile("^cn\\-\\w+\\-\\d+$"), AwsIso: regexp.MustCompile("^us\\-iso\\-\\w+\\-\\d+$"), AwsIsoB: regexp.MustCompile("^us\\-isob\\-\\w+\\-\\d+$"), @@ -172,6 +172,12 @@ var defaultPartitions = endpoints.Partitions{ endpoints.EndpointKey{ Region: "ap-southeast-4", }: endpoints.Endpoint{}, + endpoints.EndpointKey{ + Region: "ap-southeast-5", + }: endpoints.Endpoint{}, + endpoints.EndpointKey{ + Region: "ap-southeast-7", + }: endpoints.Endpoint{}, endpoints.EndpointKey{ Region: "aws-global", }: endpoints.Endpoint{ @@ -219,6 +225,9 @@ var defaultPartitions = endpoints.Partitions{ endpoints.EndpointKey{ Region: "me-south-1", }: endpoints.Endpoint{}, + endpoints.EndpointKey{ + Region: "mx-central-1", + }: endpoints.Endpoint{}, endpoints.EndpointKey{ Region: "sa-east-1", }: endpoints.Endpoint{}, @@ -435,6 +444,14 @@ var defaultPartitions = endpoints.Partitions{ }, RegionRegex: partitionRegexp.AwsIsoF, IsRegionalized: true, + Endpoints: endpoints.Endpoints{ + endpoints.EndpointKey{ + Region: "us-isof-east-1", + }: endpoints.Endpoint{}, + endpoints.EndpointKey{ + Region: "us-isof-south-1", + }: endpoints.Endpoint{}, + }, }, { ID: "aws-us-gov", diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/options.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/options.go index 5c1be79..e1398f3 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/options.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/options.go @@ -9,7 +9,9 @@ import ( internalauthsmithy "github.com/aws/aws-sdk-go-v2/internal/auth/smithy" smithyauth "github.com/aws/smithy-go/auth" "github.com/aws/smithy-go/logging" + "github.com/aws/smithy-go/metrics" "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" "net/http" ) @@ -50,8 +52,10 @@ type Options struct { // Deprecated: Deprecated: EndpointResolver and WithEndpointResolver. Providing a // value for this field will likely prevent you from using any endpoint-related // service features released after the introduction of EndpointResolverV2 and - // BaseEndpoint. To migrate an EndpointResolver implementation that uses a custom - // endpoint, set the client option BaseEndpoint instead. + // BaseEndpoint. + // + // To migrate an EndpointResolver implementation that uses a custom endpoint, set + // the client option BaseEndpoint instead. EndpointResolver EndpointResolver // Resolves the endpoint used for a particular service operation. This should be @@ -64,23 +68,29 @@ type Options struct { // The logger writer interface to write logging messages to. Logger logging.Logger + // The client meter provider. + MeterProvider metrics.MeterProvider + // The region to send requests to. (Required) Region string // RetryMaxAttempts specifies the maximum number attempts an API client will call // an operation that fails with a retryable error. A value of 0 is ignored, and // will not be used to configure the API client created default retryer, or modify - // per operation call's retry max attempts. If specified in an operation call's - // functional options with a value that is different than the constructed client's - // Options, the Client's Retryer will be wrapped to use the operation's specific - // RetryMaxAttempts value. + // per operation call's retry max attempts. + // + // If specified in an operation call's functional options with a value that is + // different than the constructed client's Options, the Client's Retryer will be + // wrapped to use the operation's specific RetryMaxAttempts value. RetryMaxAttempts int // RetryMode specifies the retry mode the API client will be created with, if - // Retryer option is not also specified. When creating a new API Clients this - // member will only be used if the Retryer Options member is nil. This value will - // be ignored if Retryer is not nil. Currently does not support per operation call - // overrides, may in the future. + // Retryer option is not also specified. + // + // When creating a new API Clients this member will only be used if the Retryer + // Options member is nil. This value will be ignored if Retryer is not nil. + // + // Currently does not support per operation call overrides, may in the future. RetryMode aws.RetryMode // Retryer guides how HTTP requests should be retried in case of recoverable @@ -95,10 +105,14 @@ type Options struct { // within your applications. RuntimeEnvironment aws.RuntimeEnvironment + // The client tracer provider. + TracerProvider tracing.TracerProvider + // The initial DefaultsMode used when the client options were constructed. If the // DefaultsMode was set to aws.DefaultsModeAuto this will store what the resolved - // value was at that point in time. Currently does not support per operation call - // overrides, may in the future. + // value was at that point in time. + // + // Currently does not support per operation call overrides, may in the future. resolvedDefaultsMode aws.DefaultsMode // The HTTP client to invoke API calls with. Defaults to client's default HTTP @@ -143,6 +157,7 @@ func WithAPIOptions(optFns ...func(*middleware.Stack) error) func(*Options) { // Deprecated: EndpointResolver and WithEndpointResolver. Providing a value for // this field will likely prevent you from using any endpoint-related service // features released after the introduction of EndpointResolverV2 and BaseEndpoint. +// // To migrate an EndpointResolver implementation that uses a custom endpoint, set // the client option BaseEndpoint instead. func WithEndpointResolver(v EndpointResolver) func(*Options) { diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/serializers.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/serializers.go index 4c08061..96b2221 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/serializers.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/serializers.go @@ -11,6 +11,7 @@ import ( smithy "github.com/aws/smithy-go" "github.com/aws/smithy-go/encoding/httpbinding" "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/tracing" smithyhttp "github.com/aws/smithy-go/transport/http" "path" ) @@ -25,6 +26,10 @@ func (*awsAwsquery_serializeOpAssumeRole) ID() string { func (m *awsAwsquery_serializeOpAssumeRole) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( out middleware.SerializeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "OperationSerializer") + endTimer := startMetricTimer(ctx, "client.call.serialization_duration") + defer endTimer() + defer span.End() request, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} @@ -76,6 +81,8 @@ func (m *awsAwsquery_serializeOpAssumeRole) HandleSerialize(ctx context.Context, } in.Request = request + endTimer() + span.End() return next.HandleSerialize(ctx, in) } @@ -89,6 +96,10 @@ func (*awsAwsquery_serializeOpAssumeRoleWithSAML) ID() string { func (m *awsAwsquery_serializeOpAssumeRoleWithSAML) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( out middleware.SerializeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "OperationSerializer") + endTimer := startMetricTimer(ctx, "client.call.serialization_duration") + defer endTimer() + defer span.End() request, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} @@ -140,6 +151,8 @@ func (m *awsAwsquery_serializeOpAssumeRoleWithSAML) HandleSerialize(ctx context. } in.Request = request + endTimer() + span.End() return next.HandleSerialize(ctx, in) } @@ -153,6 +166,10 @@ func (*awsAwsquery_serializeOpAssumeRoleWithWebIdentity) ID() string { func (m *awsAwsquery_serializeOpAssumeRoleWithWebIdentity) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( out middleware.SerializeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "OperationSerializer") + endTimer := startMetricTimer(ctx, "client.call.serialization_duration") + defer endTimer() + defer span.End() request, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} @@ -204,6 +221,78 @@ func (m *awsAwsquery_serializeOpAssumeRoleWithWebIdentity) HandleSerialize(ctx c } in.Request = request + endTimer() + span.End() + return next.HandleSerialize(ctx, in) +} + +type awsAwsquery_serializeOpAssumeRoot struct { +} + +func (*awsAwsquery_serializeOpAssumeRoot) ID() string { + return "OperationSerializer" +} + +func (m *awsAwsquery_serializeOpAssumeRoot) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + _, span := tracing.StartSpan(ctx, "OperationSerializer") + endTimer := startMetricTimer(ctx, "client.call.serialization_duration") + defer endTimer() + defer span.End() + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*AssumeRootInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + operationPath := "/" + if len(request.Request.URL.Path) == 0 { + request.Request.URL.Path = operationPath + } else { + request.Request.URL.Path = path.Join(request.Request.URL.Path, operationPath) + if request.Request.URL.Path != "/" && operationPath[len(operationPath)-1] == '/' { + request.Request.URL.Path += "/" + } + } + request.Request.Method = "POST" + httpBindingEncoder, err := httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + httpBindingEncoder.SetHeader("Content-Type").String("application/x-www-form-urlencoded") + + bodyWriter := bytes.NewBuffer(nil) + bodyEncoder := query.NewEncoder(bodyWriter) + body := bodyEncoder.Object() + body.Key("Action").String("AssumeRoot") + body.Key("Version").String("2011-06-15") + + if err := awsAwsquery_serializeOpDocumentAssumeRootInput(input, bodyEncoder.Value); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + err = bodyEncoder.Encode() + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request, err = request.SetStream(bytes.NewReader(bodyWriter.Bytes())); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request.Request, err = httpBindingEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + endTimer() + span.End() return next.HandleSerialize(ctx, in) } @@ -217,6 +306,10 @@ func (*awsAwsquery_serializeOpDecodeAuthorizationMessage) ID() string { func (m *awsAwsquery_serializeOpDecodeAuthorizationMessage) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( out middleware.SerializeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "OperationSerializer") + endTimer := startMetricTimer(ctx, "client.call.serialization_duration") + defer endTimer() + defer span.End() request, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} @@ -268,6 +361,8 @@ func (m *awsAwsquery_serializeOpDecodeAuthorizationMessage) HandleSerialize(ctx } in.Request = request + endTimer() + span.End() return next.HandleSerialize(ctx, in) } @@ -281,6 +376,10 @@ func (*awsAwsquery_serializeOpGetAccessKeyInfo) ID() string { func (m *awsAwsquery_serializeOpGetAccessKeyInfo) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( out middleware.SerializeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "OperationSerializer") + endTimer := startMetricTimer(ctx, "client.call.serialization_duration") + defer endTimer() + defer span.End() request, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} @@ -332,6 +431,8 @@ func (m *awsAwsquery_serializeOpGetAccessKeyInfo) HandleSerialize(ctx context.Co } in.Request = request + endTimer() + span.End() return next.HandleSerialize(ctx, in) } @@ -345,6 +446,10 @@ func (*awsAwsquery_serializeOpGetCallerIdentity) ID() string { func (m *awsAwsquery_serializeOpGetCallerIdentity) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( out middleware.SerializeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "OperationSerializer") + endTimer := startMetricTimer(ctx, "client.call.serialization_duration") + defer endTimer() + defer span.End() request, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} @@ -392,6 +497,8 @@ func (m *awsAwsquery_serializeOpGetCallerIdentity) HandleSerialize(ctx context.C } in.Request = request + endTimer() + span.End() return next.HandleSerialize(ctx, in) } @@ -405,6 +512,10 @@ func (*awsAwsquery_serializeOpGetFederationToken) ID() string { func (m *awsAwsquery_serializeOpGetFederationToken) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( out middleware.SerializeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "OperationSerializer") + endTimer := startMetricTimer(ctx, "client.call.serialization_duration") + defer endTimer() + defer span.End() request, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} @@ -456,6 +567,8 @@ func (m *awsAwsquery_serializeOpGetFederationToken) HandleSerialize(ctx context. } in.Request = request + endTimer() + span.End() return next.HandleSerialize(ctx, in) } @@ -469,6 +582,10 @@ func (*awsAwsquery_serializeOpGetSessionToken) ID() string { func (m *awsAwsquery_serializeOpGetSessionToken) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( out middleware.SerializeOutput, metadata middleware.Metadata, err error, ) { + _, span := tracing.StartSpan(ctx, "OperationSerializer") + endTimer := startMetricTimer(ctx, "client.call.serialization_duration") + defer endTimer() + defer span.End() request, ok := in.Request.(*smithyhttp.Request) if !ok { return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} @@ -520,6 +637,8 @@ func (m *awsAwsquery_serializeOpGetSessionToken) HandleSerialize(ctx context.Con } in.Request = request + endTimer() + span.End() return next.HandleSerialize(ctx, in) } func awsAwsquery_serializeDocumentPolicyDescriptorListType(v []types.PolicyDescriptorType, value query.Value) error { @@ -772,6 +891,30 @@ func awsAwsquery_serializeOpDocumentAssumeRoleWithWebIdentityInput(v *AssumeRole return nil } +func awsAwsquery_serializeOpDocumentAssumeRootInput(v *AssumeRootInput, value query.Value) error { + object := value.Object() + _ = object + + if v.DurationSeconds != nil { + objectKey := object.Key("DurationSeconds") + objectKey.Integer(*v.DurationSeconds) + } + + if v.TargetPrincipal != nil { + objectKey := object.Key("TargetPrincipal") + objectKey.String(*v.TargetPrincipal) + } + + if v.TaskPolicyArn != nil { + objectKey := object.Key("TaskPolicyArn") + if err := awsAwsquery_serializeDocumentPolicyDescriptorType(v.TaskPolicyArn, objectKey); err != nil { + return err + } + } + + return nil +} + func awsAwsquery_serializeOpDocumentDecodeAuthorizationMessageInput(v *DecodeAuthorizationMessageInput, value query.Value) error { object := value.Object() _ = object diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/types/errors.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/types/errors.go index 097875b..041629b 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/types/errors.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/types/errors.go @@ -65,9 +65,10 @@ func (e *IDPCommunicationErrorException) ErrorCode() string { func (e *IDPCommunicationErrorException) ErrorFault() smithy.ErrorFault { return smithy.FaultClient } // The identity provider (IdP) reported that authentication failed. This might be -// because the claim is invalid. If this error is returned for the -// AssumeRoleWithWebIdentity operation, it can also mean that the claim has expired -// or has been explicitly revoked. +// because the claim is invalid. +// +// If this error is returned for the AssumeRoleWithWebIdentity operation, it can +// also mean that the claim has expired or has been explicitly revoked. type IDPRejectedClaimException struct { Message *string @@ -94,8 +95,8 @@ func (e *IDPRejectedClaimException) ErrorCode() string { func (e *IDPRejectedClaimException) ErrorFault() smithy.ErrorFault { return smithy.FaultClient } // The error returned if the message passed to DecodeAuthorizationMessage was -// invalid. This can happen if the token contains invalid characters, such as -// linebreaks. +// invalid. This can happen if the token contains invalid characters, such as line +// breaks, or if the message has expired. type InvalidAuthorizationMessageException struct { Message *string @@ -183,11 +184,13 @@ func (e *MalformedPolicyDocumentException) ErrorFault() smithy.ErrorFault { retu // compresses the session policy document, session policy ARNs, and session tags // into a packed binary format that has a separate limit. The error message // indicates by percentage how close the policies and tags are to the upper size -// limit. For more information, see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) -// in the IAM User Guide. You could receive this error even though you meet other -// defined session policy and session tag limits. For more information, see IAM -// and STS Entity Character Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html#reference_iam-limits-entity-length) -// in the IAM User Guide. +// limit. For more information, see [Passing Session Tags in STS]in the IAM User Guide. +// +// You could receive this error even though you meet other defined session policy +// and session tag limits. For more information, see [IAM and STS Entity Character Limits]in the IAM User Guide. +// +// [Passing Session Tags in STS]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html +// [IAM and STS Entity Character Limits]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html#reference_iam-limits-entity-length type PackedPolicyTooLargeException struct { Message *string @@ -215,9 +218,10 @@ func (e *PackedPolicyTooLargeException) ErrorFault() smithy.ErrorFault { return // STS is not activated in the requested region for the account that is being // asked to generate credentials. The account administrator must use the IAM -// console to activate STS in that region. For more information, see Activating -// and Deactivating Amazon Web Services STS in an Amazon Web Services Region (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html) -// in the IAM User Guide. +// console to activate STS in that region. For more information, see [Activating and Deactivating STS in an Amazon Web Services Region]in the IAM +// User Guide. +// +// [Activating and Deactivating STS in an Amazon Web Services Region]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html type RegionDisabledException struct { Message *string diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/types/types.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/types/types.go index e3701d1..dff7a3c 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/types/types.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/types/types.go @@ -11,10 +11,11 @@ import ( // returns. type AssumedRoleUser struct { - // The ARN of the temporary security credentials that are returned from the - // AssumeRole action. For more information about ARNs and how to use them in - // policies, see IAM Identifiers (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html) - // in the IAM User Guide. + // The ARN of the temporary security credentials that are returned from the AssumeRole + // action. For more information about ARNs and how to use them in policies, see [IAM Identifiers]in + // the IAM User Guide. + // + // [IAM Identifiers]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html // // This member is required. Arn *string @@ -61,8 +62,9 @@ type FederatedUser struct { // The ARN that specifies the federated user that is associated with the // credentials. For more information about ARNs and how to use them in policies, - // see IAM Identifiers (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html) - // in the IAM User Guide. + // see [IAM Identifiers]in the IAM User Guide. + // + // [IAM Identifiers]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html // // This member is required. Arn *string @@ -81,9 +83,10 @@ type FederatedUser struct { type PolicyDescriptorType struct { // The Amazon Resource Name (ARN) of the IAM managed policy to use as a session - // policy for the role. For more information about ARNs, see Amazon Resource Names - // (ARNs) and Amazon Web Services Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) - // in the Amazon Web Services General Reference. + // policy for the role. For more information about ARNs, see [Amazon Resource Names (ARNs) and Amazon Web Services Service Namespaces]in the Amazon Web + // Services General Reference. + // + // [Amazon Resource Names (ARNs) and Amazon Web Services Service Namespaces]: https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html Arn *string noSmithyDocumentSerde @@ -107,23 +110,30 @@ type ProvidedContext struct { // You can pass custom key-value pair attributes when you assume a role or // federate a user. These are called session tags. You can then use the session -// tags to control access to resources. For more information, see Tagging Amazon -// Web Services STS Sessions (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) -// in the IAM User Guide. +// tags to control access to resources. For more information, see [Tagging Amazon Web Services STS Sessions]in the IAM User +// Guide. +// +// [Tagging Amazon Web Services STS Sessions]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html type Tag struct { - // The key for a session tag. You can pass up to 50 session tags. The plain text - // session tag keys can’t exceed 128 characters. For these and additional limits, - // see IAM and STS Character Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length) - // in the IAM User Guide. + // The key for a session tag. + // + // You can pass up to 50 session tags. The plain text session tag keys can’t + // exceed 128 characters. For these and additional limits, see [IAM and STS Character Limits]in the IAM User + // Guide. + // + // [IAM and STS Character Limits]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length // // This member is required. Key *string - // The value for a session tag. You can pass up to 50 session tags. The plain text - // session tag values can’t exceed 256 characters. For these and additional limits, - // see IAM and STS Character Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length) - // in the IAM User Guide. + // The value for a session tag. + // + // You can pass up to 50 session tags. The plain text session tag values can’t + // exceed 256 characters. For these and additional limits, see [IAM and STS Character Limits]in the IAM User + // Guide. + // + // [IAM and STS Character Limits]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length // // This member is required. Value *string diff --git a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/validators.go b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/validators.go index 3e4bad2..1026e22 100644 --- a/vendor/github.com/aws/aws-sdk-go-v2/service/sts/validators.go +++ b/vendor/github.com/aws/aws-sdk-go-v2/service/sts/validators.go @@ -70,6 +70,26 @@ func (m *validateOpAssumeRoleWithWebIdentity) HandleInitialize(ctx context.Conte return next.HandleInitialize(ctx, in) } +type validateOpAssumeRoot struct { +} + +func (*validateOpAssumeRoot) ID() string { + return "OperationInputValidation" +} + +func (m *validateOpAssumeRoot) HandleInitialize(ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler) ( + out middleware.InitializeOutput, metadata middleware.Metadata, err error, +) { + input, ok := in.Parameters.(*AssumeRootInput) + if !ok { + return out, metadata, fmt.Errorf("unknown input parameters type %T", in.Parameters) + } + if err := validateOpAssumeRootInput(input); err != nil { + return out, metadata, err + } + return next.HandleInitialize(ctx, in) +} + type validateOpDecodeAuthorizationMessage struct { } @@ -142,6 +162,10 @@ func addOpAssumeRoleWithWebIdentityValidationMiddleware(stack *middleware.Stack) return stack.Initialize.Add(&validateOpAssumeRoleWithWebIdentity{}, middleware.After) } +func addOpAssumeRootValidationMiddleware(stack *middleware.Stack) error { + return stack.Initialize.Add(&validateOpAssumeRoot{}, middleware.After) +} + func addOpDecodeAuthorizationMessageValidationMiddleware(stack *middleware.Stack) error { return stack.Initialize.Add(&validateOpDecodeAuthorizationMessage{}, middleware.After) } @@ -254,6 +278,24 @@ func validateOpAssumeRoleWithWebIdentityInput(v *AssumeRoleWithWebIdentityInput) } } +func validateOpAssumeRootInput(v *AssumeRootInput) error { + if v == nil { + return nil + } + invalidParams := smithy.InvalidParamsError{Context: "AssumeRootInput"} + if v.TargetPrincipal == nil { + invalidParams.Add(smithy.NewErrParamRequired("TargetPrincipal")) + } + if v.TaskPolicyArn == nil { + invalidParams.Add(smithy.NewErrParamRequired("TaskPolicyArn")) + } + if invalidParams.Len() > 0 { + return invalidParams + } else { + return nil + } +} + func validateOpDecodeAuthorizationMessageInput(v *DecodeAuthorizationMessageInput) error { if v == nil { return nil diff --git a/vendor/github.com/aws/smithy-go/.gitignore b/vendor/github.com/aws/smithy-go/.gitignore index c92d610..2518b34 100644 --- a/vendor/github.com/aws/smithy-go/.gitignore +++ b/vendor/github.com/aws/smithy-go/.gitignore @@ -24,3 +24,6 @@ build/ # VS Code bin/ .vscode/ + +# make +c.out diff --git a/vendor/github.com/aws/smithy-go/CHANGELOG.md b/vendor/github.com/aws/smithy-go/CHANGELOG.md index 46b1150..de39171 100644 --- a/vendor/github.com/aws/smithy-go/CHANGELOG.md +++ b/vendor/github.com/aws/smithy-go/CHANGELOG.md @@ -1,3 +1,79 @@ +# Release (2025-01-21) + +## General Highlights +* **Dependency Update**: Updated to the latest SDK module versions + +## Module Highlights +* `github.com/aws/smithy-go`: v1.22.2 + * **Bug Fix**: Fix HTTP metrics data race. + * **Bug Fix**: Replace usages of deprecated ioutil package. + +# Release (2024-11-15) + +## General Highlights +* **Dependency Update**: Updated to the latest SDK module versions + +## Module Highlights +* `github.com/aws/smithy-go`: v1.22.1 + * **Bug Fix**: Fix failure to replace URI path segments when their names overlap. + +# Release (2024-10-03) + +## General Highlights +* **Dependency Update**: Updated to the latest SDK module versions + +## Module Highlights +* `github.com/aws/smithy-go`: v1.22.0 + * **Feature**: Add HTTP client metrics. + +# Release (2024-09-25) + +## Module Highlights +* `github.com/aws/smithy-go/aws-http-auth`: [v1.0.0](aws-http-auth/CHANGELOG.md#v100-2024-09-25) + * **Release**: Initial release of module aws-http-auth, which implements generically consumable SigV4 and SigV4a request signing. + +# Release (2024-09-19) + +## General Highlights +* **Dependency Update**: Updated to the latest SDK module versions + +## Module Highlights +* `github.com/aws/smithy-go`: v1.21.0 + * **Feature**: Add tracing and metrics APIs, and builtin instrumentation for both, in generated clients. +* `github.com/aws/smithy-go/metrics/smithyotelmetrics`: [v1.0.0](metrics/smithyotelmetrics/CHANGELOG.md#v100-2024-09-19) + * **Release**: Initial release of `smithyotelmetrics` module, which is used to adapt an OpenTelemetry SDK meter provider to be used with Smithy clients. +* `github.com/aws/smithy-go/tracing/smithyoteltracing`: [v1.0.0](tracing/smithyoteltracing/CHANGELOG.md#v100-2024-09-19) + * **Release**: Initial release of `smithyoteltracing` module, which is used to adapt an OpenTelemetry SDK tracer provider to be used with Smithy clients. + +# Release (2024-08-14) + +## Module Highlights +* `github.com/aws/smithy-go`: v1.20.4 + * **Dependency Update**: Bump minimum Go version to 1.21. + +# Release (2024-06-27) + +## Module Highlights +* `github.com/aws/smithy-go`: v1.20.3 + * **Bug Fix**: Fix encoding/cbor test overflow on x86. + +# Release (2024-03-29) + +* No change notes available for this release. + +# Release (2024-02-21) + +## Module Highlights +* `github.com/aws/smithy-go`: v1.20.1 + * **Bug Fix**: Remove runtime dependency on go-cmp. + +# Release (2024-02-13) + +## Module Highlights +* `github.com/aws/smithy-go`: v1.20.0 + * **Feature**: Add codegen definition for sigv4a trait. + * **Feature**: Bump minimum Go version to 1.20 per our language support policy. + # Release (2023-12-07) ## Module Highlights diff --git a/vendor/github.com/aws/smithy-go/CONTRIBUTING.md b/vendor/github.com/aws/smithy-go/CONTRIBUTING.md index c4b6a1c..1f8d01f 100644 --- a/vendor/github.com/aws/smithy-go/CONTRIBUTING.md +++ b/vendor/github.com/aws/smithy-go/CONTRIBUTING.md @@ -39,6 +39,37 @@ To send us a pull request, please: GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). +### Changelog Documents + +(You can SKIP this step if you are only changing the code generator, and not the runtime). + +When submitting a pull request please include a changelog file on a folder named `.changelog`. +These are used to generate the content `CHANGELOG.md` and Release Notes. The format of the file is as follows: + +``` +{ + "id": "12345678-1234-1234-1234-123456789012" + "type": "bugfix" + "collapse": true + "description": "Fix improper use of printf-style functions.", + "modules": [ + "." + ] +} +``` + +* id: a UUID. This should also be used for the name of the file, so if your id is `12345678-1234-1234-1234-123456789012` the file should be named `12345678-1234-1234-1234-123456789012.json/` +* type: one of the following: + * bugfix: Fixing an existing bug + * Feature: Adding a new feature to an existing service + * Release: Releasing a new module + * Dependency: Updating dependencies + * Announcement: Making an announcement, like deprecation of a module +* collapse: whether this change should appear separately on the release notes on every module listed on `modules` (`"collapse": false`), or if it should show up as a single entry (`"collapse": true`) + * For the smithy-go repository this should always be `false` +* description: Description of this change. Most of the times is the same as the title of the PR +* modules: which Go modules does this change impact. The root module is expressed as "." + ## Finding contributions to work on Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. diff --git a/vendor/github.com/aws/smithy-go/Makefile b/vendor/github.com/aws/smithy-go/Makefile index 4b3c209..a3c2cf1 100644 --- a/vendor/github.com/aws/smithy-go/Makefile +++ b/vendor/github.com/aws/smithy-go/Makefile @@ -33,13 +33,18 @@ smithy-clean: ################## # Linting/Verify # ################## -.PHONY: verify vet +.PHONY: verify vet cover verify: vet vet: go vet ${BUILD_TAGS} --all ./... +cover: + go test ${BUILD_TAGS} -coverprofile c.out ./... + @cover=`go tool cover -func c.out | grep '^total:' | awk '{ print $$3+0 }'`; \ + echo "total (statements): $$cover%"; + ################ # Unit Testing # ################ @@ -93,5 +98,12 @@ module-version: ############## .PHONY: install-changelog +external-changelog: + mkdir -p .changelog + cp changelog-template.json .changelog/00000000-0000-0000-0000-000000000000.json + @echo "Generate a new UUID and update the file at .changelog/00000000-0000-0000-0000-000000000000.json" + @echo "Make sure to rename the file with your new id, like .changelog/12345678-1234-1234-1234-123456789012.json" + @echo "See CONTRIBUTING.md 'Changelog Documents' and an example at https://github.com/aws/smithy-go/pull/543/files" + install-changelog: go install ${REPOTOOLS_MODULE}/cmd/changelog@${REPOTOOLS_VERSION} diff --git a/vendor/github.com/aws/smithy-go/README.md b/vendor/github.com/aws/smithy-go/README.md index c374f69..08df745 100644 --- a/vendor/github.com/aws/smithy-go/README.md +++ b/vendor/github.com/aws/smithy-go/README.md @@ -1,19 +1,21 @@ -## Smithy Go +# Smithy Go [![Go Build Status](https://github.com/aws/smithy-go/actions/workflows/go.yml/badge.svg?branch=main)](https://github.com/aws/smithy-go/actions/workflows/go.yml)[![Codegen Build Status](https://github.com/aws/smithy-go/actions/workflows/codegen.yml/badge.svg?branch=main)](https://github.com/aws/smithy-go/actions/workflows/codegen.yml) -[Smithy](https://smithy.io/) code generators for Go. +[Smithy](https://smithy.io/) code generators for Go and the accompanying smithy-go runtime. + +The smithy-go runtime requires a minimum version of Go 1.20. **WARNING: All interfaces are subject to change.** -## Can I use this? +## Can I use the code generators? In order to generate a usable smithy client you must provide a [protocol definition](https://github.com/aws/smithy-go/blob/main/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/ProtocolGenerator.java), such as [AWS restJson1](https://smithy.io/2.0/aws/protocols/aws-restjson1-protocol.html), in order to generate transport mechanisms and serialization/deserialization code ("serde") accordingly. -The code generator does not currently support any protocols out of the box, +The code generator does not currently support any protocols out of the box other than the new `smithy.protocols#rpcv2Cbor`, therefore the useability of this project on its own is currently limited. Support for all [AWS protocols](https://smithy.io/2.0/aws/protocols/index.html) exists in [aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2). We are @@ -21,6 +23,70 @@ tracking the movement of those out of the SDK into smithy-go in [#458](https://github.com/aws/smithy-go/issues/458), but there's currently no timeline for doing so. +## Plugins + +This repository implements the following Smithy build plugins: + +| ID | GAV prefix | Description | +|----|------------|-------------| +| `go-codegen` | `software.amazon.smithy.go:smithy-go-codegen` | Implements Go client code generation for Smithy models. | +| `go-server-codegen` | `software.amazon.smithy.go:smithy-go-codegen` | Implements Go server code generation for Smithy models. | + +**NOTE: Build plugins are not currently published to mavenCentral. You must publish to mavenLocal to make the build plugins visible to the Smithy CLI. The artifact version is currently fixed at 0.1.0.** + +## `go-codegen` + +### Configuration + +[`GoSettings`](codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoSettings.java) +contains all of the settings enabled from `smithy-build.json` and helper +methods and types. The up-to-date list of top-level properties enabled for +`go-client-codegen` can be found in `GoSettings::from()`. + +| Setting | Type | Required | Description | +|-----------------|---------|----------|-----------------------------------------------------------------------------------------------------------------------------| +| `service` | string | yes | The Shape ID of the service for which to generate the client. | +| `module` | string | yes | Name of the module in `generated.json` (and `go.mod` if `generateGoMod` is enabled) and `doc.go`. | +| `generateGoMod` | boolean | | Whether to generate a default `go.mod` file. The default value is `false`. | +| `goDirective` | string | | [Go directive](https://go.dev/ref/mod#go-mod-file-go) of the module. The default value is the minimum supported Go version. | + +### Supported protocols + +| Protocol | Notes | +|----------|-------| +| [`smithy.protocols#rpcv2Cbor`](https://smithy.io/2.0/additional-specs/protocols/smithy-rpc-v2.html) | Event streaming not yet implemented. | + +### Example + +This example applies the `go-codegen` build plugin to the Smithy quickstart +example created from `smithy init`: + +```json +{ + "version": "1.0", + "sources": [ + "models" + ], + "maven": { + "dependencies": [ + "software.amazon.smithy.go:smithy-go-codegen:0.1.0" + ] + }, + "plugins": { + "go-codegen": { + "service": "example.weather#Weather", + "module": "github.com/example/weather", + "generateGoMod": true, + "goDirective": "1.20" + } + } +} +``` + +## `go-server-codegen` + +This plugin is a work-in-progress and is currently undocumented. + ## License This project is licensed under the Apache-2.0 License. diff --git a/vendor/github.com/aws/smithy-go/changelog-template.json b/vendor/github.com/aws/smithy-go/changelog-template.json new file mode 100644 index 0000000..d36e2b3 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/changelog-template.json @@ -0,0 +1,9 @@ +{ + "id": "00000000-0000-0000-0000-000000000000", + "type": "feature|bugfix|dependency", + "description": "Description of your changes", + "collapse": false, + "modules": [ + "." + ] +} diff --git a/vendor/github.com/aws/smithy-go/encoding/httpbinding/path_replace.go b/vendor/github.com/aws/smithy-go/encoding/httpbinding/path_replace.go index e78926c..9ae3085 100644 --- a/vendor/github.com/aws/smithy-go/encoding/httpbinding/path_replace.go +++ b/vendor/github.com/aws/smithy-go/encoding/httpbinding/path_replace.go @@ -22,33 +22,33 @@ func bufCap(b []byte, n int) []byte { // replacePathElement replaces a single element in the path []byte. // Escape is used to control whether the value will be escaped using Amazon path escape style. func replacePathElement(path, fieldBuf []byte, key, val string, escape bool) ([]byte, []byte, error) { - fieldBuf = bufCap(fieldBuf, len(key)+3) // { [+] } + // search for "{}". If not found, search for the greedy version "{+}". If none are found, return error + fieldBuf = bufCap(fieldBuf, len(key)+2) // { } fieldBuf = append(fieldBuf, uriTokenStart) fieldBuf = append(fieldBuf, key...) + fieldBuf = append(fieldBuf, uriTokenStop) start := bytes.Index(path, fieldBuf) - end := start + len(fieldBuf) - if start < 0 || len(path[end:]) == 0 { - // TODO what to do about error? - return path, fieldBuf, fmt.Errorf("invalid path index, start=%d,end=%d. %s", start, end, path) - } - encodeSep := true - if path[end] == uriTokenSkip { - // '+' token means do not escape slashes + if start < 0 { + fieldBuf = bufCap(fieldBuf, len(key)+3) // { [+] } + fieldBuf = append(fieldBuf, uriTokenStart) + fieldBuf = append(fieldBuf, key...) + fieldBuf = append(fieldBuf, uriTokenSkip) + fieldBuf = append(fieldBuf, uriTokenStop) + + start = bytes.Index(path, fieldBuf) + if start < 0 { + return path, fieldBuf, fmt.Errorf("invalid path index, start=%d. %s", start, path) + } encodeSep = false - end++ } + end := start + len(fieldBuf) if escape { val = EscapePath(val, encodeSep) } - if path[end] != uriTokenStop { - return path, fieldBuf, fmt.Errorf("invalid path element, does not contain token stop, %s", path) - } - end++ - fieldBuf = bufCap(fieldBuf, len(val)) fieldBuf = append(fieldBuf, val...) diff --git a/vendor/github.com/aws/smithy-go/go_module_metadata.go b/vendor/github.com/aws/smithy-go/go_module_metadata.go index cd6f7fa..a51ceca 100644 --- a/vendor/github.com/aws/smithy-go/go_module_metadata.go +++ b/vendor/github.com/aws/smithy-go/go_module_metadata.go @@ -3,4 +3,4 @@ package smithy // goModuleVersion is the tagged release for this module -const goModuleVersion = "1.19.0" +const goModuleVersion = "1.22.2" diff --git a/vendor/github.com/aws/smithy-go/metrics/metrics.go b/vendor/github.com/aws/smithy-go/metrics/metrics.go new file mode 100644 index 0000000..c009d9f --- /dev/null +++ b/vendor/github.com/aws/smithy-go/metrics/metrics.go @@ -0,0 +1,136 @@ +// Package metrics defines the metrics APIs used by Smithy clients. +package metrics + +import ( + "context" + + "github.com/aws/smithy-go" +) + +// MeterProvider is the entry point for creating a Meter. +type MeterProvider interface { + Meter(scope string, opts ...MeterOption) Meter +} + +// MeterOption applies configuration to a Meter. +type MeterOption func(o *MeterOptions) + +// MeterOptions represents configuration for a Meter. +type MeterOptions struct { + Properties smithy.Properties +} + +// Meter is the entry point for creation of measurement instruments. +type Meter interface { + // integer/synchronous + Int64Counter(name string, opts ...InstrumentOption) (Int64Counter, error) + Int64UpDownCounter(name string, opts ...InstrumentOption) (Int64UpDownCounter, error) + Int64Gauge(name string, opts ...InstrumentOption) (Int64Gauge, error) + Int64Histogram(name string, opts ...InstrumentOption) (Int64Histogram, error) + + // integer/asynchronous + Int64AsyncCounter(name string, callback Int64Callback, opts ...InstrumentOption) (AsyncInstrument, error) + Int64AsyncUpDownCounter(name string, callback Int64Callback, opts ...InstrumentOption) (AsyncInstrument, error) + Int64AsyncGauge(name string, callback Int64Callback, opts ...InstrumentOption) (AsyncInstrument, error) + + // floating-point/synchronous + Float64Counter(name string, opts ...InstrumentOption) (Float64Counter, error) + Float64UpDownCounter(name string, opts ...InstrumentOption) (Float64UpDownCounter, error) + Float64Gauge(name string, opts ...InstrumentOption) (Float64Gauge, error) + Float64Histogram(name string, opts ...InstrumentOption) (Float64Histogram, error) + + // floating-point/asynchronous + Float64AsyncCounter(name string, callback Float64Callback, opts ...InstrumentOption) (AsyncInstrument, error) + Float64AsyncUpDownCounter(name string, callback Float64Callback, opts ...InstrumentOption) (AsyncInstrument, error) + Float64AsyncGauge(name string, callback Float64Callback, opts ...InstrumentOption) (AsyncInstrument, error) +} + +// InstrumentOption applies configuration to an instrument. +type InstrumentOption func(o *InstrumentOptions) + +// InstrumentOptions represents configuration for an instrument. +type InstrumentOptions struct { + UnitLabel string + Description string +} + +// Int64Counter measures a monotonically increasing int64 value. +type Int64Counter interface { + Add(context.Context, int64, ...RecordMetricOption) +} + +// Int64UpDownCounter measures a fluctuating int64 value. +type Int64UpDownCounter interface { + Add(context.Context, int64, ...RecordMetricOption) +} + +// Int64Gauge samples a discrete int64 value. +type Int64Gauge interface { + Sample(context.Context, int64, ...RecordMetricOption) +} + +// Int64Histogram records multiple data points for an int64 value. +type Int64Histogram interface { + Record(context.Context, int64, ...RecordMetricOption) +} + +// Float64Counter measures a monotonically increasing float64 value. +type Float64Counter interface { + Add(context.Context, float64, ...RecordMetricOption) +} + +// Float64UpDownCounter measures a fluctuating float64 value. +type Float64UpDownCounter interface { + Add(context.Context, float64, ...RecordMetricOption) +} + +// Float64Gauge samples a discrete float64 value. +type Float64Gauge interface { + Sample(context.Context, float64, ...RecordMetricOption) +} + +// Float64Histogram records multiple data points for an float64 value. +type Float64Histogram interface { + Record(context.Context, float64, ...RecordMetricOption) +} + +// AsyncInstrument is the universal handle returned for creation of all async +// instruments. +// +// Callers use the Stop() API to unregister the callback passed at instrument +// creation. +type AsyncInstrument interface { + Stop() +} + +// Int64Callback describes a function invoked when an async int64 instrument is +// read. +type Int64Callback func(context.Context, Int64Observer) + +// Int64Observer is the interface passed to async int64 instruments. +// +// Callers use the Observe() API of this interface to report metrics to the +// underlying collector. +type Int64Observer interface { + Observe(context.Context, int64, ...RecordMetricOption) +} + +// Float64Callback describes a function invoked when an async float64 +// instrument is read. +type Float64Callback func(context.Context, Float64Observer) + +// Float64Observer is the interface passed to async int64 instruments. +// +// Callers use the Observe() API of this interface to report metrics to the +// underlying collector. +type Float64Observer interface { + Observe(context.Context, float64, ...RecordMetricOption) +} + +// RecordMetricOption applies configuration to a recorded metric. +type RecordMetricOption func(o *RecordMetricOptions) + +// RecordMetricOptions represents configuration for a recorded metric. +type RecordMetricOptions struct { + Properties smithy.Properties +} diff --git a/vendor/github.com/aws/smithy-go/metrics/nop.go b/vendor/github.com/aws/smithy-go/metrics/nop.go new file mode 100644 index 0000000..fb374e1 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/metrics/nop.go @@ -0,0 +1,67 @@ +package metrics + +import "context" + +// NopMeterProvider is a no-op metrics implementation. +type NopMeterProvider struct{} + +var _ MeterProvider = (*NopMeterProvider)(nil) + +// Meter returns a meter which creates no-op instruments. +func (NopMeterProvider) Meter(string, ...MeterOption) Meter { + return nopMeter{} +} + +type nopMeter struct{} + +var _ Meter = (*nopMeter)(nil) + +func (nopMeter) Int64Counter(string, ...InstrumentOption) (Int64Counter, error) { + return nopInstrument[int64]{}, nil +} +func (nopMeter) Int64UpDownCounter(string, ...InstrumentOption) (Int64UpDownCounter, error) { + return nopInstrument[int64]{}, nil +} +func (nopMeter) Int64Gauge(string, ...InstrumentOption) (Int64Gauge, error) { + return nopInstrument[int64]{}, nil +} +func (nopMeter) Int64Histogram(string, ...InstrumentOption) (Int64Histogram, error) { + return nopInstrument[int64]{}, nil +} +func (nopMeter) Int64AsyncCounter(string, Int64Callback, ...InstrumentOption) (AsyncInstrument, error) { + return nopInstrument[int64]{}, nil +} +func (nopMeter) Int64AsyncUpDownCounter(string, Int64Callback, ...InstrumentOption) (AsyncInstrument, error) { + return nopInstrument[int64]{}, nil +} +func (nopMeter) Int64AsyncGauge(string, Int64Callback, ...InstrumentOption) (AsyncInstrument, error) { + return nopInstrument[int64]{}, nil +} +func (nopMeter) Float64Counter(string, ...InstrumentOption) (Float64Counter, error) { + return nopInstrument[float64]{}, nil +} +func (nopMeter) Float64UpDownCounter(string, ...InstrumentOption) (Float64UpDownCounter, error) { + return nopInstrument[float64]{}, nil +} +func (nopMeter) Float64Gauge(string, ...InstrumentOption) (Float64Gauge, error) { + return nopInstrument[float64]{}, nil +} +func (nopMeter) Float64Histogram(string, ...InstrumentOption) (Float64Histogram, error) { + return nopInstrument[float64]{}, nil +} +func (nopMeter) Float64AsyncCounter(string, Float64Callback, ...InstrumentOption) (AsyncInstrument, error) { + return nopInstrument[float64]{}, nil +} +func (nopMeter) Float64AsyncUpDownCounter(string, Float64Callback, ...InstrumentOption) (AsyncInstrument, error) { + return nopInstrument[float64]{}, nil +} +func (nopMeter) Float64AsyncGauge(string, Float64Callback, ...InstrumentOption) (AsyncInstrument, error) { + return nopInstrument[float64]{}, nil +} + +type nopInstrument[N any] struct{} + +func (nopInstrument[N]) Add(context.Context, N, ...RecordMetricOption) {} +func (nopInstrument[N]) Sample(context.Context, N, ...RecordMetricOption) {} +func (nopInstrument[N]) Record(context.Context, N, ...RecordMetricOption) {} +func (nopInstrument[_]) Stop() {} diff --git a/vendor/github.com/aws/smithy-go/middleware/context.go b/vendor/github.com/aws/smithy-go/middleware/context.go new file mode 100644 index 0000000..f51aa4f --- /dev/null +++ b/vendor/github.com/aws/smithy-go/middleware/context.go @@ -0,0 +1,41 @@ +package middleware + +import "context" + +type ( + serviceIDKey struct{} + operationNameKey struct{} +) + +// WithServiceID adds a service ID to the context, scoped to middleware stack +// values. +// +// This API is called in the client runtime when bootstrapping an operation and +// should not typically be used directly. +func WithServiceID(parent context.Context, id string) context.Context { + return WithStackValue(parent, serviceIDKey{}, id) +} + +// GetServiceID retrieves the service ID from the context. This is typically +// the service shape's name from its Smithy model. Service clients for specific +// systems (e.g. AWS SDK) may use an alternate designated value. +func GetServiceID(ctx context.Context) string { + id, _ := GetStackValue(ctx, serviceIDKey{}).(string) + return id +} + +// WithOperationName adds the operation name to the context, scoped to +// middleware stack values. +// +// This API is called in the client runtime when bootstrapping an operation and +// should not typically be used directly. +func WithOperationName(parent context.Context, id string) context.Context { + return WithStackValue(parent, operationNameKey{}, id) +} + +// GetOperationName retrieves the operation name from the context. This is +// typically the operation shape's name from its Smithy model. +func GetOperationName(ctx context.Context) string { + name, _ := GetStackValue(ctx, operationNameKey{}).(string) + return name +} diff --git a/vendor/github.com/aws/smithy-go/modman.toml b/vendor/github.com/aws/smithy-go/modman.toml index 20295cd..9d94b7c 100644 --- a/vendor/github.com/aws/smithy-go/modman.toml +++ b/vendor/github.com/aws/smithy-go/modman.toml @@ -1,5 +1,4 @@ [dependencies] - "github.com/google/go-cmp" = "v0.5.8" "github.com/jmespath/go-jmespath" = "v0.4.0" [modules] diff --git a/vendor/github.com/aws/smithy-go/properties.go b/vendor/github.com/aws/smithy-go/properties.go index c9af66c..68df4c4 100644 --- a/vendor/github.com/aws/smithy-go/properties.go +++ b/vendor/github.com/aws/smithy-go/properties.go @@ -1,9 +1,11 @@ package smithy +import "maps" + // PropertiesReader provides an interface for reading metadata from the // underlying metadata container. type PropertiesReader interface { - Get(key interface{}) interface{} + Get(key any) any } // Properties provides storing and reading metadata values. Keys may be any @@ -12,14 +14,14 @@ type PropertiesReader interface { // The zero value for a Properties instance is ready for reads/writes without // any additional initialization. type Properties struct { - values map[interface{}]interface{} + values map[any]any } // Get attempts to retrieve the value the key points to. Returns nil if the // key was not found. // // Panics if key type is not comparable. -func (m *Properties) Get(key interface{}) interface{} { +func (m *Properties) Get(key any) any { m.lazyInit() return m.values[key] } @@ -28,7 +30,7 @@ func (m *Properties) Get(key interface{}) interface{} { // that key it will be replaced with the new value. // // Panics if the key type is not comparable. -func (m *Properties) Set(key, value interface{}) { +func (m *Properties) Set(key, value any) { m.lazyInit() m.values[key] = value } @@ -36,7 +38,7 @@ func (m *Properties) Set(key, value interface{}) { // Has returns whether the key exists in the metadata. // // Panics if the key type is not comparable. -func (m *Properties) Has(key interface{}) bool { +func (m *Properties) Has(key any) bool { m.lazyInit() _, ok := m.values[key] return ok @@ -55,8 +57,13 @@ func (m *Properties) SetAll(other *Properties) { } } +// Values returns a shallow clone of the property set's values. +func (m *Properties) Values() map[any]any { + return maps.Clone(m.values) +} + func (m *Properties) lazyInit() { if m.values == nil { - m.values = map[interface{}]interface{}{} + m.values = map[any]any{} } } diff --git a/vendor/github.com/aws/smithy-go/tracing/context.go b/vendor/github.com/aws/smithy-go/tracing/context.go new file mode 100644 index 0000000..a404ed9 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/tracing/context.go @@ -0,0 +1,96 @@ +package tracing + +import "context" + +type ( + operationTracerKey struct{} + spanLineageKey struct{} +) + +// GetSpan returns the active trace Span on the context. +// +// The boolean in the return indicates whether a Span was actually in the +// context, but a no-op implementation will be returned if not, so callers +// can generally disregard the boolean unless they wish to explicitly confirm +// presence/absence of a Span. +func GetSpan(ctx context.Context) (Span, bool) { + lineage := getLineage(ctx) + if len(lineage) == 0 { + return nopSpan{}, false + } + + return lineage[len(lineage)-1], true +} + +// WithSpan sets the active trace Span on the context. +func WithSpan(parent context.Context, span Span) context.Context { + lineage := getLineage(parent) + if len(lineage) == 0 { + return context.WithValue(parent, spanLineageKey{}, []Span{span}) + } + + lineage = append(lineage, span) + return context.WithValue(parent, spanLineageKey{}, lineage) +} + +// PopSpan pops the current Span off the context, setting the active Span on +// the returned Context back to its parent and returning the REMOVED one. +// +// PopSpan on a context with no active Span will return a no-op instance. +// +// This is mostly necessary for the runtime to manage base trace spans due to +// the wrapped-function nature of the middleware stack. End-users of Smithy +// clients SHOULD NOT generally be using this API. +func PopSpan(parent context.Context) (context.Context, Span) { + lineage := getLineage(parent) + if len(lineage) == 0 { + return parent, nopSpan{} + } + + span := lineage[len(lineage)-1] + lineage = lineage[:len(lineage)-1] + return context.WithValue(parent, spanLineageKey{}, lineage), span +} + +func getLineage(ctx context.Context) []Span { + v := ctx.Value(spanLineageKey{}) + if v == nil { + return nil + } + + return v.([]Span) +} + +// GetOperationTracer returns the embedded operation-scoped Tracer on a +// Context. +// +// The boolean in the return indicates whether a Tracer was actually in the +// context, but a no-op implementation will be returned if not, so callers +// can generally disregard the boolean unless they wish to explicitly confirm +// presence/absence of a Tracer. +func GetOperationTracer(ctx context.Context) (Tracer, bool) { + v := ctx.Value(operationTracerKey{}) + if v == nil { + return nopTracer{}, false + } + + return v.(Tracer), true +} + +// WithOperationTracer returns a child Context embedding the given Tracer. +// +// The runtime will use this embed a scoped tracer for client operations, +// Smithy/SDK client callers DO NOT need to do this explicitly. +func WithOperationTracer(parent context.Context, tracer Tracer) context.Context { + return context.WithValue(parent, operationTracerKey{}, tracer) +} + +// StartSpan is a convenience API for creating tracing Spans from a Context. +// +// StartSpan uses the operation-scoped Tracer, previously stored using +// [WithOperationTracer], to start the Span. If a Tracer has not been embedded +// the returned Span will be a no-op implementation. +func StartSpan(ctx context.Context, name string, opts ...SpanOption) (context.Context, Span) { + tracer, _ := GetOperationTracer(ctx) + return tracer.StartSpan(ctx, name, opts...) +} diff --git a/vendor/github.com/aws/smithy-go/tracing/nop.go b/vendor/github.com/aws/smithy-go/tracing/nop.go new file mode 100644 index 0000000..573d28b --- /dev/null +++ b/vendor/github.com/aws/smithy-go/tracing/nop.go @@ -0,0 +1,32 @@ +package tracing + +import "context" + +// NopTracerProvider is a no-op tracing implementation. +type NopTracerProvider struct{} + +var _ TracerProvider = (*NopTracerProvider)(nil) + +// Tracer returns a tracer which creates no-op spans. +func (NopTracerProvider) Tracer(string, ...TracerOption) Tracer { + return nopTracer{} +} + +type nopTracer struct{} + +var _ Tracer = (*nopTracer)(nil) + +func (nopTracer) StartSpan(ctx context.Context, name string, opts ...SpanOption) (context.Context, Span) { + return ctx, nopSpan{} +} + +type nopSpan struct{} + +var _ Span = (*nopSpan)(nil) + +func (nopSpan) Name() string { return "" } +func (nopSpan) Context() SpanContext { return SpanContext{} } +func (nopSpan) AddEvent(string, ...EventOption) {} +func (nopSpan) SetProperty(any, any) {} +func (nopSpan) SetStatus(SpanStatus) {} +func (nopSpan) End() {} diff --git a/vendor/github.com/aws/smithy-go/tracing/tracing.go b/vendor/github.com/aws/smithy-go/tracing/tracing.go new file mode 100644 index 0000000..089ed39 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/tracing/tracing.go @@ -0,0 +1,95 @@ +// Package tracing defines tracing APIs to be used by Smithy clients. +package tracing + +import ( + "context" + + "github.com/aws/smithy-go" +) + +// SpanStatus records the "success" state of an observed span. +type SpanStatus int + +// Enumeration of SpanStatus. +const ( + SpanStatusUnset SpanStatus = iota + SpanStatusOK + SpanStatusError +) + +// SpanKind indicates the nature of the work being performed. +type SpanKind int + +// Enumeration of SpanKind. +const ( + SpanKindInternal SpanKind = iota + SpanKindClient + SpanKindServer + SpanKindProducer + SpanKindConsumer +) + +// TracerProvider is the entry point for creating client traces. +type TracerProvider interface { + Tracer(scope string, opts ...TracerOption) Tracer +} + +// TracerOption applies configuration to a tracer. +type TracerOption func(o *TracerOptions) + +// TracerOptions represent configuration for tracers. +type TracerOptions struct { + Properties smithy.Properties +} + +// Tracer is the entry point for creating observed client Spans. +// +// Spans created by tracers propagate by existing on the Context. Consumers of +// the API can use [GetSpan] to pull the active Span from a Context. +// +// Creation of child Spans is implicit through Context persistence. If +// CreateSpan is called with a Context that holds a Span, the result will be a +// child of that Span. +type Tracer interface { + StartSpan(ctx context.Context, name string, opts ...SpanOption) (context.Context, Span) +} + +// SpanOption applies configuration to a span. +type SpanOption func(o *SpanOptions) + +// SpanOptions represent configuration for span events. +type SpanOptions struct { + Kind SpanKind + Properties smithy.Properties +} + +// Span records a conceptually individual unit of work that takes place in a +// Smithy client operation. +type Span interface { + Name() string + Context() SpanContext + AddEvent(name string, opts ...EventOption) + SetStatus(status SpanStatus) + SetProperty(k, v any) + End() +} + +// EventOption applies configuration to a span event. +type EventOption func(o *EventOptions) + +// EventOptions represent configuration for span events. +type EventOptions struct { + Properties smithy.Properties +} + +// SpanContext uniquely identifies a Span. +type SpanContext struct { + TraceID string + SpanID string + IsRemote bool +} + +// IsValid is true when a span has nonzero trace and span IDs. +func (ctx *SpanContext) IsValid() bool { + return len(ctx.TraceID) != 0 && len(ctx.SpanID) != 0 +} diff --git a/vendor/github.com/aws/smithy-go/transport/http/client.go b/vendor/github.com/aws/smithy-go/transport/http/client.go index e691c69..0fceae8 100644 --- a/vendor/github.com/aws/smithy-go/transport/http/client.go +++ b/vendor/github.com/aws/smithy-go/transport/http/client.go @@ -6,7 +6,9 @@ import ( "net/http" smithy "github.com/aws/smithy-go" + "github.com/aws/smithy-go/metrics" "github.com/aws/smithy-go/middleware" + "github.com/aws/smithy-go/tracing" ) // ClientDo provides the interface for custom HTTP client implementations. @@ -27,13 +29,30 @@ func (fn ClientDoFunc) Do(r *http.Request) (*http.Response, error) { // implementation is http.Client. type ClientHandler struct { client ClientDo + + Meter metrics.Meter // For HTTP client metrics. } // NewClientHandler returns an initialized middleware handler for the client. +// +// Deprecated: Use [NewClientHandlerWithOptions]. func NewClientHandler(client ClientDo) ClientHandler { - return ClientHandler{ + return NewClientHandlerWithOptions(client) +} + +// NewClientHandlerWithOptions returns an initialized middleware handler for the client +// with applied options. +func NewClientHandlerWithOptions(client ClientDo, opts ...func(*ClientHandler)) ClientHandler { + h := ClientHandler{ client: client, } + for _, opt := range opts { + opt(&h) + } + if h.Meter == nil { + h.Meter = metrics.NopMeterProvider{}.Meter("") + } + return h } // Handle implements the middleware Handler interface, that will invoke the @@ -42,6 +61,14 @@ func NewClientHandler(client ClientDo) ClientHandler { func (c ClientHandler) Handle(ctx context.Context, input interface{}) ( out interface{}, metadata middleware.Metadata, err error, ) { + ctx, span := tracing.StartSpan(ctx, "DoHTTPRequest") + defer span.End() + + ctx, client, err := withMetrics(ctx, c.client, c.Meter) + if err != nil { + return nil, metadata, fmt.Errorf("instrument with HTTP metrics: %w", err) + } + req, ok := input.(*Request) if !ok { return nil, metadata, fmt.Errorf("expect Smithy http.Request value as input, got unsupported type %T", input) @@ -52,7 +79,17 @@ func (c ClientHandler) Handle(ctx context.Context, input interface{}) ( return nil, metadata, err } - resp, err := c.client.Do(builtRequest) + span.SetProperty("http.method", req.Method) + span.SetProperty("http.request_content_length", -1) // at least indicate unknown + length, ok, err := req.StreamLength() + if err != nil { + return nil, metadata, err + } + if ok { + span.SetProperty("http.request_content_length", length) + } + + resp, err := client.Do(builtRequest) if resp == nil { // Ensure a http response value is always present to prevent unexpected // panics. @@ -79,6 +116,10 @@ func (c ClientHandler) Handle(ctx context.Context, input interface{}) ( _ = builtRequest.Body.Close() } + span.SetProperty("net.protocol.version", fmt.Sprintf("%d.%d", resp.ProtoMajor, resp.ProtoMinor)) + span.SetProperty("http.status_code", resp.StatusCode) + span.SetProperty("http.response_content_length", resp.ContentLength) + return &Response{Response: resp}, metadata, err } diff --git a/vendor/github.com/aws/smithy-go/transport/http/host.go b/vendor/github.com/aws/smithy-go/transport/http/host.go index 6b290fe..db9801b 100644 --- a/vendor/github.com/aws/smithy-go/transport/http/host.go +++ b/vendor/github.com/aws/smithy-go/transport/http/host.go @@ -69,7 +69,7 @@ func ValidPortNumber(port string) bool { return true } -// ValidHostLabel returns whether the label is a valid RFC 3986 host abel. +// ValidHostLabel returns whether the label is a valid RFC 3986 host label. func ValidHostLabel(label string) bool { if l := len(label); l == 0 || l > 63 { return false diff --git a/vendor/github.com/aws/smithy-go/transport/http/metrics.go b/vendor/github.com/aws/smithy-go/transport/http/metrics.go new file mode 100644 index 0000000..d1beaa5 --- /dev/null +++ b/vendor/github.com/aws/smithy-go/transport/http/metrics.go @@ -0,0 +1,198 @@ +package http + +import ( + "context" + "crypto/tls" + "net/http" + "net/http/httptrace" + "sync/atomic" + "time" + + "github.com/aws/smithy-go/metrics" +) + +var now = time.Now + +// withMetrics instruments an HTTP client and context to collect HTTP metrics. +func withMetrics(parent context.Context, client ClientDo, meter metrics.Meter) ( + context.Context, ClientDo, error, +) { + hm, err := newHTTPMetrics(meter) + if err != nil { + return nil, nil, err + } + + ctx := httptrace.WithClientTrace(parent, &httptrace.ClientTrace{ + DNSStart: hm.DNSStart, + ConnectStart: hm.ConnectStart, + TLSHandshakeStart: hm.TLSHandshakeStart, + + GotConn: hm.GotConn(parent), + PutIdleConn: hm.PutIdleConn(parent), + ConnectDone: hm.ConnectDone(parent), + DNSDone: hm.DNSDone(parent), + TLSHandshakeDone: hm.TLSHandshakeDone(parent), + GotFirstResponseByte: hm.GotFirstResponseByte(parent), + }) + return ctx, &timedClientDo{client, hm}, nil +} + +type timedClientDo struct { + ClientDo + hm *httpMetrics +} + +func (c *timedClientDo) Do(r *http.Request) (*http.Response, error) { + c.hm.doStart.Store(now()) + resp, err := c.ClientDo.Do(r) + + c.hm.DoRequestDuration.Record(r.Context(), c.hm.doStart.Elapsed()) + return resp, err +} + +type httpMetrics struct { + DNSLookupDuration metrics.Float64Histogram // client.http.connections.dns_lookup_duration + ConnectDuration metrics.Float64Histogram // client.http.connections.acquire_duration + TLSHandshakeDuration metrics.Float64Histogram // client.http.connections.tls_handshake_duration + ConnectionUsage metrics.Int64UpDownCounter // client.http.connections.usage + + DoRequestDuration metrics.Float64Histogram // client.http.do_request_duration + TimeToFirstByte metrics.Float64Histogram // client.http.time_to_first_byte + + doStart safeTime + dnsStart safeTime + connectStart safeTime + tlsStart safeTime +} + +func newHTTPMetrics(meter metrics.Meter) (*httpMetrics, error) { + hm := &httpMetrics{} + + var err error + hm.DNSLookupDuration, err = meter.Float64Histogram("client.http.connections.dns_lookup_duration", func(o *metrics.InstrumentOptions) { + o.UnitLabel = "s" + o.Description = "The time it takes a request to perform DNS lookup." + }) + if err != nil { + return nil, err + } + hm.ConnectDuration, err = meter.Float64Histogram("client.http.connections.acquire_duration", func(o *metrics.InstrumentOptions) { + o.UnitLabel = "s" + o.Description = "The time it takes a request to acquire a connection." + }) + if err != nil { + return nil, err + } + hm.TLSHandshakeDuration, err = meter.Float64Histogram("client.http.connections.tls_handshake_duration", func(o *metrics.InstrumentOptions) { + o.UnitLabel = "s" + o.Description = "The time it takes an HTTP request to perform the TLS handshake." + }) + if err != nil { + return nil, err + } + hm.ConnectionUsage, err = meter.Int64UpDownCounter("client.http.connections.usage", func(o *metrics.InstrumentOptions) { + o.UnitLabel = "{connection}" + o.Description = "Current state of connections pool." + }) + if err != nil { + return nil, err + } + hm.DoRequestDuration, err = meter.Float64Histogram("client.http.do_request_duration", func(o *metrics.InstrumentOptions) { + o.UnitLabel = "s" + o.Description = "Time spent performing an entire HTTP transaction." + }) + if err != nil { + return nil, err + } + hm.TimeToFirstByte, err = meter.Float64Histogram("client.http.time_to_first_byte", func(o *metrics.InstrumentOptions) { + o.UnitLabel = "s" + o.Description = "Time from start of transaction to when the first response byte is available." + }) + if err != nil { + return nil, err + } + + return hm, nil +} + +func (m *httpMetrics) DNSStart(httptrace.DNSStartInfo) { + m.dnsStart.Store(now()) +} + +func (m *httpMetrics) ConnectStart(string, string) { + m.connectStart.Store(now()) +} + +func (m *httpMetrics) TLSHandshakeStart() { + m.tlsStart.Store(now()) +} + +func (m *httpMetrics) GotConn(ctx context.Context) func(httptrace.GotConnInfo) { + return func(httptrace.GotConnInfo) { + m.addConnAcquired(ctx, 1) + } +} + +func (m *httpMetrics) PutIdleConn(ctx context.Context) func(error) { + return func(error) { + m.addConnAcquired(ctx, -1) + } +} + +func (m *httpMetrics) DNSDone(ctx context.Context) func(httptrace.DNSDoneInfo) { + return func(httptrace.DNSDoneInfo) { + m.DNSLookupDuration.Record(ctx, m.dnsStart.Elapsed()) + } +} + +func (m *httpMetrics) ConnectDone(ctx context.Context) func(string, string, error) { + return func(string, string, error) { + m.ConnectDuration.Record(ctx, m.connectStart.Elapsed()) + } +} + +func (m *httpMetrics) TLSHandshakeDone(ctx context.Context) func(tls.ConnectionState, error) { + return func(tls.ConnectionState, error) { + m.TLSHandshakeDuration.Record(ctx, m.tlsStart.Elapsed()) + } +} + +func (m *httpMetrics) GotFirstResponseByte(ctx context.Context) func() { + return func() { + m.TimeToFirstByte.Record(ctx, m.doStart.Elapsed()) + } +} + +func (m *httpMetrics) addConnAcquired(ctx context.Context, incr int64) { + m.ConnectionUsage.Add(ctx, incr, func(o *metrics.RecordMetricOptions) { + o.Properties.Set("state", "acquired") + }) +} + +// Not used: it is recommended to track acquired vs idle conn, but we can't +// determine when something is truly idle with the current HTTP client hooks +// available to us. +func (m *httpMetrics) addConnIdle(ctx context.Context, incr int64) { + m.ConnectionUsage.Add(ctx, incr, func(o *metrics.RecordMetricOptions) { + o.Properties.Set("state", "idle") + }) +} + +type safeTime struct { + atomic.Value // time.Time +} + +func (st *safeTime) Store(v time.Time) { + st.Value.Store(v) +} + +func (st *safeTime) Load() time.Time { + t, _ := st.Value.Load().(time.Time) + return t +} + +func (st *safeTime) Elapsed() float64 { + end := now() + elapsed := end.Sub(st.Load()) + return float64(elapsed) / 1e9 +} diff --git a/vendor/github.com/aws/smithy-go/transport/http/middleware_close_response_body.go b/vendor/github.com/aws/smithy-go/transport/http/middleware_close_response_body.go index 1d3b218..914338f 100644 --- a/vendor/github.com/aws/smithy-go/transport/http/middleware_close_response_body.go +++ b/vendor/github.com/aws/smithy-go/transport/http/middleware_close_response_body.go @@ -2,10 +2,10 @@ package http import ( "context" + "io" + "github.com/aws/smithy-go/logging" "github.com/aws/smithy-go/middleware" - "io" - "io/ioutil" ) // AddErrorCloseResponseBodyMiddleware adds the middleware to automatically @@ -30,7 +30,7 @@ func (m *errorCloseResponseBodyMiddleware) HandleDeserialize( if err != nil { if resp, ok := out.RawResponse.(*Response); ok && resp != nil && resp.Body != nil { // Consume the full body to prevent TCP connection resets on some platforms - _, _ = io.Copy(ioutil.Discard, resp.Body) + _, _ = io.Copy(io.Discard, resp.Body) // Do not validate that the response closes successfully. resp.Body.Close() } @@ -64,7 +64,7 @@ func (m *closeResponseBody) HandleDeserialize( if resp, ok := out.RawResponse.(*Response); ok { // Consume the full body to prevent TCP connection resets on some platforms - _, copyErr := io.Copy(ioutil.Discard, resp.Body) + _, copyErr := io.Copy(io.Discard, resp.Body) if copyErr != nil { middleware.GetLogger(ctx).Logf(logging.Warn, "failed to discard remaining HTTP response body, this may affect connection reuse") } diff --git a/vendor/github.com/aws/smithy-go/transport/http/request.go b/vendor/github.com/aws/smithy-go/transport/http/request.go index 7177d6f..5cbf6f1 100644 --- a/vendor/github.com/aws/smithy-go/transport/http/request.go +++ b/vendor/github.com/aws/smithy-go/transport/http/request.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "io" - "io/ioutil" "net/http" "net/url" "strings" @@ -167,7 +166,7 @@ func (r *Request) Build(ctx context.Context) *http.Request { switch stream := r.stream.(type) { case *io.PipeReader: - req.Body = ioutil.NopCloser(stream) + req.Body = io.NopCloser(stream) req.ContentLength = -1 default: // HTTP Client Request must only have a non-nil body if the @@ -175,7 +174,7 @@ func (r *Request) Build(ctx context.Context) *http.Request { // Client will interpret a non-nil body and ContentLength 0 as // "unknown". This is unwanted behavior. if req.ContentLength != 0 && r.stream != nil { - req.Body = iointernal.NewSafeReadCloser(ioutil.NopCloser(stream)) + req.Body = iointernal.NewSafeReadCloser(io.NopCloser(stream)) } } diff --git a/vendor/github.com/bits-and-blooms/bitset/.gitignore b/vendor/github.com/bits-and-blooms/bitset/.gitignore deleted file mode 100644 index 5c204d2..0000000 --- a/vendor/github.com/bits-and-blooms/bitset/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test -*.prof - -target diff --git a/vendor/github.com/bits-and-blooms/bitset/.travis.yml b/vendor/github.com/bits-and-blooms/bitset/.travis.yml deleted file mode 100644 index 094aa5c..0000000 --- a/vendor/github.com/bits-and-blooms/bitset/.travis.yml +++ /dev/null @@ -1,37 +0,0 @@ -language: go - -sudo: false - -branches: - except: - - release - -branches: - only: - - master - - travis - -go: - - "1.11.x" - - tip - -matrix: - allow_failures: - - go: tip - -before_install: - - if [ -n "$GH_USER" ]; then git config --global github.user ${GH_USER}; fi; - - if [ -n "$GH_TOKEN" ]; then git config --global github.token ${GH_TOKEN}; fi; - - go get github.com/mattn/goveralls - -before_script: - - make deps - -script: - - make qa - -after_failure: - - cat ./target/test/report.xml - -after_success: - - if [ "$TRAVIS_GO_VERSION" = "1.11.1" ]; then $HOME/gopath/bin/goveralls -covermode=count -coverprofile=target/report/coverage.out -service=travis-ci; fi; diff --git a/vendor/github.com/bits-and-blooms/bitset/LICENSE b/vendor/github.com/bits-and-blooms/bitset/LICENSE deleted file mode 100644 index 59cab8a..0000000 --- a/vendor/github.com/bits-and-blooms/bitset/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2014 Will Fitzgerald. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/bits-and-blooms/bitset/README.md b/vendor/github.com/bits-and-blooms/bitset/README.md deleted file mode 100644 index fe7bca6..0000000 --- a/vendor/github.com/bits-and-blooms/bitset/README.md +++ /dev/null @@ -1,159 +0,0 @@ -# bitset - -*Go language library to map between non-negative integers and boolean values* - -[![Test](https://github.com/bits-and-blooms/bitset/workflows/Test/badge.svg)](https://github.com/willf/bitset/actions?query=workflow%3ATest) -[![Go Report Card](https://goreportcard.com/badge/github.com/willf/bitset)](https://goreportcard.com/report/github.com/willf/bitset) -[![PkgGoDev](https://pkg.go.dev/badge/github.com/bits-and-blooms/bitset?tab=doc)](https://pkg.go.dev/github.com/bits-and-blooms/bitset?tab=doc) - - -This library is part of the [awesome go collection](https://github.com/avelino/awesome-go). It is used in production by several important systems: - -* [beego](https://github.com/beego/beego) -* [CubeFS](https://github.com/cubefs/cubefs) -* [Amazon EKS Distro](https://github.com/aws/eks-distro) -* [sourcegraph](https://github.com/sourcegraph/sourcegraph) -* [torrent](https://github.com/anacrolix/torrent) - - -## Description - -Package bitset implements bitsets, a mapping between non-negative integers and boolean values. -It should be more efficient than map[uint] bool. - -It provides methods for setting, clearing, flipping, and testing individual integers. - -But it also provides set intersection, union, difference, complement, and symmetric operations, as well as tests to check whether any, all, or no bits are set, and querying a bitset's current length and number of positive bits. - -BitSets are expanded to the size of the largest set bit; the memory allocation is approximately Max bits, where Max is the largest set bit. BitSets are never shrunk. On creation, a hint can be given for the number of bits that will be used. - -Many of the methods, including Set, Clear, and Flip, return a BitSet pointer, which allows for chaining. - -### Example use: - -```go -package main - -import ( - "fmt" - "math/rand" - - "github.com/bits-and-blooms/bitset" -) - -func main() { - fmt.Printf("Hello from BitSet!\n") - var b bitset.BitSet - // play some Go Fish - for i := 0; i < 100; i++ { - card1 := uint(rand.Intn(52)) - card2 := uint(rand.Intn(52)) - b.Set(card1) - if b.Test(card2) { - fmt.Println("Go Fish!") - } - b.Clear(card1) - } - - // Chaining - b.Set(10).Set(11) - - for i, e := b.NextSet(0); e; i, e = b.NextSet(i + 1) { - fmt.Println("The following bit is set:", i) - } - if b.Intersection(bitset.New(100).Set(10)).Count() == 1 { - fmt.Println("Intersection works.") - } else { - fmt.Println("Intersection doesn't work???") - } -} -``` - - -Package documentation is at: https://pkg.go.dev/github.com/bits-and-blooms/bitset?tab=doc - -## Serialization - - -You may serialize a bitset safely and portably to a stream -of bytes as follows: -```Go - const length = 9585 - const oneEvery = 97 - bs := bitset.New(length) - // Add some bits - for i := uint(0); i < length; i += oneEvery { - bs = bs.Set(i) - } - - var buf bytes.Buffer - n, err := bs.WriteTo(&buf) - if err != nil { - // failure - } - // Here n == buf.Len() -``` -You can later deserialize the result as follows: - -```Go - // Read back from buf - bs = bitset.New() - n, err = bs.ReadFrom(&buf) - if err != nil { - // error - } - // n is the number of bytes read -``` - -The `ReadFrom` function attempts to read the data into the existing -BitSet instance, to minimize memory allocations. - - -*Performance tip*: -When reading and writing to a file or a network connection, you may get better performance by -wrapping your streams with `bufio` instances. - -E.g., -```Go - f, err := os.Create("myfile") - w := bufio.NewWriter(f) -``` -```Go - f, err := os.Open("myfile") - r := bufio.NewReader(f) -``` - -## Memory Usage - -The memory usage of a bitset using `N` bits is at least `N/8` bytes. The number of bits in a bitset is at least as large as one plus the greatest bit index you have accessed. Thus it is possible to run out of memory while using a bitset. If you have lots of bits, you might prefer compressed bitsets, like the [Roaring bitmaps](http://roaringbitmap.org) and its [Go implementation](https://github.com/RoaringBitmap/roaring). - -The `roaring` library allows you to go back and forth between compressed Roaring bitmaps and the conventional bitset instances: -```Go - mybitset := roaringbitmap.ToBitSet() - newroaringbitmap := roaring.FromBitSet(mybitset) -``` - - -## Implementation Note - -Go 1.9 introduced a native `math/bits` library. We provide backward compatibility to Go 1.7, which might be removed. - -It is possible that a later version will match the `math/bits` return signature for counts (which is `int`, rather than our library's `uint64`). If so, the version will be bumped. - -## Installation - -```bash -go get github.com/bits-and-blooms/bitset -``` - -## Contributing - -If you wish to contribute to this project, please branch and issue a pull request against master ("[GitHub Flow](https://guides.github.com/introduction/flow/)") - -## Running all tests - -Before committing the code, please check if it passes tests, has adequate coverage, etc. -```bash -go test -go test -cover -``` diff --git a/vendor/github.com/bits-and-blooms/bitset/SECURITY.md b/vendor/github.com/bits-and-blooms/bitset/SECURITY.md deleted file mode 100644 index f888420..0000000 --- a/vendor/github.com/bits-and-blooms/bitset/SECURITY.md +++ /dev/null @@ -1,5 +0,0 @@ -# Security Policy - -## Reporting a Vulnerability - -You can report privately a vulnerability by email at daniel@lemire.me (current maintainer). diff --git a/vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml b/vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml deleted file mode 100644 index f9b2959..0000000 --- a/vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml +++ /dev/null @@ -1,39 +0,0 @@ -# Go -# Build your Go project. -# Add steps that test, save build artifacts, deploy, and more: -# https://docs.microsoft.com/azure/devops/pipelines/languages/go - -trigger: -- master - -pool: - vmImage: 'Ubuntu-16.04' - -variables: - GOBIN: '$(GOPATH)/bin' # Go binaries path - GOROOT: '/usr/local/go1.11' # Go installation path - GOPATH: '$(system.defaultWorkingDirectory)/gopath' # Go workspace path - modulePath: '$(GOPATH)/src/github.com/$(build.repository.name)' # Path to the module's code - -steps: -- script: | - mkdir -p '$(GOBIN)' - mkdir -p '$(GOPATH)/pkg' - mkdir -p '$(modulePath)' - shopt -s extglob - shopt -s dotglob - mv !(gopath) '$(modulePath)' - echo '##vso[task.prependpath]$(GOBIN)' - echo '##vso[task.prependpath]$(GOROOT)/bin' - displayName: 'Set up the Go workspace' - -- script: | - go version - go get -v -t -d ./... - if [ -f Gopkg.toml ]; then - curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh - dep ensure - fi - go build -v . - workingDirectory: '$(modulePath)' - displayName: 'Get dependencies, then build' diff --git a/vendor/github.com/bits-and-blooms/bitset/bitset.go b/vendor/github.com/bits-and-blooms/bitset/bitset.go deleted file mode 100644 index 9f38ed3..0000000 --- a/vendor/github.com/bits-and-blooms/bitset/bitset.go +++ /dev/null @@ -1,1184 +0,0 @@ -/* -Package bitset implements bitsets, a mapping -between non-negative integers and boolean values. It should be more -efficient than map[uint] bool. - -It provides methods for setting, clearing, flipping, and testing -individual integers. - -But it also provides set intersection, union, difference, -complement, and symmetric operations, as well as tests to -check whether any, all, or no bits are set, and querying a -bitset's current length and number of positive bits. - -BitSets are expanded to the size of the largest set bit; the -memory allocation is approximately Max bits, where Max is -the largest set bit. BitSets are never shrunk. On creation, -a hint can be given for the number of bits that will be used. - -Many of the methods, including Set,Clear, and Flip, return -a BitSet pointer, which allows for chaining. - -Example use: - - import "bitset" - var b BitSet - b.Set(10).Set(11) - if b.Test(1000) { - b.Clear(1000) - } - if B.Intersection(bitset.New(100).Set(10)).Count() > 1 { - fmt.Println("Intersection works.") - } - -As an alternative to BitSets, one should check out the 'big' package, -which provides a (less set-theoretical) view of bitsets. -*/ -package bitset - -import ( - "bytes" - "encoding/base64" - "encoding/binary" - "encoding/json" - "errors" - "fmt" - "io" - "strconv" -) - -// the wordSize of a bit set -const wordSize = uint(64) - -// the wordSize of a bit set in bytes -const wordBytes = wordSize / 8 - -// log2WordSize is lg(wordSize) -const log2WordSize = uint(6) - -// allBits has every bit set -const allBits uint64 = 0xffffffffffffffff - -// default binary BigEndian -var binaryOrder binary.ByteOrder = binary.BigEndian - -// default json encoding base64.URLEncoding -var base64Encoding = base64.URLEncoding - -// Base64StdEncoding Marshal/Unmarshal BitSet with base64.StdEncoding(Default: base64.URLEncoding) -func Base64StdEncoding() { base64Encoding = base64.StdEncoding } - -// LittleEndian Marshal/Unmarshal Binary as Little Endian(Default: binary.BigEndian) -func LittleEndian() { binaryOrder = binary.LittleEndian } - -// A BitSet is a set of bits. The zero value of a BitSet is an empty set of length 0. -type BitSet struct { - length uint - set []uint64 -} - -// Error is used to distinguish errors (panics) generated in this package. -type Error string - -// safeSet will fixup b.set to be non-nil and return the field value -func (b *BitSet) safeSet() []uint64 { - if b.set == nil { - b.set = make([]uint64, wordsNeeded(0)) - } - return b.set -} - -// SetBitsetFrom fills the bitset with an array of integers without creating a new BitSet instance -func (b *BitSet) SetBitsetFrom(buf []uint64) { - b.length = uint(len(buf)) * 64 - b.set = buf -} - -// From is a constructor used to create a BitSet from an array of words -func From(buf []uint64) *BitSet { - return FromWithLength(uint(len(buf))*64, buf) -} - -// FromWithLength constructs from an array of words and length. -func FromWithLength(len uint, set []uint64) *BitSet { - return &BitSet{len, set} -} - -// Bytes returns the bitset as array of words -func (b *BitSet) Bytes() []uint64 { - return b.set -} - -// wordsNeeded calculates the number of words needed for i bits -func wordsNeeded(i uint) int { - if i > (Cap() - wordSize + 1) { - return int(Cap() >> log2WordSize) - } - return int((i + (wordSize - 1)) >> log2WordSize) -} - -// wordsNeededUnbound calculates the number of words needed for i bits, possibly exceeding the capacity. -// This function is useful if you know that the capacity cannot be exceeded (e.g., you have an existing bitmap). -func wordsNeededUnbound(i uint) int { - return int((i + (wordSize - 1)) >> log2WordSize) -} - -// wordsIndex calculates the index of words in a `uint64` -func wordsIndex(i uint) uint { - return i & (wordSize - 1) -} - -// New creates a new BitSet with a hint that length bits will be required -func New(length uint) (bset *BitSet) { - defer func() { - if r := recover(); r != nil { - bset = &BitSet{ - 0, - make([]uint64, 0), - } - } - }() - - bset = &BitSet{ - length, - make([]uint64, wordsNeeded(length)), - } - - return bset -} - -// Cap returns the total possible capacity, or number of bits -func Cap() uint { - return ^uint(0) -} - -// Len returns the number of bits in the BitSet. -// Note the difference to method Count, see example. -func (b *BitSet) Len() uint { - return b.length -} - -// extendSet adds additional words to incorporate new bits if needed -func (b *BitSet) extendSet(i uint) { - if i >= Cap() { - panic("You are exceeding the capacity") - } - nsize := wordsNeeded(i + 1) - if b.set == nil { - b.set = make([]uint64, nsize) - } else if cap(b.set) >= nsize { - b.set = b.set[:nsize] // fast resize - } else if len(b.set) < nsize { - newset := make([]uint64, nsize, 2*nsize) // increase capacity 2x - copy(newset, b.set) - b.set = newset - } - b.length = i + 1 -} - -// Test whether bit i is set. -func (b *BitSet) Test(i uint) bool { - if i >= b.length { - return false - } - return b.set[i>>log2WordSize]&(1<= Cap(), this function will panic. -// Warning: using a very large value for 'i' -// may lead to a memory shortage and a panic: the caller is responsible -// for providing sensible parameters in line with their memory capacity. -func (b *BitSet) Set(i uint) *BitSet { - if i >= b.length { // if we need more bits, make 'em - b.extendSet(i) - } - b.set[i>>log2WordSize] |= 1 << wordsIndex(i) - return b -} - -// Clear bit i to 0 -func (b *BitSet) Clear(i uint) *BitSet { - if i >= b.length { - return b - } - b.set[i>>log2WordSize] &^= 1 << wordsIndex(i) - return b -} - -// SetTo sets bit i to value. -// If i>= Cap(), this function will panic. -// Warning: using a very large value for 'i' -// may lead to a memory shortage and a panic: the caller is responsible -// for providing sensible parameters in line with their memory capacity. -func (b *BitSet) SetTo(i uint, value bool) *BitSet { - if value { - return b.Set(i) - } - return b.Clear(i) -} - -// Flip bit at i. -// If i>= Cap(), this function will panic. -// Warning: using a very large value for 'i' -// may lead to a memory shortage and a panic: the caller is responsible -// for providing sensible parameters in line with their memory capacity. -func (b *BitSet) Flip(i uint) *BitSet { - if i >= b.length { - return b.Set(i) - } - b.set[i>>log2WordSize] ^= 1 << wordsIndex(i) - return b -} - -// FlipRange bit in [start, end). -// If end>= Cap(), this function will panic. -// Warning: using a very large value for 'end' -// may lead to a memory shortage and a panic: the caller is responsible -// for providing sensible parameters in line with their memory capacity. -func (b *BitSet) FlipRange(start, end uint) *BitSet { - if start >= end { - return b - } - if end-1 >= b.length { // if we need more bits, make 'em - b.extendSet(end - 1) - } - var startWord uint = start >> log2WordSize - var endWord uint = end >> log2WordSize - b.set[startWord] ^= ^(^uint64(0) << wordsIndex(start)) - if endWord > 0 { - // bounds check elimination - data := b.set - _ = data[endWord-1] - for i := startWord; i < endWord; i++ { - data[i] = ^data[i] - } - } - if end&(wordSize-1) != 0 { - b.set[endWord] ^= ^uint64(0) >> wordsIndex(-end) - } - return b -} - -// Shrink shrinks BitSet so that the provided value is the last possible -// set value. It clears all bits > the provided index and reduces the size -// and length of the set. -// -// Note that the parameter value is not the new length in bits: it is the -// maximal value that can be stored in the bitset after the function call. -// The new length in bits is the parameter value + 1. Thus it is not possible -// to use this function to set the length to 0, the minimal value of the length -// after this function call is 1. -// -// A new slice is allocated to store the new bits, so you may see an increase in -// memory usage until the GC runs. Normally this should not be a problem, but if you -// have an extremely large BitSet its important to understand that the old BitSet will -// remain in memory until the GC frees it. -func (b *BitSet) Shrink(lastbitindex uint) *BitSet { - length := lastbitindex + 1 - idx := wordsNeeded(length) - if idx > len(b.set) { - return b - } - shrunk := make([]uint64, idx) - copy(shrunk, b.set[:idx]) - b.set = shrunk - b.length = length - lastWordUsedBits := length % 64 - if lastWordUsedBits != 0 { - b.set[idx-1] &= allBits >> uint64(64-wordsIndex(lastWordUsedBits)) - } - return b -} - -// Compact shrinks BitSet to so that we preserve all set bits, while minimizing -// memory usage. Compact calls Shrink. -func (b *BitSet) Compact() *BitSet { - idx := len(b.set) - 1 - for ; idx >= 0 && b.set[idx] == 0; idx-- { - } - newlength := uint((idx + 1) << log2WordSize) - if newlength >= b.length { - return b // nothing to do - } - if newlength > 0 { - return b.Shrink(newlength - 1) - } - // We preserve one word - return b.Shrink(63) -} - -// InsertAt takes an index which indicates where a bit should be -// inserted. Then it shifts all the bits in the set to the left by 1, starting -// from the given index position, and sets the index position to 0. -// -// Depending on the size of your BitSet, and where you are inserting the new entry, -// this method could be extremely slow and in some cases might cause the entire BitSet -// to be recopied. -func (b *BitSet) InsertAt(idx uint) *BitSet { - insertAtElement := idx >> log2WordSize - - // if length of set is a multiple of wordSize we need to allocate more space first - if b.isLenExactMultiple() { - b.set = append(b.set, uint64(0)) - } - - var i uint - for i = uint(len(b.set) - 1); i > insertAtElement; i-- { - // all elements above the position where we want to insert can simply by shifted - b.set[i] <<= 1 - - // we take the most significant bit of the previous element and set it as - // the least significant bit of the current element - b.set[i] |= (b.set[i-1] & 0x8000000000000000) >> 63 - } - - // generate a mask to extract the data that we need to shift left - // within the element where we insert a bit - dataMask := uint64(1)< 0x40000 { - buffer.WriteString("...") - break - } - buffer.WriteString(strconv.FormatInt(int64(i), 10)) - i, e = b.NextSet(i + 1) - if e { - buffer.WriteString(",") - } - } - buffer.WriteString("}") - return buffer.String() -} - -// DeleteAt deletes the bit at the given index position from -// within the bitset -// All the bits residing on the left of the deleted bit get -// shifted right by 1 -// The running time of this operation may potentially be -// relatively slow, O(length) -func (b *BitSet) DeleteAt(i uint) *BitSet { - // the index of the slice element where we'll delete a bit - deleteAtElement := i >> log2WordSize - - // generate a mask for the data that needs to be shifted right - // within that slice element that gets modified - dataMask := ^((uint64(1) << wordsIndex(i)) - 1) - - // extract the data that we'll shift right from the slice element - data := b.set[deleteAtElement] & dataMask - - // set the masked area to 0 while leaving the rest as it is - b.set[deleteAtElement] &= ^dataMask - - // shift the previously extracted data to the right and then - // set it in the previously masked area - b.set[deleteAtElement] |= (data >> 1) & dataMask - - // loop over all the consecutive slice elements to copy each - // lowest bit into the highest position of the previous element, - // then shift the entire content to the right by 1 - for i := int(deleteAtElement) + 1; i < len(b.set); i++ { - b.set[i-1] |= (b.set[i] & 1) << 63 - b.set[i] >>= 1 - } - - b.length = b.length - 1 - - return b -} - -// NextSet returns the next bit set from the specified index, -// including possibly the current index -// along with an error code (true = valid, false = no set bit found) -// for i,e := v.NextSet(0); e; i,e = v.NextSet(i + 1) {...} -// -// Users concerned with performance may want to use NextSetMany to -// retrieve several values at once. -func (b *BitSet) NextSet(i uint) (uint, bool) { - x := int(i >> log2WordSize) - if x >= len(b.set) { - return 0, false - } - w := b.set[x] - w = w >> wordsIndex(i) - if w != 0 { - return i + trailingZeroes64(w), true - } - x++ - // bounds check elimination in the loop - if x < 0 { - return 0, false - } - for x < len(b.set) { - if b.set[x] != 0 { - return uint(x)*wordSize + trailingZeroes64(b.set[x]), true - } - x++ - - } - return 0, false -} - -// NextSetMany returns many next bit sets from the specified index, -// including possibly the current index and up to cap(buffer). -// If the returned slice has len zero, then no more set bits were found -// -// buffer := make([]uint, 256) // this should be reused -// j := uint(0) -// j, buffer = bitmap.NextSetMany(j, buffer) -// for ; len(buffer) > 0; j, buffer = bitmap.NextSetMany(j,buffer) { -// for k := range buffer { -// do something with buffer[k] -// } -// j += 1 -// } -// -// It is possible to retrieve all set bits as follow: -// -// indices := make([]uint, bitmap.Count()) -// bitmap.NextSetMany(0, indices) -// -// However if bitmap.Count() is large, it might be preferable to -// use several calls to NextSetMany, for performance reasons. -func (b *BitSet) NextSetMany(i uint, buffer []uint) (uint, []uint) { - myanswer := buffer - capacity := cap(buffer) - x := int(i >> log2WordSize) - if x >= len(b.set) || capacity == 0 { - return 0, myanswer[:0] - } - skip := wordsIndex(i) - word := b.set[x] >> skip - myanswer = myanswer[:capacity] - size := int(0) - for word != 0 { - r := trailingZeroes64(word) - t := word & ((^word) + 1) - myanswer[size] = r + i - size++ - if size == capacity { - goto End - } - word = word ^ t - } - x++ - for idx, word := range b.set[x:] { - for word != 0 { - r := trailingZeroes64(word) - t := word & ((^word) + 1) - myanswer[size] = r + (uint(x+idx) << 6) - size++ - if size == capacity { - goto End - } - word = word ^ t - } - } -End: - if size > 0 { - return myanswer[size-1], myanswer[:size] - } - return 0, myanswer[:0] -} - -// NextClear returns the next clear bit from the specified index, -// including possibly the current index -// along with an error code (true = valid, false = no bit found i.e. all bits are set) -func (b *BitSet) NextClear(i uint) (uint, bool) { - x := int(i >> log2WordSize) - if x >= len(b.set) { - return 0, false - } - w := b.set[x] - w = w >> wordsIndex(i) - wA := allBits >> wordsIndex(i) - index := i + trailingZeroes64(^w) - if w != wA && index < b.length { - return index, true - } - x++ - // bounds check elimination in the loop - if x < 0 { - return 0, false - } - for x < len(b.set) { - if b.set[x] != allBits { - index = uint(x)*wordSize + trailingZeroes64(^b.set[x]) - if index < b.length { - return index, true - } - } - x++ - } - return 0, false -} - -// ClearAll clears the entire BitSet -func (b *BitSet) ClearAll() *BitSet { - if b != nil && b.set != nil { - for i := range b.set { - b.set[i] = 0 - } - } - return b -} - -// SetAll sets the entire BitSet -func (b *BitSet) SetAll() *BitSet { - if b != nil && b.set != nil { - for i := range b.set { - b.set[i] = allBits - } - - b.cleanLastWord() - } - return b -} - -// wordCount returns the number of words used in a bit set -func (b *BitSet) wordCount() int { - return wordsNeededUnbound(b.length) -} - -// Clone this BitSet -func (b *BitSet) Clone() *BitSet { - c := New(b.length) - if b.set != nil { // Clone should not modify current object - copy(c.set, b.set) - } - return c -} - -// Copy into a destination BitSet using the Go array copy semantics: -// the number of bits copied is the minimum of the number of bits in the current -// BitSet (Len()) and the destination Bitset. -// We return the number of bits copied in the destination BitSet. -func (b *BitSet) Copy(c *BitSet) (count uint) { - if c == nil { - return - } - if b.set != nil { // Copy should not modify current object - copy(c.set, b.set) - } - count = c.length - if b.length < c.length { - count = b.length - } - // Cleaning the last word is needed to keep the invariant that other functions, such as Count, require - // that any bits in the last word that would exceed the length of the bitmask are set to 0. - c.cleanLastWord() - return -} - -// CopyFull copies into a destination BitSet such that the destination is -// identical to the source after the operation, allocating memory if necessary. -func (b *BitSet) CopyFull(c *BitSet) { - if c == nil { - return - } - c.length = b.length - if len(b.set) == 0 { - if c.set != nil { - c.set = c.set[:0] - } - } else { - if cap(c.set) < len(b.set) { - c.set = make([]uint64, len(b.set)) - } else { - c.set = c.set[:len(b.set)] - } - copy(c.set, b.set) - } -} - -// Count (number of set bits). -// Also known as "popcount" or "population count". -func (b *BitSet) Count() uint { - if b != nil && b.set != nil { - return uint(popcntSlice(b.set)) - } - return 0 -} - -// Equal tests the equivalence of two BitSets. -// False if they are of different sizes, otherwise true -// only if all the same bits are set -func (b *BitSet) Equal(c *BitSet) bool { - if c == nil || b == nil { - return c == b - } - if b.length != c.length { - return false - } - if b.length == 0 { // if they have both length == 0, then could have nil set - return true - } - wn := b.wordCount() - // bounds check elimination - if wn <= 0 { - return true - } - _ = b.set[wn-1] - _ = c.set[wn-1] - for p := 0; p < wn; p++ { - if c.set[p] != b.set[p] { - return false - } - } - return true -} - -func panicIfNull(b *BitSet) { - if b == nil { - panic(Error("BitSet must not be null")) - } -} - -// Difference of base set and other set -// This is the BitSet equivalent of &^ (and not) -func (b *BitSet) Difference(compare *BitSet) (result *BitSet) { - panicIfNull(b) - panicIfNull(compare) - result = b.Clone() // clone b (in case b is bigger than compare) - l := compare.wordCount() - if l > b.wordCount() { - l = b.wordCount() - } - for i := 0; i < l; i++ { - result.set[i] = b.set[i] &^ compare.set[i] - } - return -} - -// DifferenceCardinality computes the cardinality of the differnce -func (b *BitSet) DifferenceCardinality(compare *BitSet) uint { - panicIfNull(b) - panicIfNull(compare) - l := compare.wordCount() - if l > b.wordCount() { - l = b.wordCount() - } - cnt := uint64(0) - cnt += popcntMaskSlice(b.set[:l], compare.set[:l]) - cnt += popcntSlice(b.set[l:]) - return uint(cnt) -} - -// InPlaceDifference computes the difference of base set and other set -// This is the BitSet equivalent of &^ (and not) -func (b *BitSet) InPlaceDifference(compare *BitSet) { - panicIfNull(b) - panicIfNull(compare) - l := compare.wordCount() - if l > b.wordCount() { - l = b.wordCount() - } - if l <= 0 { - return - } - // bounds check elimination - data, cmpData := b.set, compare.set - _ = data[l-1] - _ = cmpData[l-1] - for i := 0; i < l; i++ { - data[i] &^= cmpData[i] - } -} - -// Convenience function: return two bitsets ordered by -// increasing length. Note: neither can be nil -func sortByLength(a *BitSet, b *BitSet) (ap *BitSet, bp *BitSet) { - if a.length <= b.length { - ap, bp = a, b - } else { - ap, bp = b, a - } - return -} - -// Intersection of base set and other set -// This is the BitSet equivalent of & (and) -func (b *BitSet) Intersection(compare *BitSet) (result *BitSet) { - panicIfNull(b) - panicIfNull(compare) - b, compare = sortByLength(b, compare) - result = New(b.length) - for i, word := range b.set { - result.set[i] = word & compare.set[i] - } - return -} - -// IntersectionCardinality computes the cardinality of the union -func (b *BitSet) IntersectionCardinality(compare *BitSet) uint { - panicIfNull(b) - panicIfNull(compare) - b, compare = sortByLength(b, compare) - cnt := popcntAndSlice(b.set, compare.set) - return uint(cnt) -} - -// InPlaceIntersection destructively computes the intersection of -// base set and the compare set. -// This is the BitSet equivalent of & (and) -func (b *BitSet) InPlaceIntersection(compare *BitSet) { - panicIfNull(b) - panicIfNull(compare) - l := compare.wordCount() - if l > b.wordCount() { - l = b.wordCount() - } - if l > 0 { - // bounds check elimination - data, cmpData := b.set, compare.set - _ = data[l-1] - _ = cmpData[l-1] - - for i := 0; i < l; i++ { - data[i] &= cmpData[i] - } - } - if l >= 0 { - for i := l; i < len(b.set); i++ { - b.set[i] = 0 - } - } - if compare.length > 0 { - if compare.length-1 >= b.length { - b.extendSet(compare.length - 1) - } - } -} - -// Union of base set and other set -// This is the BitSet equivalent of | (or) -func (b *BitSet) Union(compare *BitSet) (result *BitSet) { - panicIfNull(b) - panicIfNull(compare) - b, compare = sortByLength(b, compare) - result = compare.Clone() - for i, word := range b.set { - result.set[i] = word | compare.set[i] - } - return -} - -// UnionCardinality computes the cardinality of the uniton of the base set -// and the compare set. -func (b *BitSet) UnionCardinality(compare *BitSet) uint { - panicIfNull(b) - panicIfNull(compare) - b, compare = sortByLength(b, compare) - cnt := popcntOrSlice(b.set, compare.set) - if len(compare.set) > len(b.set) { - cnt += popcntSlice(compare.set[len(b.set):]) - } - return uint(cnt) -} - -// InPlaceUnion creates the destructive union of base set and compare set. -// This is the BitSet equivalent of | (or). -func (b *BitSet) InPlaceUnion(compare *BitSet) { - panicIfNull(b) - panicIfNull(compare) - l := compare.wordCount() - if l > b.wordCount() { - l = b.wordCount() - } - if compare.length > 0 && compare.length-1 >= b.length { - b.extendSet(compare.length - 1) - } - if l > 0 { - // bounds check elimination - data, cmpData := b.set, compare.set - _ = data[l-1] - _ = cmpData[l-1] - - for i := 0; i < l; i++ { - data[i] |= cmpData[i] - } - } - if len(compare.set) > l { - for i := l; i < len(compare.set); i++ { - b.set[i] = compare.set[i] - } - } -} - -// SymmetricDifference of base set and other set -// This is the BitSet equivalent of ^ (xor) -func (b *BitSet) SymmetricDifference(compare *BitSet) (result *BitSet) { - panicIfNull(b) - panicIfNull(compare) - b, compare = sortByLength(b, compare) - // compare is bigger, so clone it - result = compare.Clone() - for i, word := range b.set { - result.set[i] = word ^ compare.set[i] - } - return -} - -// SymmetricDifferenceCardinality computes the cardinality of the symmetric difference -func (b *BitSet) SymmetricDifferenceCardinality(compare *BitSet) uint { - panicIfNull(b) - panicIfNull(compare) - b, compare = sortByLength(b, compare) - cnt := popcntXorSlice(b.set, compare.set) - if len(compare.set) > len(b.set) { - cnt += popcntSlice(compare.set[len(b.set):]) - } - return uint(cnt) -} - -// InPlaceSymmetricDifference creates the destructive SymmetricDifference of base set and other set -// This is the BitSet equivalent of ^ (xor) -func (b *BitSet) InPlaceSymmetricDifference(compare *BitSet) { - panicIfNull(b) - panicIfNull(compare) - l := compare.wordCount() - if l > b.wordCount() { - l = b.wordCount() - } - if compare.length > 0 && compare.length-1 >= b.length { - b.extendSet(compare.length - 1) - } - if l > 0 { - // bounds check elimination - data, cmpData := b.set, compare.set - _ = data[l-1] - _ = cmpData[l-1] - for i := 0; i < l; i++ { - data[i] ^= cmpData[i] - } - } - if len(compare.set) > l { - for i := l; i < len(compare.set); i++ { - b.set[i] = compare.set[i] - } - } -} - -// Is the length an exact multiple of word sizes? -func (b *BitSet) isLenExactMultiple() bool { - return wordsIndex(b.length) == 0 -} - -// Clean last word by setting unused bits to 0 -func (b *BitSet) cleanLastWord() { - if !b.isLenExactMultiple() { - b.set[len(b.set)-1] &= allBits >> (wordSize - wordsIndex(b.length)) - } -} - -// Complement computes the (local) complement of a bitset (up to length bits) -func (b *BitSet) Complement() (result *BitSet) { - panicIfNull(b) - result = New(b.length) - for i, word := range b.set { - result.set[i] = ^word - } - result.cleanLastWord() - return -} - -// All returns true if all bits are set, false otherwise. Returns true for -// empty sets. -func (b *BitSet) All() bool { - panicIfNull(b) - return b.Count() == b.length -} - -// None returns true if no bit is set, false otherwise. Returns true for -// empty sets. -func (b *BitSet) None() bool { - panicIfNull(b) - if b != nil && b.set != nil { - for _, word := range b.set { - if word > 0 { - return false - } - } - } - return true -} - -// Any returns true if any bit is set, false otherwise -func (b *BitSet) Any() bool { - panicIfNull(b) - return !b.None() -} - -// IsSuperSet returns true if this is a superset of the other set -func (b *BitSet) IsSuperSet(other *BitSet) bool { - l := other.wordCount() - if b.wordCount() < l { - l = b.wordCount() - } - for i, word := range other.set[:l] { - if b.set[i]&word != word { - return false - } - } - return popcntSlice(other.set[l:]) == 0 -} - -// IsStrictSuperSet returns true if this is a strict superset of the other set -func (b *BitSet) IsStrictSuperSet(other *BitSet) bool { - return b.Count() > other.Count() && b.IsSuperSet(other) -} - -// DumpAsBits dumps a bit set as a string of bits. Following the usual convention in Go, -// the least significant bits are printed last (index 0 is at the end of the string). -func (b *BitSet) DumpAsBits() string { - if b.set == nil { - return "." - } - buffer := bytes.NewBufferString("") - i := len(b.set) - 1 - for ; i >= 0; i-- { - fmt.Fprintf(buffer, "%064b.", b.set[i]) - } - return buffer.String() -} - -// BinaryStorageSize returns the binary storage requirements (see WriteTo) in bytes. -func (b *BitSet) BinaryStorageSize() int { - return int(wordBytes + wordBytes*uint(b.wordCount())) -} - -func readUint64Array(reader io.Reader, data []uint64) error { - length := len(data) - bufferSize := 128 - buffer := make([]byte, bufferSize*int(wordBytes)) - for i := 0; i < length; i += bufferSize { - end := i + bufferSize - if end > length { - end = length - buffer = buffer[:wordBytes*uint(end-i)] - } - chunk := data[i:end] - if _, err := io.ReadFull(reader, buffer); err != nil { - return err - } - for i := range chunk { - chunk[i] = uint64(binaryOrder.Uint64(buffer[8*i:])) - } - } - return nil -} - -func writeUint64Array(writer io.Writer, data []uint64) error { - bufferSize := 128 - buffer := make([]byte, bufferSize*int(wordBytes)) - for i := 0; i < len(data); i += bufferSize { - end := i + bufferSize - if end > len(data) { - end = len(data) - buffer = buffer[:wordBytes*uint(end-i)] - } - chunk := data[i:end] - for i, x := range chunk { - binaryOrder.PutUint64(buffer[8*i:], x) - } - _, err := writer.Write(buffer) - if err != nil { - return err - } - } - return nil -} - -// WriteTo writes a BitSet to a stream. The format is: -// 1. uint64 length -// 2. []uint64 set -// Upon success, the number of bytes written is returned. -// -// Performance: if this function is used to write to a disk or network -// connection, it might be beneficial to wrap the stream in a bufio.Writer. -// E.g., -// -// f, err := os.Create("myfile") -// w := bufio.NewWriter(f) -func (b *BitSet) WriteTo(stream io.Writer) (int64, error) { - length := uint64(b.length) - // Write length - err := binary.Write(stream, binaryOrder, &length) - if err != nil { - // Upon failure, we do not guarantee that we - // return the number of bytes written. - return int64(0), err - } - err = writeUint64Array(stream, b.set[:b.wordCount()]) - if err != nil { - // Upon failure, we do not guarantee that we - // return the number of bytes written. - return int64(wordBytes), err - } - return int64(b.BinaryStorageSize()), nil -} - -// ReadFrom reads a BitSet from a stream written using WriteTo -// The format is: -// 1. uint64 length -// 2. []uint64 set -// Upon success, the number of bytes read is returned. -// If the current BitSet is not large enough to hold the data, -// it is extended. In case of error, the BitSet is either -// left unchanged or made empty if the error occurs too late -// to preserve the content. -// -// Performance: if this function is used to read from a disk or network -// connection, it might be beneficial to wrap the stream in a bufio.Reader. -// E.g., -// -// f, err := os.Open("myfile") -// r := bufio.NewReader(f) -func (b *BitSet) ReadFrom(stream io.Reader) (int64, error) { - var length uint64 - err := binary.Read(stream, binaryOrder, &length) - if err != nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - return 0, err - } - newlength := uint(length) - - if uint64(newlength) != length { - return 0, errors.New("unmarshalling error: type mismatch") - } - nWords := wordsNeeded(uint(newlength)) - if cap(b.set) >= nWords { - b.set = b.set[:nWords] - } else { - b.set = make([]uint64, nWords) - } - - b.length = newlength - - err = readUint64Array(stream, b.set) - if err != nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - // We do not want to leave the BitSet partially filled as - // it is error prone. - b.set = b.set[:0] - b.length = 0 - return 0, err - } - - return int64(b.BinaryStorageSize()), nil -} - -// MarshalBinary encodes a BitSet into a binary form and returns the result. -func (b *BitSet) MarshalBinary() ([]byte, error) { - var buf bytes.Buffer - _, err := b.WriteTo(&buf) - if err != nil { - return []byte{}, err - } - - return buf.Bytes(), err -} - -// UnmarshalBinary decodes the binary form generated by MarshalBinary. -func (b *BitSet) UnmarshalBinary(data []byte) error { - buf := bytes.NewReader(data) - _, err := b.ReadFrom(buf) - return err -} - -// MarshalJSON marshals a BitSet as a JSON structure -func (b BitSet) MarshalJSON() ([]byte, error) { - buffer := bytes.NewBuffer(make([]byte, 0, b.BinaryStorageSize())) - _, err := b.WriteTo(buffer) - if err != nil { - return nil, err - } - - // URLEncode all bytes - return json.Marshal(base64Encoding.EncodeToString(buffer.Bytes())) -} - -// UnmarshalJSON unmarshals a BitSet from JSON created using MarshalJSON -func (b *BitSet) UnmarshalJSON(data []byte) error { - // Unmarshal as string - var s string - err := json.Unmarshal(data, &s) - if err != nil { - return err - } - - // URLDecode string - buf, err := base64Encoding.DecodeString(s) - if err != nil { - return err - } - - _, err = b.ReadFrom(bytes.NewReader(buf)) - return err -} - -// Rank returns the nunber of set bits up to and including the index -// that are set in the bitset. -// See https://en.wikipedia.org/wiki/Ranking#Ranking_in_statistics -func (b *BitSet) Rank(index uint) uint { - if index >= b.length { - return b.Count() - } - leftover := (index + 1) & 63 - answer := uint(popcntSlice(b.set[:(index+1)>>6])) - if leftover != 0 { - answer += uint(popcount(b.set[(index+1)>>6] << (64 - leftover))) - } - return answer -} - -// Select returns the index of the jth set bit, where j is the argument. -// The caller is responsible to ensure that 0 <= j < Count(): when j is -// out of range, the function returns the length of the bitset (b.length). -// -// Note that this function differs in convention from the Rank function which -// returns 1 when ranking the smallest value. We follow the conventional -// textbook definition of Select and Rank. -func (b *BitSet) Select(index uint) uint { - leftover := index - for idx, word := range b.set { - w := uint(popcount(word)) - if w > leftover { - return uint(idx)*64 + select64(word, leftover) - } - leftover -= w - } - return b.length -} diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt.go b/vendor/github.com/bits-and-blooms/bitset/popcnt.go deleted file mode 100644 index 76577a8..0000000 --- a/vendor/github.com/bits-and-blooms/bitset/popcnt.go +++ /dev/null @@ -1,53 +0,0 @@ -package bitset - -// bit population count, take from -// https://code.google.com/p/go/issues/detail?id=4988#c11 -// credit: https://code.google.com/u/arnehormann/ -func popcount(x uint64) (n uint64) { - x -= (x >> 1) & 0x5555555555555555 - x = (x>>2)&0x3333333333333333 + x&0x3333333333333333 - x += x >> 4 - x &= 0x0f0f0f0f0f0f0f0f - x *= 0x0101010101010101 - return x >> 56 -} - -func popcntSliceGo(s []uint64) uint64 { - cnt := uint64(0) - for _, x := range s { - cnt += popcount(x) - } - return cnt -} - -func popcntMaskSliceGo(s, m []uint64) uint64 { - cnt := uint64(0) - for i := range s { - cnt += popcount(s[i] &^ m[i]) - } - return cnt -} - -func popcntAndSliceGo(s, m []uint64) uint64 { - cnt := uint64(0) - for i := range s { - cnt += popcount(s[i] & m[i]) - } - return cnt -} - -func popcntOrSliceGo(s, m []uint64) uint64 { - cnt := uint64(0) - for i := range s { - cnt += popcount(s[i] | m[i]) - } - return cnt -} - -func popcntXorSliceGo(s, m []uint64) uint64 { - cnt := uint64(0) - for i := range s { - cnt += popcount(s[i] ^ m[i]) - } - return cnt -} diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go b/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go deleted file mode 100644 index 7855c04..0000000 --- a/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go +++ /dev/null @@ -1,62 +0,0 @@ -//go:build go1.9 -// +build go1.9 - -package bitset - -import "math/bits" - -func popcntSlice(s []uint64) uint64 { - var cnt int - for _, x := range s { - cnt += bits.OnesCount64(x) - } - return uint64(cnt) -} - -func popcntMaskSlice(s, m []uint64) uint64 { - var cnt int - // this explicit check eliminates a bounds check in the loop - if len(m) < len(s) { - panic("mask slice is too short") - } - for i := range s { - cnt += bits.OnesCount64(s[i] &^ m[i]) - } - return uint64(cnt) -} - -func popcntAndSlice(s, m []uint64) uint64 { - var cnt int - // this explicit check eliminates a bounds check in the loop - if len(m) < len(s) { - panic("mask slice is too short") - } - for i := range s { - cnt += bits.OnesCount64(s[i] & m[i]) - } - return uint64(cnt) -} - -func popcntOrSlice(s, m []uint64) uint64 { - var cnt int - // this explicit check eliminates a bounds check in the loop - if len(m) < len(s) { - panic("mask slice is too short") - } - for i := range s { - cnt += bits.OnesCount64(s[i] | m[i]) - } - return uint64(cnt) -} - -func popcntXorSlice(s, m []uint64) uint64 { - var cnt int - // this explicit check eliminates a bounds check in the loop - if len(m) < len(s) { - panic("mask slice is too short") - } - for i := range s { - cnt += bits.OnesCount64(s[i] ^ m[i]) - } - return uint64(cnt) -} diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go b/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go deleted file mode 100644 index 116e044..0000000 --- a/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go +++ /dev/null @@ -1,68 +0,0 @@ -//go:build !go1.9 && amd64 && !appengine -// +build !go1.9,amd64,!appengine - -package bitset - -// *** the following functions are defined in popcnt_amd64.s - -//go:noescape - -func hasAsm() bool - -// useAsm is a flag used to select the GO or ASM implementation of the popcnt function -var useAsm = hasAsm() - -//go:noescape - -func popcntSliceAsm(s []uint64) uint64 - -//go:noescape - -func popcntMaskSliceAsm(s, m []uint64) uint64 - -//go:noescape - -func popcntAndSliceAsm(s, m []uint64) uint64 - -//go:noescape - -func popcntOrSliceAsm(s, m []uint64) uint64 - -//go:noescape - -func popcntXorSliceAsm(s, m []uint64) uint64 - -func popcntSlice(s []uint64) uint64 { - if useAsm { - return popcntSliceAsm(s) - } - return popcntSliceGo(s) -} - -func popcntMaskSlice(s, m []uint64) uint64 { - if useAsm { - return popcntMaskSliceAsm(s, m) - } - return popcntMaskSliceGo(s, m) -} - -func popcntAndSlice(s, m []uint64) uint64 { - if useAsm { - return popcntAndSliceAsm(s, m) - } - return popcntAndSliceGo(s, m) -} - -func popcntOrSlice(s, m []uint64) uint64 { - if useAsm { - return popcntOrSliceAsm(s, m) - } - return popcntOrSliceGo(s, m) -} - -func popcntXorSlice(s, m []uint64) uint64 { - if useAsm { - return popcntXorSliceAsm(s, m) - } - return popcntXorSliceGo(s, m) -} diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s b/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s deleted file mode 100644 index 666c0dc..0000000 --- a/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s +++ /dev/null @@ -1,104 +0,0 @@ -// +build !go1.9 -// +build amd64,!appengine - -TEXT ·hasAsm(SB),4,$0-1 -MOVQ $1, AX -CPUID -SHRQ $23, CX -ANDQ $1, CX -MOVB CX, ret+0(FP) -RET - -#define POPCNTQ_DX_DX BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0xd2 - -TEXT ·popcntSliceAsm(SB),4,$0-32 -XORQ AX, AX -MOVQ s+0(FP), SI -MOVQ s_len+8(FP), CX -TESTQ CX, CX -JZ popcntSliceEnd -popcntSliceLoop: -BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0x16 // POPCNTQ (SI), DX -ADDQ DX, AX -ADDQ $8, SI -LOOP popcntSliceLoop -popcntSliceEnd: -MOVQ AX, ret+24(FP) -RET - -TEXT ·popcntMaskSliceAsm(SB),4,$0-56 -XORQ AX, AX -MOVQ s+0(FP), SI -MOVQ s_len+8(FP), CX -TESTQ CX, CX -JZ popcntMaskSliceEnd -MOVQ m+24(FP), DI -popcntMaskSliceLoop: -MOVQ (DI), DX -NOTQ DX -ANDQ (SI), DX -POPCNTQ_DX_DX -ADDQ DX, AX -ADDQ $8, SI -ADDQ $8, DI -LOOP popcntMaskSliceLoop -popcntMaskSliceEnd: -MOVQ AX, ret+48(FP) -RET - -TEXT ·popcntAndSliceAsm(SB),4,$0-56 -XORQ AX, AX -MOVQ s+0(FP), SI -MOVQ s_len+8(FP), CX -TESTQ CX, CX -JZ popcntAndSliceEnd -MOVQ m+24(FP), DI -popcntAndSliceLoop: -MOVQ (DI), DX -ANDQ (SI), DX -POPCNTQ_DX_DX -ADDQ DX, AX -ADDQ $8, SI -ADDQ $8, DI -LOOP popcntAndSliceLoop -popcntAndSliceEnd: -MOVQ AX, ret+48(FP) -RET - -TEXT ·popcntOrSliceAsm(SB),4,$0-56 -XORQ AX, AX -MOVQ s+0(FP), SI -MOVQ s_len+8(FP), CX -TESTQ CX, CX -JZ popcntOrSliceEnd -MOVQ m+24(FP), DI -popcntOrSliceLoop: -MOVQ (DI), DX -ORQ (SI), DX -POPCNTQ_DX_DX -ADDQ DX, AX -ADDQ $8, SI -ADDQ $8, DI -LOOP popcntOrSliceLoop -popcntOrSliceEnd: -MOVQ AX, ret+48(FP) -RET - -TEXT ·popcntXorSliceAsm(SB),4,$0-56 -XORQ AX, AX -MOVQ s+0(FP), SI -MOVQ s_len+8(FP), CX -TESTQ CX, CX -JZ popcntXorSliceEnd -MOVQ m+24(FP), DI -popcntXorSliceLoop: -MOVQ (DI), DX -XORQ (SI), DX -POPCNTQ_DX_DX -ADDQ DX, AX -ADDQ $8, SI -ADDQ $8, DI -LOOP popcntXorSliceLoop -popcntXorSliceEnd: -MOVQ AX, ret+48(FP) -RET diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go b/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go deleted file mode 100644 index 9e0ad46..0000000 --- a/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go +++ /dev/null @@ -1,25 +0,0 @@ -//go:build !go1.9 && (!amd64 || appengine) -// +build !go1.9 -// +build !amd64 appengine - -package bitset - -func popcntSlice(s []uint64) uint64 { - return popcntSliceGo(s) -} - -func popcntMaskSlice(s, m []uint64) uint64 { - return popcntMaskSliceGo(s, m) -} - -func popcntAndSlice(s, m []uint64) uint64 { - return popcntAndSliceGo(s, m) -} - -func popcntOrSlice(s, m []uint64) uint64 { - return popcntOrSliceGo(s, m) -} - -func popcntXorSlice(s, m []uint64) uint64 { - return popcntXorSliceGo(s, m) -} diff --git a/vendor/github.com/bits-and-blooms/bitset/select.go b/vendor/github.com/bits-and-blooms/bitset/select.go deleted file mode 100644 index f15e74a..0000000 --- a/vendor/github.com/bits-and-blooms/bitset/select.go +++ /dev/null @@ -1,45 +0,0 @@ -package bitset - -func select64(w uint64, j uint) uint { - seen := 0 - // Divide 64bit - part := w & 0xFFFFFFFF - n := uint(popcount(part)) - if n <= j { - part = w >> 32 - seen += 32 - j -= n - } - ww := part - - // Divide 32bit - part = ww & 0xFFFF - - n = uint(popcount(part)) - if n <= j { - part = ww >> 16 - seen += 16 - j -= n - } - ww = part - - // Divide 16bit - part = ww & 0xFF - n = uint(popcount(part)) - if n <= j { - part = ww >> 8 - seen += 8 - j -= n - } - ww = part - - // Lookup in final byte - counter := 0 - for ; counter < 8; counter++ { - j -= uint((ww >> counter) & 1) - if j+1 == 0 { - break - } - } - return uint(seen + counter) -} diff --git a/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go b/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go deleted file mode 100644 index 12336e7..0000000 --- a/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build !go1.9 -// +build !go1.9 - -package bitset - -var deBruijn = [...]byte{ - 0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4, - 62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5, - 63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11, - 54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6, -} - -func trailingZeroes64(v uint64) uint { - return uint(deBruijn[((v&-v)*0x03f79d71b4ca8b09)>>58]) -} diff --git a/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go b/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go deleted file mode 100644 index cfb0a84..0000000 --- a/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build go1.9 -// +build go1.9 - -package bitset - -import "math/bits" - -func trailingZeroes64(v uint64) uint { - return uint(bits.TrailingZeros64(v)) -} diff --git a/vendor/github.com/fxamacker/cbor/v2/.golangci.yml b/vendor/github.com/fxamacker/cbor/v2/.golangci.yml index e65c053..38cb9ae 100644 --- a/vendor/github.com/fxamacker/cbor/v2/.golangci.yml +++ b/vendor/github.com/fxamacker/cbor/v2/.golangci.yml @@ -1,12 +1,26 @@ # Do not delete linter settings. Linters like gocritic can be enabled on the command line. linters-settings: + depguard: + rules: + prevent_unmaintained_packages: + list-mode: strict + files: + - $all + - "!$test" + allow: + - $gostd + - github.com/x448/float16 + deny: + - pkg: io/ioutil + desc: "replaced by io and os packages since Go 1.16: https://tip.golang.org/doc/go1.16#ioutil" dupl: threshold: 100 funlen: lines: 100 statements: 50 goconst: + ignore-tests: true min-len: 2 min-occurrences: 3 gocritic: @@ -17,12 +31,12 @@ linters-settings: - performance - style disabled-checks: + - commentedOutCode - dupImport # https://github.com/go-critic/go-critic/issues/845 - ifElseChain - octalLiteral - paramTypeCombine - whyNoLint - - wrapperFunc gofmt: simplify: false goimports: @@ -37,22 +51,32 @@ linters-settings: suggest-new: true misspell: locale: US + staticcheck: + checks: ["all"] linters: disable-all: true enable: + - asciicheck - bidichk + - depguard - errcheck + - exportloopref - goconst + - gocritic - gocyclo - gofmt - goimports + - goprintffuncname - gosec + - gosimple - govet - ineffassign - misspell + - nilerr - revive - staticcheck + - stylecheck - typecheck - unconvert - unused @@ -62,16 +86,19 @@ issues: max-issues-per-linter: 0 # max-same-issues default is 3. Set to 0 to disable limit. max-same-issues: 0 - # Excluding configuration per-path, per-linter, per-text and per-source + exclude-rules: - - path: _test\.go - linters: - - goconst - - dupl - - gomnd - - lll - - path: doc\.go - linters: - - goimports - - gomnd - - lll + - path: decode.go + text: "string ` overflows ` has (\\d+) occurrences, make it a constant" + - path: decode.go + text: "string ` \\(range is \\[` has (\\d+) occurrences, make it a constant" + - path: decode.go + text: "string `, ` has (\\d+) occurrences, make it a constant" + - path: decode.go + text: "string ` overflows Go's int64` has (\\d+) occurrences, make it a constant" + - path: decode.go + text: "string `\\]\\)` has (\\d+) occurrences, make it a constant" + - path: valid.go + text: "string ` for type ` has (\\d+) occurrences, make it a constant" + - path: valid.go + text: "string `cbor: ` has (\\d+) occurrences, make it a constant" diff --git a/vendor/github.com/fxamacker/cbor/v2/README.md b/vendor/github.com/fxamacker/cbor/v2/README.md index 2bed2e6..af0a795 100644 --- a/vendor/github.com/fxamacker/cbor/v2/README.md +++ b/vendor/github.com/fxamacker/cbor/v2/README.md @@ -6,9 +6,9 @@ CBOR is a [trusted alternative](https://www.rfc-editor.org/rfc/rfc8949.html#name-comparison-of-other-binary-) to JSON, MessagePack, Protocol Buffers, etc.  CBOR is an Internet Standard defined by [IETF STD 94 (RFC 8949)](https://www.rfc-editor.org/info/std94) and is designed to be relevant for decades. -`fxamacker/cbor` is used in projects by Arm Ltd., Cisco, Dapper Labs, EdgeX Foundry, Fraunhofer‑AISEC, Let's Encrypt (ISRG), Linux Foundation, Microsoft, Mozilla, Oasis Protocol, Tailscale, Teleport, [and others](https://github.com/fxamacker/cbor#who-uses-fxamackercbor). +`fxamacker/cbor` is used in projects by Arm Ltd., Cisco, EdgeX Foundry, Flow Foundation, Fraunhofer‑AISEC, Kubernetes, Let's Encrypt (ISRG), Linux Foundation, Microsoft, Mozilla, Oasis Protocol, Tailscale, Teleport, [etc](https://github.com/fxamacker/cbor#who-uses-fxamackercbor). -See [Quick Start](#quick-start) and [Releases](https://github.com/fxamacker/cbor/releases/). 🆕 `UnmarshalFirst` and `DiagnoseFirst` can decode CBOR Sequences. +See [Quick Start](#quick-start) and [Releases](https://github.com/fxamacker/cbor/releases/). 🆕 `UnmarshalFirst` and `DiagnoseFirst` can decode CBOR Sequences. `cbor.MarshalToBuffer()` and `UserBufferEncMode` accepts user-specified buffer. ## fxamacker/cbor @@ -17,7 +17,6 @@ See [Quick Start](#quick-start) and [Releases](https://github.com/fxamacker [![CodeQL](https://github.com/fxamacker/cbor/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/fxamacker/cbor/actions/workflows/codeql-analysis.yml) [![](https://img.shields.io/badge/fuzzing-passing-44c010)](#fuzzing-and-code-coverage) [![Go Report Card](https://goreportcard.com/badge/github.com/fxamacker/cbor)](https://goreportcard.com/report/github.com/fxamacker/cbor) -[![](https://img.shields.io/ossf-scorecard/github.com/fxamacker/cbor?label=openssf%20scorecard)](https://github.com/fxamacker/cbor#fuzzing-and-code-coverage) `fxamacker/cbor` is a CBOR codec in full conformance with [IETF STD 94 (RFC 8949)](https://www.rfc-editor.org/info/std94). It also supports CBOR Sequences ([RFC 8742](https://www.rfc-editor.org/rfc/rfc8742.html)) and Extended Diagnostic Notation ([Appendix G of RFC 8610](https://www.rfc-editor.org/rfc/rfc8610.html#appendix-G)). @@ -221,7 +220,7 @@ __Install__: `go get github.com/fxamacker/cbor/v2` and `import "github.com/fxama This library can encode and decode CBOR (RFC 8949) and CBOR Sequences (RFC 8742). -- __CBOR data item__ is a single piece of CBOR data and its structure may contain zero, one, or more nested data items. +- __CBOR data item__ is a single piece of CBOR data and its structure may contain 0 or more nested data items. - __CBOR sequence__ is a concatenation of 0 or more encoded CBOR data items. Configurable limits and options can be used to balance trade-offs. @@ -242,6 +241,9 @@ err = cbor.Unmarshal(b, &v) // decode []byte b to v decoder = cbor.NewDecoder(r) // create decoder with io.Reader r err = decoder.Decode(&v) // decode a CBOR data item to v +// v2.7.0 added MarshalToBuffer() and UserBufferEncMode interface. +err = cbor.MarshalToBuffer(v, b) // encode v to b instead of using built-in buf pool. + // v2.5.0 added new functions that return remaining bytes. // UnmarshalFirst decodes first CBOR data item and returns remaining bytes. @@ -297,6 +299,17 @@ err := encoder.Encode(v) // encode v to io.Writer w Default mode and custom modes automatically apply struct tags. +### User Specified Buffer for Encoding (v2.7.0) + +`UserBufferEncMode` interface extends `EncMode` interface to add `MarshalToBuffer()`. It accepts a user-specified buffer instead of using built-in buffer pool. + +```Go +em, err := myEncOptions.UserBufferEncMode() // create UserBufferEncMode mode + +var buf bytes.Buffer +err = em.MarshalToBuffer(v, &buf) // encode v to provided buf +``` + ### Struct Tags Struct tags (`toarray`, `keyasint`, `omitempty`) reduce encoded size of structs. @@ -459,12 +472,14 @@ Default limits may need to be increased for systems handling very large data (e. ## Status -v2.6.0 (February 2024) adds important new features, optimizations, and bug fixes. It is especially useful to systems that need to convert data between CBOR and JSON. New options and optimizations improve handling of bignum, integers, maps, and strings. +v2.7.0 (June 23, 2024) adds features and improvements that help large projects (e.g. Kubernetes) use CBOR as an alternative to JSON and Protocol Buffers. Other improvements include speedups, improved memory use, bug fixes, new serialization options, etc. It passed fuzz tests (5+ billion executions) and is production quality. For more details, see [release notes](https://github.com/fxamacker/cbor/releases). ### Prior Release +[v2.6.0](https://github.com/fxamacker/cbor/releases/tag/v2.6.0) (February 2024) adds important new features, optimizations, and bug fixes. It is especially useful to systems that need to convert data between CBOR and JSON. New options and optimizations improve handling of bignum, integers, maps, and strings. + v2.5.0 was released on Sunday, August 13, 2023 with new features and important bug fixes. It is fuzz tested and production quality after extended beta [v2.5.0-beta](https://github.com/fxamacker/cbor/releases/tag/v2.5.0-beta) (Dec 2022) -> [v2.5.0](https://github.com/fxamacker/cbor/releases/tag/v2.5.0) (Aug 2023). __IMPORTANT__: 👉 Before upgrading from v2.4 or older release, please read the notable changes highlighted in the release notes. v2.5.0 is a large release with bug fixes to error handling for extraneous data in `Unmarshal`, etc. that should be reviewed before upgrading. @@ -534,7 +549,7 @@ geomean 2.782 ## Who uses fxamacker/cbor -`fxamacker/cbor` is used in projects by Arm Ltd., Berlin Institute of Health at Charité, Chainlink, Cisco, Confidential Computing Consortium, ConsenSys, Dapper Labs, EdgeX Foundry, F5, FIDO Alliance, Fraunhofer‑AISEC, Let's Encrypt (ISRG), Linux Foundation, Matrix.org, Microsoft, Mozilla, National Cybersecurity Agency of France (govt), Netherlands (govt), Oasis Protocol, Smallstep, Tailscale, Taurus SA, Teleport, TIBCO, and others. +`fxamacker/cbor` is used in projects by Arm Ltd., Berlin Institute of Health at Charité, Chainlink, Cisco, Confidential Computing Consortium, ConsenSys, Dapper Labs, EdgeX Foundry, F5, FIDO Alliance, Fraunhofer‑AISEC, Kubernetes, Let's Encrypt (ISRG), Linux Foundation, Matrix.org, Microsoft, Mozilla, National Cybersecurity Agency of France (govt), Netherlands (govt), Oasis Protocol, Smallstep, Tailscale, Taurus SA, Teleport, TIBCO, and others. `fxamacker/cbor` passed multiple confidential security assessments. A [nonconfidential security assessment](https://github.com/veraison/go-cose/blob/v1.0.0-rc.1/reports/NCC_Microsoft-go-cose-Report_2022-05-26_v1.0.pdf) (prepared by NCC Group for Microsoft Corporation) includes a subset of fxamacker/cbor v2.4.0 in its scope. @@ -657,6 +672,8 @@ I'm especially grateful to Bastian Müller and Dieter Shirley for suggesting and I'm very grateful to Stefan Tatschner, Yawning Angel, Jernej Kos, x448, ZenGround0, and Jakob Borg for their contributions or support in the very early days. +Big thanks to Ben Luddy for his contributions in v2.6.0 and v2.7.0. + This library clearly wouldn't be possible without Carsten Bormann authoring CBOR RFCs. Special thanks to Laurence Lundblade and Jeffrey Yasskin for their help on IETF mailing list or at [7049bis](https://github.com/cbor-wg/CBORbis). diff --git a/vendor/github.com/fxamacker/cbor/v2/bytestring.go b/vendor/github.com/fxamacker/cbor/v2/bytestring.go index 52a28ed..823bff1 100644 --- a/vendor/github.com/fxamacker/cbor/v2/bytestring.go +++ b/vendor/github.com/fxamacker/cbor/v2/bytestring.go @@ -22,8 +22,8 @@ func (bs ByteString) Bytes() []byte { // MarshalCBOR encodes ByteString as CBOR byte string (major type 2). func (bs ByteString) MarshalCBOR() ([]byte, error) { - e := getEncoderBuffer() - defer putEncoderBuffer(e) + e := getEncodeBuffer() + defer putEncodeBuffer(e) // Encode length encodeHead(e, byte(cborTypeByteString), uint64(len(bs))) diff --git a/vendor/github.com/fxamacker/cbor/v2/cache.go b/vendor/github.com/fxamacker/cbor/v2/cache.go index 8a4a5c8..ea0f39e 100644 --- a/vendor/github.com/fxamacker/cbor/v2/cache.go +++ b/vendor/github.com/fxamacker/cbor/v2/cache.go @@ -6,6 +6,7 @@ package cbor import ( "bytes" "errors" + "fmt" "reflect" "sort" "strconv" @@ -84,9 +85,25 @@ func newTypeInfo(t reflect.Type) *typeInfo { } type decodingStructType struct { - fields fields - err error - toArray bool + fields fields + fieldIndicesByName map[string]int + err error + toArray bool +} + +// The stdlib errors.Join was introduced in Go 1.20, and we still support Go 1.17, so instead, +// here's a very basic implementation of an aggregated error. +type multierror []error + +func (m multierror) Error() string { + var sb strings.Builder + for i, err := range m { + sb.WriteString(err.Error()) + if i < len(m)-1 { + sb.WriteString(", ") + } + } + return sb.String() } func getDecodingStructType(t reflect.Type) *decodingStructType { @@ -98,12 +115,12 @@ func getDecodingStructType(t reflect.Type) *decodingStructType { toArray := hasToArrayOption(structOptions) - var err error + var errs []error for i := 0; i < len(flds); i++ { if flds[i].keyAsInt { nameAsInt, numErr := strconv.Atoi(flds[i].name) if numErr != nil { - err = errors.New("cbor: failed to parse field name \"" + flds[i].name + "\" to int (" + numErr.Error() + ")") + errs = append(errs, errors.New("cbor: failed to parse field name \""+flds[i].name+"\" to int ("+numErr.Error()+")")) break } flds[i].nameAsInt = int64(nameAsInt) @@ -112,7 +129,36 @@ func getDecodingStructType(t reflect.Type) *decodingStructType { flds[i].typInfo = getTypeInfo(flds[i].typ) } - structType := &decodingStructType{fields: flds, err: err, toArray: toArray} + fieldIndicesByName := make(map[string]int, len(flds)) + for i, fld := range flds { + if _, ok := fieldIndicesByName[fld.name]; ok { + errs = append(errs, fmt.Errorf("cbor: two or more fields of %v have the same name %q", t, fld.name)) + continue + } + fieldIndicesByName[fld.name] = i + } + + var err error + { + var multi multierror + for _, each := range errs { + if each != nil { + multi = append(multi, each) + } + } + if len(multi) == 1 { + err = multi[0] + } else if len(multi) > 1 { + err = multi + } + } + + structType := &decodingStructType{ + fields: flds, + fieldIndicesByName: fieldIndicesByName, + err: err, + toArray: toArray, + } decodingStructTypeCache.Store(t, structType) return structType } @@ -124,17 +170,17 @@ type encodingStructType struct { omitEmptyFieldsIdx []int err error toArray bool - fixedLength bool // Struct type doesn't have any omitempty or anonymous fields. } func (st *encodingStructType) getFields(em *encMode) fields { - if em.sort == SortNone { + switch em.sort { + case SortNone, SortFastShuffle: return st.fields - } - if em.sort == SortLengthFirst { + case SortLengthFirst: return st.lengthFirstFields + default: + return st.bytewiseFields } - return st.bytewiseFields } type bytewiseFieldSorter struct { @@ -188,8 +234,7 @@ func getEncodingStructType(t reflect.Type) (*encodingStructType, error) { var hasKeyAsInt bool var hasKeyAsStr bool var omitEmptyIdx []int - fixedLength := true - e := getEncoderBuffer() + e := getEncodeBuffer() for i := 0; i < len(flds); i++ { // Get field's encodeFunc flds[i].ef, flds[i].ief = getEncodeFunc(flds[i].typ) @@ -231,23 +276,18 @@ func getEncodingStructType(t reflect.Type) (*encodingStructType, error) { copy(flds[i].cborNameByteString, flds[i].cborName) // Reset encoded CBOR type to byte string, preserving the "additional // information" bits: - flds[i].cborNameByteString[0] = byte(cborTypeByteString) | (flds[i].cborNameByteString[0] & 0x1f) + flds[i].cborNameByteString[0] = byte(cborTypeByteString) | + getAdditionalInformation(flds[i].cborNameByteString[0]) hasKeyAsStr = true } - // Check if field is from embedded struct - if len(flds[i].idx) > 1 { - fixedLength = false - } - // Check if field can be omitted when empty if flds[i].omitEmpty { - fixedLength = false omitEmptyIdx = append(omitEmptyIdx, i) } } - putEncoderBuffer(e) + putEncodeBuffer(e) if err != nil { structType := &encodingStructType{err: err} @@ -272,8 +312,8 @@ func getEncodingStructType(t reflect.Type) (*encodingStructType, error) { bytewiseFields: bytewiseFields, lengthFirstFields: lengthFirstFields, omitEmptyFieldsIdx: omitEmptyIdx, - fixedLength: fixedLength, } + encodingStructTypeCache.Store(t, structType) return structType, structType.err } @@ -290,9 +330,8 @@ func getEncodingStructToArrayType(t reflect.Type, flds fields) (*encodingStructT } structType := &encodingStructType{ - fields: flds, - toArray: true, - fixedLength: true, + fields: flds, + toArray: true, } encodingStructTypeCache.Store(t, structType) return structType, structType.err diff --git a/vendor/github.com/fxamacker/cbor/v2/common.go b/vendor/github.com/fxamacker/cbor/v2/common.go new file mode 100644 index 0000000..ec038a4 --- /dev/null +++ b/vendor/github.com/fxamacker/cbor/v2/common.go @@ -0,0 +1,182 @@ +// Copyright (c) Faye Amacker. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +package cbor + +import ( + "fmt" + "strconv" +) + +type cborType uint8 + +const ( + cborTypePositiveInt cborType = 0x00 + cborTypeNegativeInt cborType = 0x20 + cborTypeByteString cborType = 0x40 + cborTypeTextString cborType = 0x60 + cborTypeArray cborType = 0x80 + cborTypeMap cborType = 0xa0 + cborTypeTag cborType = 0xc0 + cborTypePrimitives cborType = 0xe0 +) + +func (t cborType) String() string { + switch t { + case cborTypePositiveInt: + return "positive integer" + case cborTypeNegativeInt: + return "negative integer" + case cborTypeByteString: + return "byte string" + case cborTypeTextString: + return "UTF-8 text string" + case cborTypeArray: + return "array" + case cborTypeMap: + return "map" + case cborTypeTag: + return "tag" + case cborTypePrimitives: + return "primitives" + default: + return "Invalid type " + strconv.Itoa(int(t)) + } +} + +type additionalInformation uint8 + +const ( + maxAdditionalInformationWithoutArgument = 23 + additionalInformationWith1ByteArgument = 24 + additionalInformationWith2ByteArgument = 25 + additionalInformationWith4ByteArgument = 26 + additionalInformationWith8ByteArgument = 27 + + // For major type 7. + additionalInformationAsFalse = 20 + additionalInformationAsTrue = 21 + additionalInformationAsNull = 22 + additionalInformationAsUndefined = 23 + additionalInformationAsFloat16 = 25 + additionalInformationAsFloat32 = 26 + additionalInformationAsFloat64 = 27 + + // For major type 2, 3, 4, 5. + additionalInformationAsIndefiniteLengthFlag = 31 +) + +const ( + maxSimpleValueInAdditionalInformation = 23 + minSimpleValueIn1ByteArgument = 32 +) + +func (ai additionalInformation) isIndefiniteLength() bool { + return ai == additionalInformationAsIndefiniteLengthFlag +} + +const ( + // From RFC 8949 Section 3: + // "The initial byte of each encoded data item contains both information about the major type + // (the high-order 3 bits, described in Section 3.1) and additional information + // (the low-order 5 bits)." + + // typeMask is used to extract major type in initial byte of encoded data item. + typeMask = 0xe0 + + // additionalInformationMask is used to extract additional information in initial byte of encoded data item. + additionalInformationMask = 0x1f +) + +func getType(raw byte) cborType { + return cborType(raw & typeMask) +} + +func getAdditionalInformation(raw byte) byte { + return raw & additionalInformationMask +} + +func isBreakFlag(raw byte) bool { + return raw == cborBreakFlag +} + +func parseInitialByte(b byte) (t cborType, ai byte) { + return getType(b), getAdditionalInformation(b) +} + +const ( + tagNumRFC3339Time = 0 + tagNumEpochTime = 1 + tagNumUnsignedBignum = 2 + tagNumNegativeBignum = 3 + tagNumExpectedLaterEncodingBase64URL = 21 + tagNumExpectedLaterEncodingBase64 = 22 + tagNumExpectedLaterEncodingBase16 = 23 + tagNumSelfDescribedCBOR = 55799 +) + +const ( + cborBreakFlag = byte(0xff) + cborByteStringWithIndefiniteLengthHead = byte(0x5f) + cborTextStringWithIndefiniteLengthHead = byte(0x7f) + cborArrayWithIndefiniteLengthHead = byte(0x9f) + cborMapWithIndefiniteLengthHead = byte(0xbf) +) + +var ( + cborFalse = []byte{0xf4} + cborTrue = []byte{0xf5} + cborNil = []byte{0xf6} + cborNaN = []byte{0xf9, 0x7e, 0x00} + cborPositiveInfinity = []byte{0xf9, 0x7c, 0x00} + cborNegativeInfinity = []byte{0xf9, 0xfc, 0x00} +) + +// validBuiltinTag checks that supported built-in tag numbers are followed by expected content types. +func validBuiltinTag(tagNum uint64, contentHead byte) error { + t := getType(contentHead) + switch tagNum { + case tagNumRFC3339Time: + // Tag content (date/time text string in RFC 3339 format) must be string type. + if t != cborTypeTextString { + return newInadmissibleTagContentTypeError( + tagNumRFC3339Time, + "text string", + t.String()) + } + return nil + + case tagNumEpochTime: + // Tag content (epoch date/time) must be uint, int, or float type. + if t != cborTypePositiveInt && t != cborTypeNegativeInt && (contentHead < 0xf9 || contentHead > 0xfb) { + return newInadmissibleTagContentTypeError( + tagNumEpochTime, + "integer or floating-point number", + t.String()) + } + return nil + + case tagNumUnsignedBignum, tagNumNegativeBignum: + // Tag content (bignum) must be byte type. + if t != cborTypeByteString { + return newInadmissibleTagContentTypeErrorf( + fmt.Sprintf( + "tag number %d or %d must be followed by byte string, got %s", + tagNumUnsignedBignum, + tagNumNegativeBignum, + t.String(), + )) + } + return nil + + case tagNumExpectedLaterEncodingBase64URL, tagNumExpectedLaterEncodingBase64, tagNumExpectedLaterEncodingBase16: + // From RFC 8949 3.4.5.2: + // The data item tagged can be a byte string or any other data item. In the latter + // case, the tag applies to all of the byte string data items contained in the data + // item, except for those contained in a nested data item tagged with an expected + // conversion. + return nil + } + + return nil +} diff --git a/vendor/github.com/fxamacker/cbor/v2/decode.go b/vendor/github.com/fxamacker/cbor/v2/decode.go index 0b44124..85842ac 100644 --- a/vendor/github.com/fxamacker/cbor/v2/decode.go +++ b/vendor/github.com/fxamacker/cbor/v2/decode.go @@ -5,7 +5,9 @@ package cbor import ( "encoding" + "encoding/base64" "encoding/binary" + "encoding/hex" "errors" "fmt" "io" @@ -87,7 +89,8 @@ import ( // To unmarshal a CBOR text string into a time.Time value, Unmarshal parses text // string formatted in RFC3339. To unmarshal a CBOR integer/float into a // time.Time value, Unmarshal creates an unix time with integer/float as seconds -// and fractional seconds since January 1, 1970 UTC. +// and fractional seconds since January 1, 1970 UTC. As a special case, Infinite +// and NaN float values decode to time.Time's zero value. // // To unmarshal CBOR null (0xf6) and undefined (0xf7) values into a // slice/map/pointer, Unmarshal sets Go value to nil. Because null is often @@ -207,7 +210,95 @@ func (e *UnknownFieldError) Error() string { return fmt.Sprintf("cbor: found unknown field at map element index %d", e.Index) } -// DupMapKeyMode specifies how to enforce duplicate map key. +// UnacceptableDataItemError is returned when unmarshaling a CBOR input that contains a data item +// that is not acceptable to a specific CBOR-based application protocol ("invalid or unexpected" as +// described in RFC 8949 Section 5 Paragraph 3). +type UnacceptableDataItemError struct { + CBORType string + Message string +} + +func (e UnacceptableDataItemError) Error() string { + return fmt.Sprintf("cbor: data item of cbor type %s is not accepted by protocol: %s", e.CBORType, e.Message) +} + +// ByteStringExpectedFormatError is returned when unmarshaling CBOR byte string fails when +// using non-default ByteStringExpectedFormat decoding option that makes decoder expect +// a specified format such as base64, hex, etc. +type ByteStringExpectedFormatError struct { + expectedFormatOption ByteStringExpectedFormatMode + err error +} + +func newByteStringExpectedFormatError(expectedFormatOption ByteStringExpectedFormatMode, err error) *ByteStringExpectedFormatError { + return &ByteStringExpectedFormatError{expectedFormatOption, err} +} + +func (e *ByteStringExpectedFormatError) Error() string { + switch e.expectedFormatOption { + case ByteStringExpectedBase64URL: + return fmt.Sprintf("cbor: failed to decode base64url from byte string: %s", e.err) + + case ByteStringExpectedBase64: + return fmt.Sprintf("cbor: failed to decode base64 from byte string: %s", e.err) + + case ByteStringExpectedBase16: + return fmt.Sprintf("cbor: failed to decode hex from byte string: %s", e.err) + + default: + return fmt.Sprintf("cbor: failed to decode byte string in expected format %d: %s", e.expectedFormatOption, e.err) + } +} + +func (e *ByteStringExpectedFormatError) Unwrap() error { + return e.err +} + +// InadmissibleTagContentTypeError is returned when unmarshaling built-in CBOR tags +// fails because of inadmissible type for tag content. Currently, the built-in +// CBOR tags in this codec are tags 0-3 and 21-23. +// See "Tag validity" in RFC 8949 Section 5.3.2. +type InadmissibleTagContentTypeError struct { + s string + tagNum int + expectedTagContentType string + gotTagContentType string +} + +func newInadmissibleTagContentTypeError( + tagNum int, + expectedTagContentType string, + gotTagContentType string, +) *InadmissibleTagContentTypeError { + return &InadmissibleTagContentTypeError{ + tagNum: tagNum, + expectedTagContentType: expectedTagContentType, + gotTagContentType: gotTagContentType, + } +} + +func newInadmissibleTagContentTypeErrorf(s string) *InadmissibleTagContentTypeError { + return &InadmissibleTagContentTypeError{s: "cbor: " + s} //nolint:goconst // ignore "cbor" +} + +func (e *InadmissibleTagContentTypeError) Error() string { + if e.s == "" { + return fmt.Sprintf( + "cbor: tag number %d must be followed by %s, got %s", + e.tagNum, + e.expectedTagContentType, + e.gotTagContentType, + ) + } + return e.s +} + +// DupMapKeyMode specifies how to enforce duplicate map key. Two map keys are considered duplicates if: +// 1. When decoding into a struct, both keys match the same struct field. The keys are also +// considered duplicates if neither matches any field and decoding to interface{} would produce +// equal (==) values for both keys. +// 2. When decoding into a map, both keys are equal (==) when decoded into values of the +// destination map's key type. type DupMapKeyMode int const ( @@ -422,6 +513,13 @@ const ( // ByteStringToStringAllowed permits decoding a CBOR byte string into a Go string. ByteStringToStringAllowed + // ByteStringToStringAllowedWithExpectedLaterEncoding permits decoding a CBOR byte string + // into a Go string. Also, if the byte string is enclosed (directly or indirectly) by one of + // the "expected later encoding" tags (numbers 21 through 23), the destination string will + // be populated by applying the designated text encoding to the contents of the input byte + // string. + ByteStringToStringAllowedWithExpectedLaterEncoding + maxByteStringToStringMode ) @@ -466,13 +564,214 @@ func (uttam UnrecognizedTagToAnyMode) valid() bool { return uttam >= 0 && uttam < maxUnrecognizedTagToAny } +// TimeTagToAnyMode specifies how to decode CBOR tag 0 and 1 into an empty interface (any). +// Based on the specified mode, Unmarshal can return a time.Time value or a time string in a specific format. +type TimeTagToAnyMode int + +const ( + // TimeTagToTime decodes CBOR tag 0 and 1 into a time.Time value + // when decoding tag 0 or 1 into an empty interface. + TimeTagToTime TimeTagToAnyMode = iota + + // TimeTagToRFC3339 decodes CBOR tag 0 and 1 into a time string in RFC3339 format + // when decoding tag 0 or 1 into an empty interface. + TimeTagToRFC3339 + + // TimeTagToRFC3339Nano decodes CBOR tag 0 and 1 into a time string in RFC3339Nano format + // when decoding tag 0 or 1 into an empty interface. + TimeTagToRFC3339Nano + + maxTimeTagToAnyMode +) + +func (tttam TimeTagToAnyMode) valid() bool { + return tttam >= 0 && tttam < maxTimeTagToAnyMode +} + +// SimpleValueRegistry is a registry of unmarshaling behaviors for each possible CBOR simple value +// number (0...23 and 32...255). +type SimpleValueRegistry struct { + rejected [256]bool +} + +// WithRejectedSimpleValue registers the given simple value as rejected. If the simple value is +// encountered in a CBOR input during unmarshaling, an UnacceptableDataItemError is returned. +func WithRejectedSimpleValue(sv SimpleValue) func(*SimpleValueRegistry) error { + return func(r *SimpleValueRegistry) error { + if sv >= 24 && sv <= 31 { + return fmt.Errorf("cbor: cannot set analog for reserved simple value %d", sv) + } + r.rejected[sv] = true + return nil + } +} + +// Creates a new SimpleValueRegistry. The registry state is initialized by executing the provided +// functions in order against a registry that is pre-populated with the defaults for all well-formed +// simple value numbers. +func NewSimpleValueRegistryFromDefaults(fns ...func(*SimpleValueRegistry) error) (*SimpleValueRegistry, error) { + var r SimpleValueRegistry + for _, fn := range fns { + if err := fn(&r); err != nil { + return nil, err + } + } + return &r, nil +} + +// NaNMode specifies how to decode floating-point values (major type 7, additional information 25 +// through 27) representing NaN (not-a-number). +type NaNMode int + +const ( + // NaNDecodeAllowed will decode NaN values to Go float32 or float64. + NaNDecodeAllowed NaNMode = iota + + // NaNDecodeForbidden will return an UnacceptableDataItemError on an attempt to decode a NaN value. + NaNDecodeForbidden + + maxNaNDecode +) + +func (ndm NaNMode) valid() bool { + return ndm >= 0 && ndm < maxNaNDecode +} + +// InfMode specifies how to decode floating-point values (major type 7, additional information 25 +// through 27) representing positive or negative infinity. +type InfMode int + +const ( + // InfDecodeAllowed will decode infinite values to Go float32 or float64. + InfDecodeAllowed InfMode = iota + + // InfDecodeForbidden will return an UnacceptableDataItemError on an attempt to decode an + // infinite value. + InfDecodeForbidden + + maxInfDecode +) + +func (idm InfMode) valid() bool { + return idm >= 0 && idm < maxInfDecode +} + +// ByteStringToTimeMode specifies the behavior when decoding a CBOR byte string into a Go time.Time. +type ByteStringToTimeMode int + +const ( + // ByteStringToTimeForbidden generates an error on an attempt to decode a CBOR byte string into a Go time.Time. + ByteStringToTimeForbidden ByteStringToTimeMode = iota + + // ByteStringToTimeAllowed permits decoding a CBOR byte string into a Go time.Time. + ByteStringToTimeAllowed + + maxByteStringToTimeMode +) + +func (bttm ByteStringToTimeMode) valid() bool { + return bttm >= 0 && bttm < maxByteStringToTimeMode +} + +// ByteStringExpectedFormatMode specifies how to decode CBOR byte string into Go byte slice +// when the byte string is NOT enclosed in CBOR tag 21, 22, or 23. An error is returned if +// the CBOR byte string does not contain the expected format (e.g. base64) specified. +// For tags 21-23, see "Expected Later Encoding for CBOR-to-JSON Converters" +// in RFC 8949 Section 3.4.5.2. +type ByteStringExpectedFormatMode int + +const ( + // ByteStringExpectedFormatNone copies the unmodified CBOR byte string into Go byte slice + // if the byte string is not tagged by CBOR tag 21-23. + ByteStringExpectedFormatNone ByteStringExpectedFormatMode = iota + + // ByteStringExpectedBase64URL expects CBOR byte strings to contain base64url-encoded bytes + // if the byte string is not tagged by CBOR tag 21-23. The decoder will attempt to decode + // the base64url-encoded bytes into Go slice. + ByteStringExpectedBase64URL + + // ByteStringExpectedBase64 expects CBOR byte strings to contain base64-encoded bytes + // if the byte string is not tagged by CBOR tag 21-23. The decoder will attempt to decode + // the base64-encoded bytes into Go slice. + ByteStringExpectedBase64 + + // ByteStringExpectedBase16 expects CBOR byte strings to contain base16-encoded bytes + // if the byte string is not tagged by CBOR tag 21-23. The decoder will attempt to decode + // the base16-encoded bytes into Go slice. + ByteStringExpectedBase16 + + maxByteStringExpectedFormatMode +) + +func (bsefm ByteStringExpectedFormatMode) valid() bool { + return bsefm >= 0 && bsefm < maxByteStringExpectedFormatMode +} + +// BignumTagMode specifies whether or not the "bignum" tags 2 and 3 (RFC 8949 Section 3.4.3) can be +// decoded. +type BignumTagMode int + +const ( + // BignumTagAllowed allows bignum tags to be decoded. + BignumTagAllowed BignumTagMode = iota + + // BignumTagForbidden produces an UnacceptableDataItemError during Unmarshal if a bignum tag + // is encountered in the input. + BignumTagForbidden + + maxBignumTag +) + +func (btm BignumTagMode) valid() bool { + return btm >= 0 && btm < maxBignumTag +} + +// BinaryUnmarshalerMode specifies how to decode into types that implement +// encoding.BinaryUnmarshaler. +type BinaryUnmarshalerMode int + +const ( + // BinaryUnmarshalerByteString will invoke UnmarshalBinary on the contents of a CBOR byte + // string when decoding into a value that implements BinaryUnmarshaler. + BinaryUnmarshalerByteString BinaryUnmarshalerMode = iota + + // BinaryUnmarshalerNone does not recognize BinaryUnmarshaler implementations during decode. + BinaryUnmarshalerNone + + maxBinaryUnmarshalerMode +) + +func (bum BinaryUnmarshalerMode) valid() bool { + return bum >= 0 && bum < maxBinaryUnmarshalerMode +} + // DecOptions specifies decoding options. type DecOptions struct { // DupMapKey specifies whether to enforce duplicate map key. DupMapKey DupMapKeyMode - // TimeTag specifies whether to check validity of time.Time (e.g. valid tag number and tag content type). - // For now, valid tag number means 0 or 1 as specified in RFC 7049 if the Go type is time.Time. + // TimeTag specifies whether or not untagged data items, or tags other + // than tag 0 and tag 1, can be decoded to time.Time. If tag 0 or tag 1 + // appears in an input, the type of its content is always validated as + // specified in RFC 8949. That behavior is not controlled by this + // option. The behavior of the supported modes are: + // + // DecTagIgnored (default): Untagged text strings and text strings + // enclosed in tags other than 0 and 1 are decoded as though enclosed + // in tag 0. Untagged unsigned integers, negative integers, and + // floating-point numbers (or those enclosed in tags other than 0 and + // 1) are decoded as though enclosed in tag 1. Decoding a tag other + // than 0 or 1 enclosing simple values null or undefined into a + // time.Time does not modify the destination value. + // + // DecTagOptional: Untagged text strings are decoded as though + // enclosed in tag 0. Untagged unsigned integers, negative integers, + // and floating-point numbers are decoded as though enclosed in tag + // 1. Tags other than 0 and 1 will produce an error on attempts to + // decode them into a time.Time. + // + // DecTagRequired: Only tags 0 and 1 can be decoded to time.Time. Any + // other input will produce an error. TimeTag DecTagMode // MaxNestedLevels specifies the max nested levels allowed for any combination of CBOR array, maps, and tags. @@ -538,22 +837,85 @@ type DecOptions struct { // UnrecognizedTagToAny specifies how to decode unrecognized CBOR tag into an empty interface. // Currently, recognized CBOR tag numbers are 0, 1, 2, 3, or registered by TagSet. UnrecognizedTagToAny UnrecognizedTagToAnyMode + + // TimeTagToAny specifies how to decode CBOR tag 0 and 1 into an empty interface (any). + // Based on the specified mode, Unmarshal can return a time.Time value or a time string in a specific format. + TimeTagToAny TimeTagToAnyMode + + // SimpleValues is an immutable mapping from each CBOR simple value to a corresponding + // unmarshal behavior. If nil, the simple values false, true, null, and undefined are mapped + // to the Go analog values false, true, nil, and nil, respectively, and all other simple + // values N (except the reserved simple values 24 through 31) are mapped to + // cbor.SimpleValue(N). In other words, all well-formed simple values can be decoded. + // + // Users may provide a custom SimpleValueRegistry constructed via + // NewSimpleValueRegistryFromDefaults. + SimpleValues *SimpleValueRegistry + + // NaN specifies how to decode floating-point values (major type 7, additional information + // 25 through 27) representing NaN (not-a-number). + NaN NaNMode + + // Inf specifies how to decode floating-point values (major type 7, additional information + // 25 through 27) representing positive or negative infinity. + Inf InfMode + + // ByteStringToTime specifies how to decode CBOR byte string into Go time.Time. + ByteStringToTime ByteStringToTimeMode + + // ByteStringExpectedFormat specifies how to decode CBOR byte string into Go byte slice + // when the byte string is NOT enclosed in CBOR tag 21, 22, or 23. An error is returned if + // the CBOR byte string does not contain the expected format (e.g. base64) specified. + // For tags 21-23, see "Expected Later Encoding for CBOR-to-JSON Converters" + // in RFC 8949 Section 3.4.5.2. + ByteStringExpectedFormat ByteStringExpectedFormatMode + + // BignumTag specifies whether or not the "bignum" tags 2 and 3 (RFC 8949 Section 3.4.3) can + // be decoded. Unlike BigIntDec, this option applies to all bignum tags encountered in a + // CBOR input, independent of the type of the destination value of a particular Unmarshal + // operation. + BignumTag BignumTagMode + + // BinaryUnmarshaler specifies how to decode into types that implement + // encoding.BinaryUnmarshaler. + BinaryUnmarshaler BinaryUnmarshalerMode } // DecMode returns DecMode with immutable options and no tags (safe for concurrency). -func (opts DecOptions) DecMode() (DecMode, error) { +func (opts DecOptions) DecMode() (DecMode, error) { //nolint:gocritic // ignore hugeParam return opts.decMode() } -// DecModeWithTags returns DecMode with options and tags that are both immutable (safe for concurrency). -func (opts DecOptions) DecModeWithTags(tags TagSet) (DecMode, error) { +// validForTags checks that the provided tag set is compatible with these options and returns a +// non-nil error if and only if the provided tag set is incompatible. +func (opts DecOptions) validForTags(tags TagSet) error { //nolint:gocritic // ignore hugeParam if opts.TagsMd == TagsForbidden { - return nil, errors.New("cbor: cannot create DecMode with TagSet when TagsMd is TagsForbidden") + return errors.New("cbor: cannot create DecMode with TagSet when TagsMd is TagsForbidden") } if tags == nil { - return nil, errors.New("cbor: cannot create DecMode with nil value as TagSet") + return errors.New("cbor: cannot create DecMode with nil value as TagSet") } + if opts.ByteStringToString == ByteStringToStringAllowedWithExpectedLaterEncoding || + opts.ByteStringExpectedFormat != ByteStringExpectedFormatNone { + for _, tagNum := range []uint64{ + tagNumExpectedLaterEncodingBase64URL, + tagNumExpectedLaterEncodingBase64, + tagNumExpectedLaterEncodingBase16, + } { + if rt := tags.getTypeFromTagNum([]uint64{tagNum}); rt != nil { + return fmt.Errorf("cbor: DecMode with non-default StringExpectedEncoding or ByteSliceExpectedEncoding treats tag %d as built-in and conflicts with the provided TagSet's registration of %v", tagNum, rt) + } + } + } + return nil +} + +// DecModeWithTags returns DecMode with options and tags that are both immutable (safe for concurrency). +func (opts DecOptions) DecModeWithTags(tags TagSet) (DecMode, error) { //nolint:gocritic // ignore hugeParam + if err := opts.validForTags(tags); err != nil { + return nil, err + } dm, err := opts.decMode() if err != nil { return nil, err @@ -578,12 +940,9 @@ func (opts DecOptions) DecModeWithTags(tags TagSet) (DecMode, error) { } // DecModeWithSharedTags returns DecMode with immutable options and mutable shared tags (safe for concurrency). -func (opts DecOptions) DecModeWithSharedTags(tags TagSet) (DecMode, error) { - if opts.TagsMd == TagsForbidden { - return nil, errors.New("cbor: cannot create DecMode with TagSet when TagsMd is TagsForbidden") - } - if tags == nil { - return nil, errors.New("cbor: cannot create DecMode with nil value as TagSet") +func (opts DecOptions) DecModeWithSharedTags(tags TagSet) (DecMode, error) { //nolint:gocritic // ignore hugeParam + if err := opts.validForTags(tags); err != nil { + return nil, err } dm, err := opts.decMode() if err != nil { @@ -601,89 +960,166 @@ const ( defaultMaxMapPairs = 131072 minMaxMapPairs = 16 maxMaxMapPairs = 2147483647 + + defaultMaxNestedLevels = 32 + minMaxNestedLevels = 4 + maxMaxNestedLevels = 65535 ) -func (opts DecOptions) decMode() (*decMode, error) { +var defaultSimpleValues = func() *SimpleValueRegistry { + registry, err := NewSimpleValueRegistryFromDefaults() + if err != nil { + panic(err) + } + return registry +}() + +//nolint:gocyclo // Each option comes with some manageable boilerplate +func (opts DecOptions) decMode() (*decMode, error) { //nolint:gocritic // ignore hugeParam if !opts.DupMapKey.valid() { return nil, errors.New("cbor: invalid DupMapKey " + strconv.Itoa(int(opts.DupMapKey))) } + if !opts.TimeTag.valid() { return nil, errors.New("cbor: invalid TimeTag " + strconv.Itoa(int(opts.TimeTag))) } + if !opts.IndefLength.valid() { return nil, errors.New("cbor: invalid IndefLength " + strconv.Itoa(int(opts.IndefLength))) } + if !opts.TagsMd.valid() { return nil, errors.New("cbor: invalid TagsMd " + strconv.Itoa(int(opts.TagsMd))) } + if !opts.IntDec.valid() { return nil, errors.New("cbor: invalid IntDec " + strconv.Itoa(int(opts.IntDec))) } + if !opts.MapKeyByteString.valid() { return nil, errors.New("cbor: invalid MapKeyByteString " + strconv.Itoa(int(opts.MapKeyByteString))) } + if opts.MaxNestedLevels == 0 { - opts.MaxNestedLevels = 32 - } else if opts.MaxNestedLevels < 4 || opts.MaxNestedLevels > 65535 { - return nil, errors.New("cbor: invalid MaxNestedLevels " + strconv.Itoa(opts.MaxNestedLevels) + " (range is [4, 65535])") + opts.MaxNestedLevels = defaultMaxNestedLevels + } else if opts.MaxNestedLevels < minMaxNestedLevels || opts.MaxNestedLevels > maxMaxNestedLevels { + return nil, errors.New("cbor: invalid MaxNestedLevels " + strconv.Itoa(opts.MaxNestedLevels) + + " (range is [" + strconv.Itoa(minMaxNestedLevels) + ", " + strconv.Itoa(maxMaxNestedLevels) + "])") } + if opts.MaxArrayElements == 0 { opts.MaxArrayElements = defaultMaxArrayElements } else if opts.MaxArrayElements < minMaxArrayElements || opts.MaxArrayElements > maxMaxArrayElements { - return nil, errors.New("cbor: invalid MaxArrayElements " + strconv.Itoa(opts.MaxArrayElements) + " (range is [" + strconv.Itoa(minMaxArrayElements) + ", " + strconv.Itoa(maxMaxArrayElements) + "])") + return nil, errors.New("cbor: invalid MaxArrayElements " + strconv.Itoa(opts.MaxArrayElements) + + " (range is [" + strconv.Itoa(minMaxArrayElements) + ", " + strconv.Itoa(maxMaxArrayElements) + "])") } + if opts.MaxMapPairs == 0 { opts.MaxMapPairs = defaultMaxMapPairs } else if opts.MaxMapPairs < minMaxMapPairs || opts.MaxMapPairs > maxMaxMapPairs { - return nil, errors.New("cbor: invalid MaxMapPairs " + strconv.Itoa(opts.MaxMapPairs) + " (range is [" + strconv.Itoa(minMaxMapPairs) + ", " + strconv.Itoa(maxMaxMapPairs) + "])") + return nil, errors.New("cbor: invalid MaxMapPairs " + strconv.Itoa(opts.MaxMapPairs) + + " (range is [" + strconv.Itoa(minMaxMapPairs) + ", " + strconv.Itoa(maxMaxMapPairs) + "])") } + if !opts.ExtraReturnErrors.valid() { return nil, errors.New("cbor: invalid ExtraReturnErrors " + strconv.Itoa(int(opts.ExtraReturnErrors))) } + if opts.DefaultMapType != nil && opts.DefaultMapType.Kind() != reflect.Map { return nil, fmt.Errorf("cbor: invalid DefaultMapType %s", opts.DefaultMapType) } + if !opts.UTF8.valid() { return nil, errors.New("cbor: invalid UTF8 " + strconv.Itoa(int(opts.UTF8))) } + if !opts.FieldNameMatching.valid() { return nil, errors.New("cbor: invalid FieldNameMatching " + strconv.Itoa(int(opts.FieldNameMatching))) } + if !opts.BigIntDec.valid() { return nil, errors.New("cbor: invalid BigIntDec " + strconv.Itoa(int(opts.BigIntDec))) } - if opts.DefaultByteStringType != nil && opts.DefaultByteStringType.Kind() != reflect.String && (opts.DefaultByteStringType.Kind() != reflect.Slice || opts.DefaultByteStringType.Elem().Kind() != reflect.Uint8) { + + if opts.DefaultByteStringType != nil && + opts.DefaultByteStringType.Kind() != reflect.String && + (opts.DefaultByteStringType.Kind() != reflect.Slice || opts.DefaultByteStringType.Elem().Kind() != reflect.Uint8) { return nil, fmt.Errorf("cbor: invalid DefaultByteStringType: %s is not of kind string or []uint8", opts.DefaultByteStringType) } + if !opts.ByteStringToString.valid() { return nil, errors.New("cbor: invalid ByteStringToString " + strconv.Itoa(int(opts.ByteStringToString))) } + if !opts.FieldNameByteString.valid() { return nil, errors.New("cbor: invalid FieldNameByteString " + strconv.Itoa(int(opts.FieldNameByteString))) } + if !opts.UnrecognizedTagToAny.valid() { return nil, errors.New("cbor: invalid UnrecognizedTagToAnyMode " + strconv.Itoa(int(opts.UnrecognizedTagToAny))) } - dm := decMode{ - dupMapKey: opts.DupMapKey, - timeTag: opts.TimeTag, - maxNestedLevels: opts.MaxNestedLevels, - maxArrayElements: opts.MaxArrayElements, - maxMapPairs: opts.MaxMapPairs, - indefLength: opts.IndefLength, - tagsMd: opts.TagsMd, - intDec: opts.IntDec, - mapKeyByteString: opts.MapKeyByteString, - extraReturnErrors: opts.ExtraReturnErrors, - defaultMapType: opts.DefaultMapType, - utf8: opts.UTF8, - fieldNameMatching: opts.FieldNameMatching, - bigIntDec: opts.BigIntDec, - defaultByteStringType: opts.DefaultByteStringType, - byteStringToString: opts.ByteStringToString, - fieldNameByteString: opts.FieldNameByteString, - unrecognizedTagToAny: opts.UnrecognizedTagToAny, + simpleValues := opts.SimpleValues + if simpleValues == nil { + simpleValues = defaultSimpleValues } + + if !opts.TimeTagToAny.valid() { + return nil, errors.New("cbor: invalid TimeTagToAny " + strconv.Itoa(int(opts.TimeTagToAny))) + } + + if !opts.NaN.valid() { + return nil, errors.New("cbor: invalid NaNDec " + strconv.Itoa(int(opts.NaN))) + } + + if !opts.Inf.valid() { + return nil, errors.New("cbor: invalid InfDec " + strconv.Itoa(int(opts.Inf))) + } + + if !opts.ByteStringToTime.valid() { + return nil, errors.New("cbor: invalid ByteStringToTime " + strconv.Itoa(int(opts.ByteStringToTime))) + } + + if !opts.ByteStringExpectedFormat.valid() { + return nil, errors.New("cbor: invalid ByteStringExpectedFormat " + strconv.Itoa(int(opts.ByteStringExpectedFormat))) + } + + if !opts.BignumTag.valid() { + return nil, errors.New("cbor: invalid BignumTag " + strconv.Itoa(int(opts.BignumTag))) + } + + if !opts.BinaryUnmarshaler.valid() { + return nil, errors.New("cbor: invalid BinaryUnmarshaler " + strconv.Itoa(int(opts.BinaryUnmarshaler))) + } + + dm := decMode{ + dupMapKey: opts.DupMapKey, + timeTag: opts.TimeTag, + maxNestedLevels: opts.MaxNestedLevels, + maxArrayElements: opts.MaxArrayElements, + maxMapPairs: opts.MaxMapPairs, + indefLength: opts.IndefLength, + tagsMd: opts.TagsMd, + intDec: opts.IntDec, + mapKeyByteString: opts.MapKeyByteString, + extraReturnErrors: opts.ExtraReturnErrors, + defaultMapType: opts.DefaultMapType, + utf8: opts.UTF8, + fieldNameMatching: opts.FieldNameMatching, + bigIntDec: opts.BigIntDec, + defaultByteStringType: opts.DefaultByteStringType, + byteStringToString: opts.ByteStringToString, + fieldNameByteString: opts.FieldNameByteString, + unrecognizedTagToAny: opts.UnrecognizedTagToAny, + timeTagToAny: opts.TimeTagToAny, + simpleValues: simpleValues, + nanDec: opts.NaN, + infDec: opts.Inf, + byteStringToTime: opts.ByteStringToTime, + byteStringExpectedFormat: opts.ByteStringExpectedFormat, + bignumTag: opts.BignumTag, + binaryUnmarshaler: opts.BinaryUnmarshaler, + } + return &dm, nil } @@ -734,50 +1170,73 @@ type DecMode interface { } type decMode struct { - tags tagProvider - dupMapKey DupMapKeyMode - timeTag DecTagMode - maxNestedLevels int - maxArrayElements int - maxMapPairs int - indefLength IndefLengthMode - tagsMd TagsMode - intDec IntDecMode - mapKeyByteString MapKeyByteStringMode - extraReturnErrors ExtraDecErrorCond - defaultMapType reflect.Type - utf8 UTF8Mode - fieldNameMatching FieldNameMatchingMode - bigIntDec BigIntDecMode - defaultByteStringType reflect.Type - byteStringToString ByteStringToStringMode - fieldNameByteString FieldNameByteStringMode - unrecognizedTagToAny UnrecognizedTagToAnyMode + tags tagProvider + dupMapKey DupMapKeyMode + timeTag DecTagMode + maxNestedLevels int + maxArrayElements int + maxMapPairs int + indefLength IndefLengthMode + tagsMd TagsMode + intDec IntDecMode + mapKeyByteString MapKeyByteStringMode + extraReturnErrors ExtraDecErrorCond + defaultMapType reflect.Type + utf8 UTF8Mode + fieldNameMatching FieldNameMatchingMode + bigIntDec BigIntDecMode + defaultByteStringType reflect.Type + byteStringToString ByteStringToStringMode + fieldNameByteString FieldNameByteStringMode + unrecognizedTagToAny UnrecognizedTagToAnyMode + timeTagToAny TimeTagToAnyMode + simpleValues *SimpleValueRegistry + nanDec NaNMode + infDec InfMode + byteStringToTime ByteStringToTimeMode + byteStringExpectedFormat ByteStringExpectedFormatMode + bignumTag BignumTagMode + binaryUnmarshaler BinaryUnmarshalerMode } var defaultDecMode, _ = DecOptions{}.decMode() // DecOptions returns user specified options used to create this DecMode. func (dm *decMode) DecOptions() DecOptions { + simpleValues := dm.simpleValues + if simpleValues == defaultSimpleValues { + // Users can't explicitly set this to defaultSimpleValues. It must have been nil in + // the original DecOptions. + simpleValues = nil + } + return DecOptions{ - DupMapKey: dm.dupMapKey, - TimeTag: dm.timeTag, - MaxNestedLevels: dm.maxNestedLevels, - MaxArrayElements: dm.maxArrayElements, - MaxMapPairs: dm.maxMapPairs, - IndefLength: dm.indefLength, - TagsMd: dm.tagsMd, - IntDec: dm.intDec, - MapKeyByteString: dm.mapKeyByteString, - ExtraReturnErrors: dm.extraReturnErrors, - DefaultMapType: dm.defaultMapType, - UTF8: dm.utf8, - FieldNameMatching: dm.fieldNameMatching, - BigIntDec: dm.bigIntDec, - DefaultByteStringType: dm.defaultByteStringType, - ByteStringToString: dm.byteStringToString, - FieldNameByteString: dm.fieldNameByteString, - UnrecognizedTagToAny: dm.unrecognizedTagToAny, + DupMapKey: dm.dupMapKey, + TimeTag: dm.timeTag, + MaxNestedLevels: dm.maxNestedLevels, + MaxArrayElements: dm.maxArrayElements, + MaxMapPairs: dm.maxMapPairs, + IndefLength: dm.indefLength, + TagsMd: dm.tagsMd, + IntDec: dm.intDec, + MapKeyByteString: dm.mapKeyByteString, + ExtraReturnErrors: dm.extraReturnErrors, + DefaultMapType: dm.defaultMapType, + UTF8: dm.utf8, + FieldNameMatching: dm.fieldNameMatching, + BigIntDec: dm.bigIntDec, + DefaultByteStringType: dm.defaultByteStringType, + ByteStringToString: dm.byteStringToString, + FieldNameByteString: dm.fieldNameByteString, + UnrecognizedTagToAny: dm.unrecognizedTagToAny, + TimeTagToAny: dm.timeTagToAny, + SimpleValues: simpleValues, + NaN: dm.nanDec, + Inf: dm.infDec, + ByteStringToTime: dm.byteStringToTime, + ByteStringExpectedFormat: dm.byteStringExpectedFormat, + BignumTag: dm.bignumTag, + BinaryUnmarshaler: dm.binaryUnmarshaler, } } @@ -790,9 +1249,9 @@ func (dm *decMode) Unmarshal(data []byte, v interface{}) error { d := decoder{data: data, dm: dm} // Check well-formedness. - off := d.off // Save offset before data validation - err := d.wellformed(false) // don't allow any extra data after valid data item. - d.off = off // Restore offset + off := d.off // Save offset before data validation + err := d.wellformed(false, false) // don't allow any extra data after valid data item. + d.off = off // Restore offset if err != nil { return err } @@ -810,9 +1269,9 @@ func (dm *decMode) UnmarshalFirst(data []byte, v interface{}) (rest []byte, err d := decoder{data: data, dm: dm} // check well-formedness. - off := d.off // Save offset before data validation - err = d.wellformed(true) // allow extra data after well-formed data item - d.off = off // Restore offset + off := d.off // Save offset before data validation + err = d.wellformed(true, false) // allow extra data after well-formed data item + d.off = off // Restore offset // If it is well-formed, parse the value. This is structured like this to allow // better test coverage @@ -853,7 +1312,7 @@ func (dm *decMode) Valid(data []byte) error { // an ExtraneousDataError is returned. func (dm *decMode) Wellformed(data []byte) error { d := decoder{data: data, dm: dm} - return d.wellformed(false) + return d.wellformed(false, false) } // NewDecoder returns a new decoder that reads from r using dm DecMode. @@ -865,6 +1324,17 @@ type decoder struct { data []byte off int // next read offset in data dm *decMode + + // expectedLaterEncodingTags stores a stack of encountered "Expected Later Encoding" tags, + // if any. + // + // The "Expected Later Encoding" tags (21 to 23) are valid for any data item. When decoding + // byte strings, the effective encoding comes from the tag nearest to the byte string being + // decoded. For example, the effective encoding of the byte string 21(22(h'41')) would be + // controlled by tag 22,and in the data item 23(h'42', 22([21(h'43')])]) the effective + // encoding of the byte strings h'42' and h'43' would be controlled by tag 23 and 21, + // respectively. + expectedLaterEncodingTags []uint64 } // value decodes CBOR data item into the value pointed to by v. @@ -886,46 +1356,6 @@ func (d *decoder) value(v interface{}) error { return d.parseToValue(rv, getTypeInfo(rv.Type())) } -type cborType uint8 - -const ( - cborTypePositiveInt cborType = 0x00 - cborTypeNegativeInt cborType = 0x20 - cborTypeByteString cborType = 0x40 - cborTypeTextString cborType = 0x60 - cborTypeArray cborType = 0x80 - cborTypeMap cborType = 0xa0 - cborTypeTag cborType = 0xc0 - cborTypePrimitives cborType = 0xe0 -) - -func (t cborType) String() string { - switch t { - case cborTypePositiveInt: - return "positive integer" - case cborTypeNegativeInt: - return "negative integer" - case cborTypeByteString: - return "byte string" - case cborTypeTextString: - return "UTF-8 text string" - case cborTypeArray: - return "array" - case cborTypeMap: - return "map" - case cborTypeTag: - return "tag" - case cborTypePrimitives: - return "primitives" - default: - return "Invalid type " + strconv.Itoa(int(t)) - } -} - -const ( - selfDescribedCBORTagNum = 55799 -) - // parseToValue decodes CBOR data to value. It assumes data is well-formed, // and does not perform bounds checking. func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolint:gocyclo @@ -942,7 +1372,7 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin // Use value type v = v.Elem() tInfo = getTypeInfo(v.Type()) - } else { + } else { //nolint:gocritic // Create and use registered type if CBOR data is registered tag if d.dm.tags != nil && d.nextCBORType() == cborTypeTag { @@ -984,22 +1414,22 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin for d.nextCBORType() == cborTypeTag { off := d.off _, _, tagNum := d.getHead() - if tagNum != selfDescribedCBORTagNum { + if tagNum != tagNumSelfDescribedCBOR { d.off = off break } } // Check validity of supported built-in tags. - if d.nextCBORType() == cborTypeTag { - off := d.off + off := d.off + for d.nextCBORType() == cborTypeTag { _, _, tagNum := d.getHead() if err := validBuiltinTag(tagNum, d.data[d.off]); err != nil { d.skip() return err } - d.off = off } + d.off = off if tInfo.spclType != specialTypeNone { switch tInfo.spclType { @@ -1009,20 +1439,25 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin v.Set(reflect.ValueOf(iv)) } return err + case specialTypeTag: return d.parseToTag(v) + case specialTypeTime: if d.nextCBORNil() { // Decoding CBOR null and undefined to time.Time is no-op. d.skip() return nil } - tm, err := d.parseToTime() + tm, ok, err := d.parseToTime() if err != nil { return err } - v.Set(reflect.ValueOf(tm)) + if ok { + v.Set(reflect.ValueOf(tm)) + } return nil + case specialTypeUnmarshalerIface: return d.parseToUnmarshaler(v) } @@ -1076,7 +1511,12 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin case cborTypeByteString: b, copied := d.parseByteString() - return fillByteString(t, b, !copied, v, d.dm.byteStringToString) + b, converted, err := d.applyByteStringTextConversion(b, v.Type()) + if err != nil { + return err + } + copied = copied || converted + return fillByteString(t, b, !copied, v, d.dm.byteStringToString, d.dm.binaryUnmarshaler) case cborTypeTextString: b, err := d.parseTextString() @@ -1088,21 +1528,35 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin case cborTypePrimitives: _, ai, val := d.getHead() switch ai { - case 25: + case additionalInformationAsFloat16: f := float64(float16.Frombits(uint16(val)).Float32()) return fillFloat(t, f, v) - case 26: + + case additionalInformationAsFloat32: f := float64(math.Float32frombits(uint32(val))) return fillFloat(t, f, v) - case 27: + + case additionalInformationAsFloat64: f := math.Float64frombits(val) return fillFloat(t, f, v) + default: // ai <= 24 + if d.dm.simpleValues.rejected[SimpleValue(val)] { + return &UnacceptableDataItemError{ + CBORType: t.String(), + Message: "simple value " + strconv.FormatInt(int64(val), 10) + " is not recognized", + } + } + switch ai { - case 20, 21: - return fillBool(t, ai == 21, v) - case 22, 23: + case additionalInformationAsFalse, + additionalInformationAsTrue: + return fillBool(t, ai == additionalInformationAsTrue, v) + + case additionalInformationAsNull, + additionalInformationAsUndefined: return fillNil(t, v) + default: return fillPositiveInt(t, val, v) } @@ -1111,7 +1565,7 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin case cborTypeTag: _, _, tagNum := d.getHead() switch tagNum { - case 2: + case tagNumUnsignedBignum: // Bignum (tag 2) can be decoded to uint, int, float, slice, array, or big.Int. b, copied := d.parseByteString() bi := new(big.Int).SetBytes(b) @@ -1121,7 +1575,7 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin return nil } if tInfo.nonPtrKind == reflect.Slice || tInfo.nonPtrKind == reflect.Array { - return fillByteString(t, b, !copied, v, ByteStringToStringForbidden) + return fillByteString(t, b, !copied, v, ByteStringToStringForbidden, d.dm.binaryUnmarshaler) } if bi.IsUint64() { return fillPositiveInt(t, bi.Uint64(), v) @@ -1131,7 +1585,8 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin GoType: tInfo.nonPtrType.String(), errorMsg: bi.String() + " overflows " + v.Type().String(), } - case 3: + + case tagNumNegativeBignum: // Bignum (tag 3) can be decoded to int, float, slice, array, or big.Int. b, copied := d.parseByteString() bi := new(big.Int).SetBytes(b) @@ -1143,7 +1598,7 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin return nil } if tInfo.nonPtrKind == reflect.Slice || tInfo.nonPtrKind == reflect.Array { - return fillByteString(t, b, !copied, v, ByteStringToStringForbidden) + return fillByteString(t, b, !copied, v, ByteStringToStringForbidden, d.dm.binaryUnmarshaler) } if bi.IsInt64() { return fillNegativeInt(t, bi.Int64(), v) @@ -1153,7 +1608,18 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin GoType: tInfo.nonPtrType.String(), errorMsg: bi.String() + " overflows " + v.Type().String(), } + + case tagNumExpectedLaterEncodingBase64URL, tagNumExpectedLaterEncodingBase64, tagNumExpectedLaterEncodingBase16: + // If conversion for interoperability with text encodings is not configured, + // treat tags 21-23 as unregistered tags. + if d.dm.byteStringToString == ByteStringToStringAllowedWithExpectedLaterEncoding || d.dm.byteStringExpectedFormat != ByteStringExpectedFormatNone { + d.expectedLaterEncodingTags = append(d.expectedLaterEncodingTags, tagNum) + defer func() { + d.expectedLaterEncodingTags = d.expectedLaterEncodingTags[:len(d.expectedLaterEncodingTags)-1] + }() + } } + return d.parseToValue(v, tInfo) case cborTypeArray: @@ -1206,64 +1672,116 @@ func (d *decoder) parseToTag(v reflect.Value) error { return nil } -func (d *decoder) parseToTime() (tm time.Time, err error) { - t := d.nextCBORType() - +// parseToTime decodes the current data item as a time.Time. The bool return value is false if and +// only if the destination value should remain unmodified. +func (d *decoder) parseToTime() (time.Time, bool, error) { // Verify that tag number or absence of tag number is acceptable to specified timeTag. - if t == cborTypeTag { + if t := d.nextCBORType(); t == cborTypeTag { if d.dm.timeTag == DecTagIgnored { - // Skip tag number + // Skip all enclosing tags for t == cborTypeTag { d.getHead() t = d.nextCBORType() } + if d.nextCBORNil() { + d.skip() + return time.Time{}, false, nil + } } else { // Read tag number _, _, tagNum := d.getHead() if tagNum != 0 && tagNum != 1 { - d.skip() - err = errors.New("cbor: wrong tag number for time.Time, got " + strconv.Itoa(int(tagNum)) + ", expect 0 or 1") - return + d.skip() // skip tag content + return time.Time{}, false, errors.New("cbor: wrong tag number for time.Time, got " + strconv.Itoa(int(tagNum)) + ", expect 0 or 1") } } } else { if d.dm.timeTag == DecTagRequired { d.skip() - err = &UnmarshalTypeError{CBORType: t.String(), GoType: typeTime.String(), errorMsg: "expect CBOR tag value"} - return + return time.Time{}, false, &UnmarshalTypeError{CBORType: t.String(), GoType: typeTime.String(), errorMsg: "expect CBOR tag value"} } } - var content interface{} - content, err = d.parse(false) - if err != nil { - return - } - - switch c := content.(type) { - case nil: - return - case uint64: - return time.Unix(int64(c), 0), nil - case int64: - return time.Unix(c, 0), nil - case float64: - if math.IsNaN(c) || math.IsInf(c, 0) { - return + switch t := d.nextCBORType(); t { + case cborTypeByteString: + if d.dm.byteStringToTime == ByteStringToTimeAllowed { + b, _ := d.parseByteString() + t, err := time.Parse(time.RFC3339, string(b)) + if err != nil { + return time.Time{}, false, fmt.Errorf("cbor: cannot set %q for time.Time: %w", string(b), err) + } + return t, true, nil } - f1, f2 := math.Modf(c) - return time.Unix(int64(f1), int64(f2*1e9)), nil - case string: - tm, err = time.Parse(time.RFC3339, c) + return time.Time{}, false, &UnmarshalTypeError{CBORType: t.String(), GoType: typeTime.String()} + + case cborTypeTextString: + s, err := d.parseTextString() if err != nil { - tm = time.Time{} - err = errors.New("cbor: cannot set " + c + " for time.Time: " + err.Error()) - return + return time.Time{}, false, err } - return + t, err := time.Parse(time.RFC3339, string(s)) + if err != nil { + return time.Time{}, false, errors.New("cbor: cannot set " + string(s) + " for time.Time: " + err.Error()) + } + return t, true, nil + + case cborTypePositiveInt: + _, _, val := d.getHead() + if val > math.MaxInt64 { + return time.Time{}, false, &UnmarshalTypeError{ + CBORType: t.String(), + GoType: typeTime.String(), + errorMsg: fmt.Sprintf("%d overflows Go's int64", val), + } + } + return time.Unix(int64(val), 0), true, nil + + case cborTypeNegativeInt: + _, _, val := d.getHead() + if val > math.MaxInt64 { + if val == math.MaxUint64 { + // Maximum absolute value representable by negative integer is 2^64, + // not 2^64-1, so it overflows uint64. + return time.Time{}, false, &UnmarshalTypeError{ + CBORType: t.String(), + GoType: typeTime.String(), + errorMsg: "-18446744073709551616 overflows Go's int64", + } + } + return time.Time{}, false, &UnmarshalTypeError{ + CBORType: t.String(), + GoType: typeTime.String(), + errorMsg: fmt.Sprintf("-%d overflows Go's int64", val+1), + } + } + return time.Unix(int64(-1)^int64(val), 0), true, nil + + case cborTypePrimitives: + _, ai, val := d.getHead() + var f float64 + switch ai { + case additionalInformationAsFloat16: + f = float64(float16.Frombits(uint16(val)).Float32()) + + case additionalInformationAsFloat32: + f = float64(math.Float32frombits(uint32(val))) + + case additionalInformationAsFloat64: + f = math.Float64frombits(val) + + default: + return time.Time{}, false, &UnmarshalTypeError{CBORType: t.String(), GoType: typeTime.String()} + } + + if math.IsNaN(f) || math.IsInf(f, 0) { + // https://www.rfc-editor.org/rfc/rfc8949.html#section-3.4.2-6 + return time.Time{}, true, nil + } + seconds, fractional := math.Modf(f) + return time.Unix(int64(seconds), int64(fractional*1e9)), true, nil + default: - err = &UnmarshalTypeError{CBORType: t.String(), GoType: typeTime.String()} - return + return time.Time{}, false, &UnmarshalTypeError{CBORType: t.String(), GoType: typeTime.String()} } } @@ -1295,7 +1813,7 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli for d.nextCBORType() == cborTypeTag { off := d.off _, _, tagNum := d.getHead() - if tagNum != selfDescribedCBORTagNum { + if tagNum != tagNumSelfDescribedCBOR { d.off = off break } @@ -1303,15 +1821,15 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli } // Check validity of supported built-in tags. - if d.nextCBORType() == cborTypeTag { - off := d.off + off := d.off + for d.nextCBORType() == cborTypeTag { _, _, tagNum := d.getHead() if err := validBuiltinTag(tagNum, d.data[d.off]); err != nil { d.skip() return nil, err } - d.off = off } + d.off = off t := d.nextCBORType() switch t { @@ -1375,20 +1893,30 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli return nValue, nil case cborTypeByteString: - switch d.dm.defaultByteStringType { - case nil, typeByteSlice: - b, copied := d.parseByteString() + b, copied := d.parseByteString() + var effectiveByteStringType = d.dm.defaultByteStringType + if effectiveByteStringType == nil { + effectiveByteStringType = typeByteSlice + } + b, converted, err := d.applyByteStringTextConversion(b, effectiveByteStringType) + if err != nil { + return nil, err + } + copied = copied || converted + + switch effectiveByteStringType { + case typeByteSlice: if copied { return b, nil } clone := make([]byte, len(b)) copy(clone, b) return clone, nil + case typeString: - b, _ := d.parseByteString() return string(b), nil + default: - b, copied := d.parseByteString() if copied || d.dm.defaultByteStringType.Kind() == reflect.String { // Avoid an unnecessary copy since the conversion to string must // copy the underlying bytes. @@ -1398,22 +1926,62 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli copy(clone, b) return reflect.ValueOf(clone).Convert(d.dm.defaultByteStringType).Interface(), nil } + case cborTypeTextString: b, err := d.parseTextString() if err != nil { return nil, err } return string(b), nil + case cborTypeTag: tagOff := d.off _, _, tagNum := d.getHead() contentOff := d.off switch tagNum { - case 0, 1: + case tagNumRFC3339Time, tagNumEpochTime: d.off = tagOff - return d.parseToTime() - case 2: + tm, _, err := d.parseToTime() + if err != nil { + return nil, err + } + + switch d.dm.timeTagToAny { + case TimeTagToTime: + return tm, nil + + case TimeTagToRFC3339: + if tagNum == 1 { + tm = tm.UTC() + } + // Call time.MarshalText() to format decoded time to RFC3339 format, + // and return error on time value that cannot be represented in + // RFC3339 format. E.g. year cannot exceed 9999, etc. + text, err := tm.Truncate(time.Second).MarshalText() + if err != nil { + return nil, fmt.Errorf("cbor: decoded time cannot be represented in RFC3339 format: %v", err) + } + return string(text), nil + + case TimeTagToRFC3339Nano: + if tagNum == 1 { + tm = tm.UTC() + } + // Call time.MarshalText() to format decoded time to RFC3339 format, + // and return error on time value that cannot be represented in + // RFC3339 format with sub-second precision. + text, err := tm.MarshalText() + if err != nil { + return nil, fmt.Errorf("cbor: decoded time cannot be represented in RFC3339 format with sub-second precision: %v", err) + } + return string(text), nil + + default: + // not reachable + } + + case tagNumUnsignedBignum: b, _ := d.parseByteString() bi := new(big.Int).SetBytes(b) @@ -1421,7 +1989,8 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli return bi, nil } return *bi, nil - case 3: + + case tagNumNegativeBignum: b, _ := d.parseByteString() bi := new(big.Int).SetBytes(b) bi.Add(bi, big.NewInt(1)) @@ -1431,6 +2000,18 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli return bi, nil } return *bi, nil + + case tagNumExpectedLaterEncodingBase64URL, tagNumExpectedLaterEncodingBase64, tagNumExpectedLaterEncodingBase16: + // If conversion for interoperability with text encodings is not configured, + // treat tags 21-23 as unregistered tags. + if d.dm.byteStringToString == ByteStringToStringAllowedWithExpectedLaterEncoding || + d.dm.byteStringExpectedFormat != ByteStringExpectedFormatNone { + d.expectedLaterEncodingTags = append(d.expectedLaterEncodingTags, tagNum) + defer func() { + d.expectedLaterEncodingTags = d.expectedLaterEncodingTags[:len(d.expectedLaterEncodingTags)-1] + }() + return d.parse(false) + } } if d.dm.tags != nil { @@ -1461,28 +2042,44 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli return content, nil } return Tag{tagNum, content}, nil + case cborTypePrimitives: _, ai, val := d.getHead() + if ai <= 24 && d.dm.simpleValues.rejected[SimpleValue(val)] { + return nil, &UnacceptableDataItemError{ + CBORType: t.String(), + Message: "simple value " + strconv.FormatInt(int64(val), 10) + " is not recognized", + } + } if ai < 20 || ai == 24 { return SimpleValue(val), nil } + switch ai { - case 20, 21: - return (ai == 21), nil - case 22, 23: + case additionalInformationAsFalse, + additionalInformationAsTrue: + return (ai == additionalInformationAsTrue), nil + + case additionalInformationAsNull, + additionalInformationAsUndefined: return nil, nil - case 25: + + case additionalInformationAsFloat16: f := float64(float16.Frombits(uint16(val)).Float32()) return f, nil - case 26: + + case additionalInformationAsFloat32: f := float64(math.Float32frombits(uint32(val))) return f, nil - case 27: + + case additionalInformationAsFloat64: f := math.Float64frombits(val) return f, nil } + case cborTypeArray: return d.parseArray() + case cborTypeMap: if d.dm.defaultMapType != nil { m := reflect.New(d.dm.defaultMapType) @@ -1494,6 +2091,7 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli } return d.parseMap() } + return nil, nil } @@ -1502,8 +2100,8 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli // and only if the slice is backed by a copy of the input. Callers are // responsible for making a copy if necessary. func (d *decoder) parseByteString() ([]byte, bool) { - _, ai, val := d.getHead() - if ai != 31 { + _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() + if !indefiniteLength { b := d.data[d.off : d.off+int(val)] d.off += int(val) return b, false @@ -1518,12 +2116,90 @@ func (d *decoder) parseByteString() ([]byte, bool) { return b, true } +// applyByteStringTextConversion converts bytes read from a byte string to or from a configured text +// encoding. If no transformation was performed (because it was not required), the original byte +// slice is returned and the bool return value is false. Otherwise, a new slice containing the +// converted bytes is returned along with the bool value true. +func (d *decoder) applyByteStringTextConversion( + src []byte, + dstType reflect.Type, +) ( + dst []byte, + transformed bool, + err error, +) { + switch dstType.Kind() { + case reflect.String: + if d.dm.byteStringToString != ByteStringToStringAllowedWithExpectedLaterEncoding || len(d.expectedLaterEncodingTags) == 0 { + return src, false, nil + } + + switch d.expectedLaterEncodingTags[len(d.expectedLaterEncodingTags)-1] { + case tagNumExpectedLaterEncodingBase64URL: + encoded := make([]byte, base64.RawURLEncoding.EncodedLen(len(src))) + base64.RawURLEncoding.Encode(encoded, src) + return encoded, true, nil + + case tagNumExpectedLaterEncodingBase64: + encoded := make([]byte, base64.StdEncoding.EncodedLen(len(src))) + base64.StdEncoding.Encode(encoded, src) + return encoded, true, nil + + case tagNumExpectedLaterEncodingBase16: + encoded := make([]byte, hex.EncodedLen(len(src))) + hex.Encode(encoded, src) + return encoded, true, nil + + default: + // If this happens, there is a bug: the decoder has pushed an invalid + // "expected later encoding" tag to the stack. + panic(fmt.Sprintf("unrecognized expected later encoding tag: %d", d.expectedLaterEncodingTags)) + } + + case reflect.Slice: + if dstType.Elem().Kind() != reflect.Uint8 || len(d.expectedLaterEncodingTags) > 0 { + // Either the destination is not a slice of bytes, or the encoder that + // produced the input indicated an expected text encoding tag and therefore + // the content of the byte string has NOT been text encoded. + return src, false, nil + } + + switch d.dm.byteStringExpectedFormat { + case ByteStringExpectedBase64URL: + decoded := make([]byte, base64.RawURLEncoding.DecodedLen(len(src))) + n, err := base64.RawURLEncoding.Decode(decoded, src) + if err != nil { + return nil, false, newByteStringExpectedFormatError(ByteStringExpectedBase64URL, err) + } + return decoded[:n], true, nil + + case ByteStringExpectedBase64: + decoded := make([]byte, base64.StdEncoding.DecodedLen(len(src))) + n, err := base64.StdEncoding.Decode(decoded, src) + if err != nil { + return nil, false, newByteStringExpectedFormatError(ByteStringExpectedBase64, err) + } + return decoded[:n], true, nil + + case ByteStringExpectedBase16: + decoded := make([]byte, hex.DecodedLen(len(src))) + n, err := hex.Decode(decoded, src) + if err != nil { + return nil, false, newByteStringExpectedFormatError(ByteStringExpectedBase16, err) + } + return decoded[:n], true, nil + } + } + + return src, false, nil +} + // parseTextString parses CBOR encoded text string. It returns a byte slice // to prevent creating an extra copy of string. Caller should wrap returned // byte slice as string when needed. func (d *decoder) parseTextString() ([]byte, error) { - _, ai, val := d.getHead() - if ai != 31 { + _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() + if !indefiniteLength { b := d.data[d.off : d.off+int(val)] d.off += int(val) if d.dm.utf8 == UTF8RejectInvalid && !utf8.Valid(b) { @@ -1549,8 +2225,8 @@ func (d *decoder) parseTextString() ([]byte, error) { } func (d *decoder) parseArray() ([]interface{}, error) { - _, ai, val := d.getHead() - hasSize := (ai != 31) + _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() + hasSize := !indefiniteLength count := int(val) if !hasSize { count = d.numOfItemsUntilBreak() // peek ahead to get array size to preallocate slice for better performance @@ -1571,8 +2247,8 @@ func (d *decoder) parseArray() ([]interface{}, error) { } func (d *decoder) parseArrayToSlice(v reflect.Value, tInfo *typeInfo) error { - _, ai, val := d.getHead() - hasSize := (ai != 31) + _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() + hasSize := !indefiniteLength count := int(val) if !hasSize { count = d.numOfItemsUntilBreak() // peek ahead to get array size to preallocate slice for better performance @@ -1593,8 +2269,8 @@ func (d *decoder) parseArrayToSlice(v reflect.Value, tInfo *typeInfo) error { } func (d *decoder) parseArrayToArray(v reflect.Value, tInfo *typeInfo) error { - _, ai, val := d.getHead() - hasSize := (ai != 31) + _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() + hasSize := !indefiniteLength count := int(val) gi := 0 vLen := v.Len() @@ -1623,8 +2299,8 @@ func (d *decoder) parseArrayToArray(v reflect.Value, tInfo *typeInfo) error { } func (d *decoder) parseMap() (interface{}, error) { - _, ai, val := d.getHead() - hasSize := (ai != 31) + _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() + hasSize := !indefiniteLength count := int(val) m := make(map[interface{}]interface{}) var k, e interface{} @@ -1688,8 +2364,8 @@ func (d *decoder) parseMap() (interface{}, error) { } func (d *decoder) parseMapToMap(v reflect.Value, tInfo *typeInfo) error { //nolint:gocyclo - _, ai, val := d.getHead() - hasSize := (ai != 31) + _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() + hasSize := !indefiniteLength count := int(val) if v.IsNil() { mapsize := count @@ -1813,8 +2489,8 @@ func (d *decoder) parseArrayToStruct(v reflect.Value, tInfo *typeInfo) error { } start := d.off - t, ai, val := d.getHead() - hasSize := (ai != 31) + _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() + hasSize := !indefiniteLength count := int(val) if !hasSize { count = d.numOfItemsUntilBreak() // peek ahead to get array size @@ -1823,7 +2499,7 @@ func (d *decoder) parseArrayToStruct(v reflect.Value, tInfo *typeInfo) error { d.off = start d.skip() return &UnmarshalTypeError{ - CBORType: t.String(), + CBORType: cborTypeArray.String(), GoType: tInfo.typ.String(), errorMsg: "cannot decode CBOR array to struct with different number of elements", } @@ -1888,25 +2564,37 @@ func (d *decoder) parseMapToStruct(v reflect.Value, tInfo *typeInfo) error { //n var err, lastErr error // Get CBOR map size - _, ai, val := d.getHead() - hasSize := (ai != 31) + _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() + hasSize := !indefiniteLength count := int(val) // Keeps track of matched struct fields - foundFldIdx := make([]bool, len(structType.fields)) + var foundFldIdx []bool + { + const maxStackFields = 128 + if nfields := len(structType.fields); nfields <= maxStackFields { + // For structs with typical field counts, expect that this can be + // stack-allocated. + var a [maxStackFields]bool + foundFldIdx = a[:nfields] + } else { + foundFldIdx = make([]bool, len(structType.fields)) + } + } // Keeps track of CBOR map keys to detect duplicate map key keyCount := 0 var mapKeys map[interface{}]struct{} - if d.dm.dupMapKey == DupMapKeyEnforcedAPF { - mapKeys = make(map[interface{}]struct{}, len(structType.fields)) - } errOnUnknownField := (d.dm.extraReturnErrors & ExtraDecErrorUnknownField) > 0 +MapEntryLoop: for j := 0; (hasSize && j < count) || (!hasSize && !d.foundBreak()); j++ { var f *field - var k interface{} // Used by duplicate map key detection + + // If duplicate field detection is enabled and the key at index j did not match any + // field, k will hold the map key. + var k interface{} t := d.nextCBORType() if t == cborTypeTextString || (t == cborTypeByteString && d.dm.fieldNameByteString == FieldNameByteStringAllowed) { @@ -1924,30 +2612,61 @@ func (d *decoder) parseMapToStruct(v reflect.Value, tInfo *typeInfo) error { //n keyBytes, _ = d.parseByteString() } - keyLen := len(keyBytes) - // Find field with exact match - for i := 0; i < len(structType.fields); i++ { + // Check for exact match on field name. + if i, ok := structType.fieldIndicesByName[string(keyBytes)]; ok { fld := structType.fields[i] - if !foundFldIdx[i] && len(fld.name) == keyLen && fld.name == string(keyBytes) { + + if !foundFldIdx[i] { f = fld foundFldIdx[i] = true - break + } else if d.dm.dupMapKey == DupMapKeyEnforcedAPF { + err = &DupMapKeyError{fld.name, j} + d.skip() // skip value + j++ + // skip the rest of the map + for ; (hasSize && j < count) || (!hasSize && !d.foundBreak()); j++ { + d.skip() + d.skip() + } + return err + } else { + // discard repeated match + d.skip() + continue MapEntryLoop } } + // Find field with case-insensitive match if f == nil && d.dm.fieldNameMatching == FieldNameMatchingPreferCaseSensitive { + keyLen := len(keyBytes) keyString := string(keyBytes) for i := 0; i < len(structType.fields); i++ { fld := structType.fields[i] - if !foundFldIdx[i] && len(fld.name) == keyLen && strings.EqualFold(fld.name, keyString) { - f = fld - foundFldIdx[i] = true + if len(fld.name) == keyLen && strings.EqualFold(fld.name, keyString) { + if !foundFldIdx[i] { + f = fld + foundFldIdx[i] = true + } else if d.dm.dupMapKey == DupMapKeyEnforcedAPF { + err = &DupMapKeyError{keyString, j} + d.skip() // skip value + j++ + // skip the rest of the map + for ; (hasSize && j < count) || (!hasSize && !d.foundBreak()); j++ { + d.skip() + d.skip() + } + return err + } else { + // discard repeated match + d.skip() + continue MapEntryLoop + } break } } } - if d.dm.dupMapKey == DupMapKeyEnforcedAPF { + if d.dm.dupMapKey == DupMapKeyEnforcedAPF && f == nil { k = string(keyBytes) } } else if t <= cborTypeNegativeInt { // uint/int @@ -1975,14 +2694,30 @@ func (d *decoder) parseMapToStruct(v reflect.Value, tInfo *typeInfo) error { //n // Find field for i := 0; i < len(structType.fields); i++ { fld := structType.fields[i] - if !foundFldIdx[i] && fld.keyAsInt && fld.nameAsInt == nameAsInt { - f = fld - foundFldIdx[i] = true + if fld.keyAsInt && fld.nameAsInt == nameAsInt { + if !foundFldIdx[i] { + f = fld + foundFldIdx[i] = true + } else if d.dm.dupMapKey == DupMapKeyEnforcedAPF { + err = &DupMapKeyError{nameAsInt, j} + d.skip() // skip value + j++ + // skip the rest of the map + for ; (hasSize && j < count) || (!hasSize && !d.foundBreak()); j++ { + d.skip() + d.skip() + } + return err + } else { + // discard repeated match + d.skip() + continue MapEntryLoop + } break } } - if d.dm.dupMapKey == DupMapKeyEnforcedAPF { + if d.dm.dupMapKey == DupMapKeyEnforcedAPF && f == nil { k = nameAsInt } } else { @@ -2010,23 +2745,6 @@ func (d *decoder) parseMapToStruct(v reflect.Value, tInfo *typeInfo) error { //n } } - if d.dm.dupMapKey == DupMapKeyEnforcedAPF { - mapKeys[k] = struct{}{} - newKeyCount := len(mapKeys) - if newKeyCount == keyCount { - err = &DupMapKeyError{k, j} - d.skip() // skip value - j++ - // skip the rest of the map - for ; (hasSize && j < count) || (!hasSize && !d.foundBreak()); j++ { - d.skip() - d.skip() - } - return err - } - keyCount = newKeyCount - } - if f == nil { if errOnUnknownField { err = &UnknownFieldError{j} @@ -2039,6 +2757,31 @@ func (d *decoder) parseMapToStruct(v reflect.Value, tInfo *typeInfo) error { //n } return err } + + // Two map keys that match the same struct field are immediately considered + // duplicates. This check detects duplicates between two map keys that do + // not match a struct field. If unknown field errors are enabled, then this + // check is never reached. + if d.dm.dupMapKey == DupMapKeyEnforcedAPF { + if mapKeys == nil { + mapKeys = make(map[interface{}]struct{}, 1) + } + mapKeys[k] = struct{}{} + newKeyCount := len(mapKeys) + if newKeyCount == keyCount { + err = &DupMapKeyError{k, j} + d.skip() // skip value + j++ + // skip the rest of the map + for ; (hasSize && j < count) || (!hasSize && !d.foundBreak()); j++ { + d.skip() + d.skip() + } + return err + } + keyCount = newKeyCount + } + d.skip() // Skip value continue } @@ -2105,13 +2848,13 @@ func (d *decoder) getRegisteredTagItem(vt reflect.Type) *tagItem { // skip moves data offset to the next item. skip assumes data is well-formed, // and does not perform bounds checking. func (d *decoder) skip() { - t, ai, val := d.getHead() + t, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() - if ai == 31 { + if indefiniteLength { switch t { case cborTypeByteString, cborTypeTextString, cborTypeArray, cborTypeMap: for { - if d.data[d.off] == 0xff { + if isBreakFlag(d.data[d.off]) { d.off++ return } @@ -2123,47 +2866,67 @@ func (d *decoder) skip() { switch t { case cborTypeByteString, cborTypeTextString: d.off += int(val) + case cborTypeArray: for i := 0; i < int(val); i++ { d.skip() } + case cborTypeMap: for i := 0; i < int(val)*2; i++ { d.skip() } + case cborTypeTag: d.skip() } } +func (d *decoder) getHeadWithIndefiniteLengthFlag() ( + t cborType, + ai byte, + val uint64, + indefiniteLength bool, +) { + t, ai, val = d.getHead() + indefiniteLength = additionalInformation(ai).isIndefiniteLength() + return +} + // getHead assumes data is well-formed, and does not perform bounds checking. func (d *decoder) getHead() (t cborType, ai byte, val uint64) { - t = cborType(d.data[d.off] & 0xe0) - ai = d.data[d.off] & 0x1f + t, ai = parseInitialByte(d.data[d.off]) val = uint64(ai) d.off++ - if ai < 24 { + if ai <= maxAdditionalInformationWithoutArgument { return } - if ai == 24 { + + if ai == additionalInformationWith1ByteArgument { val = uint64(d.data[d.off]) d.off++ return } - if ai == 25 { - val = uint64(binary.BigEndian.Uint16(d.data[d.off : d.off+2])) - d.off += 2 + + if ai == additionalInformationWith2ByteArgument { + const argumentSize = 2 + val = uint64(binary.BigEndian.Uint16(d.data[d.off : d.off+argumentSize])) + d.off += argumentSize return } - if ai == 26 { - val = uint64(binary.BigEndian.Uint32(d.data[d.off : d.off+4])) - d.off += 4 + + if ai == additionalInformationWith4ByteArgument { + const argumentSize = 4 + val = uint64(binary.BigEndian.Uint32(d.data[d.off : d.off+argumentSize])) + d.off += argumentSize return } - if ai == 27 { - val = binary.BigEndian.Uint64(d.data[d.off : d.off+8]) - d.off += 8 + + if ai == additionalInformationWith8ByteArgument { + const argumentSize = 8 + val = binary.BigEndian.Uint64(d.data[d.off : d.off+argumentSize]) + d.off += argumentSize return } return @@ -2180,9 +2943,11 @@ func (d *decoder) numOfItemsUntilBreak() int { return i } +// foundBreak returns true if next byte is CBOR break code and moves cursor by 1, +// otherwise it returns false. // foundBreak assumes data is well-formed, and does not perform bounds checking. func (d *decoder) foundBreak() bool { - if d.data[d.off] == 0xff { + if isBreakFlag(d.data[d.off]) { d.off++ return true } @@ -2192,10 +2957,11 @@ func (d *decoder) foundBreak() bool { func (d *decoder) reset(data []byte) { d.data = data d.off = 0 + d.expectedLaterEncodingTags = d.expectedLaterEncodingTags[:0] } func (d *decoder) nextCBORType() cborType { - return cborType(d.data[d.off] & 0xe0) + return getType(d.data[d.off]) } func (d *decoder) nextCBORNil() bool { @@ -2240,6 +3006,7 @@ func fillPositiveInt(t cborType, val uint64, v reflect.Value) error { } v.SetInt(int64(val)) return nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: if v.OverflowUint(val) { return &UnmarshalTypeError{ @@ -2250,11 +3017,13 @@ func fillPositiveInt(t cborType, val uint64, v reflect.Value) error { } v.SetUint(val) return nil + case reflect.Float32, reflect.Float64: f := float64(val) v.SetFloat(f) return nil } + if v.Type() == typeBigInt { i := new(big.Int).SetUint64(val) v.Set(reflect.ValueOf(*i)) @@ -2275,6 +3044,7 @@ func fillNegativeInt(t cborType, val int64, v reflect.Value) error { } v.SetInt(val) return nil + case reflect.Float32, reflect.Float64: f := float64(val) v.SetFloat(f) @@ -2312,8 +3082,8 @@ func fillFloat(t cborType, val float64, v reflect.Value) error { return &UnmarshalTypeError{CBORType: t.String(), GoType: v.Type().String()} } -func fillByteString(t cborType, val []byte, shared bool, v reflect.Value, bsts ByteStringToStringMode) error { - if reflect.PtrTo(v.Type()).Implements(typeBinaryUnmarshaler) { +func fillByteString(t cborType, val []byte, shared bool, v reflect.Value, bsts ByteStringToStringMode, bum BinaryUnmarshalerMode) error { + if bum == BinaryUnmarshalerByteString && reflect.PtrTo(v.Type()).Implements(typeBinaryUnmarshaler) { if v.CanAddr() { v = v.Addr() if u, ok := v.Interface().(encoding.BinaryUnmarshaler); ok { @@ -2325,7 +3095,7 @@ func fillByteString(t cborType, val []byte, shared bool, v reflect.Value, bsts B } return errors.New("cbor: cannot set new value for " + v.Type().String()) } - if bsts == ByteStringToStringAllowed && v.Kind() == reflect.String { + if bsts != ByteStringToStringForbidden && v.Kind() == reflect.String { v.SetString(string(val)) return nil } @@ -2373,6 +3143,7 @@ func isImmutableKind(k reflect.Kind) bool { reflect.Float32, reflect.Float64, reflect.String: return true + default: return false } @@ -2382,6 +3153,7 @@ func isHashableValue(rv reflect.Value) bool { switch rv.Kind() { case reflect.Slice, reflect.Map, reflect.Func: return false + case reflect.Struct: switch rv.Type() { case typeTag: @@ -2404,6 +3176,7 @@ func convertByteSliceToByteString(v interface{}) (interface{}, bool) { switch v := v.(type) { case []byte: return ByteString(v), true + case Tag: content, converted := convertByteSliceToByteString(v.Content) if converted { @@ -2412,29 +3185,3 @@ func convertByteSliceToByteString(v interface{}) (interface{}, bool) { } return v, false } - -// validBuiltinTag checks that supported built-in tag numbers are followed by expected content types. -func validBuiltinTag(tagNum uint64, contentHead byte) error { - t := cborType(contentHead & 0xe0) - switch tagNum { - case 0: - // Tag content (date/time text string in RFC 3339 format) must be string type. - if t != cborTypeTextString { - return errors.New("cbor: tag number 0 must be followed by text string, got " + t.String()) - } - return nil - case 1: - // Tag content (epoch date/time) must be uint, int, or float type. - if t != cborTypePositiveInt && t != cborTypeNegativeInt && (contentHead < 0xf9 || contentHead > 0xfb) { - return errors.New("cbor: tag number 1 must be followed by integer or floating-point number, got " + t.String()) - } - return nil - case 2, 3: - // Tag content (bignum) must be byte type. - if t != cborTypeByteString { - return errors.New("cbor: tag number 2 or 3 must be followed by byte string, got " + t.String()) - } - return nil - } - return nil -} diff --git a/vendor/github.com/fxamacker/cbor/v2/diagnose.go b/vendor/github.com/fxamacker/cbor/v2/diagnose.go index 43e6a14..44afb86 100644 --- a/vendor/github.com/fxamacker/cbor/v2/diagnose.go +++ b/vendor/github.com/fxamacker/cbor/v2/diagnose.go @@ -9,6 +9,7 @@ import ( "encoding/base64" "encoding/hex" "errors" + "fmt" "io" "math" "math/big" @@ -158,7 +159,7 @@ func (dm *diagMode) Diagnose(data []byte) (string, error) { } // DiagnoseFirst returns extended diagnostic notation (EDN) of the first CBOR data item using the DiagMode. Any remaining bytes are returned in rest. -func (dm *diagMode) DiagnoseFirst(data []byte) (string, []byte, error) { +func (dm *diagMode) DiagnoseFirst(data []byte) (diagNotation string, rest []byte, err error) { return newDiagnose(data, dm.decMode, dm).diagFirst() } @@ -173,7 +174,7 @@ func Diagnose(data []byte) (string, error) { } // Diagnose returns extended diagnostic notation (EDN) of the first CBOR data item using the DiagMode. Any remaining bytes are returned in rest. -func DiagnoseFirst(data []byte) (string, []byte, error) { +func DiagnoseFirst(data []byte) (diagNotation string, rest []byte, err error) { return defaultDiagMode.DiagnoseFirst(data) } @@ -198,13 +199,11 @@ func (di *diagnose) diag(cborSequence bool) (string, error) { switch err := di.wellformed(cborSequence); err { case nil: if !firstItem { - if err = di.writeString(", "); err != nil { - return di.w.String(), err - } + di.w.WriteString(", ") } firstItem = false - if err = di.item(); err != nil { - return di.w.String(), err + if itemErr := di.item(); itemErr != nil { + return di.w.String(), itemErr } case io.EOF: @@ -219,8 +218,8 @@ func (di *diagnose) diag(cborSequence bool) (string, error) { } } -func (di *diagnose) diagFirst() (string, []byte, error) { - err := di.wellformed(true) +func (di *diagnose) diagFirst() (diagNotation string, rest []byte, err error) { + err = di.wellformed(true) if err == nil { err = di.item() } @@ -235,7 +234,7 @@ func (di *diagnose) diagFirst() (string, []byte, error) { func (di *diagnose) wellformed(allowExtraData bool) error { off := di.d.off - err := di.d.wellformed(allowExtraData) + err := di.d.wellformed(allowExtraData, false) di.d.off = off return err } @@ -243,30 +242,29 @@ func (di *diagnose) wellformed(allowExtraData bool) error { func (di *diagnose) item() error { //nolint:gocyclo initialByte := di.d.data[di.d.off] switch initialByte { - case 0x5f, 0x7f: // indefinite-length byte/text string + case cborByteStringWithIndefiniteLengthHead, + cborTextStringWithIndefiniteLengthHead: // indefinite-length byte/text string di.d.off++ - if di.d.data[di.d.off] == 0xff { + if isBreakFlag(di.d.data[di.d.off]) { di.d.off++ switch initialByte { - case 0x5f: + case cborByteStringWithIndefiniteLengthHead: // indefinite-length bytes with no chunks. - return di.writeString(`''_`) - case 0x7f: + di.w.WriteString(`''_`) + return nil + case cborTextStringWithIndefiniteLengthHead: // indefinite-length text with no chunks. - return di.writeString(`""_`) + di.w.WriteString(`""_`) + return nil } } - if err := di.writeString("(_ "); err != nil { - return err - } + di.w.WriteString("(_ ") i := 0 for !di.d.foundBreak() { if i > 0 { - if err := di.writeString(", "); err != nil { - return err - } + di.w.WriteString(", ") } i++ @@ -276,20 +274,17 @@ func (di *diagnose) item() error { //nolint:gocyclo } } - return di.writeByte(')') + di.w.WriteByte(')') + return nil - case 0x9f: // indefinite-length array + case cborArrayWithIndefiniteLengthHead: // indefinite-length array di.d.off++ - if err := di.writeString("[_ "); err != nil { - return err - } + di.w.WriteString("[_ ") i := 0 for !di.d.foundBreak() { if i > 0 { - if err := di.writeString(", "); err != nil { - return err - } + di.w.WriteString(", ") } i++ @@ -298,20 +293,17 @@ func (di *diagnose) item() error { //nolint:gocyclo } } - return di.writeByte(']') + di.w.WriteByte(']') + return nil - case 0xbf: // indefinite-length map + case cborMapWithIndefiniteLengthHead: // indefinite-length map di.d.off++ - if err := di.writeString("{_ "); err != nil { - return err - } + di.w.WriteString("{_ ") i := 0 for !di.d.foundBreak() { if i > 0 { - if err := di.writeString(", "); err != nil { - return err - } + di.w.WriteString(", ") } i++ @@ -320,9 +312,7 @@ func (di *diagnose) item() error { //nolint:gocyclo return err } - if err := di.writeString(": "); err != nil { - return err - } + di.w.WriteString(": ") // value if err := di.item(); err != nil { @@ -330,14 +320,16 @@ func (di *diagnose) item() error { //nolint:gocyclo } } - return di.writeByte('}') + di.w.WriteByte('}') + return nil } t := di.d.nextCBORType() switch t { case cborTypePositiveInt: _, _, val := di.d.getHead() - return di.writeString(strconv.FormatUint(val, 10)) + di.w.WriteString(strconv.FormatUint(val, 10)) + return nil case cborTypeNegativeInt: _, _, val := di.d.getHead() @@ -347,11 +339,13 @@ func (di *diagnose) item() error { //nolint:gocyclo bi.SetUint64(val) bi.Add(bi, big.NewInt(1)) bi.Neg(bi) - return di.writeString(bi.String()) + di.w.WriteString(bi.String()) + return nil } nValue := int64(-1) ^ int64(val) - return di.writeString(strconv.FormatInt(nValue, 10)) + di.w.WriteString(strconv.FormatInt(nValue, 10)) + return nil case cborTypeByteString: b, _ := di.d.parseByteString() @@ -367,135 +361,129 @@ func (di *diagnose) item() error { //nolint:gocyclo case cborTypeArray: _, _, val := di.d.getHead() count := int(val) - if err := di.writeByte('['); err != nil { - return err - } + di.w.WriteByte('[') for i := 0; i < count; i++ { if i > 0 { - if err := di.writeString(", "); err != nil { - return err - } + di.w.WriteString(", ") } if err := di.item(); err != nil { return err } } - return di.writeByte(']') + di.w.WriteByte(']') + return nil case cborTypeMap: _, _, val := di.d.getHead() count := int(val) - if err := di.writeByte('{'); err != nil { - return err - } + di.w.WriteByte('{') for i := 0; i < count; i++ { if i > 0 { - if err := di.writeString(", "); err != nil { - return err - } + di.w.WriteString(", ") } // key if err := di.item(); err != nil { return err } - if err := di.writeString(": "); err != nil { - return err - } + di.w.WriteString(": ") // value if err := di.item(); err != nil { return err } } - return di.writeByte('}') + di.w.WriteByte('}') + return nil case cborTypeTag: _, _, tagNum := di.d.getHead() switch tagNum { - case 2: + case tagNumUnsignedBignum: if nt := di.d.nextCBORType(); nt != cborTypeByteString { - return errors.New("cbor: tag number 2 must be followed by byte string, got " + nt.String()) + return newInadmissibleTagContentTypeError( + tagNumUnsignedBignum, + "byte string", + nt.String()) } b, _ := di.d.parseByteString() bi := new(big.Int).SetBytes(b) - return di.writeString(bi.String()) + di.w.WriteString(bi.String()) + return nil - case 3: + case tagNumNegativeBignum: if nt := di.d.nextCBORType(); nt != cborTypeByteString { - return errors.New("cbor: tag number 3 must be followed by byte string, got " + nt.String()) + return newInadmissibleTagContentTypeError( + tagNumNegativeBignum, + "byte string", + nt.String(), + ) } b, _ := di.d.parseByteString() bi := new(big.Int).SetBytes(b) bi.Add(bi, big.NewInt(1)) bi.Neg(bi) - return di.writeString(bi.String()) + di.w.WriteString(bi.String()) + return nil default: - if err := di.writeString(strconv.FormatUint(tagNum, 10)); err != nil { - return err - } - if err := di.writeByte('('); err != nil { - return err - } + di.w.WriteString(strconv.FormatUint(tagNum, 10)) + di.w.WriteByte('(') if err := di.item(); err != nil { return err } - return di.writeByte(')') + di.w.WriteByte(')') + return nil } case cborTypePrimitives: _, ai, val := di.d.getHead() switch ai { - case 20: - return di.writeString("false") + case additionalInformationAsFalse: + di.w.WriteString("false") + return nil - case 21: - return di.writeString("true") + case additionalInformationAsTrue: + di.w.WriteString("true") + return nil - case 22: - return di.writeString("null") + case additionalInformationAsNull: + di.w.WriteString("null") + return nil - case 23: - return di.writeString("undefined") + case additionalInformationAsUndefined: + di.w.WriteString("undefined") + return nil - case 25, 26, 27: + case additionalInformationAsFloat16, + additionalInformationAsFloat32, + additionalInformationAsFloat64: return di.encodeFloat(ai, val) default: - if err := di.writeString("simple("); err != nil { - return err - } - if err := di.writeString(strconv.FormatUint(val, 10)); err != nil { - return err - } - return di.writeByte(')') + di.w.WriteString("simple(") + di.w.WriteString(strconv.FormatUint(val, 10)) + di.w.WriteByte(')') + return nil } } return nil } -func (di *diagnose) writeByte(val byte) error { - return di.w.WriteByte(val) -} - -func (di *diagnose) writeString(val string) error { - _, err := di.w.WriteString(val) - return err -} - // writeU16 format a rune as "\uxxxx" -func (di *diagnose) writeU16(val rune) error { - if err := di.writeString("\\u"); err != nil { - return err - } - b := make([]byte, 2) - b[0] = byte(val >> 8) - b[1] = byte(val) - return di.writeString(hex.EncodeToString(b)) +func (di *diagnose) writeU16(val rune) { + di.w.WriteString("\\u") + var in [2]byte + in[0] = byte(val >> 8) + in[1] = byte(val) + sz := hex.EncodedLen(len(in)) + di.w.Grow(sz) + dst := di.w.Bytes()[di.w.Len() : di.w.Len()+sz] + hex.Encode(dst, in[:]) + di.w.Write(dst) } var rawBase32Encoding = base32.StdEncoding.WithPadding(base32.NoPadding) @@ -511,95 +499,91 @@ func (di *diagnose) encodeByteString(val []byte) error { di2 := newDiagnose(val, di.dm.decMode, di.dm) // should always notating embedded CBOR sequence. if str, err := di2.diag(true); err == nil { - if err := di.writeString("<<"); err != nil { - return err - } - if err := di.writeString(str); err != nil { - return err - } - return di.writeString(">>") + di.w.WriteString("<<") + di.w.WriteString(str) + di.w.WriteString(">>") + return nil } } } switch di.dm.byteStringEncoding { case ByteStringBase16Encoding: - if err := di.writeString("h'"); err != nil { - return err - } - - encoder := hex.NewEncoder(di.w) + di.w.WriteString("h'") if di.dm.byteStringHexWhitespace { - for i, b := range val { + sz := hex.EncodedLen(len(val)) + if len(val) > 0 { + sz += len(val) - 1 + } + di.w.Grow(sz) + + dst := di.w.Bytes()[di.w.Len():] + for i := range val { if i > 0 { - if err := di.writeByte(' '); err != nil { - return err - } - } - if _, err := encoder.Write([]byte{b}); err != nil { - return err + dst = append(dst, ' ') } + hex.Encode(dst[len(dst):len(dst)+2], val[i:i+1]) + dst = dst[:len(dst)+2] } + di.w.Write(dst) } else { - if _, err := encoder.Write(val); err != nil { - return err - } + sz := hex.EncodedLen(len(val)) + di.w.Grow(sz) + dst := di.w.Bytes()[di.w.Len() : di.w.Len()+sz] + hex.Encode(dst, val) + di.w.Write(dst) } - return di.writeByte('\'') + di.w.WriteByte('\'') + return nil case ByteStringBase32Encoding: - if err := di.writeString("b32'"); err != nil { - return err - } - encoder := base32.NewEncoder(rawBase32Encoding, di.w) - if _, err := encoder.Write(val); err != nil { - return err - } - encoder.Close() - return di.writeByte('\'') + di.w.WriteString("b32'") + sz := rawBase32Encoding.EncodedLen(len(val)) + di.w.Grow(sz) + dst := di.w.Bytes()[di.w.Len() : di.w.Len()+sz] + rawBase32Encoding.Encode(dst, val) + di.w.Write(dst) + di.w.WriteByte('\'') + return nil case ByteStringBase32HexEncoding: - if err := di.writeString("h32'"); err != nil { - return err - } - encoder := base32.NewEncoder(rawBase32HexEncoding, di.w) - if _, err := encoder.Write(val); err != nil { - return err - } - encoder.Close() - return di.writeByte('\'') + di.w.WriteString("h32'") + sz := rawBase32HexEncoding.EncodedLen(len(val)) + di.w.Grow(sz) + dst := di.w.Bytes()[di.w.Len() : di.w.Len()+sz] + rawBase32HexEncoding.Encode(dst, val) + di.w.Write(dst) + di.w.WriteByte('\'') + return nil case ByteStringBase64Encoding: - if err := di.writeString("b64'"); err != nil { - return err - } - encoder := base64.NewEncoder(base64.RawURLEncoding, di.w) - if _, err := encoder.Write(val); err != nil { - return err - } - encoder.Close() - return di.writeByte('\'') + di.w.WriteString("b64'") + sz := base64.RawURLEncoding.EncodedLen(len(val)) + di.w.Grow(sz) + dst := di.w.Bytes()[di.w.Len() : di.w.Len()+sz] + base64.RawURLEncoding.Encode(dst, val) + di.w.Write(dst) + di.w.WriteByte('\'') + return nil default: - return di.dm.byteStringEncoding.valid() + // It should not be possible for users to construct a *diagMode with an invalid byte + // string encoding. + panic(fmt.Sprintf("diagmode has invalid ByteStringEncoding %v", di.dm.byteStringEncoding)) } } -var utf16SurrSelf = rune(0x10000) +const utf16SurrSelf = rune(0x10000) // quote should be either `'` or `"` func (di *diagnose) encodeTextString(val string, quote byte) error { - if err := di.writeByte(quote); err != nil { - return err - } + di.w.WriteByte(quote) for i := 0; i < len(val); { if b := val[i]; b < utf8.RuneSelf { switch { case b == '\t', b == '\n', b == '\r', b == '\\', b == quote: - if err := di.writeByte('\\'); err != nil { - return err - } + di.w.WriteByte('\\') switch b { case '\t': @@ -609,19 +593,13 @@ func (di *diagnose) encodeTextString(val string, quote byte) error { case '\r': b = 'r' } - if err := di.writeByte(b); err != nil { - return err - } + di.w.WriteByte(b) case b >= ' ' && b <= '~': - if err := di.writeByte(b); err != nil { - return err - } + di.w.WriteByte(b) default: - if err := di.writeU16(rune(b)); err != nil { - return err - } + di.writeU16(rune(b)) } i++ @@ -631,84 +609,86 @@ func (di *diagnose) encodeTextString(val string, quote byte) error { c, size := utf8.DecodeRuneInString(val[i:]) switch { case c == utf8.RuneError: - // if err := di.writeU16(rune(val[i])); err != nil { - // return err - // } return &SemanticError{"cbor: invalid UTF-8 string"} case c < utf16SurrSelf: - if err := di.writeU16(c); err != nil { - return err - } + di.writeU16(c) default: c1, c2 := utf16.EncodeRune(c) - if err := di.writeU16(c1); err != nil { - return err - } - if err := di.writeU16(c2); err != nil { - return err - } + di.writeU16(c1) + di.writeU16(c2) } i += size } - return di.writeByte(quote) + di.w.WriteByte(quote) + return nil } func (di *diagnose) encodeFloat(ai byte, val uint64) error { f64 := float64(0) switch ai { - case 25: + case additionalInformationAsFloat16: f16 := float16.Frombits(uint16(val)) switch { case f16.IsNaN(): - return di.writeString("NaN") + di.w.WriteString("NaN") + return nil case f16.IsInf(1): - return di.writeString("Infinity") + di.w.WriteString("Infinity") + return nil case f16.IsInf(-1): - return di.writeString("-Infinity") + di.w.WriteString("-Infinity") + return nil default: f64 = float64(f16.Float32()) } - case 26: + case additionalInformationAsFloat32: f32 := math.Float32frombits(uint32(val)) switch { case f32 != f32: - return di.writeString("NaN") + di.w.WriteString("NaN") + return nil case f32 > math.MaxFloat32: - return di.writeString("Infinity") + di.w.WriteString("Infinity") + return nil case f32 < -math.MaxFloat32: - return di.writeString("-Infinity") + di.w.WriteString("-Infinity") + return nil default: f64 = float64(f32) } - case 27: + case additionalInformationAsFloat64: f64 = math.Float64frombits(val) switch { case f64 != f64: - return di.writeString("NaN") + di.w.WriteString("NaN") + return nil case f64 > math.MaxFloat64: - return di.writeString("Infinity") + di.w.WriteString("Infinity") + return nil case f64 < -math.MaxFloat64: - return di.writeString("-Infinity") + di.w.WriteString("-Infinity") + return nil } } // Use ES6 number to string conversion which should match most JSON generators. // Inspired by https://github.com/golang/go/blob/4df10fba1687a6d4f51d7238a403f8f2298f6a16/src/encoding/json/encode.go#L585 + const bitSize = 64 b := make([]byte, 0, 32) if abs := math.Abs(f64); abs != 0 && (abs < 1e-6 || abs >= 1e21) { - b = strconv.AppendFloat(b, f64, 'e', -1, 64) + b = strconv.AppendFloat(b, f64, 'e', -1, bitSize) // clean up e-09 to e-9 n := len(b) if n >= 4 && string(b[n-4:n-1]) == "e-0" { b = append(b[:n-2], b[n-1]) } } else { - b = strconv.AppendFloat(b, f64, 'f', -1, 64) + b = strconv.AppendFloat(b, f64, 'f', -1, bitSize) } // add decimal point and trailing zero if needed @@ -722,18 +702,21 @@ func (di *diagnose) encodeFloat(ai byte, val uint64) error { } } - if err := di.writeString(string(b)); err != nil { - return err - } + di.w.WriteString(string(b)) if di.dm.floatPrecisionIndicator { switch ai { - case 25: - return di.writeString("_1") - case 26: - return di.writeString("_2") - case 27: - return di.writeString("_3") + case additionalInformationAsFloat16: + di.w.WriteString("_1") + return nil + + case additionalInformationAsFloat32: + di.w.WriteString("_2") + return nil + + case additionalInformationAsFloat64: + di.w.WriteString("_3") + return nil } } diff --git a/vendor/github.com/fxamacker/cbor/v2/encode.go b/vendor/github.com/fxamacker/cbor/v2/encode.go index 86cc47a..6508e29 100644 --- a/vendor/github.com/fxamacker/cbor/v2/encode.go +++ b/vendor/github.com/fxamacker/cbor/v2/encode.go @@ -8,9 +8,11 @@ import ( "encoding" "encoding/binary" "errors" + "fmt" "io" "math" "math/big" + "math/rand" "reflect" "sort" "strconv" @@ -94,12 +96,40 @@ func Marshal(v interface{}) ([]byte, error) { return defaultEncMode.Marshal(v) } +// MarshalToBuffer encodes v into provided buffer (instead of using built-in buffer pool) +// and uses default encoding options. +// +// NOTE: Unlike Marshal, the buffer provided to MarshalToBuffer can contain +// partially encoded data if error is returned. +// +// See Marshal for more details. +func MarshalToBuffer(v interface{}, buf *bytes.Buffer) error { + return defaultEncMode.MarshalToBuffer(v, buf) +} + // Marshaler is the interface implemented by types that can marshal themselves // into valid CBOR. type Marshaler interface { MarshalCBOR() ([]byte, error) } +// MarshalerError represents error from checking encoded CBOR data item +// returned from MarshalCBOR for well-formedness and some very limited tag validation. +type MarshalerError struct { + typ reflect.Type + err error +} + +func (e *MarshalerError) Error() string { + return "cbor: error calling MarshalCBOR for type " + + e.typ.String() + + ": " + e.err.Error() +} + +func (e *MarshalerError) Unwrap() error { + return e.err +} + // UnsupportedTypeError is returned by Marshal when attempting to encode value // of an unsupported type. type UnsupportedTypeError struct { @@ -124,7 +154,7 @@ func (e *UnsupportedValueError) Error() string { type SortMode int const ( - // SortNone means no sorting. + // SortNone encodes map pairs and struct fields in an arbitrary order. SortNone SortMode = 0 // SortLengthFirst causes map keys or struct fields to be sorted such that: @@ -140,6 +170,12 @@ const ( // in RFC 7049bis. SortBytewiseLexical SortMode = 2 + // SortShuffle encodes map pairs and struct fields in a shuffled + // order. This mode does not guarantee an unbiased permutation, but it + // does guarantee that the runtime of the shuffle algorithm used will be + // constant. + SortFastShuffle SortMode = 3 + // SortCanonical is used in "Canonical CBOR" encoding in RFC 7049 3.9. SortCanonical SortMode = SortLengthFirst @@ -149,7 +185,7 @@ const ( // SortCoreDeterministic is used in "Core Deterministic Encoding" in RFC 7049bis. SortCoreDeterministic SortMode = SortBytewiseLexical - maxSortMode SortMode = 3 + maxSortMode SortMode = 4 ) func (sm SortMode) valid() bool { @@ -171,6 +207,7 @@ func (st StringMode) cborType() (cborType, error) { switch st { case StringToTextString: return cborTypeTextString, nil + case StringToByteString: return cborTypeByteString, nil } @@ -223,6 +260,9 @@ const ( // NaN payload. NaNConvertQuiet + // NaNConvertReject returns UnsupportedValueError on attempts to encode a NaN value. + NaNConvertReject + maxNaNConvert ) @@ -241,6 +281,9 @@ const ( // InfConvertNone never converts (used by CTAP2 Canonical CBOR). InfConvertNone + // InfConvertReject returns UnsupportedValueError on attempts to encode an infinite value. + InfConvertReject + maxInfConvert ) @@ -288,6 +331,9 @@ const ( // converting it to another CBOR type. BigIntConvertNone + // BigIntConvertReject returns an UnsupportedTypeError instead of marshaling a big.Int. + BigIntConvertReject + maxBigIntConvert ) @@ -357,6 +403,84 @@ func (fnm FieldNameMode) valid() bool { return fnm >= 0 && fnm < maxFieldNameMode } +// ByteSliceLaterFormatMode specifies which later format conversion hint (CBOR tag 21-23) +// to include (if any) when encoding Go byte slice to CBOR byte string. The encoder will +// always encode unmodified bytes from the byte slice and just wrap it within +// CBOR tag 21, 22, or 23 if specified. +// See "Expected Later Encoding for CBOR-to-JSON Converters" in RFC 8949 Section 3.4.5.2. +type ByteSliceLaterFormatMode int + +const ( + // ByteSliceLaterFormatNone encodes unmodified bytes from Go byte slice to CBOR byte string (major type 2) + // without adding CBOR tag 21, 22, or 23. + ByteSliceLaterFormatNone ByteSliceLaterFormatMode = iota + + // ByteSliceLaterFormatBase64URL encodes unmodified bytes from Go byte slice to CBOR byte string (major type 2) + // inside CBOR tag 21 (expected later conversion to base64url encoding, see RFC 8949 Section 3.4.5.2). + ByteSliceLaterFormatBase64URL + + // ByteSliceLaterFormatBase64 encodes unmodified bytes from Go byte slice to CBOR byte string (major type 2) + // inside CBOR tag 22 (expected later conversion to base64 encoding, see RFC 8949 Section 3.4.5.2). + ByteSliceLaterFormatBase64 + + // ByteSliceLaterFormatBase16 encodes unmodified bytes from Go byte slice to CBOR byte string (major type 2) + // inside CBOR tag 23 (expected later conversion to base16 encoding, see RFC 8949 Section 3.4.5.2). + ByteSliceLaterFormatBase16 +) + +func (bsefm ByteSliceLaterFormatMode) encodingTag() (uint64, error) { + switch bsefm { + case ByteSliceLaterFormatNone: + return 0, nil + + case ByteSliceLaterFormatBase64URL: + return tagNumExpectedLaterEncodingBase64URL, nil + + case ByteSliceLaterFormatBase64: + return tagNumExpectedLaterEncodingBase64, nil + + case ByteSliceLaterFormatBase16: + return tagNumExpectedLaterEncodingBase16, nil + } + return 0, errors.New("cbor: invalid ByteSliceLaterFormat " + strconv.Itoa(int(bsefm))) +} + +// ByteArrayMode specifies how to encode byte arrays. +type ByteArrayMode int + +const ( + // ByteArrayToByteSlice encodes byte arrays the same way that a byte slice with identical + // length and contents is encoded. + ByteArrayToByteSlice ByteArrayMode = iota + + // ByteArrayToArray encodes byte arrays to the CBOR array type with one unsigned integer + // item for each byte in the array. + ByteArrayToArray + + maxByteArrayMode +) + +func (bam ByteArrayMode) valid() bool { + return bam >= 0 && bam < maxByteArrayMode +} + +// BinaryMarshalerMode specifies how to encode types that implement encoding.BinaryMarshaler. +type BinaryMarshalerMode int + +const ( + // BinaryMarshalerByteString encodes the output of MarshalBinary to a CBOR byte string. + BinaryMarshalerByteString BinaryMarshalerMode = iota + + // BinaryMarshalerNone does not recognize BinaryMarshaler implementations during encode. + BinaryMarshalerNone + + maxBinaryMarshalerMode +) + +func (bmm BinaryMarshalerMode) valid() bool { + return bmm >= 0 && bmm < maxBinaryMarshalerMode +} + // EncOptions specifies encoding options. type EncOptions struct { // Sort specifies sorting order. @@ -401,6 +525,19 @@ type EncOptions struct { // FieldName specifies the CBOR type to use when encoding struct field names. FieldName FieldNameMode + + // ByteSliceLaterFormat specifies which later format conversion hint (CBOR tag 21-23) + // to include (if any) when encoding Go byte slice to CBOR byte string. The encoder will + // always encode unmodified bytes from the byte slice and just wrap it within + // CBOR tag 21, 22, or 23 if specified. + // See "Expected Later Encoding for CBOR-to-JSON Converters" in RFC 8949 Section 3.4.5.2. + ByteSliceLaterFormat ByteSliceLaterFormatMode + + // ByteArray specifies how to encode byte arrays. + ByteArray ByteArrayMode + + // BinaryMarshaler specifies how to encode types that implement encoding.BinaryMarshaler. + BinaryMarshaler BinaryMarshalerMode } // CanonicalEncOptions returns EncOptions for "Canonical CBOR" encoding, @@ -494,12 +631,22 @@ func PreferredUnsortedEncOptions() EncOptions { } // EncMode returns EncMode with immutable options and no tags (safe for concurrency). -func (opts EncOptions) EncMode() (EncMode, error) { +func (opts EncOptions) EncMode() (EncMode, error) { //nolint:gocritic // ignore hugeParam + return opts.encMode() +} + +// UserBufferEncMode returns UserBufferEncMode with immutable options and no tags (safe for concurrency). +func (opts EncOptions) UserBufferEncMode() (UserBufferEncMode, error) { //nolint:gocritic // ignore hugeParam return opts.encMode() } // EncModeWithTags returns EncMode with options and tags that are both immutable (safe for concurrency). -func (opts EncOptions) EncModeWithTags(tags TagSet) (EncMode, error) { +func (opts EncOptions) EncModeWithTags(tags TagSet) (EncMode, error) { //nolint:gocritic // ignore hugeParam + return opts.UserBufferEncModeWithTags(tags) +} + +// UserBufferEncModeWithTags returns UserBufferEncMode with options and tags that are both immutable (safe for concurrency). +func (opts EncOptions) UserBufferEncModeWithTags(tags TagSet) (UserBufferEncMode, error) { //nolint:gocritic // ignore hugeParam if opts.TagsMd == TagsForbidden { return nil, errors.New("cbor: cannot create EncMode with TagSet when TagsMd is TagsForbidden") } @@ -527,7 +674,12 @@ func (opts EncOptions) EncModeWithTags(tags TagSet) (EncMode, error) { } // EncModeWithSharedTags returns EncMode with immutable options and mutable shared tags (safe for concurrency). -func (opts EncOptions) EncModeWithSharedTags(tags TagSet) (EncMode, error) { +func (opts EncOptions) EncModeWithSharedTags(tags TagSet) (EncMode, error) { //nolint:gocritic // ignore hugeParam + return opts.UserBufferEncModeWithSharedTags(tags) +} + +// UserBufferEncModeWithSharedTags returns UserBufferEncMode with immutable options and mutable shared tags (safe for concurrency). +func (opts EncOptions) UserBufferEncModeWithSharedTags(tags TagSet) (UserBufferEncMode, error) { //nolint:gocritic // ignore hugeParam if opts.TagsMd == TagsForbidden { return nil, errors.New("cbor: cannot create EncMode with TagSet when TagsMd is TagsForbidden") } @@ -542,7 +694,7 @@ func (opts EncOptions) EncModeWithSharedTags(tags TagSet) (EncMode, error) { return em, nil } -func (opts EncOptions) encMode() (*encMode, error) { +func (opts EncOptions) encMode() (*encMode, error) { //nolint:gocritic // ignore hugeParam if !opts.Sort.valid() { return nil, errors.New("cbor: invalid SortMode " + strconv.Itoa(int(opts.Sort))) } @@ -586,21 +738,35 @@ func (opts EncOptions) encMode() (*encMode, error) { if !opts.FieldName.valid() { return nil, errors.New("cbor: invalid FieldName " + strconv.Itoa(int(opts.FieldName))) } + byteSliceLaterEncodingTag, err := opts.ByteSliceLaterFormat.encodingTag() + if err != nil { + return nil, err + } + if !opts.ByteArray.valid() { + return nil, errors.New("cbor: invalid ByteArray " + strconv.Itoa(int(opts.ByteArray))) + } + if !opts.BinaryMarshaler.valid() { + return nil, errors.New("cbor: invalid BinaryMarshaler " + strconv.Itoa(int(opts.BinaryMarshaler))) + } em := encMode{ - sort: opts.Sort, - shortestFloat: opts.ShortestFloat, - nanConvert: opts.NaNConvert, - infConvert: opts.InfConvert, - bigIntConvert: opts.BigIntConvert, - time: opts.Time, - timeTag: opts.TimeTag, - indefLength: opts.IndefLength, - nilContainers: opts.NilContainers, - tagsMd: opts.TagsMd, - omitEmpty: opts.OmitEmpty, - stringType: opts.String, - stringMajorType: stringMajorType, - fieldName: opts.FieldName, + sort: opts.Sort, + shortestFloat: opts.ShortestFloat, + nanConvert: opts.NaNConvert, + infConvert: opts.InfConvert, + bigIntConvert: opts.BigIntConvert, + time: opts.Time, + timeTag: opts.TimeTag, + indefLength: opts.IndefLength, + nilContainers: opts.NilContainers, + tagsMd: opts.TagsMd, + omitEmpty: opts.OmitEmpty, + stringType: opts.String, + stringMajorType: stringMajorType, + fieldName: opts.FieldName, + byteSliceLaterFormat: opts.ByteSliceLaterFormat, + byteSliceLaterEncodingTag: byteSliceLaterEncodingTag, + byteArray: opts.ByteArray, + binaryMarshaler: opts.BinaryMarshaler, } return &em, nil } @@ -612,45 +778,137 @@ type EncMode interface { EncOptions() EncOptions } +// UserBufferEncMode is an interface for CBOR encoding, which extends EncMode by +// adding MarshalToBuffer to support user specified buffer rather than encoding +// into the built-in buffer pool. +type UserBufferEncMode interface { + EncMode + MarshalToBuffer(v interface{}, buf *bytes.Buffer) error + + // This private method is to prevent users implementing + // this interface and so future additions to it will + // not be breaking changes. + // See https://go.dev/blog/module-compatibility + unexport() +} + type encMode struct { - tags tagProvider - sort SortMode - shortestFloat ShortestFloatMode - nanConvert NaNConvertMode - infConvert InfConvertMode - bigIntConvert BigIntConvertMode - time TimeMode - timeTag EncTagMode - indefLength IndefLengthMode - nilContainers NilContainersMode - tagsMd TagsMode - omitEmpty OmitEmptyMode - stringType StringMode - stringMajorType cborType - fieldName FieldNameMode + tags tagProvider + sort SortMode + shortestFloat ShortestFloatMode + nanConvert NaNConvertMode + infConvert InfConvertMode + bigIntConvert BigIntConvertMode + time TimeMode + timeTag EncTagMode + indefLength IndefLengthMode + nilContainers NilContainersMode + tagsMd TagsMode + omitEmpty OmitEmptyMode + stringType StringMode + stringMajorType cborType + fieldName FieldNameMode + byteSliceLaterFormat ByteSliceLaterFormatMode + byteSliceLaterEncodingTag uint64 + byteArray ByteArrayMode + binaryMarshaler BinaryMarshalerMode } var defaultEncMode, _ = EncOptions{}.encMode() +// These four decoding modes are used by getMarshalerDecMode. +// maxNestedLevels, maxArrayElements, and maxMapPairs are +// set to max allowed limits to avoid rejecting Marshaler +// output that would have been the allowable output of a +// non-Marshaler object that exceeds default limits. +var ( + marshalerForbidIndefLengthForbidTagsDecMode = decMode{ + maxNestedLevels: maxMaxNestedLevels, + maxArrayElements: maxMaxArrayElements, + maxMapPairs: maxMaxMapPairs, + indefLength: IndefLengthForbidden, + tagsMd: TagsForbidden, + } + + marshalerAllowIndefLengthForbidTagsDecMode = decMode{ + maxNestedLevels: maxMaxNestedLevels, + maxArrayElements: maxMaxArrayElements, + maxMapPairs: maxMaxMapPairs, + indefLength: IndefLengthAllowed, + tagsMd: TagsForbidden, + } + + marshalerForbidIndefLengthAllowTagsDecMode = decMode{ + maxNestedLevels: maxMaxNestedLevels, + maxArrayElements: maxMaxArrayElements, + maxMapPairs: maxMaxMapPairs, + indefLength: IndefLengthForbidden, + tagsMd: TagsAllowed, + } + + marshalerAllowIndefLengthAllowTagsDecMode = decMode{ + maxNestedLevels: maxMaxNestedLevels, + maxArrayElements: maxMaxArrayElements, + maxMapPairs: maxMaxMapPairs, + indefLength: IndefLengthAllowed, + tagsMd: TagsAllowed, + } +) + +// getMarshalerDecMode returns one of four existing decoding modes +// which can be reused (safe for parallel use) for the purpose of +// checking if data returned by Marshaler is well-formed. +func getMarshalerDecMode(indefLength IndefLengthMode, tagsMd TagsMode) *decMode { + switch { + case indefLength == IndefLengthAllowed && tagsMd == TagsAllowed: + return &marshalerAllowIndefLengthAllowTagsDecMode + + case indefLength == IndefLengthAllowed && tagsMd == TagsForbidden: + return &marshalerAllowIndefLengthForbidTagsDecMode + + case indefLength == IndefLengthForbidden && tagsMd == TagsAllowed: + return &marshalerForbidIndefLengthAllowTagsDecMode + + case indefLength == IndefLengthForbidden && tagsMd == TagsForbidden: + return &marshalerForbidIndefLengthForbidTagsDecMode + + default: + // This should never happen, unless we add new options to + // IndefLengthMode or TagsMode without updating this function. + return &decMode{ + maxNestedLevels: maxMaxNestedLevels, + maxArrayElements: maxMaxArrayElements, + maxMapPairs: maxMaxMapPairs, + indefLength: indefLength, + tagsMd: tagsMd, + } + } +} + // EncOptions returns user specified options used to create this EncMode. func (em *encMode) EncOptions() EncOptions { return EncOptions{ - Sort: em.sort, - ShortestFloat: em.shortestFloat, - NaNConvert: em.nanConvert, - InfConvert: em.infConvert, - BigIntConvert: em.bigIntConvert, - Time: em.time, - TimeTag: em.timeTag, - IndefLength: em.indefLength, - NilContainers: em.nilContainers, - TagsMd: em.tagsMd, - OmitEmpty: em.omitEmpty, - String: em.stringType, - FieldName: em.fieldName, + Sort: em.sort, + ShortestFloat: em.shortestFloat, + NaNConvert: em.nanConvert, + InfConvert: em.infConvert, + BigIntConvert: em.bigIntConvert, + Time: em.time, + TimeTag: em.timeTag, + IndefLength: em.indefLength, + NilContainers: em.nilContainers, + TagsMd: em.tagsMd, + OmitEmpty: em.omitEmpty, + String: em.stringType, + FieldName: em.fieldName, + ByteSliceLaterFormat: em.byteSliceLaterFormat, + ByteArray: em.byteArray, + BinaryMarshaler: em.binaryMarshaler, } } +func (em *encMode) unexport() {} + func (em *encMode) encTagBytes(t reflect.Type) []byte { if em.tags != nil { if tagItem := em.tags.getTagItemFromType(t); tagItem != nil { @@ -664,61 +922,61 @@ func (em *encMode) encTagBytes(t reflect.Type) []byte { // // See the documentation for Marshal for details. func (em *encMode) Marshal(v interface{}) ([]byte, error) { - e := getEncoderBuffer() + e := getEncodeBuffer() if err := encode(e, em, reflect.ValueOf(v)); err != nil { - putEncoderBuffer(e) + putEncodeBuffer(e) return nil, err } buf := make([]byte, e.Len()) copy(buf, e.Bytes()) - putEncoderBuffer(e) + putEncodeBuffer(e) return buf, nil } +// MarshalToBuffer encodes v into provided buffer (instead of using built-in buffer pool) +// and uses em encoding mode. +// +// NOTE: Unlike Marshal, the buffer provided to MarshalToBuffer can contain +// partially encoded data if error is returned. +// +// See Marshal for more details. +func (em *encMode) MarshalToBuffer(v interface{}, buf *bytes.Buffer) error { + if buf == nil { + return fmt.Errorf("cbor: encoding buffer provided by user is nil") + } + return encode(buf, em, reflect.ValueOf(v)) +} + // NewEncoder returns a new encoder that writes to w using em EncMode. func (em *encMode) NewEncoder(w io.Writer) *Encoder { return &Encoder{w: w, em: em} } -type encoderBuffer struct { - bytes.Buffer - scratch [16]byte -} - -// encoderBufferPool caches unused encoderBuffer objects for later reuse. -var encoderBufferPool = sync.Pool{ +// encodeBufferPool caches unused bytes.Buffer objects for later reuse. +var encodeBufferPool = sync.Pool{ New: func() interface{} { - e := new(encoderBuffer) + e := new(bytes.Buffer) e.Grow(32) // TODO: make this configurable return e }, } -func getEncoderBuffer() *encoderBuffer { - return encoderBufferPool.Get().(*encoderBuffer) +func getEncodeBuffer() *bytes.Buffer { + return encodeBufferPool.Get().(*bytes.Buffer) } -func putEncoderBuffer(e *encoderBuffer) { +func putEncodeBuffer(e *bytes.Buffer) { e.Reset() - encoderBufferPool.Put(e) + encodeBufferPool.Put(e) } -type encodeFunc func(e *encoderBuffer, em *encMode, v reflect.Value) error +type encodeFunc func(e *bytes.Buffer, em *encMode, v reflect.Value) error type isEmptyFunc func(em *encMode, v reflect.Value) (empty bool, err error) -var ( - cborFalse = []byte{0xf4} - cborTrue = []byte{0xf5} - cborNil = []byte{0xf6} - cborNaN = []byte{0xf9, 0x7e, 0x00} - cborPositiveInfinity = []byte{0xf9, 0x7c, 0x00} - cborNegativeInfinity = []byte{0xf9, 0xfc, 0x00} -) - -func encode(e *encoderBuffer, em *encMode, v reflect.Value) error { +func encode(e *bytes.Buffer, em *encMode, v reflect.Value) error { if !v.IsValid() { // v is zero value e.Write(cborNil) @@ -733,7 +991,7 @@ func encode(e *encoderBuffer, em *encMode, v reflect.Value) error { return f(e, em, v) } -func encodeBool(e *encoderBuffer, em *encMode, v reflect.Value) error { +func encodeBool(e *bytes.Buffer, em *encMode, v reflect.Value) error { if b := em.encTagBytes(v.Type()); b != nil { e.Write(b) } @@ -745,7 +1003,7 @@ func encodeBool(e *encoderBuffer, em *encMode, v reflect.Value) error { return nil } -func encodeInt(e *encoderBuffer, em *encMode, v reflect.Value) error { +func encodeInt(e *bytes.Buffer, em *encMode, v reflect.Value) error { if b := em.encTagBytes(v.Type()); b != nil { e.Write(b) } @@ -759,7 +1017,7 @@ func encodeInt(e *encoderBuffer, em *encMode, v reflect.Value) error { return nil } -func encodeUint(e *encoderBuffer, em *encMode, v reflect.Value) error { +func encodeUint(e *bytes.Buffer, em *encMode, v reflect.Value) error { if b := em.encTagBytes(v.Type()); b != nil { e.Write(b) } @@ -767,7 +1025,7 @@ func encodeUint(e *encoderBuffer, em *encMode, v reflect.Value) error { return nil } -func encodeFloat(e *encoderBuffer, em *encMode, v reflect.Value) error { +func encodeFloat(e *bytes.Buffer, em *encMode, v reflect.Value) error { if b := em.encTagBytes(v.Type()); b != nil { e.Write(b) } @@ -782,9 +1040,12 @@ func encodeFloat(e *encoderBuffer, em *encMode, v reflect.Value) error { if v.Kind() == reflect.Float64 && (fopt == ShortestFloatNone || cannotFitFloat32(f64)) { // Encode float64 // Don't use encodeFloat64() because it cannot be inlined. - e.scratch[0] = byte(cborTypePrimitives) | byte(27) - binary.BigEndian.PutUint64(e.scratch[1:], math.Float64bits(f64)) - e.Write(e.scratch[:9]) + const argumentSize = 8 + const headSize = 1 + argumentSize + var scratch [headSize]byte + scratch[0] = byte(cborTypePrimitives) | byte(additionalInformationAsFloat64) + binary.BigEndian.PutUint64(scratch[1:], math.Float64bits(f64)) + e.Write(scratch[:]) return nil } @@ -805,24 +1066,34 @@ func encodeFloat(e *encoderBuffer, em *encMode, v reflect.Value) error { if p == float16.PrecisionExact { // Encode float16 // Don't use encodeFloat16() because it cannot be inlined. - e.scratch[0] = byte(cborTypePrimitives) | byte(25) - binary.BigEndian.PutUint16(e.scratch[1:], uint16(f16)) - e.Write(e.scratch[:3]) + const argumentSize = 2 + const headSize = 1 + argumentSize + var scratch [headSize]byte + scratch[0] = byte(cborTypePrimitives) | additionalInformationAsFloat16 + binary.BigEndian.PutUint16(scratch[1:], uint16(f16)) + e.Write(scratch[:]) return nil } } // Encode float32 // Don't use encodeFloat32() because it cannot be inlined. - e.scratch[0] = byte(cborTypePrimitives) | byte(26) - binary.BigEndian.PutUint32(e.scratch[1:], math.Float32bits(f32)) - e.Write(e.scratch[:5]) + const argumentSize = 4 + const headSize = 1 + argumentSize + var scratch [headSize]byte + scratch[0] = byte(cborTypePrimitives) | additionalInformationAsFloat32 + binary.BigEndian.PutUint32(scratch[1:], math.Float32bits(f32)) + e.Write(scratch[:]) return nil } -func encodeInf(e *encoderBuffer, em *encMode, v reflect.Value) error { +func encodeInf(e *bytes.Buffer, em *encMode, v reflect.Value) error { f64 := v.Float() - if em.infConvert == InfConvertFloat16 { + switch em.infConvert { + case InfConvertReject: + return &UnsupportedValueError{msg: "floating-point infinity"} + + case InfConvertFloat16: if f64 > 0 { e.Write(cborPositiveInfinity) } else { @@ -836,7 +1107,7 @@ func encodeInf(e *encoderBuffer, em *encMode, v reflect.Value) error { return encodeFloat32(e, float32(f64)) } -func encodeNaN(e *encoderBuffer, em *encMode, v reflect.Value) error { +func encodeNaN(e *bytes.Buffer, em *encMode, v reflect.Value) error { switch em.nanConvert { case NaNConvert7e00: e.Write(cborNaN) @@ -849,6 +1120,9 @@ func encodeNaN(e *encoderBuffer, em *encMode, v reflect.Value) error { f32 := float32NaNFromReflectValue(v) return encodeFloat32(e, f32) + case NaNConvertReject: + return &UnsupportedValueError{msg: "floating-point NaN"} + default: // NaNConvertPreserveSignal, NaNConvertQuiet if v.Kind() == reflect.Float64 { f64 := v.Float() @@ -894,33 +1168,45 @@ func encodeNaN(e *encoderBuffer, em *encMode, v reflect.Value) error { } } -func encodeFloat16(e *encoderBuffer, f16 float16.Float16) error { - e.scratch[0] = byte(cborTypePrimitives) | byte(25) - binary.BigEndian.PutUint16(e.scratch[1:], uint16(f16)) - e.Write(e.scratch[:3]) +func encodeFloat16(e *bytes.Buffer, f16 float16.Float16) error { + const argumentSize = 2 + const headSize = 1 + argumentSize + var scratch [headSize]byte + scratch[0] = byte(cborTypePrimitives) | additionalInformationAsFloat16 + binary.BigEndian.PutUint16(scratch[1:], uint16(f16)) + e.Write(scratch[:]) return nil } -func encodeFloat32(e *encoderBuffer, f32 float32) error { - e.scratch[0] = byte(cborTypePrimitives) | byte(26) - binary.BigEndian.PutUint32(e.scratch[1:], math.Float32bits(f32)) - e.Write(e.scratch[:5]) +func encodeFloat32(e *bytes.Buffer, f32 float32) error { + const argumentSize = 4 + const headSize = 1 + argumentSize + var scratch [headSize]byte + scratch[0] = byte(cborTypePrimitives) | additionalInformationAsFloat32 + binary.BigEndian.PutUint32(scratch[1:], math.Float32bits(f32)) + e.Write(scratch[:]) return nil } -func encodeFloat64(e *encoderBuffer, f64 float64) error { - e.scratch[0] = byte(cborTypePrimitives) | byte(27) - binary.BigEndian.PutUint64(e.scratch[1:], math.Float64bits(f64)) - e.Write(e.scratch[:9]) +func encodeFloat64(e *bytes.Buffer, f64 float64) error { + const argumentSize = 8 + const headSize = 1 + argumentSize + var scratch [headSize]byte + scratch[0] = byte(cborTypePrimitives) | additionalInformationAsFloat64 + binary.BigEndian.PutUint64(scratch[1:], math.Float64bits(f64)) + e.Write(scratch[:]) return nil } -func encodeByteString(e *encoderBuffer, em *encMode, v reflect.Value) error { +func encodeByteString(e *bytes.Buffer, em *encMode, v reflect.Value) error { vk := v.Kind() if vk == reflect.Slice && v.IsNil() && em.nilContainers == NilContainerAsNull { e.Write(cborNil) return nil } + if vk == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 && em.byteSliceLaterEncodingTag != 0 { + encodeHead(e, byte(cborTypeTag), em.byteSliceLaterEncodingTag) + } if b := em.encTagBytes(v.Type()); b != nil { e.Write(b) } @@ -939,7 +1225,7 @@ func encodeByteString(e *encoderBuffer, em *encMode, v reflect.Value) error { return nil } -func encodeString(e *encoderBuffer, em *encMode, v reflect.Value) error { +func encodeString(e *bytes.Buffer, em *encMode, v reflect.Value) error { if b := em.encTagBytes(v.Type()); b != nil { e.Write(b) } @@ -953,7 +1239,10 @@ type arrayEncodeFunc struct { f encodeFunc } -func (ae arrayEncodeFunc) encode(e *encoderBuffer, em *encMode, v reflect.Value) error { +func (ae arrayEncodeFunc) encode(e *bytes.Buffer, em *encMode, v reflect.Value) error { + if em.byteArray == ByteArrayToByteSlice && v.Type().Elem().Kind() == reflect.Uint8 { + return encodeByteString(e, em, v) + } if v.Kind() == reflect.Slice && v.IsNil() && em.nilContainers == NilContainerAsNull { e.Write(cborNil) return nil @@ -977,13 +1266,13 @@ func (ae arrayEncodeFunc) encode(e *encoderBuffer, em *encMode, v reflect.Value) // encodeKeyValueFunc encodes key/value pairs in map (v). // If kvs is provided (having the same length as v), length of encoded key and value are stored in kvs. // kvs is used for canonical encoding of map. -type encodeKeyValueFunc func(e *encoderBuffer, em *encMode, v reflect.Value, kvs []keyValue) error +type encodeKeyValueFunc func(e *bytes.Buffer, em *encMode, v reflect.Value, kvs []keyValue) error type mapEncodeFunc struct { e encodeKeyValueFunc } -func (me mapEncodeFunc) encode(e *encoderBuffer, em *encMode, v reflect.Value) error { +func (me mapEncodeFunc) encode(e *bytes.Buffer, em *encMode, v reflect.Value) error { if v.IsNil() && em.nilContainers == NilContainerAsNull { e.Write(cborNil) return nil @@ -995,21 +1284,58 @@ func (me mapEncodeFunc) encode(e *encoderBuffer, em *encMode, v reflect.Value) e if mlen == 0 { return e.WriteByte(byte(cborTypeMap)) } - if em.sort != SortNone { - return me.encodeCanonical(e, em, v) - } - encodeHead(e, byte(cborTypeMap), uint64(mlen)) - return me.e(e, em, v, nil) + encodeHead(e, byte(cborTypeMap), uint64(mlen)) + if em.sort == SortNone || em.sort == SortFastShuffle || mlen <= 1 { + return me.e(e, em, v, nil) + } + + kvsp := getKeyValues(v.Len()) // for sorting keys + defer putKeyValues(kvsp) + kvs := *kvsp + + kvBeginOffset := e.Len() + if err := me.e(e, em, v, kvs); err != nil { + return err + } + kvTotalLen := e.Len() - kvBeginOffset + + // Use the capacity at the tail of the encode buffer as a staging area to rearrange the + // encoded pairs into sorted order. + e.Grow(kvTotalLen) + tmp := e.Bytes()[e.Len() : e.Len()+kvTotalLen] // Can use e.AvailableBuffer() in Go 1.21+. + dst := e.Bytes()[kvBeginOffset:] + + if em.sort == SortBytewiseLexical { + sort.Sort(&bytewiseKeyValueSorter{kvs: kvs, data: dst}) + } else { + sort.Sort(&lengthFirstKeyValueSorter{kvs: kvs, data: dst}) + } + + // This is where the encoded bytes are actually rearranged in the output buffer to reflect + // the desired order. + sortedOffset := 0 + for _, kv := range kvs { + copy(tmp[sortedOffset:], dst[kv.offset:kv.nextOffset]) + sortedOffset += kv.nextOffset - kv.offset + } + copy(dst, tmp[:kvTotalLen]) + + return nil + } +// keyValue is the position of an encoded pair in a buffer. All offsets are zero-based and relative +// to the first byte of the first encoded pair. type keyValue struct { - keyCBORData, keyValueCBORData []byte - keyLen, keyValueLen int + offset int + valueOffset int + nextOffset int } type bytewiseKeyValueSorter struct { - kvs []keyValue + kvs []keyValue + data []byte } func (x *bytewiseKeyValueSorter) Len() int { @@ -1021,11 +1347,13 @@ func (x *bytewiseKeyValueSorter) Swap(i, j int) { } func (x *bytewiseKeyValueSorter) Less(i, j int) bool { - return bytes.Compare(x.kvs[i].keyCBORData, x.kvs[j].keyCBORData) <= 0 + kvi, kvj := x.kvs[i], x.kvs[j] + return bytes.Compare(x.data[kvi.offset:kvi.valueOffset], x.data[kvj.offset:kvj.valueOffset]) <= 0 } type lengthFirstKeyValueSorter struct { - kvs []keyValue + kvs []keyValue + data []byte } func (x *lengthFirstKeyValueSorter) Len() int { @@ -1037,10 +1365,11 @@ func (x *lengthFirstKeyValueSorter) Swap(i, j int) { } func (x *lengthFirstKeyValueSorter) Less(i, j int) bool { - if len(x.kvs[i].keyCBORData) != len(x.kvs[j].keyCBORData) { - return len(x.kvs[i].keyCBORData) < len(x.kvs[j].keyCBORData) + kvi, kvj := x.kvs[i], x.kvs[j] + if keyLengthDifference := (kvi.valueOffset - kvi.offset) - (kvj.valueOffset - kvj.offset); keyLengthDifference != 0 { + return keyLengthDifference < 0 } - return bytes.Compare(x.kvs[i].keyCBORData, x.kvs[j].keyCBORData) <= 0 + return bytes.Compare(x.data[kvi.offset:kvi.valueOffset], x.data[kvj.offset:kvj.valueOffset]) <= 0 } var keyValuePool = sync.Pool{} @@ -1068,42 +1397,7 @@ func putKeyValues(x *[]keyValue) { keyValuePool.Put(x) } -func (me mapEncodeFunc) encodeCanonical(e *encoderBuffer, em *encMode, v reflect.Value) error { - kve := getEncoderBuffer() // accumulated cbor encoded key-values - defer putEncoderBuffer(kve) - - kvsp := getKeyValues(v.Len()) // for sorting keys - defer putKeyValues(kvsp) - - kvs := *kvsp - - err := me.e(kve, em, v, kvs) - if err != nil { - return err - } - - b := kve.Bytes() - for i, off := 0, 0; i < len(kvs); i++ { - kvs[i].keyCBORData = b[off : off+kvs[i].keyLen] - kvs[i].keyValueCBORData = b[off : off+kvs[i].keyValueLen] - off += kvs[i].keyValueLen - } - - if em.sort == SortBytewiseLexical { - sort.Sort(&bytewiseKeyValueSorter{kvs}) - } else { - sort.Sort(&lengthFirstKeyValueSorter{kvs}) - } - - encodeHead(e, byte(cborTypeMap), uint64(len(kvs))) - for i := 0; i < len(kvs); i++ { - e.Write(kvs[i].keyValueCBORData) - } - - return nil -} - -func encodeStructToArray(e *encoderBuffer, em *encMode, v reflect.Value) (err error) { +func encodeStructToArray(e *bytes.Buffer, em *encMode, v reflect.Value) (err error) { structType, err := getEncodingStructType(v.Type()) if err != nil { return err @@ -1124,7 +1418,7 @@ func encodeStructToArray(e *encoderBuffer, em *encMode, v reflect.Value) (err er fv = v.Field(f.idx[0]) } else { // Get embedded field value. No error is expected. - fv, _ = getFieldValue(v, f.idx, func(v reflect.Value) (reflect.Value, error) { + fv, _ = getFieldValue(v, f.idx, func(reflect.Value) (reflect.Value, error) { // Write CBOR nil for null pointer to embedded struct e.Write(cborNil) return reflect.Value{}, nil @@ -1141,31 +1435,7 @@ func encodeStructToArray(e *encoderBuffer, em *encMode, v reflect.Value) (err er return nil } -func encodeFixedLengthStruct(e *encoderBuffer, em *encMode, v reflect.Value, flds fields) error { - if b := em.encTagBytes(v.Type()); b != nil { - e.Write(b) - } - - encodeHead(e, byte(cborTypeMap), uint64(len(flds))) - - for i := 0; i < len(flds); i++ { - f := flds[i] - if !f.keyAsInt && em.fieldName == FieldNameToByteString { - e.Write(f.cborNameByteString) - } else { // int or text string - e.Write(f.cborName) - } - - fv := v.Field(f.idx[0]) - if err := f.ef(e, em, fv); err != nil { - return err - } - } - - return nil -} - -func encodeStruct(e *encoderBuffer, em *encMode, v reflect.Value) (err error) { +func encodeStruct(e *bytes.Buffer, em *encMode, v reflect.Value) (err error) { structType, err := getEncodingStructType(v.Type()) if err != nil { return err @@ -1173,21 +1443,30 @@ func encodeStruct(e *encoderBuffer, em *encMode, v reflect.Value) (err error) { flds := structType.getFields(em) - if structType.fixedLength { - return encodeFixedLengthStruct(e, em, v, flds) + start := 0 + if em.sort == SortFastShuffle && len(flds) > 0 { + start = rand.Intn(len(flds)) //nolint:gosec // Don't need a CSPRNG for deck cutting. } - kve := getEncoderBuffer() // encode key-value pairs based on struct field tag options + if b := em.encTagBytes(v.Type()); b != nil { + e.Write(b) + } + + // Encode head with struct field count. + // Head is rewritten later if actual encoded field count is different from struct field count. + encodedHeadLen := encodeHead(e, byte(cborTypeMap), uint64(len(flds))) + + kvbegin := e.Len() kvcount := 0 - for i := 0; i < len(flds); i++ { - f := flds[i] + for offset := 0; offset < len(flds); offset++ { + f := flds[(start+offset)%len(flds)] var fv reflect.Value if len(f.idx) == 1 { fv = v.Field(f.idx[0]) } else { // Get embedded field value. No error is expected. - fv, _ = getFieldValue(v, f.idx, func(v reflect.Value) (reflect.Value, error) { + fv, _ = getFieldValue(v, f.idx, func(reflect.Value) (reflect.Value, error) { // Skip null pointer to embedded struct return reflect.Value{}, nil }) @@ -1198,7 +1477,6 @@ func encodeStruct(e *encoderBuffer, em *encMode, v reflect.Value) (err error) { if f.omitEmpty { empty, err := f.ief(em, fv) if err != nil { - putEncoderBuffer(kve) return err } if empty { @@ -1207,30 +1485,51 @@ func encodeStruct(e *encoderBuffer, em *encMode, v reflect.Value) (err error) { } if !f.keyAsInt && em.fieldName == FieldNameToByteString { - kve.Write(f.cborNameByteString) + e.Write(f.cborNameByteString) } else { // int or text string - kve.Write(f.cborName) + e.Write(f.cborName) } - if err := f.ef(kve, em, fv); err != nil { - putEncoderBuffer(kve) + if err := f.ef(e, em, fv); err != nil { return err } + kvcount++ } - if b := em.encTagBytes(v.Type()); b != nil { - e.Write(b) + if len(flds) == kvcount { + // Encoded element count in head is the same as actual element count. + return nil } - encodeHead(e, byte(cborTypeMap), uint64(kvcount)) - e.Write(kve.Bytes()) + // Overwrite the bytes that were reserved for the head before encoding the map entries. + var actualHeadLen int + { + headbuf := *bytes.NewBuffer(e.Bytes()[kvbegin-encodedHeadLen : kvbegin-encodedHeadLen : kvbegin]) + actualHeadLen = encodeHead(&headbuf, byte(cborTypeMap), uint64(kvcount)) + } - putEncoderBuffer(kve) + if actualHeadLen == encodedHeadLen { + // The bytes reserved for the encoded head were exactly the right size, so the + // encoded entries are already in their final positions. + return nil + } + + // We reserved more bytes than needed for the encoded head, based on the number of fields + // encoded. The encoded entries are offset to the right by the number of excess reserved + // bytes. Shift the entries left to remove the gap. + excessReservedBytes := encodedHeadLen - actualHeadLen + dst := e.Bytes()[kvbegin-excessReservedBytes : e.Len()-excessReservedBytes] + src := e.Bytes()[kvbegin:e.Len()] + copy(dst, src) + + // After shifting, the excess bytes are at the end of the output buffer and they are + // garbage. + e.Truncate(e.Len() - excessReservedBytes) return nil } -func encodeIntf(e *encoderBuffer, em *encMode, v reflect.Value) error { +func encodeIntf(e *bytes.Buffer, em *encMode, v reflect.Value) error { if v.IsNil() { e.Write(cborNil) return nil @@ -1238,7 +1537,7 @@ func encodeIntf(e *encoderBuffer, em *encMode, v reflect.Value) error { return encode(e, em, v.Elem()) } -func encodeTime(e *encoderBuffer, em *encMode, v reflect.Value) error { +func encodeTime(e *bytes.Buffer, em *encMode, v reflect.Value) error { t := v.Interface().(time.Time) if t.IsZero() { e.Write(cborNil) // Even if tag is required, encode as CBOR null. @@ -1255,10 +1554,12 @@ func encodeTime(e *encoderBuffer, em *encMode, v reflect.Value) error { case TimeUnix: secs := t.Unix() return encodeInt(e, em, reflect.ValueOf(secs)) + case TimeUnixMicro: t = t.UTC().Round(time.Microsecond) f := float64(t.UnixNano()) / 1e9 return encodeFloat(e, em, reflect.ValueOf(f)) + case TimeUnixDynamic: t = t.UTC().Round(time.Microsecond) secs, nsecs := t.Unix(), uint64(t.Nanosecond()) @@ -1267,16 +1568,22 @@ func encodeTime(e *encoderBuffer, em *encMode, v reflect.Value) error { } f := float64(secs) + float64(nsecs)/1e9 return encodeFloat(e, em, reflect.ValueOf(f)) + case TimeRFC3339: s := t.Format(time.RFC3339) return encodeString(e, em, reflect.ValueOf(s)) + default: // TimeRFC3339Nano s := t.Format(time.RFC3339Nano) return encodeString(e, em, reflect.ValueOf(s)) } } -func encodeBigInt(e *encoderBuffer, em *encMode, v reflect.Value) error { +func encodeBigInt(e *bytes.Buffer, em *encMode, v reflect.Value) error { + if em.bigIntConvert == BigIntConvertReject { + return &UnsupportedTypeError{Type: typeBigInt} + } + vbi := v.Interface().(big.Int) sign := vbi.Sign() bi := new(big.Int).SetBytes(vbi.Bytes()) // bi is absolute value of v @@ -1311,7 +1618,16 @@ func encodeBigInt(e *encoderBuffer, em *encMode, v reflect.Value) error { return nil } -func encodeBinaryMarshalerType(e *encoderBuffer, em *encMode, v reflect.Value) error { +type binaryMarshalerEncoder struct { + alternateEncode encodeFunc + alternateIsEmpty isEmptyFunc +} + +func (bme binaryMarshalerEncoder) encode(e *bytes.Buffer, em *encMode, v reflect.Value) error { + if em.binaryMarshaler != BinaryMarshalerByteString { + return bme.alternateEncode(e, em, v) + } + vt := v.Type() m, ok := v.Interface().(encoding.BinaryMarshaler) if !ok { @@ -1331,7 +1647,25 @@ func encodeBinaryMarshalerType(e *encoderBuffer, em *encMode, v reflect.Value) e return nil } -func encodeMarshalerType(e *encoderBuffer, em *encMode, v reflect.Value) error { +func (bme binaryMarshalerEncoder) isEmpty(em *encMode, v reflect.Value) (bool, error) { + if em.binaryMarshaler != BinaryMarshalerByteString { + return bme.alternateIsEmpty(em, v) + } + + m, ok := v.Interface().(encoding.BinaryMarshaler) + if !ok { + pv := reflect.New(v.Type()) + pv.Elem().Set(v) + m = pv.Interface().(encoding.BinaryMarshaler) + } + data, err := m.MarshalBinary() + if err != nil { + return false, err + } + return len(data) == 0, nil +} + +func encodeMarshalerType(e *bytes.Buffer, em *encMode, v reflect.Value) error { if em.tagsMd == TagsForbidden && v.Type() == typeRawTag { return errors.New("cbor: cannot encode cbor.RawTag when TagsMd is TagsForbidden") } @@ -1345,11 +1679,19 @@ func encodeMarshalerType(e *encoderBuffer, em *encMode, v reflect.Value) error { if err != nil { return err } + + // Verify returned CBOR data item from MarshalCBOR() is well-formed and passes tag validity for builtin tags 0-3. + d := decoder{data: data, dm: getMarshalerDecMode(em.indefLength, em.tagsMd)} + err = d.wellformed(false, true) + if err != nil { + return &MarshalerError{typ: v.Type(), err: err} + } + e.Write(data) return nil } -func encodeTag(e *encoderBuffer, em *encMode, v reflect.Value) error { +func encodeTag(e *bytes.Buffer, em *encMode, v reflect.Value) error { if em.tagsMd == TagsForbidden { return errors.New("cbor: cannot encode cbor.Tag when TagsMd is TagsForbidden") } @@ -1365,36 +1707,65 @@ func encodeTag(e *encoderBuffer, em *encMode, v reflect.Value) error { // Marshal tag number encodeHead(e, byte(cborTypeTag), t.Number) + vem := *em // shallow copy + + // For built-in tags, disable settings that may introduce tag validity errors when + // marshaling certain Content values. + switch t.Number { + case tagNumRFC3339Time: + vem.stringType = StringToTextString + vem.stringMajorType = cborTypeTextString + case tagNumUnsignedBignum, tagNumNegativeBignum: + vem.byteSliceLaterFormat = ByteSliceLaterFormatNone + vem.byteSliceLaterEncodingTag = 0 + } + // Marshal tag content - return encode(e, em, reflect.ValueOf(t.Content)) + return encode(e, &vem, reflect.ValueOf(t.Content)) } -func encodeHead(e *encoderBuffer, t byte, n uint64) { - if n <= 23 { +// encodeHead writes CBOR head of specified type t and returns number of bytes written. +func encodeHead(e *bytes.Buffer, t byte, n uint64) int { + if n <= maxAdditionalInformationWithoutArgument { + const headSize = 1 e.WriteByte(t | byte(n)) - return + return headSize } + if n <= math.MaxUint8 { - e.scratch[0] = t | byte(24) - e.scratch[1] = byte(n) - e.Write(e.scratch[:2]) - return + const headSize = 2 + scratch := [headSize]byte{ + t | byte(additionalInformationWith1ByteArgument), + byte(n), + } + e.Write(scratch[:]) + return headSize } + if n <= math.MaxUint16 { - e.scratch[0] = t | byte(25) - binary.BigEndian.PutUint16(e.scratch[1:], uint16(n)) - e.Write(e.scratch[:3]) - return + const headSize = 3 + var scratch [headSize]byte + scratch[0] = t | byte(additionalInformationWith2ByteArgument) + binary.BigEndian.PutUint16(scratch[1:], uint16(n)) + e.Write(scratch[:]) + return headSize } + if n <= math.MaxUint32 { - e.scratch[0] = t | byte(26) - binary.BigEndian.PutUint32(e.scratch[1:], uint32(n)) - e.Write(e.scratch[:5]) - return + const headSize = 5 + var scratch [headSize]byte + scratch[0] = t | byte(additionalInformationWith4ByteArgument) + binary.BigEndian.PutUint32(scratch[1:], uint32(n)) + e.Write(scratch[:]) + return headSize } - e.scratch[0] = t | byte(27) - binary.BigEndian.PutUint64(e.scratch[1:], n) - e.Write(e.scratch[:9]) + + const headSize = 9 + var scratch [headSize]byte + scratch[0] = t | byte(additionalInformationWith8ByteArgument) + binary.BigEndian.PutUint64(scratch[1:], n) + e.Write(scratch[:]) + return headSize } var ( @@ -1404,7 +1775,7 @@ var ( typeByteString = reflect.TypeOf(ByteString("")) ) -func getEncodeFuncInternal(t reflect.Type) (encodeFunc, isEmptyFunc) { +func getEncodeFuncInternal(t reflect.Type) (ef encodeFunc, ief isEmptyFunc) { k := t.Kind() if k == reflect.Ptr { return getEncodeIndirectValueFunc(t), isEmptyPtr @@ -1412,14 +1783,19 @@ func getEncodeFuncInternal(t reflect.Type) (encodeFunc, isEmptyFunc) { switch t { case typeSimpleValue: return encodeMarshalerType, isEmptyUint + case typeTag: return encodeTag, alwaysNotEmpty + case typeTime: return encodeTime, alwaysNotEmpty + case typeBigInt: return encodeBigInt, alwaysNotEmpty + case typeRawMessage: return encodeMarshalerType, isEmptySlice + case typeByteString: return encodeMarshalerType, isEmptyString } @@ -1427,34 +1803,52 @@ func getEncodeFuncInternal(t reflect.Type) (encodeFunc, isEmptyFunc) { return encodeMarshalerType, alwaysNotEmpty } if reflect.PtrTo(t).Implements(typeBinaryMarshaler) { - return encodeBinaryMarshalerType, isEmptyBinaryMarshaler + defer func() { + // capture encoding method used for modes that disable BinaryMarshaler + bme := binaryMarshalerEncoder{ + alternateEncode: ef, + alternateIsEmpty: ief, + } + ef = bme.encode + ief = bme.isEmpty + }() } switch k { case reflect.Bool: return encodeBool, isEmptyBool + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return encodeInt, isEmptyInt + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return encodeUint, isEmptyUint + case reflect.Float32, reflect.Float64: return encodeFloat, isEmptyFloat + case reflect.String: return encodeString, isEmptyString - case reflect.Slice, reflect.Array: + + case reflect.Slice: if t.Elem().Kind() == reflect.Uint8 { return encodeByteString, isEmptySlice } + fallthrough + + case reflect.Array: f, _ := getEncodeFunc(t.Elem()) if f == nil { return nil, nil } return arrayEncodeFunc{f: f}.encode, isEmptySlice + case reflect.Map: f := getEncodeMapFunc(t) if f == nil { return nil, nil } return f, isEmptyMap + case reflect.Struct: // Get struct's special field "_" tag options if f, ok := t.FieldByName("_"); ok { @@ -1466,6 +1860,7 @@ func getEncodeFuncInternal(t reflect.Type) (encodeFunc, isEmptyFunc) { } } return encodeStruct, isEmptyStruct + case reflect.Interface: return encodeIntf, isEmptyIntf } @@ -1480,7 +1875,7 @@ func getEncodeIndirectValueFunc(t reflect.Type) encodeFunc { if f == nil { return nil } - return func(e *encoderBuffer, em *encMode, v reflect.Value) error { + return func(e *bytes.Buffer, em *encMode, v reflect.Value) error { for v.Kind() == reflect.Ptr && !v.IsNil() { v = v.Elem() } @@ -1559,7 +1954,7 @@ func isEmptyStruct(em *encMode, v reflect.Value) (bool, error) { fv = v.Field(f.idx[0]) } else { // Get embedded field value. No error is expected. - fv, _ = getFieldValue(v, f.idx, func(v reflect.Value) (reflect.Value, error) { + fv, _ = getFieldValue(v, f.idx, func(reflect.Value) (reflect.Value, error) { // Skip null pointer to embedded struct return reflect.Value{}, nil }) @@ -1579,20 +1974,6 @@ func isEmptyStruct(em *encMode, v reflect.Value) (bool, error) { return true, nil } -func isEmptyBinaryMarshaler(_ *encMode, v reflect.Value) (bool, error) { - m, ok := v.Interface().(encoding.BinaryMarshaler) - if !ok { - pv := reflect.New(v.Type()) - pv.Elem().Set(v) - m = pv.Interface().(encoding.BinaryMarshaler) - } - data, err := m.MarshalBinary() - if err != nil { - return false, err - } - return len(data) == 0, nil -} - func cannotFitFloat32(f64 float64) bool { f32 := float32(f64) return float64(f32) != f64 diff --git a/vendor/github.com/fxamacker/cbor/v2/encode_map.go b/vendor/github.com/fxamacker/cbor/v2/encode_map.go index 9850dc0..8b4b4bb 100644 --- a/vendor/github.com/fxamacker/cbor/v2/encode_map.go +++ b/vendor/github.com/fxamacker/cbor/v2/encode_map.go @@ -6,6 +6,7 @@ package cbor import ( + "bytes" "reflect" "sync" ) @@ -15,8 +16,7 @@ type mapKeyValueEncodeFunc struct { kpool, vpool sync.Pool } -func (me *mapKeyValueEncodeFunc) encodeKeyValues(e *encoderBuffer, em *encMode, v reflect.Value, kvs []keyValue) error { - trackKeyValueLength := len(kvs) == v.Len() +func (me *mapKeyValueEncodeFunc) encodeKeyValues(e *bytes.Buffer, em *encMode, v reflect.Value, kvs []keyValue) error { iterk := me.kpool.Get().(*reflect.Value) defer func() { iterk.SetZero() @@ -27,24 +27,39 @@ func (me *mapKeyValueEncodeFunc) encodeKeyValues(e *encoderBuffer, em *encMode, iterv.SetZero() me.vpool.Put(iterv) }() - iter := v.MapRange() - for i := 0; iter.Next(); i++ { - off := e.Len() + + if kvs == nil { + for i, iter := 0, v.MapRange(); iter.Next(); i++ { + iterk.SetIterKey(iter) + iterv.SetIterValue(iter) + + if err := me.kf(e, em, *iterk); err != nil { + return err + } + if err := me.ef(e, em, *iterv); err != nil { + return err + } + } + return nil + } + + initial := e.Len() + for i, iter := 0, v.MapRange(); iter.Next(); i++ { iterk.SetIterKey(iter) iterv.SetIterValue(iter) + offset := e.Len() if err := me.kf(e, em, *iterk); err != nil { return err } - if trackKeyValueLength { - kvs[i].keyLen = e.Len() - off - } - + valueOffset := e.Len() if err := me.ef(e, em, *iterv); err != nil { return err } - if trackKeyValueLength { - kvs[i].keyValueLen = e.Len() - off + kvs[i] = keyValue{ + offset: offset - initial, + valueOffset: valueOffset - initial, + nextOffset: e.Len() - initial, } } diff --git a/vendor/github.com/fxamacker/cbor/v2/encode_map_go117.go b/vendor/github.com/fxamacker/cbor/v2/encode_map_go117.go index f942147..31c3933 100644 --- a/vendor/github.com/fxamacker/cbor/v2/encode_map_go117.go +++ b/vendor/github.com/fxamacker/cbor/v2/encode_map_go117.go @@ -6,6 +6,7 @@ package cbor import ( + "bytes" "reflect" ) @@ -13,25 +14,33 @@ type mapKeyValueEncodeFunc struct { kf, ef encodeFunc } -func (me *mapKeyValueEncodeFunc) encodeKeyValues(e *encoderBuffer, em *encMode, v reflect.Value, kvs []keyValue) error { - trackKeyValueLength := len(kvs) == v.Len() - - iter := v.MapRange() - for i := 0; iter.Next(); i++ { - off := e.Len() +func (me *mapKeyValueEncodeFunc) encodeKeyValues(e *bytes.Buffer, em *encMode, v reflect.Value, kvs []keyValue) error { + if kvs == nil { + for i, iter := 0, v.MapRange(); iter.Next(); i++ { + if err := me.kf(e, em, iter.Key()); err != nil { + return err + } + if err := me.ef(e, em, iter.Value()); err != nil { + return err + } + } + return nil + } + initial := e.Len() + for i, iter := 0, v.MapRange(); iter.Next(); i++ { + offset := e.Len() if err := me.kf(e, em, iter.Key()); err != nil { return err } - if trackKeyValueLength { - kvs[i].keyLen = e.Len() - off - } - + valueOffset := e.Len() if err := me.ef(e, em, iter.Value()); err != nil { return err } - if trackKeyValueLength { - kvs[i].keyValueLen = e.Len() - off + kvs[i] = keyValue{ + offset: offset - initial, + valueOffset: valueOffset - initial, + nextOffset: e.Len() - initial, } } diff --git a/vendor/github.com/fxamacker/cbor/v2/simplevalue.go b/vendor/github.com/fxamacker/cbor/v2/simplevalue.go index 6f93f67..de175ce 100644 --- a/vendor/github.com/fxamacker/cbor/v2/simplevalue.go +++ b/vendor/github.com/fxamacker/cbor/v2/simplevalue.go @@ -33,11 +33,11 @@ func (sv SimpleValue) MarshalCBOR() ([]byte, error) { // only has a single representation variant)." switch { - case sv <= 23: + case sv <= maxSimpleValueInAdditionalInformation: return []byte{byte(cborTypePrimitives) | byte(sv)}, nil - case sv >= 32: - return []byte{byte(cborTypePrimitives) | byte(24), byte(sv)}, nil + case sv >= minSimpleValueIn1ByteArgument: + return []byte{byte(cborTypePrimitives) | additionalInformationWith1ByteArgument, byte(sv)}, nil default: return nil, &UnsupportedValueError{msg: fmt.Sprintf("SimpleValue(%d)", sv)} @@ -57,7 +57,7 @@ func (sv *SimpleValue) UnmarshalCBOR(data []byte) error { if typ != cborTypePrimitives { return &UnmarshalTypeError{CBORType: typ.String(), GoType: "SimpleValue"} } - if ai > 24 { + if ai > additionalInformationWith1ByteArgument { return &UnmarshalTypeError{CBORType: typ.String(), GoType: "SimpleValue", errorMsg: "not simple values"} } diff --git a/vendor/github.com/fxamacker/cbor/v2/stream.go b/vendor/github.com/fxamacker/cbor/v2/stream.go index 02fea43..507ab6c 100644 --- a/vendor/github.com/fxamacker/cbor/v2/stream.go +++ b/vendor/github.com/fxamacker/cbor/v2/stream.go @@ -84,7 +84,7 @@ func (dec *Decoder) readNext() (int, error) { if dec.off < len(dec.buf) { dec.d.reset(dec.buf[dec.off:]) off := dec.off // Save offset before data validation - validErr = dec.d.wellformed(true) + validErr = dec.d.wellformed(true, false) dec.off = off // Restore offset if validErr == nil { @@ -187,14 +187,14 @@ func (enc *Encoder) Encode(v interface{}) error { } } - buf := getEncoderBuffer() + buf := getEncodeBuffer() err := encode(buf, enc.em, reflect.ValueOf(v)) if err == nil { _, err = enc.w.Write(buf.Bytes()) } - putEncoderBuffer(buf) + putEncodeBuffer(buf) return err } @@ -231,7 +231,7 @@ func (enc *Encoder) EndIndefinite() error { if len(enc.indefTypes) == 0 { return errors.New("cbor: cannot encode \"break\" code outside indefinite length values") } - _, err := enc.w.Write([]byte{0xff}) + _, err := enc.w.Write([]byte{cborBreakFlag}) if err == nil { enc.indefTypes = enc.indefTypes[:len(enc.indefTypes)-1] } @@ -239,10 +239,10 @@ func (enc *Encoder) EndIndefinite() error { } var cborIndefHeader = map[cborType][]byte{ - cborTypeByteString: {0x5f}, - cborTypeTextString: {0x7f}, - cborTypeArray: {0x9f}, - cborTypeMap: {0xbf}, + cborTypeByteString: {cborByteStringWithIndefiniteLengthHead}, + cborTypeTextString: {cborTextStringWithIndefiniteLengthHead}, + cborTypeArray: {cborArrayWithIndefiniteLengthHead}, + cborTypeMap: {cborMapWithIndefiniteLengthHead}, } func (enc *Encoder) startIndefinite(typ cborType) error { diff --git a/vendor/github.com/fxamacker/cbor/v2/structfields.go b/vendor/github.com/fxamacker/cbor/v2/structfields.go index 23a12be..81228ac 100644 --- a/vendor/github.com/fxamacker/cbor/v2/structfields.go +++ b/vendor/github.com/fxamacker/cbor/v2/structfields.go @@ -144,7 +144,15 @@ func getFields(t reflect.Type) (flds fields, structOptions string) { } // appendFields appends type t's exportable fields to flds and anonymous struct fields to nTypes . -func appendFields(t reflect.Type, idx []int, flds fields, nTypes map[reflect.Type][][]int) (fields, map[reflect.Type][][]int) { +func appendFields( + t reflect.Type, + idx []int, + flds fields, + nTypes map[reflect.Type][][]int, +) ( + _flds fields, + _nTypes map[reflect.Type][][]int, +) { for i := 0; i < t.NumField(); i++ { f := t.Field(i) @@ -165,12 +173,12 @@ func appendFields(t reflect.Type, idx []int, flds fields, nTypes map[reflect.Typ continue } - tagged := len(tag) > 0 + tagged := tag != "" // Parse field tag options var tagFieldName string var omitempty, keyasint bool - for j := 0; len(tag) > 0; j++ { + for j := 0; tag != ""; j++ { var token string idx := strings.IndexByte(tag, ',') if idx == -1 { @@ -199,7 +207,7 @@ func appendFields(t reflect.Type, idx []int, flds fields, nTypes map[reflect.Typ copy(fIdx, idx) fIdx[len(fIdx)-1] = i - if !f.Anonymous || ft.Kind() != reflect.Struct || len(tagFieldName) > 0 { + if !f.Anonymous || ft.Kind() != reflect.Struct || tagFieldName != "" { flds = append(flds, &field{ name: fieldName, idx: fIdx, @@ -221,7 +229,7 @@ func appendFields(t reflect.Type, idx []int, flds fields, nTypes map[reflect.Typ // isFieldExportable returns true if f is an exportable (regular or anonymous) field or // a nonexportable anonymous field of struct type. // Nonexportable anonymous field of struct type can contain exportable fields. -func isFieldExportable(f reflect.StructField, fk reflect.Kind) bool { +func isFieldExportable(f reflect.StructField, fk reflect.Kind) bool { //nolint:gocritic // ignore hugeParam exportable := f.PkgPath == "" return exportable || (f.Anonymous && fk == reflect.Struct) } diff --git a/vendor/github.com/fxamacker/cbor/v2/tag.go b/vendor/github.com/fxamacker/cbor/v2/tag.go index aefb4d3..5c4d2b7 100644 --- a/vendor/github.com/fxamacker/cbor/v2/tag.go +++ b/vendor/github.com/fxamacker/cbor/v2/tag.go @@ -7,7 +7,9 @@ import ( "sync" ) -// Tag represents CBOR tag data, including tag number and unmarshaled tag content. +// Tag represents CBOR tag data, including tag number and unmarshaled tag content. Marshaling and +// unmarshaling of tag content is subject to any encode and decode options that would apply to +// enclosed data item if it were to appear outside of a tag. type Tag struct { Number uint64 Content interface{} @@ -56,7 +58,7 @@ func (t RawTag) MarshalCBOR() ([]byte, error) { return b, nil } - e := getEncoderBuffer() + e := getEncodeBuffer() encodeHead(e, byte(cborTypeTag), t.Number) @@ -69,7 +71,7 @@ func (t RawTag) MarshalCBOR() ([]byte, error) { n := copy(buf, e.Bytes()) copy(buf[n:], content) - putEncoderBuffer(e) + putEncodeBuffer(e) return buf, nil } @@ -261,7 +263,7 @@ func newTagItem(opts TagOptions, contentType reflect.Type, num uint64, nestedNum if num == 2 || num == 3 { return nil, errors.New("cbor: cannot add tag number 2 or 3 to TagSet, it's built-in and supported automatically") } - if num == selfDescribedCBORTagNum { + if num == tagNumSelfDescribedCBOR { return nil, errors.New("cbor: cannot add tag number 55799 to TagSet, it's built-in and ignored automatically") } @@ -269,13 +271,13 @@ func newTagItem(opts TagOptions, contentType reflect.Type, num uint64, nestedNum te.num = append(te.num, nestedNum...) // Cache encoded tag numbers - e := getEncoderBuffer() + e := getEncodeBuffer() for _, n := range te.num { encodeHead(e, byte(cborTypeTag), n) } te.cborTagNum = make([]byte, e.Len()) copy(te.cborTagNum, e.Bytes()) - putEncoderBuffer(e) + putEncodeBuffer(e) return &te, nil } diff --git a/vendor/github.com/fxamacker/cbor/v2/valid.go b/vendor/github.com/fxamacker/cbor/v2/valid.go index a5213d0..b40793b 100644 --- a/vendor/github.com/fxamacker/cbor/v2/valid.go +++ b/vendor/github.com/fxamacker/cbor/v2/valid.go @@ -7,7 +7,10 @@ import ( "encoding/binary" "errors" "io" + "math" "strconv" + + "github.com/x448/float16" ) // SyntaxError is a description of a CBOR syntax error. @@ -82,11 +85,11 @@ func (e *ExtraneousDataError) Error() string { // allowExtraData indicates if extraneous data is allowed after the CBOR data item. // - use allowExtraData = true when using Decoder.Decode() // - use allowExtraData = false when using Unmarshal() -func (d *decoder) wellformed(allowExtraData bool) error { +func (d *decoder) wellformed(allowExtraData bool, checkBuiltinTags bool) error { if len(d.data) == d.off { return io.EOF } - _, err := d.wellformedInternal(0) + _, err := d.wellformedInternal(0, checkBuiltinTags) if err == nil { if !allowExtraData && d.off != len(d.data) { err = &ExtraneousDataError{len(d.data) - d.off, d.off} @@ -96,19 +99,19 @@ func (d *decoder) wellformed(allowExtraData bool) error { } // wellformedInternal checks data's well-formedness and returns max depth and error. -func (d *decoder) wellformedInternal(depth int) (int, error) { - t, ai, val, err := d.wellformedHead() +func (d *decoder) wellformedInternal(depth int, checkBuiltinTags bool) (int, error) { //nolint:gocyclo + t, _, val, indefiniteLength, err := d.wellformedHeadWithIndefiniteLengthFlag() if err != nil { return 0, err } switch t { case cborTypeByteString, cborTypeTextString: - if ai == 31 { + if indefiniteLength { if d.dm.indefLength == IndefLengthForbidden { return 0, &IndefiniteLengthError{t} } - return d.wellformedIndefiniteString(t, depth) + return d.wellformedIndefiniteString(t, depth, checkBuiltinTags) } valInt := int(val) if valInt < 0 { @@ -119,17 +122,18 @@ func (d *decoder) wellformedInternal(depth int) (int, error) { return 0, io.ErrUnexpectedEOF } d.off += valInt + case cborTypeArray, cborTypeMap: depth++ if depth > d.dm.maxNestedLevels { return 0, &MaxNestedLevelError{d.dm.maxNestedLevels} } - if ai == 31 { + if indefiniteLength { if d.dm.indefLength == IndefLengthForbidden { return 0, &IndefiniteLengthError{t} } - return d.wellformedIndefiniteArrayOrMap(t, depth) + return d.wellformedIndefiniteArrayOrMap(t, depth, checkBuiltinTags) } valInt := int(val) @@ -156,7 +160,7 @@ func (d *decoder) wellformedInternal(depth int) (int, error) { for j := 0; j < count; j++ { for i := 0; i < valInt; i++ { var dpt int - if dpt, err = d.wellformedInternal(depth); err != nil { + if dpt, err = d.wellformedInternal(depth, checkBuiltinTags); err != nil { return 0, err } if dpt > maxDepth { @@ -165,20 +169,35 @@ func (d *decoder) wellformedInternal(depth int) (int, error) { } } depth = maxDepth + case cborTypeTag: if d.dm.tagsMd == TagsForbidden { return 0, &TagsMdError{} } + tagNum := val + // Scan nested tag numbers to avoid recursion. for { if len(d.data) == d.off { // Tag number must be followed by tag content. return 0, io.ErrUnexpectedEOF } - if cborType(d.data[d.off]&0xe0) != cborTypeTag { + if checkBuiltinTags { + err = validBuiltinTag(tagNum, d.data[d.off]) + if err != nil { + return 0, err + } + } + if d.dm.bignumTag == BignumTagForbidden && (tagNum == 2 || tagNum == 3) { + return 0, &UnacceptableDataItemError{ + CBORType: cborTypeTag.String(), + Message: "bignum", + } + } + if getType(d.data[d.off]) != cborTypeTag { break } - if _, _, _, err = d.wellformedHead(); err != nil { + if _, _, tagNum, err = d.wellformedHead(); err != nil { return 0, err } depth++ @@ -187,31 +206,32 @@ func (d *decoder) wellformedInternal(depth int) (int, error) { } } // Check tag content. - return d.wellformedInternal(depth) + return d.wellformedInternal(depth, checkBuiltinTags) } + return depth, nil } // wellformedIndefiniteString checks indefinite length byte/text string's well-formedness and returns max depth and error. -func (d *decoder) wellformedIndefiniteString(t cborType, depth int) (int, error) { +func (d *decoder) wellformedIndefiniteString(t cborType, depth int, checkBuiltinTags bool) (int, error) { var err error for { if len(d.data) == d.off { return 0, io.ErrUnexpectedEOF } - if d.data[d.off] == 0xff { + if isBreakFlag(d.data[d.off]) { d.off++ break } // Peek ahead to get next type and indefinite length status. - nt := cborType(d.data[d.off] & 0xe0) + nt, ai := parseInitialByte(d.data[d.off]) if t != nt { return 0, &SyntaxError{"cbor: wrong element type " + nt.String() + " for indefinite-length " + t.String()} } - if (d.data[d.off] & 0x1f) == 31 { + if additionalInformation(ai).isIndefiniteLength() { return 0, &SyntaxError{"cbor: indefinite-length " + t.String() + " chunk is not definite-length"} } - if depth, err = d.wellformedInternal(depth); err != nil { + if depth, err = d.wellformedInternal(depth, checkBuiltinTags); err != nil { return 0, err } } @@ -219,7 +239,7 @@ func (d *decoder) wellformedIndefiniteString(t cborType, depth int) (int, error) } // wellformedIndefiniteArrayOrMap checks indefinite length array/map's well-formedness and returns max depth and error. -func (d *decoder) wellformedIndefiniteArrayOrMap(t cborType, depth int) (int, error) { +func (d *decoder) wellformedIndefiniteArrayOrMap(t cborType, depth int, checkBuiltinTags bool) (int, error) { var err error maxDepth := depth i := 0 @@ -227,12 +247,12 @@ func (d *decoder) wellformedIndefiniteArrayOrMap(t cborType, depth int) (int, er if len(d.data) == d.off { return 0, io.ErrUnexpectedEOF } - if d.data[d.off] == 0xff { + if isBreakFlag(d.data[d.off]) { d.off++ break } var dpt int - if dpt, err = d.wellformedInternal(depth); err != nil { + if dpt, err = d.wellformedInternal(depth, checkBuiltinTags); err != nil { return 0, err } if dpt > maxDepth { @@ -255,22 +275,39 @@ func (d *decoder) wellformedIndefiniteArrayOrMap(t cborType, depth int) (int, er return maxDepth, nil } +func (d *decoder) wellformedHeadWithIndefiniteLengthFlag() ( + t cborType, + ai byte, + val uint64, + indefiniteLength bool, + err error, +) { + t, ai, val, err = d.wellformedHead() + if err != nil { + return + } + indefiniteLength = additionalInformation(ai).isIndefiniteLength() + return +} + func (d *decoder) wellformedHead() (t cborType, ai byte, val uint64, err error) { dataLen := len(d.data) - d.off if dataLen == 0 { return 0, 0, 0, io.ErrUnexpectedEOF } - t = cborType(d.data[d.off] & 0xe0) - ai = d.data[d.off] & 0x1f + t, ai = parseInitialByte(d.data[d.off]) val = uint64(ai) d.off++ + dataLen-- - if ai < 24 { + if ai <= maxAdditionalInformationWithoutArgument { return t, ai, val, nil } - if ai == 24 { - if dataLen < 2 { + + if ai == additionalInformationWith1ByteArgument { + const argumentSize = 1 + if dataLen < argumentSize { return 0, 0, 0, io.ErrUnexpectedEOF } val = uint64(d.data[d.off]) @@ -280,31 +317,53 @@ func (d *decoder) wellformedHead() (t cborType, ai byte, val uint64, err error) } return t, ai, val, nil } - if ai == 25 { - if dataLen < 3 { + + if ai == additionalInformationWith2ByteArgument { + const argumentSize = 2 + if dataLen < argumentSize { return 0, 0, 0, io.ErrUnexpectedEOF } - val = uint64(binary.BigEndian.Uint16(d.data[d.off : d.off+2])) - d.off += 2 + val = uint64(binary.BigEndian.Uint16(d.data[d.off : d.off+argumentSize])) + d.off += argumentSize + if t == cborTypePrimitives { + if err := d.acceptableFloat(float64(float16.Frombits(uint16(val)).Float32())); err != nil { + return 0, 0, 0, err + } + } return t, ai, val, nil } - if ai == 26 { - if dataLen < 5 { + + if ai == additionalInformationWith4ByteArgument { + const argumentSize = 4 + if dataLen < argumentSize { return 0, 0, 0, io.ErrUnexpectedEOF } - val = uint64(binary.BigEndian.Uint32(d.data[d.off : d.off+4])) - d.off += 4 + val = uint64(binary.BigEndian.Uint32(d.data[d.off : d.off+argumentSize])) + d.off += argumentSize + if t == cborTypePrimitives { + if err := d.acceptableFloat(float64(math.Float32frombits(uint32(val)))); err != nil { + return 0, 0, 0, err + } + } return t, ai, val, nil } - if ai == 27 { - if dataLen < 9 { + + if ai == additionalInformationWith8ByteArgument { + const argumentSize = 8 + if dataLen < argumentSize { return 0, 0, 0, io.ErrUnexpectedEOF } - val = binary.BigEndian.Uint64(d.data[d.off : d.off+8]) - d.off += 8 + val = binary.BigEndian.Uint64(d.data[d.off : d.off+argumentSize]) + d.off += argumentSize + if t == cborTypePrimitives { + if err := d.acceptableFloat(math.Float64frombits(val)); err != nil { + return 0, 0, 0, err + } + } return t, ai, val, nil } - if ai == 31 { + + if additionalInformation(ai).isIndefiniteLength() { switch t { case cborTypePositiveInt, cborTypeNegativeInt, cborTypeTag: return 0, 0, 0, &SyntaxError{"cbor: invalid additional information " + strconv.Itoa(int(ai)) + " for type " + t.String()} @@ -313,6 +372,23 @@ func (d *decoder) wellformedHead() (t cborType, ai byte, val uint64, err error) } return t, ai, val, nil } + // ai == 28, 29, 30 return 0, 0, 0, &SyntaxError{"cbor: invalid additional information " + strconv.Itoa(int(ai)) + " for type " + t.String()} } + +func (d *decoder) acceptableFloat(f float64) error { + switch { + case d.dm.nanDec == NaNDecodeForbidden && math.IsNaN(f): + return &UnacceptableDataItemError{ + CBORType: cborTypePrimitives.String(), + Message: "floating-point NaN", + } + case d.dm.infDec == InfDecodeForbidden && math.IsInf(f, 0): + return &UnacceptableDataItemError{ + CBORType: cborTypePrimitives.String(), + Message: "floating-point infinity", + } + } + return nil +} diff --git a/vendor/github.com/gaissmai/bart/.gitignore b/vendor/github.com/gaissmai/bart/.gitignore new file mode 100644 index 0000000..0bcd7ad --- /dev/null +++ b/vendor/github.com/gaissmai/bart/.gitignore @@ -0,0 +1,27 @@ +# Allowlisting gitignore template for GO projects prevents us +# from adding various unwanted local files, such as generated +# files, developer configurations or IDE-specific files etc. +# +# Recommended: Go.AllowList.gitignore + +# Ignore everything +* + +# But not these files... +!/.gitignore + +!*.yml +!*.yaml + +!*.go +!go.sum +!go.mod + +!*.md +!LICENSE* + +# ...even if they are in subdirectories +!*/ + +!doc/* +!testdata/* diff --git a/vendor/github.com/gaissmai/bart/.golangci.yml b/vendor/github.com/gaissmai/bart/.golangci.yml new file mode 100644 index 0000000..487db91 --- /dev/null +++ b/vendor/github.com/gaissmai/bart/.golangci.yml @@ -0,0 +1,34 @@ +linters: + enable: + - gofmt + - gofumpt + - goimports + - govet + - gosimple + - gocyclo + - gosmopolitan + - errcheck + - staticcheck + - intrange + - ineffassign + - unused + - typecheck + - unconvert + - unparam + - misspell + - decorder + - errorlint + - predeclared + - reassign + - stylecheck + - usestdlibvars + - wastedassign + - nakedret + # + # - gosec + # - dupl + # - wrapcheck + +linters-settings: + gocyclo: + min-complexity: 30 diff --git a/vendor/github.com/gaissmai/bart/README.md b/vendor/github.com/gaissmai/bart/README.md index 6506cad..ecc62eb 100644 --- a/vendor/github.com/gaissmai/bart/README.md +++ b/vendor/github.com/gaissmai/bart/README.md @@ -1,38 +1,88 @@ # package bart -[![Go Reference](https://pkg.go.dev/badge/github.com/gaissmai/bart.svg)](https://pkg.go.dev/github.com/gaissmai/bart#section-documentation) ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/gaissmai/bart) +[![Go Reference](https://pkg.go.dev/badge/github.com/gaissmai/bart.svg)](https://pkg.go.dev/github.com/gaissmai/bart#section-documentation) +[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge-flat.svg)](https://github.com/avelino/awesome-go) [![CI](https://github.com/gaissmai/bart/actions/workflows/go.yml/badge.svg)](https://github.com/gaissmai/bart/actions/workflows/go.yml) [![Coverage Status](https://coveralls.io/repos/github/gaissmai/bart/badge.svg)](https://coveralls.io/github/gaissmai/bart) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Go Report Card](https://goreportcard.com/badge/github.com/gaissmai/bart)](https://goreportcard.com/report/github.com/gaissmai/bart) +[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua) ## Overview `package bart` provides a Balanced-Routing-Table (BART). -BART is balanced in terms of memory consumption versus -lookup time. - -The lookup time is by a factor of ~2 slower on average as the -routing algorithms ART, SMART, CPE, ... but reduces the memory -consumption by an order of magnitude in comparison. +BART is balanced in terms of memory usage and lookup time +for the longest-prefix match. BART is a multibit-trie with fixed stride length of 8 bits, using the _baseIndex_ function from the ART algorithm to build the complete-binary-tree (CBT) of prefixes for each stride. -The second key factor is popcount array compression at each stride level -of the CBT prefix tree and backtracking along the CBT in O(k). - -The CBT is implemented as a bitvector, backtracking is just +The CBT is implemented as a bit-vector, backtracking is just a matter of fast cache friendly bitmask operations. -The child array at each stride level is also popcount compressed. +The Table is implemented with popcount compressed sparse arrays +together with path compression. This reduces storage consumption +by almost two orders of magnitude in comparison to ART with +comparable or even better lookup times for longest prefix match. +The algorithm is also excellent for determining whether two tables +contain overlapping IP addresses. + +## Example + +```golang +func ExampleTable_Contains() { + // Create a new routing table + table := new(bart.Table[struct{}]) + + // Insert some prefixes + prefixes := []string{ + "192.168.0.0/16", // corporate + "192.168.1.0/24", // department + "2001:7c0:3100::/40", // corporate + "2001:7c0:3100:1::/64", // department + "fc00::/7", // unique local + } + + for _, s := range prefixes { + pfx := netip.MustParsePrefix(s) + table.Insert(pfx, struct{}{}) + } + + // Test some IP addresses for black/whitelist containment + ips := []string{ + "192.168.1.100", // must match, department + "192.168.2.1", // must match, corporate + "2001:7c0:3100:1::1", // must match, department + "2001:7c0:3100:2::1", // must match, corporate + "fc00::1", // must match, unique local + // + "172.16.0.1", // must NOT match + "2003:dead:beef::1", // must NOT match + } + + for _, s := range ips { + ip := netip.MustParseAddr(s) + fmt.Printf("%-20s is contained: %t\n", ip, table.Contains(ip)) + } + + // Output: + // 192.168.1.100 is contained: true + // 192.168.2.1 is contained: true + // 2001:7c0:3100:1::1 is contained: true + // 2001:7c0:3100:2::1 is contained: true + // fc00::1 is contained: true + // 172.16.0.1 is contained: false + // 2003:dead:beef::1 is contained: false +} +``` ## API -The API changes in v0.4.2, 0.5.3, v0.6.3, v0.10.1, v0.11.0 +Release v0.18 requires at least go1.23 and we use the `iter.Seq2[netip.Prefix, V]` types for iterators. +The lock-free versions of insert, update and delete are added, but still experimentell. ```golang import "github.com/gaissmai/bart" @@ -44,41 +94,53 @@ The API changes in v0.4.2, 0.5.3, v0.6.3, v0.10.1, v0.11.0 ready to use. The Table is safe for concurrent readers but not for concurrent readers - and/or writers. + and/or writers. Either the update operations must be protected by an + external lock mechanism or the various ...Persist functions must be used + which return a modified routing table by leaving the original unchanged + + A Table must not be copied by value, see Table.Clone. func (t *Table[V]) Insert(pfx netip.Prefix, val V) func (t *Table[V]) Delete(pfx netip.Prefix) - func (t *Table[V]) Get(pfx netip.Prefix) (val V, ok bool) func (t *Table[V]) Update(pfx netip.Prefix, cb func(val V, ok bool) V) (newVal V) + func (t *Table[V]) InsertPersist(pfx netip.Prefix, val V) *Table[V] + func (t *Table[V]) DeletePersist(pfx netip.Prefix) *Table[V] + func (t *Table[V]) UpdatePersist(pfx netip.Prefix, cb func(val V, ok bool) V) (pt *Table[V], newVal V) + + func (t *Table[V]) Get(pfx netip.Prefix) (val V, ok bool) + func (t *Table[V]) GetAndDelete(pfx netip.Prefix) (val V, ok bool) + func (t *Table[V]) GetAndDeletePersist(pfx netip.Prefix) (pt *Table[V], val V, ok bool) + func (t *Table[V]) Union(o *Table[V]) func (t *Table[V]) Clone() *Table[V] + func (t *Table[V]) Contains(ip netip.Addr) bool func (t *Table[V]) Lookup(ip netip.Addr) (val V, ok bool) - func (t *Table[V]) LookupPrefix(pfx netip.Prefix) (val V, ok bool) func (t *Table[V]) LookupPrefixLPM(pfx netip.Prefix) (lpm netip.Prefix, val V, ok bool) - func (t *Table[V]) EachLookupPrefix(pfx netip.Prefix, yield func(pfx netip.Prefix, val V) bool) - func (t *Table[V]) EachSubnet(pfx netip.Prefix, yield func(pfx netip.Prefix, val V) bool) func (t *Table[V]) OverlapsPrefix(pfx netip.Prefix) bool - func (t *Table[V]) Overlaps(o *Table[V]) bool + func (t *Table[V]) Overlaps(o *Table[V]) bool func (t *Table[V]) Overlaps4(o *Table[V]) bool func (t *Table[V]) Overlaps6(o *Table[V]) bool + func (t *Table[V]) Subnets(pfx netip.Prefix) iter.Seq2[netip.Prefix, V] + func (t *Table[V]) Supernets(pfx netip.Prefix) iter.Seq2[netip.Prefix, V] + + func (t *Table[V]) All() iter.Seq2[netip.Prefix, V] + func (t *Table[V]) All4() iter.Seq2[netip.Prefix, V] + func (t *Table[V]) All6() iter.Seq2[netip.Prefix, V] + + func (t *Table[V]) AllSorted() iter.Seq2[netip.Prefix, V] + func (t *Table[V]) AllSorted4() iter.Seq2[netip.Prefix, V] + func (t *Table[V]) AllSorted6() iter.Seq2[netip.Prefix, V] + func (t *Table[V]) Size() int func (t *Table[V]) Size4() int func (t *Table[V]) Size6() int - func (t *Table[V]) All(yield func(pfx netip.Prefix, val V) bool) - func (t *Table[V]) All4(yield func(pfx netip.Prefix, val V) bool) - func (t *Table[V]) All6(yield func(pfx netip.Prefix, val V) bool) - - func (t *Table[V]) AllSorted(yield func(pfx netip.Prefix, val V) bool) - func (t *Table[V]) All4Sorted(yield func(pfx netip.Prefix, val V) bool) - func (t *Table[V]) All6Sorted(yield func(pfx netip.Prefix, val V) bool) - func (t *Table[V]) String() string func (t *Table[V]) Fprint(w io.Writer) error func (t *Table[V]) MarshalText() ([]byte, error) @@ -92,31 +154,56 @@ The API changes in v0.4.2, 0.5.3, v0.6.3, v0.10.1, v0.11.0 Please see the extensive [benchmarks](https://github.com/gaissmai/iprbench) comparing `bart` with other IP routing table implementations. -Just a teaser, LPM lookups against the full Internet routing table with random probes: +Just a teaser, Contains and Lookups against the full Internet routing table with random IP address probes: ``` goos: linux goarch: amd64 pkg: github.com/gaissmai/bart cpu: Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz +BenchmarkFullMatchV4/Contains 55906228 21.39 ns/op 0 B/op 0 allocs/op +BenchmarkFullMatchV6/Contains 100000000 11.38 ns/op 0 B/op 0 allocs/op +BenchmarkFullMissV4/Contains 52927538 22.69 ns/op 0 B/op 0 allocs/op +BenchmarkFullMissV6/Contains 250386540 4.883 ns/op 0 B/op 0 allocs/op +PASS +ok github.com/gaissmai/bart 11.291s -BenchmarkFullMatchV4/Lookup 24484828 49.03 ns/op -BenchmarkFullMatchV6/Lookup 17098262 70.15 ns/op -BenchmarkFullMissV4/Lookup 24480925 49.15 ns/op -BenchmarkFullMissV6/Lookup 54955310 21.79 ns/op +goos: linux +goarch: amd64 +pkg: github.com/gaissmai/bart +cpu: Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz +BenchmarkFullMatchV4/Lookup 53578766 21.77 ns/op 0 B/op 0 allocs/op +BenchmarkFullMatchV6/Lookup 57054618 21.07 ns/op 0 B/op 0 allocs/op +BenchmarkFullMissV4/Lookup 48289306 25.60 ns/op 0 B/op 0 allocs/op +BenchmarkFullMissV6/Lookup 142917571 8.387 ns/op 0 B/op 0 allocs/op +PASS +ok github.com/gaissmai/bart 10.455s ``` +## Compatibility Guarantees + +The package is currently released as a pre-v1 version, which gives the author the freedom to break +backward compatibility to help improve the API as he learns which initial design decisions would need +to be revisited to better support the use cases that the library solves for. + +These occurrences are expected to be rare in frequency and the API is already quite stable. + ## CONTRIBUTION Please open an issue for discussion before sending a pull request. ## CREDIT -Credits for many inspirations go to the clever guys at tailscale, -to Daniel Lemire for the super-fast bitset package and -to Donald E. Knuth for the **ART** routing algorithm and -all the rest of his *Art* and for keeping important algorithms -in the public domain! +Standing on the shoulders of giants. + +Credits for many inspirations go to + +- the clever guys at tailscale, +- to Daniel Lemire for his inspiring blog, +- to Donald E. Knuth for the **ART** routing algorithm and +- to Yoichi Hariguchi who deciphered it for us mere mortals + +And last but not least to the Go team who do a wonderful job! ## LICENSE diff --git a/vendor/github.com/gaissmai/bart/SECURITY.md b/vendor/github.com/gaissmai/bart/SECURITY.md new file mode 100644 index 0000000..e2074f4 --- /dev/null +++ b/vendor/github.com/gaissmai/bart/SECURITY.md @@ -0,0 +1,5 @@ +# Security Policy + +## Reporting a Vulnerability + +You can report privately a vulnerability by email at karl.gaissmaier@uni-ulm.de (author and maintainer). diff --git a/vendor/github.com/gaissmai/bart/allot_lookuptbl.go b/vendor/github.com/gaissmai/bart/allot_lookuptbl.go new file mode 100644 index 0000000..55f575a --- /dev/null +++ b/vendor/github.com/gaissmai/bart/allot_lookuptbl.go @@ -0,0 +1,542 @@ +// Copyright (c) 2024 Karl Gaissmaier +// SPDX-License-Identifier: MIT + +package bart + +import "github.com/gaissmai/bart/internal/bitset" + +// allotLookupTbl, as precalculated bitsets, +// map the baseIndex to bitset with precomputed complete binary tree. +// +// // 1 <= idx <= 511 +// func allotRec(aTbl *bitset.BitSet, idx uint) { +// aTbl = aTbl.Set(idx) +// if idx >= 256 { +// return +// } +// allotRec(aTbl, idx<<1) +// allotRec(aTbl, idx<<1+1) +// } +// +// Only used for fast bitset intersections instead of +// range loops in table overlaps methods. +// +// Please read the ART paper ./doc/artlookup.pdf to understand the allotment algorithm. +var allotLookupTbl = [512]bitset.BitSet{ + /* idx: 0 */ {}, // idx is invalid + /* idx: 1 */ {0xfffffffffffffffe, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff}, + /* idx: 2 */ {0xffff00ff0f34, 0xffffffff, 0xffffffffffffffff, 0x0, 0xffffffffffffffff, 0xffffffffffffffff}, + /* idx: 3 */ {0xffff0000ff00f0c8, 0xffffffff00000000, 0x0, 0xffffffffffffffff, 0x0, 0x0, 0xffffffffffffffff, 0xffffffffffffffff}, + /* idx: 4 */ {0xff000f0310, 0xffff, 0xffffffff, 0x0, 0xffffffffffffffff}, + /* idx: 5 */ {0xff0000f00c20, 0xffff0000, 0xffffffff00000000, 0x0, 0x0, 0xffffffffffffffff}, + /* idx: 6 */ {0xff00000f003040, 0xffff00000000, 0x0, 0xffffffff, 0x0, 0x0, 0xffffffffffffffff}, + /* idx: 7 */ {0xff000000f000c080, 0xffff000000000000, 0x0, 0xffffffff00000000, 0x0, 0x0, 0x0, 0xffffffffffffffff}, + /* idx: 8 */ {0xf00030100, 0xff, 0xffff, 0x0, 0xffffffff}, + /* idx: 9 */ {0xf0000c0200, 0xff00, 0xffff0000, 0x0, 0xffffffff00000000}, + /* idx: 10 */ {0xf0000300400, 0xff0000, 0xffff00000000, 0x0, 0x0, 0xffffffff}, + /* idx: 11 */ {0xf00000c00800, 0xff000000, 0xffff000000000000, 0x0, 0x0, 0xffffffff00000000}, + /* idx: 12 */ {0xf000003001000, 0xff00000000, 0x0, 0xffff, 0x0, 0x0, 0xffffffff}, + /* idx: 13 */ {0xf000000c002000, 0xff0000000000, 0x0, 0xffff0000, 0x0, 0x0, 0xffffffff00000000}, + /* idx: 14 */ {0xf00000030004000, 0xff000000000000, 0x0, 0xffff00000000, 0x0, 0x0, 0x0, 0xffffffff}, + /* idx: 15 */ {0xf0000000c0008000, 0xff00000000000000, 0x0, 0xffff000000000000, 0x0, 0x0, 0x0, 0xffffffff00000000}, + /* idx: 16 */ {0x300010000, 0xf, 0xff, 0x0, 0xffff}, + /* idx: 17 */ {0xc00020000, 0xf0, 0xff00, 0x0, 0xffff0000}, + /* idx: 18 */ {0x3000040000, 0xf00, 0xff0000, 0x0, 0xffff00000000}, + /* idx: 19 */ {0xc000080000, 0xf000, 0xff000000, 0x0, 0xffff000000000000}, + /* idx: 20 */ {0x30000100000, 0xf0000, 0xff00000000, 0x0, 0x0, 0xffff}, + /* idx: 21 */ {0xc0000200000, 0xf00000, 0xff0000000000, 0x0, 0x0, 0xffff0000}, + /* idx: 22 */ {0x300000400000, 0xf000000, 0xff000000000000, 0x0, 0x0, 0xffff00000000}, + /* idx: 23 */ {0xc00000800000, 0xf0000000, 0xff00000000000000, 0x0, 0x0, 0xffff000000000000}, + /* idx: 24 */ {0x3000001000000, 0xf00000000, 0x0, 0xff, 0x0, 0x0, 0xffff}, + /* idx: 25 */ {0xc000002000000, 0xf000000000, 0x0, 0xff00, 0x0, 0x0, 0xffff0000}, + /* idx: 26 */ {0x30000004000000, 0xf0000000000, 0x0, 0xff0000, 0x0, 0x0, 0xffff00000000}, + /* idx: 27 */ {0xc0000008000000, 0xf00000000000, 0x0, 0xff000000, 0x0, 0x0, 0xffff000000000000}, + /* idx: 28 */ {0x300000010000000, 0xf000000000000, 0x0, 0xff00000000, 0x0, 0x0, 0x0, 0xffff}, + /* idx: 29 */ {0xc00000020000000, 0xf0000000000000, 0x0, 0xff0000000000, 0x0, 0x0, 0x0, 0xffff0000}, + /* idx: 30 */ {0x3000000040000000, 0xf00000000000000, 0x0, 0xff000000000000, 0x0, 0x0, 0x0, 0xffff00000000}, + /* idx: 31 */ {0xc000000080000000, 0xf000000000000000, 0x0, 0xff00000000000000, 0x0, 0x0, 0x0, 0xffff000000000000}, + /* idx: 32 */ {0x100000000, 0x3, 0xf, 0x0, 0xff}, + /* idx: 33 */ {0x200000000, 0xc, 0xf0, 0x0, 0xff00}, + /* idx: 34 */ {0x400000000, 0x30, 0xf00, 0x0, 0xff0000}, + /* idx: 35 */ {0x800000000, 0xc0, 0xf000, 0x0, 0xff000000}, + /* idx: 36 */ {0x1000000000, 0x300, 0xf0000, 0x0, 0xff00000000}, + /* idx: 37 */ {0x2000000000, 0xc00, 0xf00000, 0x0, 0xff0000000000}, + /* idx: 38 */ {0x4000000000, 0x3000, 0xf000000, 0x0, 0xff000000000000}, + /* idx: 39 */ {0x8000000000, 0xc000, 0xf0000000, 0x0, 0xff00000000000000}, + /* idx: 40 */ {0x10000000000, 0x30000, 0xf00000000, 0x0, 0x0, 0xff}, + /* idx: 41 */ {0x20000000000, 0xc0000, 0xf000000000, 0x0, 0x0, 0xff00}, + /* idx: 42 */ {0x40000000000, 0x300000, 0xf0000000000, 0x0, 0x0, 0xff0000}, + /* idx: 43 */ {0x80000000000, 0xc00000, 0xf00000000000, 0x0, 0x0, 0xff000000}, + /* idx: 44 */ {0x100000000000, 0x3000000, 0xf000000000000, 0x0, 0x0, 0xff00000000}, + /* idx: 45 */ {0x200000000000, 0xc000000, 0xf0000000000000, 0x0, 0x0, 0xff0000000000}, + /* idx: 46 */ {0x400000000000, 0x30000000, 0xf00000000000000, 0x0, 0x0, 0xff000000000000}, + /* idx: 47 */ {0x800000000000, 0xc0000000, 0xf000000000000000, 0x0, 0x0, 0xff00000000000000}, + /* idx: 48 */ {0x1000000000000, 0x300000000, 0x0, 0xf, 0x0, 0x0, 0xff}, + /* idx: 49 */ {0x2000000000000, 0xc00000000, 0x0, 0xf0, 0x0, 0x0, 0xff00}, + /* idx: 50 */ {0x4000000000000, 0x3000000000, 0x0, 0xf00, 0x0, 0x0, 0xff0000}, + /* idx: 51 */ {0x8000000000000, 0xc000000000, 0x0, 0xf000, 0x0, 0x0, 0xff000000}, + /* idx: 52 */ {0x10000000000000, 0x30000000000, 0x0, 0xf0000, 0x0, 0x0, 0xff00000000}, + /* idx: 53 */ {0x20000000000000, 0xc0000000000, 0x0, 0xf00000, 0x0, 0x0, 0xff0000000000}, + /* idx: 54 */ {0x40000000000000, 0x300000000000, 0x0, 0xf000000, 0x0, 0x0, 0xff000000000000}, + /* idx: 55 */ {0x80000000000000, 0xc00000000000, 0x0, 0xf0000000, 0x0, 0x0, 0xff00000000000000}, + /* idx: 56 */ {0x100000000000000, 0x3000000000000, 0x0, 0xf00000000, 0x0, 0x0, 0x0, 0xff}, + /* idx: 57 */ {0x200000000000000, 0xc000000000000, 0x0, 0xf000000000, 0x0, 0x0, 0x0, 0xff00}, + /* idx: 58 */ {0x400000000000000, 0x30000000000000, 0x0, 0xf0000000000, 0x0, 0x0, 0x0, 0xff0000}, + /* idx: 59 */ {0x800000000000000, 0xc0000000000000, 0x0, 0xf00000000000, 0x0, 0x0, 0x0, 0xff000000}, + /* idx: 60 */ {0x1000000000000000, 0x300000000000000, 0x0, 0xf000000000000, 0x0, 0x0, 0x0, 0xff00000000}, + /* idx: 61 */ {0x2000000000000000, 0xc00000000000000, 0x0, 0xf0000000000000, 0x0, 0x0, 0x0, 0xff0000000000}, + /* idx: 62 */ {0x4000000000000000, 0x3000000000000000, 0x0, 0xf00000000000000, 0x0, 0x0, 0x0, 0xff000000000000}, + /* idx: 63 */ {0x8000000000000000, 0xc000000000000000, 0x0, 0xf000000000000000, 0x0, 0x0, 0x0, 0xff00000000000000}, + /* idx: 64 */ {0x0, 0x1, 0x3, 0x0, 0xf}, + /* idx: 65 */ {0x0, 0x2, 0xc, 0x0, 0xf0}, + /* idx: 66 */ {0x0, 0x4, 0x30, 0x0, 0xf00}, + /* idx: 67 */ {0x0, 0x8, 0xc0, 0x0, 0xf000}, + /* idx: 68 */ {0x0, 0x10, 0x300, 0x0, 0xf0000}, + /* idx: 69 */ {0x0, 0x20, 0xc00, 0x0, 0xf00000}, + /* idx: 70 */ {0x0, 0x40, 0x3000, 0x0, 0xf000000}, + /* idx: 71 */ {0x0, 0x80, 0xc000, 0x0, 0xf0000000}, + /* idx: 72 */ {0x0, 0x100, 0x30000, 0x0, 0xf00000000}, + /* idx: 73 */ {0x0, 0x200, 0xc0000, 0x0, 0xf000000000}, + /* idx: 74 */ {0x0, 0x400, 0x300000, 0x0, 0xf0000000000}, + /* idx: 75 */ {0x0, 0x800, 0xc00000, 0x0, 0xf00000000000}, + /* idx: 76 */ {0x0, 0x1000, 0x3000000, 0x0, 0xf000000000000}, + /* idx: 77 */ {0x0, 0x2000, 0xc000000, 0x0, 0xf0000000000000}, + /* idx: 78 */ {0x0, 0x4000, 0x30000000, 0x0, 0xf00000000000000}, + /* idx: 79 */ {0x0, 0x8000, 0xc0000000, 0x0, 0xf000000000000000}, + /* idx: 80 */ {0x0, 0x10000, 0x300000000, 0x0, 0x0, 0xf}, + /* idx: 81 */ {0x0, 0x20000, 0xc00000000, 0x0, 0x0, 0xf0}, + /* idx: 82 */ {0x0, 0x40000, 0x3000000000, 0x0, 0x0, 0xf00}, + /* idx: 83 */ {0x0, 0x80000, 0xc000000000, 0x0, 0x0, 0xf000}, + /* idx: 84 */ {0x0, 0x100000, 0x30000000000, 0x0, 0x0, 0xf0000}, + /* idx: 85 */ {0x0, 0x200000, 0xc0000000000, 0x0, 0x0, 0xf00000}, + /* idx: 86 */ {0x0, 0x400000, 0x300000000000, 0x0, 0x0, 0xf000000}, + /* idx: 87 */ {0x0, 0x800000, 0xc00000000000, 0x0, 0x0, 0xf0000000}, + /* idx: 88 */ {0x0, 0x1000000, 0x3000000000000, 0x0, 0x0, 0xf00000000}, + /* idx: 89 */ {0x0, 0x2000000, 0xc000000000000, 0x0, 0x0, 0xf000000000}, + /* idx: 90 */ {0x0, 0x4000000, 0x30000000000000, 0x0, 0x0, 0xf0000000000}, + /* idx: 91 */ {0x0, 0x8000000, 0xc0000000000000, 0x0, 0x0, 0xf00000000000}, + /* idx: 92 */ {0x0, 0x10000000, 0x300000000000000, 0x0, 0x0, 0xf000000000000}, + /* idx: 93 */ {0x0, 0x20000000, 0xc00000000000000, 0x0, 0x0, 0xf0000000000000}, + /* idx: 94 */ {0x0, 0x40000000, 0x3000000000000000, 0x0, 0x0, 0xf00000000000000}, + /* idx: 95 */ {0x0, 0x80000000, 0xc000000000000000, 0x0, 0x0, 0xf000000000000000}, + /* idx: 96 */ {0x0, 0x100000000, 0x0, 0x3, 0x0, 0x0, 0xf}, + /* idx: 97 */ {0x0, 0x200000000, 0x0, 0xc, 0x0, 0x0, 0xf0}, + /* idx: 98 */ {0x0, 0x400000000, 0x0, 0x30, 0x0, 0x0, 0xf00}, + /* idx: 99 */ {0x0, 0x800000000, 0x0, 0xc0, 0x0, 0x0, 0xf000}, + /* idx: 100 */ {0x0, 0x1000000000, 0x0, 0x300, 0x0, 0x0, 0xf0000}, + /* idx: 101 */ {0x0, 0x2000000000, 0x0, 0xc00, 0x0, 0x0, 0xf00000}, + /* idx: 102 */ {0x0, 0x4000000000, 0x0, 0x3000, 0x0, 0x0, 0xf000000}, + /* idx: 103 */ {0x0, 0x8000000000, 0x0, 0xc000, 0x0, 0x0, 0xf0000000}, + /* idx: 104 */ {0x0, 0x10000000000, 0x0, 0x30000, 0x0, 0x0, 0xf00000000}, + /* idx: 105 */ {0x0, 0x20000000000, 0x0, 0xc0000, 0x0, 0x0, 0xf000000000}, + /* idx: 106 */ {0x0, 0x40000000000, 0x0, 0x300000, 0x0, 0x0, 0xf0000000000}, + /* idx: 107 */ {0x0, 0x80000000000, 0x0, 0xc00000, 0x0, 0x0, 0xf00000000000}, + /* idx: 108 */ {0x0, 0x100000000000, 0x0, 0x3000000, 0x0, 0x0, 0xf000000000000}, + /* idx: 109 */ {0x0, 0x200000000000, 0x0, 0xc000000, 0x0, 0x0, 0xf0000000000000}, + /* idx: 110 */ {0x0, 0x400000000000, 0x0, 0x30000000, 0x0, 0x0, 0xf00000000000000}, + /* idx: 111 */ {0x0, 0x800000000000, 0x0, 0xc0000000, 0x0, 0x0, 0xf000000000000000}, + /* idx: 112 */ {0x0, 0x1000000000000, 0x0, 0x300000000, 0x0, 0x0, 0x0, 0xf}, + /* idx: 113 */ {0x0, 0x2000000000000, 0x0, 0xc00000000, 0x0, 0x0, 0x0, 0xf0}, + /* idx: 114 */ {0x0, 0x4000000000000, 0x0, 0x3000000000, 0x0, 0x0, 0x0, 0xf00}, + /* idx: 115 */ {0x0, 0x8000000000000, 0x0, 0xc000000000, 0x0, 0x0, 0x0, 0xf000}, + /* idx: 116 */ {0x0, 0x10000000000000, 0x0, 0x30000000000, 0x0, 0x0, 0x0, 0xf0000}, + /* idx: 117 */ {0x0, 0x20000000000000, 0x0, 0xc0000000000, 0x0, 0x0, 0x0, 0xf00000}, + /* idx: 118 */ {0x0, 0x40000000000000, 0x0, 0x300000000000, 0x0, 0x0, 0x0, 0xf000000}, + /* idx: 119 */ {0x0, 0x80000000000000, 0x0, 0xc00000000000, 0x0, 0x0, 0x0, 0xf0000000}, + /* idx: 120 */ {0x0, 0x100000000000000, 0x0, 0x3000000000000, 0x0, 0x0, 0x0, 0xf00000000}, + /* idx: 121 */ {0x0, 0x200000000000000, 0x0, 0xc000000000000, 0x0, 0x0, 0x0, 0xf000000000}, + /* idx: 122 */ {0x0, 0x400000000000000, 0x0, 0x30000000000000, 0x0, 0x0, 0x0, 0xf0000000000}, + /* idx: 123 */ {0x0, 0x800000000000000, 0x0, 0xc0000000000000, 0x0, 0x0, 0x0, 0xf00000000000}, + /* idx: 124 */ {0x0, 0x1000000000000000, 0x0, 0x300000000000000, 0x0, 0x0, 0x0, 0xf000000000000}, + /* idx: 125 */ {0x0, 0x2000000000000000, 0x0, 0xc00000000000000, 0x0, 0x0, 0x0, 0xf0000000000000}, + /* idx: 126 */ {0x0, 0x4000000000000000, 0x0, 0x3000000000000000, 0x0, 0x0, 0x0, 0xf00000000000000}, + /* idx: 127 */ {0x0, 0x8000000000000000, 0x0, 0xc000000000000000, 0x0, 0x0, 0x0, 0xf000000000000000}, + /* idx: 128 */ {0x0, 0x0, 0x1, 0x0, 0x3}, + /* idx: 129 */ {0x0, 0x0, 0x2, 0x0, 0xc}, + /* idx: 130 */ {0x0, 0x0, 0x4, 0x0, 0x30}, + /* idx: 131 */ {0x0, 0x0, 0x8, 0x0, 0xc0}, + /* idx: 132 */ {0x0, 0x0, 0x10, 0x0, 0x300}, + /* idx: 133 */ {0x0, 0x0, 0x20, 0x0, 0xc00}, + /* idx: 134 */ {0x0, 0x0, 0x40, 0x0, 0x3000}, + /* idx: 135 */ {0x0, 0x0, 0x80, 0x0, 0xc000}, + /* idx: 136 */ {0x0, 0x0, 0x100, 0x0, 0x30000}, + /* idx: 137 */ {0x0, 0x0, 0x200, 0x0, 0xc0000}, + /* idx: 138 */ {0x0, 0x0, 0x400, 0x0, 0x300000}, + /* idx: 139 */ {0x0, 0x0, 0x800, 0x0, 0xc00000}, + /* idx: 140 */ {0x0, 0x0, 0x1000, 0x0, 0x3000000}, + /* idx: 141 */ {0x0, 0x0, 0x2000, 0x0, 0xc000000}, + /* idx: 142 */ {0x0, 0x0, 0x4000, 0x0, 0x30000000}, + /* idx: 143 */ {0x0, 0x0, 0x8000, 0x0, 0xc0000000}, + /* idx: 144 */ {0x0, 0x0, 0x10000, 0x0, 0x300000000}, + /* idx: 145 */ {0x0, 0x0, 0x20000, 0x0, 0xc00000000}, + /* idx: 146 */ {0x0, 0x0, 0x40000, 0x0, 0x3000000000}, + /* idx: 147 */ {0x0, 0x0, 0x80000, 0x0, 0xc000000000}, + /* idx: 148 */ {0x0, 0x0, 0x100000, 0x0, 0x30000000000}, + /* idx: 149 */ {0x0, 0x0, 0x200000, 0x0, 0xc0000000000}, + /* idx: 150 */ {0x0, 0x0, 0x400000, 0x0, 0x300000000000}, + /* idx: 151 */ {0x0, 0x0, 0x800000, 0x0, 0xc00000000000}, + /* idx: 152 */ {0x0, 0x0, 0x1000000, 0x0, 0x3000000000000}, + /* idx: 153 */ {0x0, 0x0, 0x2000000, 0x0, 0xc000000000000}, + /* idx: 154 */ {0x0, 0x0, 0x4000000, 0x0, 0x30000000000000}, + /* idx: 155 */ {0x0, 0x0, 0x8000000, 0x0, 0xc0000000000000}, + /* idx: 156 */ {0x0, 0x0, 0x10000000, 0x0, 0x300000000000000}, + /* idx: 157 */ {0x0, 0x0, 0x20000000, 0x0, 0xc00000000000000}, + /* idx: 158 */ {0x0, 0x0, 0x40000000, 0x0, 0x3000000000000000}, + /* idx: 159 */ {0x0, 0x0, 0x80000000, 0x0, 0xc000000000000000}, + /* idx: 160 */ {0x0, 0x0, 0x100000000, 0x0, 0x0, 0x3}, + /* idx: 161 */ {0x0, 0x0, 0x200000000, 0x0, 0x0, 0xc}, + /* idx: 162 */ {0x0, 0x0, 0x400000000, 0x0, 0x0, 0x30}, + /* idx: 163 */ {0x0, 0x0, 0x800000000, 0x0, 0x0, 0xc0}, + /* idx: 164 */ {0x0, 0x0, 0x1000000000, 0x0, 0x0, 0x300}, + /* idx: 165 */ {0x0, 0x0, 0x2000000000, 0x0, 0x0, 0xc00}, + /* idx: 166 */ {0x0, 0x0, 0x4000000000, 0x0, 0x0, 0x3000}, + /* idx: 167 */ {0x0, 0x0, 0x8000000000, 0x0, 0x0, 0xc000}, + /* idx: 168 */ {0x0, 0x0, 0x10000000000, 0x0, 0x0, 0x30000}, + /* idx: 169 */ {0x0, 0x0, 0x20000000000, 0x0, 0x0, 0xc0000}, + /* idx: 170 */ {0x0, 0x0, 0x40000000000, 0x0, 0x0, 0x300000}, + /* idx: 171 */ {0x0, 0x0, 0x80000000000, 0x0, 0x0, 0xc00000}, + /* idx: 172 */ {0x0, 0x0, 0x100000000000, 0x0, 0x0, 0x3000000}, + /* idx: 173 */ {0x0, 0x0, 0x200000000000, 0x0, 0x0, 0xc000000}, + /* idx: 174 */ {0x0, 0x0, 0x400000000000, 0x0, 0x0, 0x30000000}, + /* idx: 175 */ {0x0, 0x0, 0x800000000000, 0x0, 0x0, 0xc0000000}, + /* idx: 176 */ {0x0, 0x0, 0x1000000000000, 0x0, 0x0, 0x300000000}, + /* idx: 177 */ {0x0, 0x0, 0x2000000000000, 0x0, 0x0, 0xc00000000}, + /* idx: 178 */ {0x0, 0x0, 0x4000000000000, 0x0, 0x0, 0x3000000000}, + /* idx: 179 */ {0x0, 0x0, 0x8000000000000, 0x0, 0x0, 0xc000000000}, + /* idx: 180 */ {0x0, 0x0, 0x10000000000000, 0x0, 0x0, 0x30000000000}, + /* idx: 181 */ {0x0, 0x0, 0x20000000000000, 0x0, 0x0, 0xc0000000000}, + /* idx: 182 */ {0x0, 0x0, 0x40000000000000, 0x0, 0x0, 0x300000000000}, + /* idx: 183 */ {0x0, 0x0, 0x80000000000000, 0x0, 0x0, 0xc00000000000}, + /* idx: 184 */ {0x0, 0x0, 0x100000000000000, 0x0, 0x0, 0x3000000000000}, + /* idx: 185 */ {0x0, 0x0, 0x200000000000000, 0x0, 0x0, 0xc000000000000}, + /* idx: 186 */ {0x0, 0x0, 0x400000000000000, 0x0, 0x0, 0x30000000000000}, + /* idx: 187 */ {0x0, 0x0, 0x800000000000000, 0x0, 0x0, 0xc0000000000000}, + /* idx: 188 */ {0x0, 0x0, 0x1000000000000000, 0x0, 0x0, 0x300000000000000}, + /* idx: 189 */ {0x0, 0x0, 0x2000000000000000, 0x0, 0x0, 0xc00000000000000}, + /* idx: 190 */ {0x0, 0x0, 0x4000000000000000, 0x0, 0x0, 0x3000000000000000}, + /* idx: 191 */ {0x0, 0x0, 0x8000000000000000, 0x0, 0x0, 0xc000000000000000}, + /* idx: 192 */ {0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x3}, + /* idx: 193 */ {0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0xc}, + /* idx: 194 */ {0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x30}, + /* idx: 195 */ {0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0xc0}, + /* idx: 196 */ {0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x300}, + /* idx: 197 */ {0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0xc00}, + /* idx: 198 */ {0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x3000}, + /* idx: 199 */ {0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0xc000}, + /* idx: 200 */ {0x0, 0x0, 0x0, 0x100, 0x0, 0x0, 0x30000}, + /* idx: 201 */ {0x0, 0x0, 0x0, 0x200, 0x0, 0x0, 0xc0000}, + /* idx: 202 */ {0x0, 0x0, 0x0, 0x400, 0x0, 0x0, 0x300000}, + /* idx: 203 */ {0x0, 0x0, 0x0, 0x800, 0x0, 0x0, 0xc00000}, + /* idx: 204 */ {0x0, 0x0, 0x0, 0x1000, 0x0, 0x0, 0x3000000}, + /* idx: 205 */ {0x0, 0x0, 0x0, 0x2000, 0x0, 0x0, 0xc000000}, + /* idx: 206 */ {0x0, 0x0, 0x0, 0x4000, 0x0, 0x0, 0x30000000}, + /* idx: 207 */ {0x0, 0x0, 0x0, 0x8000, 0x0, 0x0, 0xc0000000}, + /* idx: 208 */ {0x0, 0x0, 0x0, 0x10000, 0x0, 0x0, 0x300000000}, + /* idx: 209 */ {0x0, 0x0, 0x0, 0x20000, 0x0, 0x0, 0xc00000000}, + /* idx: 210 */ {0x0, 0x0, 0x0, 0x40000, 0x0, 0x0, 0x3000000000}, + /* idx: 211 */ {0x0, 0x0, 0x0, 0x80000, 0x0, 0x0, 0xc000000000}, + /* idx: 212 */ {0x0, 0x0, 0x0, 0x100000, 0x0, 0x0, 0x30000000000}, + /* idx: 213 */ {0x0, 0x0, 0x0, 0x200000, 0x0, 0x0, 0xc0000000000}, + /* idx: 214 */ {0x0, 0x0, 0x0, 0x400000, 0x0, 0x0, 0x300000000000}, + /* idx: 215 */ {0x0, 0x0, 0x0, 0x800000, 0x0, 0x0, 0xc00000000000}, + /* idx: 216 */ {0x0, 0x0, 0x0, 0x1000000, 0x0, 0x0, 0x3000000000000}, + /* idx: 217 */ {0x0, 0x0, 0x0, 0x2000000, 0x0, 0x0, 0xc000000000000}, + /* idx: 218 */ {0x0, 0x0, 0x0, 0x4000000, 0x0, 0x0, 0x30000000000000}, + /* idx: 219 */ {0x0, 0x0, 0x0, 0x8000000, 0x0, 0x0, 0xc0000000000000}, + /* idx: 220 */ {0x0, 0x0, 0x0, 0x10000000, 0x0, 0x0, 0x300000000000000}, + /* idx: 221 */ {0x0, 0x0, 0x0, 0x20000000, 0x0, 0x0, 0xc00000000000000}, + /* idx: 222 */ {0x0, 0x0, 0x0, 0x40000000, 0x0, 0x0, 0x3000000000000000}, + /* idx: 223 */ {0x0, 0x0, 0x0, 0x80000000, 0x0, 0x0, 0xc000000000000000}, + /* idx: 224 */ {0x0, 0x0, 0x0, 0x100000000, 0x0, 0x0, 0x0, 0x3}, + /* idx: 225 */ {0x0, 0x0, 0x0, 0x200000000, 0x0, 0x0, 0x0, 0xc}, + /* idx: 226 */ {0x0, 0x0, 0x0, 0x400000000, 0x0, 0x0, 0x0, 0x30}, + /* idx: 227 */ {0x0, 0x0, 0x0, 0x800000000, 0x0, 0x0, 0x0, 0xc0}, + /* idx: 228 */ {0x0, 0x0, 0x0, 0x1000000000, 0x0, 0x0, 0x0, 0x300}, + /* idx: 229 */ {0x0, 0x0, 0x0, 0x2000000000, 0x0, 0x0, 0x0, 0xc00}, + /* idx: 230 */ {0x0, 0x0, 0x0, 0x4000000000, 0x0, 0x0, 0x0, 0x3000}, + /* idx: 231 */ {0x0, 0x0, 0x0, 0x8000000000, 0x0, 0x0, 0x0, 0xc000}, + /* idx: 232 */ {0x0, 0x0, 0x0, 0x10000000000, 0x0, 0x0, 0x0, 0x30000}, + /* idx: 233 */ {0x0, 0x0, 0x0, 0x20000000000, 0x0, 0x0, 0x0, 0xc0000}, + /* idx: 234 */ {0x0, 0x0, 0x0, 0x40000000000, 0x0, 0x0, 0x0, 0x300000}, + /* idx: 235 */ {0x0, 0x0, 0x0, 0x80000000000, 0x0, 0x0, 0x0, 0xc00000}, + /* idx: 236 */ {0x0, 0x0, 0x0, 0x100000000000, 0x0, 0x0, 0x0, 0x3000000}, + /* idx: 237 */ {0x0, 0x0, 0x0, 0x200000000000, 0x0, 0x0, 0x0, 0xc000000}, + /* idx: 238 */ {0x0, 0x0, 0x0, 0x400000000000, 0x0, 0x0, 0x0, 0x30000000}, + /* idx: 239 */ {0x0, 0x0, 0x0, 0x800000000000, 0x0, 0x0, 0x0, 0xc0000000}, + /* idx: 240 */ {0x0, 0x0, 0x0, 0x1000000000000, 0x0, 0x0, 0x0, 0x300000000}, + /* idx: 241 */ {0x0, 0x0, 0x0, 0x2000000000000, 0x0, 0x0, 0x0, 0xc00000000}, + /* idx: 242 */ {0x0, 0x0, 0x0, 0x4000000000000, 0x0, 0x0, 0x0, 0x3000000000}, + /* idx: 243 */ {0x0, 0x0, 0x0, 0x8000000000000, 0x0, 0x0, 0x0, 0xc000000000}, + /* idx: 244 */ {0x0, 0x0, 0x0, 0x10000000000000, 0x0, 0x0, 0x0, 0x30000000000}, + /* idx: 245 */ {0x0, 0x0, 0x0, 0x20000000000000, 0x0, 0x0, 0x0, 0xc0000000000}, + /* idx: 246 */ {0x0, 0x0, 0x0, 0x40000000000000, 0x0, 0x0, 0x0, 0x300000000000}, + /* idx: 247 */ {0x0, 0x0, 0x0, 0x80000000000000, 0x0, 0x0, 0x0, 0xc00000000000}, + /* idx: 248 */ {0x0, 0x0, 0x0, 0x100000000000000, 0x0, 0x0, 0x0, 0x3000000000000}, + /* idx: 249 */ {0x0, 0x0, 0x0, 0x200000000000000, 0x0, 0x0, 0x0, 0xc000000000000}, + /* idx: 250 */ {0x0, 0x0, 0x0, 0x400000000000000, 0x0, 0x0, 0x0, 0x30000000000000}, + /* idx: 251 */ {0x0, 0x0, 0x0, 0x800000000000000, 0x0, 0x0, 0x0, 0xc0000000000000}, + /* idx: 252 */ {0x0, 0x0, 0x0, 0x1000000000000000, 0x0, 0x0, 0x0, 0x300000000000000}, + /* idx: 253 */ {0x0, 0x0, 0x0, 0x2000000000000000, 0x0, 0x0, 0x0, 0xc00000000000000}, + /* idx: 254 */ {0x0, 0x0, 0x0, 0x4000000000000000, 0x0, 0x0, 0x0, 0x3000000000000000}, + /* idx: 255 */ {0x0, 0x0, 0x0, 0x8000000000000000, 0x0, 0x0, 0x0, 0xc000000000000000}, + // + // START of HOST ROUTES, pfxLen == 8 + // [:4] are all 0 and only one bit is set in [4:] + // + /* idx: 256 */ {0x0, 0x0, 0x0, 0x0, 0x1}, + /* idx: 257 */ {0x0, 0x0, 0x0, 0x0, 0x2}, + /* idx: 258 */ {0x0, 0x0, 0x0, 0x0, 0x4}, + /* idx: 259 */ {0x0, 0x0, 0x0, 0x0, 0x8}, + /* idx: 260 */ {0x0, 0x0, 0x0, 0x0, 0x10}, + /* idx: 261 */ {0x0, 0x0, 0x0, 0x0, 0x20}, + /* idx: 262 */ {0x0, 0x0, 0x0, 0x0, 0x40}, + /* idx: 263 */ {0x0, 0x0, 0x0, 0x0, 0x80}, + /* idx: 264 */ {0x0, 0x0, 0x0, 0x0, 0x100}, + /* idx: 265 */ {0x0, 0x0, 0x0, 0x0, 0x200}, + /* idx: 266 */ {0x0, 0x0, 0x0, 0x0, 0x400}, + /* idx: 267 */ {0x0, 0x0, 0x0, 0x0, 0x800}, + /* idx: 268 */ {0x0, 0x0, 0x0, 0x0, 0x1000}, + /* idx: 269 */ {0x0, 0x0, 0x0, 0x0, 0x2000}, + /* idx: 270 */ {0x0, 0x0, 0x0, 0x0, 0x4000}, + /* idx: 271 */ {0x0, 0x0, 0x0, 0x0, 0x8000}, + /* idx: 272 */ {0x0, 0x0, 0x0, 0x0, 0x10000}, + /* idx: 273 */ {0x0, 0x0, 0x0, 0x0, 0x20000}, + /* idx: 274 */ {0x0, 0x0, 0x0, 0x0, 0x40000}, + /* idx: 275 */ {0x0, 0x0, 0x0, 0x0, 0x80000}, + /* idx: 276 */ {0x0, 0x0, 0x0, 0x0, 0x100000}, + /* idx: 277 */ {0x0, 0x0, 0x0, 0x0, 0x200000}, + /* idx: 278 */ {0x0, 0x0, 0x0, 0x0, 0x400000}, + /* idx: 279 */ {0x0, 0x0, 0x0, 0x0, 0x800000}, + /* idx: 280 */ {0x0, 0x0, 0x0, 0x0, 0x1000000}, + /* idx: 281 */ {0x0, 0x0, 0x0, 0x0, 0x2000000}, + /* idx: 282 */ {0x0, 0x0, 0x0, 0x0, 0x4000000}, + /* idx: 283 */ {0x0, 0x0, 0x0, 0x0, 0x8000000}, + /* idx: 284 */ {0x0, 0x0, 0x0, 0x0, 0x10000000}, + /* idx: 285 */ {0x0, 0x0, 0x0, 0x0, 0x20000000}, + /* idx: 286 */ {0x0, 0x0, 0x0, 0x0, 0x40000000}, + /* idx: 287 */ {0x0, 0x0, 0x0, 0x0, 0x80000000}, + /* idx: 288 */ {0x0, 0x0, 0x0, 0x0, 0x100000000}, + /* idx: 289 */ {0x0, 0x0, 0x0, 0x0, 0x200000000}, + /* idx: 290 */ {0x0, 0x0, 0x0, 0x0, 0x400000000}, + /* idx: 291 */ {0x0, 0x0, 0x0, 0x0, 0x800000000}, + /* idx: 292 */ {0x0, 0x0, 0x0, 0x0, 0x1000000000}, + /* idx: 293 */ {0x0, 0x0, 0x0, 0x0, 0x2000000000}, + /* idx: 294 */ {0x0, 0x0, 0x0, 0x0, 0x4000000000}, + /* idx: 295 */ {0x0, 0x0, 0x0, 0x0, 0x8000000000}, + /* idx: 296 */ {0x0, 0x0, 0x0, 0x0, 0x10000000000}, + /* idx: 297 */ {0x0, 0x0, 0x0, 0x0, 0x20000000000}, + /* idx: 298 */ {0x0, 0x0, 0x0, 0x0, 0x40000000000}, + /* idx: 299 */ {0x0, 0x0, 0x0, 0x0, 0x80000000000}, + /* idx: 300 */ {0x0, 0x0, 0x0, 0x0, 0x100000000000}, + /* idx: 301 */ {0x0, 0x0, 0x0, 0x0, 0x200000000000}, + /* idx: 302 */ {0x0, 0x0, 0x0, 0x0, 0x400000000000}, + /* idx: 303 */ {0x0, 0x0, 0x0, 0x0, 0x800000000000}, + /* idx: 304 */ {0x0, 0x0, 0x0, 0x0, 0x1000000000000}, + /* idx: 305 */ {0x0, 0x0, 0x0, 0x0, 0x2000000000000}, + /* idx: 306 */ {0x0, 0x0, 0x0, 0x0, 0x4000000000000}, + /* idx: 307 */ {0x0, 0x0, 0x0, 0x0, 0x8000000000000}, + /* idx: 308 */ {0x0, 0x0, 0x0, 0x0, 0x10000000000000}, + /* idx: 309 */ {0x0, 0x0, 0x0, 0x0, 0x20000000000000}, + /* idx: 310 */ {0x0, 0x0, 0x0, 0x0, 0x40000000000000}, + /* idx: 311 */ {0x0, 0x0, 0x0, 0x0, 0x80000000000000}, + /* idx: 312 */ {0x0, 0x0, 0x0, 0x0, 0x100000000000000}, + /* idx: 313 */ {0x0, 0x0, 0x0, 0x0, 0x200000000000000}, + /* idx: 314 */ {0x0, 0x0, 0x0, 0x0, 0x400000000000000}, + /* idx: 315 */ {0x0, 0x0, 0x0, 0x0, 0x800000000000000}, + /* idx: 316 */ {0x0, 0x0, 0x0, 0x0, 0x1000000000000000}, + /* idx: 317 */ {0x0, 0x0, 0x0, 0x0, 0x2000000000000000}, + /* idx: 318 */ {0x0, 0x0, 0x0, 0x0, 0x4000000000000000}, + /* idx: 319 */ {0x0, 0x0, 0x0, 0x0, 0x8000000000000000}, + /* idx: 320 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x1}, + /* idx: 321 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x2}, + /* idx: 322 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x4}, + /* idx: 323 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x8}, + /* idx: 324 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x10}, + /* idx: 325 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x20}, + /* idx: 326 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x40}, + /* idx: 327 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x80}, + /* idx: 328 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x100}, + /* idx: 329 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x200}, + /* idx: 330 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x400}, + /* idx: 331 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x800}, + /* idx: 332 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x1000}, + /* idx: 333 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x2000}, + /* idx: 334 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x4000}, + /* idx: 335 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x8000}, + /* idx: 336 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x10000}, + /* idx: 337 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}, + /* idx: 338 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x40000}, + /* idx: 339 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x80000}, + /* idx: 340 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x100000}, + /* idx: 341 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x200000}, + /* idx: 342 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x400000}, + /* idx: 343 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x800000}, + /* idx: 344 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000}, + /* idx: 345 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x2000000}, + /* idx: 346 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x4000000}, + /* idx: 347 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x8000000}, + /* idx: 348 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000}, + /* idx: 349 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000}, + /* idx: 350 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x40000000}, + /* idx: 351 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x80000000}, + /* idx: 352 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x100000000}, + /* idx: 353 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x200000000}, + /* idx: 354 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x400000000}, + /* idx: 355 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x800000000}, + /* idx: 356 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000000}, + /* idx: 357 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x2000000000}, + /* idx: 358 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x4000000000}, + /* idx: 359 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x8000000000}, + /* idx: 360 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000000}, + /* idx: 361 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000000}, + /* idx: 362 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x40000000000}, + /* idx: 363 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x80000000000}, + /* idx: 364 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x100000000000}, + /* idx: 365 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x200000000000}, + /* idx: 366 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x400000000000}, + /* idx: 367 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x800000000000}, + /* idx: 368 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000000000}, + /* idx: 369 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x2000000000000}, + /* idx: 370 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x4000000000000}, + /* idx: 371 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x8000000000000}, + /* idx: 372 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000000000}, + /* idx: 373 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000000000}, + /* idx: 374 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x40000000000000}, + /* idx: 375 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x80000000000000}, + /* idx: 376 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x100000000000000}, + /* idx: 377 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x200000000000000}, + /* idx: 378 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x400000000000000}, + /* idx: 379 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x800000000000000}, + /* idx: 380 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000000000000}, + /* idx: 381 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x2000000000000000}, + /* idx: 382 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x4000000000000000}, + /* idx: 383 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x8000000000000000}, + /* idx: 384 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}, + /* idx: 385 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}, + /* idx: 386 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4}, + /* idx: 387 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8}, + /* idx: 388 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10}, + /* idx: 389 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20}, + /* idx: 390 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40}, + /* idx: 391 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80}, + /* idx: 392 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100}, + /* idx: 393 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200}, + /* idx: 394 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400}, + /* idx: 395 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800}, + /* idx: 396 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000}, + /* idx: 397 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000}, + /* idx: 398 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000}, + /* idx: 399 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8000}, + /* idx: 400 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000}, + /* idx: 401 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}, + /* idx: 402 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40000}, + /* idx: 403 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000}, + /* idx: 404 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100000}, + /* idx: 405 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200000}, + /* idx: 406 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400000}, + /* idx: 407 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800000}, + /* idx: 408 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000}, + /* idx: 409 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000000}, + /* idx: 410 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000000}, + /* idx: 411 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8000000}, + /* idx: 412 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000}, + /* idx: 413 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000}, + /* idx: 414 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40000000}, + /* idx: 415 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000000}, + /* idx: 416 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100000000}, + /* idx: 417 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200000000}, + /* idx: 418 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400000000}, + /* idx: 419 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800000000}, + /* idx: 420 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000000}, + /* idx: 421 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000000000}, + /* idx: 422 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000000000}, + /* idx: 423 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8000000000}, + /* idx: 424 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000000}, + /* idx: 425 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000000}, + /* idx: 426 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40000000000}, + /* idx: 427 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000000000}, + /* idx: 428 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100000000000}, + /* idx: 429 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200000000000}, + /* idx: 430 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400000000000}, + /* idx: 431 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800000000000}, + /* idx: 432 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000000000}, + /* idx: 433 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000000000000}, + /* idx: 434 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000000000000}, + /* idx: 435 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8000000000000}, + /* idx: 436 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000000000}, + /* idx: 437 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000000000}, + /* idx: 438 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40000000000000}, + /* idx: 439 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000000000000}, + /* idx: 440 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100000000000000}, + /* idx: 441 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200000000000000}, + /* idx: 442 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400000000000000}, + /* idx: 443 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800000000000000}, + /* idx: 444 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000000000000}, + /* idx: 445 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000000000000000}, + /* idx: 446 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000000000000000}, + /* idx: 447 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8000000000000000}, + /* idx: 448 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}, + /* idx: 449 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}, + /* idx: 450 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4}, + /* idx: 451 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8}, + /* idx: 452 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10}, + /* idx: 453 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20}, + /* idx: 454 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40}, + /* idx: 455 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80}, + /* idx: 456 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100}, + /* idx: 457 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200}, + /* idx: 458 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400}, + /* idx: 459 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800}, + /* idx: 460 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000}, + /* idx: 461 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000}, + /* idx: 462 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000}, + /* idx: 463 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8000}, + /* idx: 464 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000}, + /* idx: 465 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000}, + /* idx: 466 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40000}, + /* idx: 467 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000}, + /* idx: 468 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100000}, + /* idx: 469 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200000}, + /* idx: 470 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400000}, + /* idx: 471 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800000}, + /* idx: 472 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000}, + /* idx: 473 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000000}, + /* idx: 474 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000000}, + /* idx: 475 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8000000}, + /* idx: 476 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000}, + /* idx: 477 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000}, + /* idx: 478 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40000000}, + /* idx: 479 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000000}, + /* idx: 480 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100000000}, + /* idx: 481 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200000000}, + /* idx: 482 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400000000}, + /* idx: 483 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800000000}, + /* idx: 484 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000000}, + /* idx: 485 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000000000}, + /* idx: 486 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000000000}, + /* idx: 487 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8000000000}, + /* idx: 488 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000000}, + /* idx: 489 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000000}, + /* idx: 490 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40000000000}, + /* idx: 491 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000000000}, + /* idx: 492 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100000000000}, + /* idx: 493 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200000000000}, + /* idx: 494 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400000000000}, + /* idx: 495 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800000000000}, + /* idx: 496 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000000000}, + /* idx: 497 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000000000000}, + /* idx: 498 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000000000000}, + /* idx: 499 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8000000000000}, + /* idx: 500 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10000000000000}, + /* idx: 501 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20000000000000}, + /* idx: 502 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40000000000000}, + /* idx: 503 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000000000000}, + /* idx: 504 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100000000000000}, + /* idx: 505 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x200000000000000}, + /* idx: 506 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400000000000000}, + /* idx: 507 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x800000000000000}, + /* idx: 508 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000000000000000}, + /* idx: 509 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2000000000000000}, + /* idx: 510 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4000000000000000}, + /* idx: 511 */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8000000000000000}, +} diff --git a/vendor/github.com/gaissmai/bart/base_index.go b/vendor/github.com/gaissmai/bart/base_index.go index 205851a..561c0f4 100644 --- a/vendor/github.com/gaissmai/bart/base_index.go +++ b/vendor/github.com/gaissmai/bart/base_index.go @@ -1,621 +1,595 @@ // Copyright (c) 2024 Karl Gaissmaier // SPDX-License-Identifier: MIT -package bart - -import "cmp" - // Please read the ART paper ./doc/artlookup.pdf // to understand the baseIndex algorithm. -// hostMasks as lookup table -var hostMasks = []uint8{ - 0b1111_1111, // bits == 0 - 0b0111_1111, // bits == 1 - 0b0011_1111, // bits == 2 - 0b0001_1111, // bits == 3 - 0b0000_1111, // bits == 4 - 0b0000_0111, // bits == 5 - 0b0000_0011, // bits == 6 - 0b0000_0001, // bits == 7 - 0b0000_0000, // bits == 8 +package bart + +// netmask for bits +// +// 0b0000_0000, // bits == 0 +// 0b1000_0000, // bits == 1 +// 0b1100_0000, // bits == 2 +// 0b1110_0000, // bits == 3 +// 0b1111_0000, // bits == 4 +// 0b1111_1000, // bits == 5 +// 0b1111_1100, // bits == 6 +// 0b1111_1110, // bits == 7 +// 0b1111_1111, // bits == 8 +func netMask(bits int) uint8 { + return 0b1111_1111 << (8 - bits) } -func netMask(mask int) uint8 { - return ^hostMasks[uint8(mask)] -} +// baseIndex of the first host route 0/8: pfxToIdx(0,8) +const firstHostIdx = 256 -const ( - - // baseIndex of the first host route: prefixToBaseIndex(0,8) - firstHostIndex = 0b1_0000_0000 // 256 - - // baseIndex of the last host route: prefixToBaseIndex(255,8) - //nolint:unused - lastHostIndex = 0b1_1111_1111 // 511 -) - -// prefixToBaseIndex, maps a prefix table as a 'complete binary tree'. -// This is the so-called baseIndex a.k.a heapFunc: -func prefixToBaseIndex(octet byte, prefixLen int) uint { +// pfxToIdx, maps a prefix table as a 'complete binary tree'. +func pfxToIdx(octet byte, prefixLen int) uint { return uint(octet>>(strideLen-prefixLen)) + (1 << prefixLen) } -// octetToBaseIndex, just prefixToBaseIndex(octet, 8), a.k.a host routes -// but faster, use it for host routes in Lookup. -func octetToBaseIndex(octet byte) uint { - return uint(octet) + firstHostIndex // just: octet + 256 +// hostIndex, just pfxToIdx(octet, 8) but faster. +func hostIndex(octet uint) uint { + return octet + firstHostIdx } -// baseIndexToPrefixLen, calc the bits from baseIndex and octect depth -func baseIndexToPrefixLen(baseIdx uint, depth int) int { - _, pfxLen := baseIndexToPrefix(baseIdx) - return depth*strideLen + pfxLen +// cmpIndexRank, sort indexes in prefix sort order. +func cmpIndexRank(aIdx, bIdx uint) int { + // convert idx to prefix + aOctet, aBits := idxToPfx(aIdx) + bOctet, bBits := idxToPfx(bIdx) + + // cmp the prefixes, first by address and then by bits + if aOctet == bOctet { + if aBits <= bBits { + return -1 + } + + return 1 + } + + if aOctet < bOctet { + return -1 + } + + return 1 } -// hostRoutesByIndex, get range of host routes for this idx. -// -// idx: 72 -// prefix: 32/6 -// lower: 256 + 32 = 288 -// upper: 256 + (32 | 0b0000_0011) = 291 -// -// Use the pre computed lookup table. -// -// func hostRoutesByIndex(idx uint) (uint, uint) { -// octet, bits := baseIndexToPrefix(idx) -// return octetToBaseIndex(octet), octetToBaseIndex(octet | hostMasks[bits]) -// } -func hostRoutesByIndex(idx uint) (uint, uint) { - item := baseIdxLookupTbl[idx] - return uint(item.lower), uint(item.upper) +// idxToPfx returns the octet and prefix len of baseIdx. +// It's the inverse to pfxToIdx. +func idxToPfx(idx uint) (octet byte, pfxLen int) { + return baseIdxLookupTbl[idx].octet, int(baseIdxLookupTbl[idx].pfxLen) } -// baseIndexToPrefix returns the octet and prefix len of baseIdx. -// It's the inverse to prefixToBaseIndex. +// baseIdxLookupTbl, maps back from idx => octet/bits // -// Use the pre computed lookup table, bits.LeadingZeros is too slow. +// Use the pre computed lookup table, the func baseIndexToPrefix is too slow +// in comparison to an array access. // -// func baseIndexToPrefix(baseIdx uint) (octet byte, pfxLen int) { -// nlz := bits.LeadingZeros(baseIdx) +// func baseIndexToPrefix(idx uint) (octet byte, pfxLen int) { +// nlz := bits.LeadingZeros(idx) // pfxLen = strconv.IntSize - nlz - 1 -// octet = (baseIdx & (0xFF >> (8 - pfxLen))) << (8 - pfxLen) +// octet = byte((idx & (0xFF >> (8 - pfxLen))) << (8 - pfxLen)) // return octet, pfxLen // } -func baseIndexToPrefix(baseIdx uint) (octet byte, pfxLen int) { - item := baseIdxLookupTbl[baseIdx] - return item.octet, int(item.bits) -} - -// cmpIndexRank, compare SortFunc to sort indexes in prefix sort order. -func cmpIndexRank(a, b uint) int { - return cmp.Compare(baseIdxLookupTbl[a].rank, baseIdxLookupTbl[b].rank) -} - -// baseIdxLookupTbl -// -// octet, bits, -// host route boundaries, -// prefix sort rank -// -// as lookup table. var baseIdxLookupTbl = [512]struct { - octet byte - bits int8 - lower uint16 // host route lower bound - upper uint16 // host route upper bound - rank uint16 // prefix sort rank + octet byte + pfxLen int8 }{ - {0, -1, 0, 0, 0}, // idx == 0 invalid! - {0, 0, 256, 511, 1}, // idx == 1 - {0, 1, 256, 383, 2}, // idx == 2 - {128, 1, 384, 511, 257}, // idx == 3 - {0, 2, 256, 319, 3}, // idx == 4 - {64, 2, 320, 383, 130}, // idx == 5 - {128, 2, 384, 447, 258}, // idx == 6 - {192, 2, 448, 511, 385}, // idx == 7 - {0, 3, 256, 287, 4}, // idx == 8 - {32, 3, 288, 319, 67}, // idx == 9 - {64, 3, 320, 351, 131}, // idx == 10 - {96, 3, 352, 383, 194}, // idx == 11 - {128, 3, 384, 415, 259}, // idx == 12 - {160, 3, 416, 447, 322}, // idx == 13 - {192, 3, 448, 479, 386}, // idx == 14 - {224, 3, 480, 511, 449}, // idx == 15 - {0, 4, 256, 271, 5}, // idx == 16 - {16, 4, 272, 287, 36}, // idx == 17 - {32, 4, 288, 303, 68}, // idx == 18 - {48, 4, 304, 319, 99}, // idx == 19 - {64, 4, 320, 335, 132}, // idx == 20 - {80, 4, 336, 351, 163}, // idx == 21 - {96, 4, 352, 367, 195}, // idx == 22 - {112, 4, 368, 383, 226}, // idx == 23 - {128, 4, 384, 399, 260}, // idx == 24 - {144, 4, 400, 415, 291}, // idx == 25 - {160, 4, 416, 431, 323}, // idx == 26 - {176, 4, 432, 447, 354}, // idx == 27 - {192, 4, 448, 463, 387}, // idx == 28 - {208, 4, 464, 479, 418}, // idx == 29 - {224, 4, 480, 495, 450}, // idx == 30 - {240, 4, 496, 511, 481}, // idx == 31 - {0, 5, 256, 263, 6}, // idx == 32 - {8, 5, 264, 271, 21}, // idx == 33 - {16, 5, 272, 279, 37}, // idx == 34 - {24, 5, 280, 287, 52}, // idx == 35 - {32, 5, 288, 295, 69}, // idx == 36 - {40, 5, 296, 303, 84}, // idx == 37 - {48, 5, 304, 311, 100}, // idx == 38 - {56, 5, 312, 319, 115}, // idx == 39 - {64, 5, 320, 327, 133}, // idx == 40 - {72, 5, 328, 335, 148}, // idx == 41 - {80, 5, 336, 343, 164}, // idx == 42 - {88, 5, 344, 351, 179}, // idx == 43 - {96, 5, 352, 359, 196}, // idx == 44 - {104, 5, 360, 367, 211}, // idx == 45 - {112, 5, 368, 375, 227}, // idx == 46 - {120, 5, 376, 383, 242}, // idx == 47 - {128, 5, 384, 391, 261}, // idx == 48 - {136, 5, 392, 399, 276}, // idx == 49 - {144, 5, 400, 407, 292}, // idx == 50 - {152, 5, 408, 415, 307}, // idx == 51 - {160, 5, 416, 423, 324}, // idx == 52 - {168, 5, 424, 431, 339}, // idx == 53 - {176, 5, 432, 439, 355}, // idx == 54 - {184, 5, 440, 447, 370}, // idx == 55 - {192, 5, 448, 455, 388}, // idx == 56 - {200, 5, 456, 463, 403}, // idx == 57 - {208, 5, 464, 471, 419}, // idx == 58 - {216, 5, 472, 479, 434}, // idx == 59 - {224, 5, 480, 487, 451}, // idx == 60 - {232, 5, 488, 495, 466}, // idx == 61 - {240, 5, 496, 503, 482}, // idx == 62 - {248, 5, 504, 511, 497}, // idx == 63 - {0, 6, 256, 259, 7}, // idx == 64 - {4, 6, 260, 263, 14}, // idx == 65 - {8, 6, 264, 267, 22}, // idx == 66 - {12, 6, 268, 271, 29}, // idx == 67 - {16, 6, 272, 275, 38}, // idx == 68 - {20, 6, 276, 279, 45}, // idx == 69 - {24, 6, 280, 283, 53}, // idx == 70 - {28, 6, 284, 287, 60}, // idx == 71 - {32, 6, 288, 291, 70}, // idx == 72 - {36, 6, 292, 295, 77}, // idx == 73 - {40, 6, 296, 299, 85}, // idx == 74 - {44, 6, 300, 303, 92}, // idx == 75 - {48, 6, 304, 307, 101}, // idx == 76 - {52, 6, 308, 311, 108}, // idx == 77 - {56, 6, 312, 315, 116}, // idx == 78 - {60, 6, 316, 319, 123}, // idx == 79 - {64, 6, 320, 323, 134}, // idx == 80 - {68, 6, 324, 327, 141}, // idx == 81 - {72, 6, 328, 331, 149}, // idx == 82 - {76, 6, 332, 335, 156}, // idx == 83 - {80, 6, 336, 339, 165}, // idx == 84 - {84, 6, 340, 343, 172}, // idx == 85 - {88, 6, 344, 347, 180}, // idx == 86 - {92, 6, 348, 351, 187}, // idx == 87 - {96, 6, 352, 355, 197}, // idx == 88 - {100, 6, 356, 359, 204}, // idx == 89 - {104, 6, 360, 363, 212}, // idx == 90 - {108, 6, 364, 367, 219}, // idx == 91 - {112, 6, 368, 371, 228}, // idx == 92 - {116, 6, 372, 375, 235}, // idx == 93 - {120, 6, 376, 379, 243}, // idx == 94 - {124, 6, 380, 383, 250}, // idx == 95 - {128, 6, 384, 387, 262}, // idx == 96 - {132, 6, 388, 391, 269}, // idx == 97 - {136, 6, 392, 395, 277}, // idx == 98 - {140, 6, 396, 399, 284}, // idx == 99 - {144, 6, 400, 403, 293}, // idx == 100 - {148, 6, 404, 407, 300}, // idx == 101 - {152, 6, 408, 411, 308}, // idx == 102 - {156, 6, 412, 415, 315}, // idx == 103 - {160, 6, 416, 419, 325}, // idx == 104 - {164, 6, 420, 423, 332}, // idx == 105 - {168, 6, 424, 427, 340}, // idx == 106 - {172, 6, 428, 431, 347}, // idx == 107 - {176, 6, 432, 435, 356}, // idx == 108 - {180, 6, 436, 439, 363}, // idx == 109 - {184, 6, 440, 443, 371}, // idx == 110 - {188, 6, 444, 447, 378}, // idx == 111 - {192, 6, 448, 451, 389}, // idx == 112 - {196, 6, 452, 455, 396}, // idx == 113 - {200, 6, 456, 459, 404}, // idx == 114 - {204, 6, 460, 463, 411}, // idx == 115 - {208, 6, 464, 467, 420}, // idx == 116 - {212, 6, 468, 471, 427}, // idx == 117 - {216, 6, 472, 475, 435}, // idx == 118 - {220, 6, 476, 479, 442}, // idx == 119 - {224, 6, 480, 483, 452}, // idx == 120 - {228, 6, 484, 487, 459}, // idx == 121 - {232, 6, 488, 491, 467}, // idx == 122 - {236, 6, 492, 495, 474}, // idx == 123 - {240, 6, 496, 499, 483}, // idx == 124 - {244, 6, 500, 503, 490}, // idx == 125 - {248, 6, 504, 507, 498}, // idx == 126 - {252, 6, 508, 511, 505}, // idx == 127 - {0, 7, 256, 257, 8}, // idx == 128 - {2, 7, 258, 259, 11}, // idx == 129 - {4, 7, 260, 261, 15}, // idx == 130 - {6, 7, 262, 263, 18}, // idx == 131 - {8, 7, 264, 265, 23}, // idx == 132 - {10, 7, 266, 267, 26}, // idx == 133 - {12, 7, 268, 269, 30}, // idx == 134 - {14, 7, 270, 271, 33}, // idx == 135 - {16, 7, 272, 273, 39}, // idx == 136 - {18, 7, 274, 275, 42}, // idx == 137 - {20, 7, 276, 277, 46}, // idx == 138 - {22, 7, 278, 279, 49}, // idx == 139 - {24, 7, 280, 281, 54}, // idx == 140 - {26, 7, 282, 283, 57}, // idx == 141 - {28, 7, 284, 285, 61}, // idx == 142 - {30, 7, 286, 287, 64}, // idx == 143 - {32, 7, 288, 289, 71}, // idx == 144 - {34, 7, 290, 291, 74}, // idx == 145 - {36, 7, 292, 293, 78}, // idx == 146 - {38, 7, 294, 295, 81}, // idx == 147 - {40, 7, 296, 297, 86}, // idx == 148 - {42, 7, 298, 299, 89}, // idx == 149 - {44, 7, 300, 301, 93}, // idx == 150 - {46, 7, 302, 303, 96}, // idx == 151 - {48, 7, 304, 305, 102}, // idx == 152 - {50, 7, 306, 307, 105}, // idx == 153 - {52, 7, 308, 309, 109}, // idx == 154 - {54, 7, 310, 311, 112}, // idx == 155 - {56, 7, 312, 313, 117}, // idx == 156 - {58, 7, 314, 315, 120}, // idx == 157 - {60, 7, 316, 317, 124}, // idx == 158 - {62, 7, 318, 319, 127}, // idx == 159 - {64, 7, 320, 321, 135}, // idx == 160 - {66, 7, 322, 323, 138}, // idx == 161 - {68, 7, 324, 325, 142}, // idx == 162 - {70, 7, 326, 327, 145}, // idx == 163 - {72, 7, 328, 329, 150}, // idx == 164 - {74, 7, 330, 331, 153}, // idx == 165 - {76, 7, 332, 333, 157}, // idx == 166 - {78, 7, 334, 335, 160}, // idx == 167 - {80, 7, 336, 337, 166}, // idx == 168 - {82, 7, 338, 339, 169}, // idx == 169 - {84, 7, 340, 341, 173}, // idx == 170 - {86, 7, 342, 343, 176}, // idx == 171 - {88, 7, 344, 345, 181}, // idx == 172 - {90, 7, 346, 347, 184}, // idx == 173 - {92, 7, 348, 349, 188}, // idx == 174 - {94, 7, 350, 351, 191}, // idx == 175 - {96, 7, 352, 353, 198}, // idx == 176 - {98, 7, 354, 355, 201}, // idx == 177 - {100, 7, 356, 357, 205}, // idx == 178 - {102, 7, 358, 359, 208}, // idx == 179 - {104, 7, 360, 361, 213}, // idx == 180 - {106, 7, 362, 363, 216}, // idx == 181 - {108, 7, 364, 365, 220}, // idx == 182 - {110, 7, 366, 367, 223}, // idx == 183 - {112, 7, 368, 369, 229}, // idx == 184 - {114, 7, 370, 371, 232}, // idx == 185 - {116, 7, 372, 373, 236}, // idx == 186 - {118, 7, 374, 375, 239}, // idx == 187 - {120, 7, 376, 377, 244}, // idx == 188 - {122, 7, 378, 379, 247}, // idx == 189 - {124, 7, 380, 381, 251}, // idx == 190 - {126, 7, 382, 383, 254}, // idx == 191 - {128, 7, 384, 385, 263}, // idx == 192 - {130, 7, 386, 387, 266}, // idx == 193 - {132, 7, 388, 389, 270}, // idx == 194 - {134, 7, 390, 391, 273}, // idx == 195 - {136, 7, 392, 393, 278}, // idx == 196 - {138, 7, 394, 395, 281}, // idx == 197 - {140, 7, 396, 397, 285}, // idx == 198 - {142, 7, 398, 399, 288}, // idx == 199 - {144, 7, 400, 401, 294}, // idx == 200 - {146, 7, 402, 403, 297}, // idx == 201 - {148, 7, 404, 405, 301}, // idx == 202 - {150, 7, 406, 407, 304}, // idx == 203 - {152, 7, 408, 409, 309}, // idx == 204 - {154, 7, 410, 411, 312}, // idx == 205 - {156, 7, 412, 413, 316}, // idx == 206 - {158, 7, 414, 415, 319}, // idx == 207 - {160, 7, 416, 417, 326}, // idx == 208 - {162, 7, 418, 419, 329}, // idx == 209 - {164, 7, 420, 421, 333}, // idx == 210 - {166, 7, 422, 423, 336}, // idx == 211 - {168, 7, 424, 425, 341}, // idx == 212 - {170, 7, 426, 427, 344}, // idx == 213 - {172, 7, 428, 429, 348}, // idx == 214 - {174, 7, 430, 431, 351}, // idx == 215 - {176, 7, 432, 433, 357}, // idx == 216 - {178, 7, 434, 435, 360}, // idx == 217 - {180, 7, 436, 437, 364}, // idx == 218 - {182, 7, 438, 439, 367}, // idx == 219 - {184, 7, 440, 441, 372}, // idx == 220 - {186, 7, 442, 443, 375}, // idx == 221 - {188, 7, 444, 445, 379}, // idx == 222 - {190, 7, 446, 447, 382}, // idx == 223 - {192, 7, 448, 449, 390}, // idx == 224 - {194, 7, 450, 451, 393}, // idx == 225 - {196, 7, 452, 453, 397}, // idx == 226 - {198, 7, 454, 455, 400}, // idx == 227 - {200, 7, 456, 457, 405}, // idx == 228 - {202, 7, 458, 459, 408}, // idx == 229 - {204, 7, 460, 461, 412}, // idx == 230 - {206, 7, 462, 463, 415}, // idx == 231 - {208, 7, 464, 465, 421}, // idx == 232 - {210, 7, 466, 467, 424}, // idx == 233 - {212, 7, 468, 469, 428}, // idx == 234 - {214, 7, 470, 471, 431}, // idx == 235 - {216, 7, 472, 473, 436}, // idx == 236 - {218, 7, 474, 475, 439}, // idx == 237 - {220, 7, 476, 477, 443}, // idx == 238 - {222, 7, 478, 479, 446}, // idx == 239 - {224, 7, 480, 481, 453}, // idx == 240 - {226, 7, 482, 483, 456}, // idx == 241 - {228, 7, 484, 485, 460}, // idx == 242 - {230, 7, 486, 487, 463}, // idx == 243 - {232, 7, 488, 489, 468}, // idx == 244 - {234, 7, 490, 491, 471}, // idx == 245 - {236, 7, 492, 493, 475}, // idx == 246 - {238, 7, 494, 495, 478}, // idx == 247 - {240, 7, 496, 497, 484}, // idx == 248 - {242, 7, 498, 499, 487}, // idx == 249 - {244, 7, 500, 501, 491}, // idx == 250 - {246, 7, 502, 503, 494}, // idx == 251 - {248, 7, 504, 505, 499}, // idx == 252 - {250, 7, 506, 507, 502}, // idx == 253 - {252, 7, 508, 509, 506}, // idx == 254 - {254, 7, 510, 511, 509}, // idx == 255 - {0, 8, 256, 256, 9}, // idx == 256 -- first host route - {1, 8, 257, 257, 10}, // idx == 257 - {2, 8, 258, 258, 12}, // idx == 258 - {3, 8, 259, 259, 13}, // idx == 259 - {4, 8, 260, 260, 16}, // idx == 260 - {5, 8, 261, 261, 17}, // idx == 261 - {6, 8, 262, 262, 19}, // idx == 262 - {7, 8, 263, 263, 20}, // idx == 263 - {8, 8, 264, 264, 24}, // idx == 264 - {9, 8, 265, 265, 25}, // idx == 265 - {10, 8, 266, 266, 27}, // idx == 266 - {11, 8, 267, 267, 28}, // idx == 267 - {12, 8, 268, 268, 31}, // idx == 268 - {13, 8, 269, 269, 32}, // idx == 269 - {14, 8, 270, 270, 34}, // idx == 270 - {15, 8, 271, 271, 35}, // idx == 271 - {16, 8, 272, 272, 40}, // idx == 272 - {17, 8, 273, 273, 41}, // idx == 273 - {18, 8, 274, 274, 43}, // idx == 274 - {19, 8, 275, 275, 44}, // idx == 275 - {20, 8, 276, 276, 47}, // idx == 276 - {21, 8, 277, 277, 48}, // idx == 277 - {22, 8, 278, 278, 50}, // idx == 278 - {23, 8, 279, 279, 51}, // idx == 279 - {24, 8, 280, 280, 55}, // idx == 280 - {25, 8, 281, 281, 56}, // idx == 281 - {26, 8, 282, 282, 58}, // idx == 282 - {27, 8, 283, 283, 59}, // idx == 283 - {28, 8, 284, 284, 62}, // idx == 284 - {29, 8, 285, 285, 63}, // idx == 285 - {30, 8, 286, 286, 65}, // idx == 286 - {31, 8, 287, 287, 66}, // idx == 287 - {32, 8, 288, 288, 72}, // idx == 288 - {33, 8, 289, 289, 73}, // idx == 289 - {34, 8, 290, 290, 75}, // idx == 290 - {35, 8, 291, 291, 76}, // idx == 291 - {36, 8, 292, 292, 79}, // idx == 292 - {37, 8, 293, 293, 80}, // idx == 293 - {38, 8, 294, 294, 82}, // idx == 294 - {39, 8, 295, 295, 83}, // idx == 295 - {40, 8, 296, 296, 87}, // idx == 296 - {41, 8, 297, 297, 88}, // idx == 297 - {42, 8, 298, 298, 90}, // idx == 298 - {43, 8, 299, 299, 91}, // idx == 299 - {44, 8, 300, 300, 94}, // idx == 300 - {45, 8, 301, 301, 95}, // idx == 301 - {46, 8, 302, 302, 97}, // idx == 302 - {47, 8, 303, 303, 98}, // idx == 303 - {48, 8, 304, 304, 103}, // idx == 304 - {49, 8, 305, 305, 104}, // idx == 305 - {50, 8, 306, 306, 106}, // idx == 306 - {51, 8, 307, 307, 107}, // idx == 307 - {52, 8, 308, 308, 110}, // idx == 308 - {53, 8, 309, 309, 111}, // idx == 309 - {54, 8, 310, 310, 113}, // idx == 310 - {55, 8, 311, 311, 114}, // idx == 311 - {56, 8, 312, 312, 118}, // idx == 312 - {57, 8, 313, 313, 119}, // idx == 313 - {58, 8, 314, 314, 121}, // idx == 314 - {59, 8, 315, 315, 122}, // idx == 315 - {60, 8, 316, 316, 125}, // idx == 316 - {61, 8, 317, 317, 126}, // idx == 317 - {62, 8, 318, 318, 128}, // idx == 318 - {63, 8, 319, 319, 129}, // idx == 319 - {64, 8, 320, 320, 136}, // idx == 320 - {65, 8, 321, 321, 137}, // idx == 321 - {66, 8, 322, 322, 139}, // idx == 322 - {67, 8, 323, 323, 140}, // idx == 323 - {68, 8, 324, 324, 143}, // idx == 324 - {69, 8, 325, 325, 144}, // idx == 325 - {70, 8, 326, 326, 146}, // idx == 326 - {71, 8, 327, 327, 147}, // idx == 327 - {72, 8, 328, 328, 151}, // idx == 328 - {73, 8, 329, 329, 152}, // idx == 329 - {74, 8, 330, 330, 154}, // idx == 330 - {75, 8, 331, 331, 155}, // idx == 331 - {76, 8, 332, 332, 158}, // idx == 332 - {77, 8, 333, 333, 159}, // idx == 333 - {78, 8, 334, 334, 161}, // idx == 334 - {79, 8, 335, 335, 162}, // idx == 335 - {80, 8, 336, 336, 167}, // idx == 336 - {81, 8, 337, 337, 168}, // idx == 337 - {82, 8, 338, 338, 170}, // idx == 338 - {83, 8, 339, 339, 171}, // idx == 339 - {84, 8, 340, 340, 174}, // idx == 340 - {85, 8, 341, 341, 175}, // idx == 341 - {86, 8, 342, 342, 177}, // idx == 342 - {87, 8, 343, 343, 178}, // idx == 343 - {88, 8, 344, 344, 182}, // idx == 344 - {89, 8, 345, 345, 183}, // idx == 345 - {90, 8, 346, 346, 185}, // idx == 346 - {91, 8, 347, 347, 186}, // idx == 347 - {92, 8, 348, 348, 189}, // idx == 348 - {93, 8, 349, 349, 190}, // idx == 349 - {94, 8, 350, 350, 192}, // idx == 350 - {95, 8, 351, 351, 193}, // idx == 351 - {96, 8, 352, 352, 199}, // idx == 352 - {97, 8, 353, 353, 200}, // idx == 353 - {98, 8, 354, 354, 202}, // idx == 354 - {99, 8, 355, 355, 203}, // idx == 355 - {100, 8, 356, 356, 206}, // idx == 356 - {101, 8, 357, 357, 207}, // idx == 357 - {102, 8, 358, 358, 209}, // idx == 358 - {103, 8, 359, 359, 210}, // idx == 359 - {104, 8, 360, 360, 214}, // idx == 360 - {105, 8, 361, 361, 215}, // idx == 361 - {106, 8, 362, 362, 217}, // idx == 362 - {107, 8, 363, 363, 218}, // idx == 363 - {108, 8, 364, 364, 221}, // idx == 364 - {109, 8, 365, 365, 222}, // idx == 365 - {110, 8, 366, 366, 224}, // idx == 366 - {111, 8, 367, 367, 225}, // idx == 367 - {112, 8, 368, 368, 230}, // idx == 368 - {113, 8, 369, 369, 231}, // idx == 369 - {114, 8, 370, 370, 233}, // idx == 370 - {115, 8, 371, 371, 234}, // idx == 371 - {116, 8, 372, 372, 237}, // idx == 372 - {117, 8, 373, 373, 238}, // idx == 373 - {118, 8, 374, 374, 240}, // idx == 374 - {119, 8, 375, 375, 241}, // idx == 375 - {120, 8, 376, 376, 245}, // idx == 376 - {121, 8, 377, 377, 246}, // idx == 377 - {122, 8, 378, 378, 248}, // idx == 378 - {123, 8, 379, 379, 249}, // idx == 379 - {124, 8, 380, 380, 252}, // idx == 380 - {125, 8, 381, 381, 253}, // idx == 381 - {126, 8, 382, 382, 255}, // idx == 382 - {127, 8, 383, 383, 256}, // idx == 383 - {128, 8, 384, 384, 264}, // idx == 384 - {129, 8, 385, 385, 265}, // idx == 385 - {130, 8, 386, 386, 267}, // idx == 386 - {131, 8, 387, 387, 268}, // idx == 387 - {132, 8, 388, 388, 271}, // idx == 388 - {133, 8, 389, 389, 272}, // idx == 389 - {134, 8, 390, 390, 274}, // idx == 390 - {135, 8, 391, 391, 275}, // idx == 391 - {136, 8, 392, 392, 279}, // idx == 392 - {137, 8, 393, 393, 280}, // idx == 393 - {138, 8, 394, 394, 282}, // idx == 394 - {139, 8, 395, 395, 283}, // idx == 395 - {140, 8, 396, 396, 286}, // idx == 396 - {141, 8, 397, 397, 287}, // idx == 397 - {142, 8, 398, 398, 289}, // idx == 398 - {143, 8, 399, 399, 290}, // idx == 399 - {144, 8, 400, 400, 295}, // idx == 400 - {145, 8, 401, 401, 296}, // idx == 401 - {146, 8, 402, 402, 298}, // idx == 402 - {147, 8, 403, 403, 299}, // idx == 403 - {148, 8, 404, 404, 302}, // idx == 404 - {149, 8, 405, 405, 303}, // idx == 405 - {150, 8, 406, 406, 305}, // idx == 406 - {151, 8, 407, 407, 306}, // idx == 407 - {152, 8, 408, 408, 310}, // idx == 408 - {153, 8, 409, 409, 311}, // idx == 409 - {154, 8, 410, 410, 313}, // idx == 410 - {155, 8, 411, 411, 314}, // idx == 411 - {156, 8, 412, 412, 317}, // idx == 412 - {157, 8, 413, 413, 318}, // idx == 413 - {158, 8, 414, 414, 320}, // idx == 414 - {159, 8, 415, 415, 321}, // idx == 415 - {160, 8, 416, 416, 327}, // idx == 416 - {161, 8, 417, 417, 328}, // idx == 417 - {162, 8, 418, 418, 330}, // idx == 418 - {163, 8, 419, 419, 331}, // idx == 419 - {164, 8, 420, 420, 334}, // idx == 420 - {165, 8, 421, 421, 335}, // idx == 421 - {166, 8, 422, 422, 337}, // idx == 422 - {167, 8, 423, 423, 338}, // idx == 423 - {168, 8, 424, 424, 342}, // idx == 424 - {169, 8, 425, 425, 343}, // idx == 425 - {170, 8, 426, 426, 345}, // idx == 426 - {171, 8, 427, 427, 346}, // idx == 427 - {172, 8, 428, 428, 349}, // idx == 428 - {173, 8, 429, 429, 350}, // idx == 429 - {174, 8, 430, 430, 352}, // idx == 430 - {175, 8, 431, 431, 353}, // idx == 431 - {176, 8, 432, 432, 358}, // idx == 432 - {177, 8, 433, 433, 359}, // idx == 433 - {178, 8, 434, 434, 361}, // idx == 434 - {179, 8, 435, 435, 362}, // idx == 435 - {180, 8, 436, 436, 365}, // idx == 436 - {181, 8, 437, 437, 366}, // idx == 437 - {182, 8, 438, 438, 368}, // idx == 438 - {183, 8, 439, 439, 369}, // idx == 439 - {184, 8, 440, 440, 373}, // idx == 440 - {185, 8, 441, 441, 374}, // idx == 441 - {186, 8, 442, 442, 376}, // idx == 442 - {187, 8, 443, 443, 377}, // idx == 443 - {188, 8, 444, 444, 380}, // idx == 444 - {189, 8, 445, 445, 381}, // idx == 445 - {190, 8, 446, 446, 383}, // idx == 446 - {191, 8, 447, 447, 384}, // idx == 447 - {192, 8, 448, 448, 391}, // idx == 448 - {193, 8, 449, 449, 392}, // idx == 449 - {194, 8, 450, 450, 394}, // idx == 450 - {195, 8, 451, 451, 395}, // idx == 451 - {196, 8, 452, 452, 398}, // idx == 452 - {197, 8, 453, 453, 399}, // idx == 453 - {198, 8, 454, 454, 401}, // idx == 454 - {199, 8, 455, 455, 402}, // idx == 455 - {200, 8, 456, 456, 406}, // idx == 456 - {201, 8, 457, 457, 407}, // idx == 457 - {202, 8, 458, 458, 409}, // idx == 458 - {203, 8, 459, 459, 410}, // idx == 459 - {204, 8, 460, 460, 413}, // idx == 460 - {205, 8, 461, 461, 414}, // idx == 461 - {206, 8, 462, 462, 416}, // idx == 462 - {207, 8, 463, 463, 417}, // idx == 463 - {208, 8, 464, 464, 422}, // idx == 464 - {209, 8, 465, 465, 423}, // idx == 465 - {210, 8, 466, 466, 425}, // idx == 466 - {211, 8, 467, 467, 426}, // idx == 467 - {212, 8, 468, 468, 429}, // idx == 468 - {213, 8, 469, 469, 430}, // idx == 469 - {214, 8, 470, 470, 432}, // idx == 470 - {215, 8, 471, 471, 433}, // idx == 471 - {216, 8, 472, 472, 437}, // idx == 472 - {217, 8, 473, 473, 438}, // idx == 473 - {218, 8, 474, 474, 440}, // idx == 474 - {219, 8, 475, 475, 441}, // idx == 475 - {220, 8, 476, 476, 444}, // idx == 476 - {221, 8, 477, 477, 445}, // idx == 477 - {222, 8, 478, 478, 447}, // idx == 478 - {223, 8, 479, 479, 448}, // idx == 479 - {224, 8, 480, 480, 454}, // idx == 480 - {225, 8, 481, 481, 455}, // idx == 481 - {226, 8, 482, 482, 457}, // idx == 482 - {227, 8, 483, 483, 458}, // idx == 483 - {228, 8, 484, 484, 461}, // idx == 484 - {229, 8, 485, 485, 462}, // idx == 485 - {230, 8, 486, 486, 464}, // idx == 486 - {231, 8, 487, 487, 465}, // idx == 487 - {232, 8, 488, 488, 469}, // idx == 488 - {233, 8, 489, 489, 470}, // idx == 489 - {234, 8, 490, 490, 472}, // idx == 490 - {235, 8, 491, 491, 473}, // idx == 491 - {236, 8, 492, 492, 476}, // idx == 492 - {237, 8, 493, 493, 477}, // idx == 493 - {238, 8, 494, 494, 479}, // idx == 494 - {239, 8, 495, 495, 480}, // idx == 495 - {240, 8, 496, 496, 485}, // idx == 496 - {241, 8, 497, 497, 486}, // idx == 497 - {242, 8, 498, 498, 488}, // idx == 498 - {243, 8, 499, 499, 489}, // idx == 499 - {244, 8, 500, 500, 492}, // idx == 500 - {245, 8, 501, 501, 493}, // idx == 501 - {246, 8, 502, 502, 495}, // idx == 502 - {247, 8, 503, 503, 496}, // idx == 503 - {248, 8, 504, 504, 500}, // idx == 504 - {249, 8, 505, 505, 501}, // idx == 505 - {250, 8, 506, 506, 503}, // idx == 506 - {251, 8, 507, 507, 504}, // idx == 507 - {252, 8, 508, 508, 507}, // idx == 508 - {253, 8, 509, 509, 508}, // idx == 509 - {254, 8, 510, 510, 510}, // idx == 510 - {255, 8, 511, 511, 511}, // idx == 511 + {0, -1}, // idx == 0, invalid + {0, 0}, // idx == 1 + {0, 1}, // idx == 2 + {128, 1}, // idx == 3, e.g. 128.0.0.0/1, 8000::/1 + {0, 2}, // idx == 4 + {64, 2}, // idx == 5 + {128, 2}, // idx == 6 + {192, 2}, // idx == 7 + {0, 3}, // idx == 8 + {32, 3}, // idx == 9 + {64, 3}, // idx == 10 + {96, 3}, // idx == 11 + {128, 3}, // idx == 12 + {160, 3}, // idx == 13 + {192, 3}, // idx == 14 + {224, 3}, // idx == 15 + {0, 4}, // idx == 16 + {16, 4}, // idx == 17 + {32, 4}, // idx == 18 + {48, 4}, // idx == 19 + {64, 4}, // idx == 20 + {80, 4}, // idx == 21 + {96, 4}, // idx == 22 + {112, 4}, // idx == 23 + {128, 4}, // idx == 24 + {144, 4}, // idx == 25 + {160, 4}, // idx == 26 + {176, 4}, // idx == 27 + {192, 4}, // idx == 28 + {208, 4}, // idx == 29 + {224, 4}, // idx == 30 + {240, 4}, // idx == 31 + {0, 5}, // idx == 32 + {8, 5}, // idx == 33 + {16, 5}, // idx == 34 + {24, 5}, // idx == 35 + {32, 5}, // idx == 36 + {40, 5}, // idx == 37 + {48, 5}, // idx == 38 + {56, 5}, // idx == 39 + {64, 5}, // idx == 40 + {72, 5}, // idx == 41 + {80, 5}, // idx == 42 + {88, 5}, // idx == 43 + {96, 5}, // idx == 44 + {104, 5}, // idx == 45 + {112, 5}, // idx == 46 + {120, 5}, // idx == 47 + {128, 5}, // idx == 48 + {136, 5}, // idx == 49 + {144, 5}, // idx == 50 + {152, 5}, // idx == 51 + {160, 5}, // idx == 52 + {168, 5}, // idx == 53 + {176, 5}, // idx == 54 + {184, 5}, // idx == 55 + {192, 5}, // idx == 56 + {200, 5}, // idx == 57 + {208, 5}, // idx == 58 + {216, 5}, // idx == 59 + {224, 5}, // idx == 60 + {232, 5}, // idx == 61 + {240, 5}, // idx == 62 + {248, 5}, // idx == 63 + {0, 6}, // idx == 64 + {4, 6}, // idx == 65 + {8, 6}, // idx == 66 + {12, 6}, // idx == 67 + {16, 6}, // idx == 68 + {20, 6}, // idx == 69 + {24, 6}, // idx == 70 + {28, 6}, // idx == 71 + {32, 6}, // idx == 72 + {36, 6}, // idx == 73 + {40, 6}, // idx == 74 + {44, 6}, // idx == 75 + {48, 6}, // idx == 76 + {52, 6}, // idx == 77 + {56, 6}, // idx == 78 + {60, 6}, // idx == 79 + {64, 6}, // idx == 80 + {68, 6}, // idx == 81 + {72, 6}, // idx == 82 + {76, 6}, // idx == 83 + {80, 6}, // idx == 84 + {84, 6}, // idx == 85 + {88, 6}, // idx == 86 + {92, 6}, // idx == 87 + {96, 6}, // idx == 88 + {100, 6}, // idx == 89 + {104, 6}, // idx == 90 + {108, 6}, // idx == 91 + {112, 6}, // idx == 92 + {116, 6}, // idx == 93 + {120, 6}, // idx == 94 + {124, 6}, // idx == 95 + {128, 6}, // idx == 96 + {132, 6}, // idx == 97 + {136, 6}, // idx == 98 + {140, 6}, // idx == 99 + {144, 6}, // idx == 100 + {148, 6}, // idx == 101 + {152, 6}, // idx == 102 + {156, 6}, // idx == 103 + {160, 6}, // idx == 104 + {164, 6}, // idx == 105 + {168, 6}, // idx == 106 + {172, 6}, // idx == 107 + {176, 6}, // idx == 108 + {180, 6}, // idx == 109 + {184, 6}, // idx == 110 + {188, 6}, // idx == 111 + {192, 6}, // idx == 112 + {196, 6}, // idx == 113 + {200, 6}, // idx == 114 + {204, 6}, // idx == 115 + {208, 6}, // idx == 116 + {212, 6}, // idx == 117 + {216, 6}, // idx == 118 + {220, 6}, // idx == 119 + {224, 6}, // idx == 120 + {228, 6}, // idx == 121 + {232, 6}, // idx == 122 + {236, 6}, // idx == 123 + {240, 6}, // idx == 124 + {244, 6}, // idx == 125 + {248, 6}, // idx == 126 + {252, 6}, // idx == 127 + {0, 7}, // idx == 128 + {2, 7}, // idx == 129 + {4, 7}, // idx == 130 + {6, 7}, // idx == 131 + {8, 7}, // idx == 132 + {10, 7}, // idx == 133 + {12, 7}, // idx == 134 + {14, 7}, // idx == 135 + {16, 7}, // idx == 136 + {18, 7}, // idx == 137 + {20, 7}, // idx == 138 + {22, 7}, // idx == 139 + {24, 7}, // idx == 140 + {26, 7}, // idx == 141 + {28, 7}, // idx == 142 + {30, 7}, // idx == 143 + {32, 7}, // idx == 144 + {34, 7}, // idx == 145 + {36, 7}, // idx == 146 + {38, 7}, // idx == 147 + {40, 7}, // idx == 148 + {42, 7}, // idx == 149 + {44, 7}, // idx == 150 + {46, 7}, // idx == 151 + {48, 7}, // idx == 152 + {50, 7}, // idx == 153 + {52, 7}, // idx == 154 + {54, 7}, // idx == 155 + {56, 7}, // idx == 156 + {58, 7}, // idx == 157 + {60, 7}, // idx == 158 + {62, 7}, // idx == 159 + {64, 7}, // idx == 160 + {66, 7}, // idx == 161 + {68, 7}, // idx == 162 + {70, 7}, // idx == 163 + {72, 7}, // idx == 164 + {74, 7}, // idx == 165 + {76, 7}, // idx == 166 + {78, 7}, // idx == 167 + {80, 7}, // idx == 168 + {82, 7}, // idx == 169 + {84, 7}, // idx == 170 + {86, 7}, // idx == 171 + {88, 7}, // idx == 172 + {90, 7}, // idx == 173 + {92, 7}, // idx == 174 + {94, 7}, // idx == 175 + {96, 7}, // idx == 176 + {98, 7}, // idx == 177 + {100, 7}, // idx == 178 + {102, 7}, // idx == 179 + {104, 7}, // idx == 180 + {106, 7}, // idx == 181 + {108, 7}, // idx == 182 + {110, 7}, // idx == 183 + {112, 7}, // idx == 184 + {114, 7}, // idx == 185 + {116, 7}, // idx == 186 + {118, 7}, // idx == 187 + {120, 7}, // idx == 188 + {122, 7}, // idx == 189 + {124, 7}, // idx == 190 + {126, 7}, // idx == 191 + {128, 7}, // idx == 192 + {130, 7}, // idx == 193 + {132, 7}, // idx == 194 + {134, 7}, // idx == 195 + {136, 7}, // idx == 196 + {138, 7}, // idx == 197 + {140, 7}, // idx == 198 + {142, 7}, // idx == 199 + {144, 7}, // idx == 200 + {146, 7}, // idx == 201 + {148, 7}, // idx == 202 + {150, 7}, // idx == 203 + {152, 7}, // idx == 204 + {154, 7}, // idx == 205 + {156, 7}, // idx == 206 + {158, 7}, // idx == 207 + {160, 7}, // idx == 208 + {162, 7}, // idx == 209 + {164, 7}, // idx == 210 + {166, 7}, // idx == 211 + {168, 7}, // idx == 212 + {170, 7}, // idx == 213 + {172, 7}, // idx == 214 + {174, 7}, // idx == 215 + {176, 7}, // idx == 216 + {178, 7}, // idx == 217 + {180, 7}, // idx == 218 + {182, 7}, // idx == 219 + {184, 7}, // idx == 220 + {186, 7}, // idx == 221 + {188, 7}, // idx == 222 + {190, 7}, // idx == 223 + {192, 7}, // idx == 224 + {194, 7}, // idx == 225 + {196, 7}, // idx == 226 + {198, 7}, // idx == 227 + {200, 7}, // idx == 228 + {202, 7}, // idx == 229 + {204, 7}, // idx == 230 + {206, 7}, // idx == 231 + {208, 7}, // idx == 232 + {210, 7}, // idx == 233 + {212, 7}, // idx == 234 + {214, 7}, // idx == 235 + {216, 7}, // idx == 236 + {218, 7}, // idx == 237 + {220, 7}, // idx == 238 + {222, 7}, // idx == 239 + {224, 7}, // idx == 240 + {226, 7}, // idx == 241 + {228, 7}, // idx == 242 + {230, 7}, // idx == 243 + {232, 7}, // idx == 244 + {234, 7}, // idx == 245 + {236, 7}, // idx == 246 + {238, 7}, // idx == 247 + {240, 7}, // idx == 248 + {242, 7}, // idx == 249 + {244, 7}, // idx == 250 + {246, 7}, // idx == 251 + {248, 7}, // idx == 252 + {250, 7}, // idx == 253 + {252, 7}, // idx == 254 + {254, 7}, // idx == 255 + // + // host routes, pfxLen == 8 + // + {0, 8}, // idx == 256, e.g. 0.0.0.0/8, ::/8 + {1, 8}, // idx == 257 + {2, 8}, // idx == 258 + {3, 8}, // idx == 259 + {4, 8}, // idx == 260 + {5, 8}, // idx == 261 + {6, 8}, // idx == 262 + {7, 8}, // idx == 263 + {8, 8}, // idx == 264 + {9, 8}, // idx == 265 + {10, 8}, // idx == 266, 10.0.0.0/8, 0a00::/8 + {11, 8}, // idx == 267 + {12, 8}, // idx == 268 + {13, 8}, // idx == 269 + {14, 8}, // idx == 270 + {15, 8}, // idx == 271 + {16, 8}, // idx == 272 + {17, 8}, // idx == 273 + {18, 8}, // idx == 274 + {19, 8}, // idx == 275 + {20, 8}, // idx == 276 + {21, 8}, // idx == 277 + {22, 8}, // idx == 278 + {23, 8}, // idx == 279 + {24, 8}, // idx == 280 + {25, 8}, // idx == 281 + {26, 8}, // idx == 282 + {27, 8}, // idx == 283 + {28, 8}, // idx == 284 + {29, 8}, // idx == 285 + {30, 8}, // idx == 286 + {31, 8}, // idx == 287 + {32, 8}, // idx == 288 + {33, 8}, // idx == 289 + {34, 8}, // idx == 290 + {35, 8}, // idx == 291 + {36, 8}, // idx == 292 + {37, 8}, // idx == 293 + {38, 8}, // idx == 294 + {39, 8}, // idx == 295 + {40, 8}, // idx == 296 + {41, 8}, // idx == 297 + {42, 8}, // idx == 298 + {43, 8}, // idx == 299 + {44, 8}, // idx == 300 + {45, 8}, // idx == 301 + {46, 8}, // idx == 302 + {47, 8}, // idx == 303 + {48, 8}, // idx == 304 + {49, 8}, // idx == 305 + {50, 8}, // idx == 306 + {51, 8}, // idx == 307 + {52, 8}, // idx == 308 + {53, 8}, // idx == 309 + {54, 8}, // idx == 310 + {55, 8}, // idx == 311 + {56, 8}, // idx == 312 + {57, 8}, // idx == 313 + {58, 8}, // idx == 314 + {59, 8}, // idx == 315 + {60, 8}, // idx == 316 + {61, 8}, // idx == 317 + {62, 8}, // idx == 318 + {63, 8}, // idx == 319 + {64, 8}, // idx == 320 + {65, 8}, // idx == 321 + {66, 8}, // idx == 322 + {67, 8}, // idx == 323 + {68, 8}, // idx == 324 + {69, 8}, // idx == 325 + {70, 8}, // idx == 326 + {71, 8}, // idx == 327 + {72, 8}, // idx == 328 + {73, 8}, // idx == 329 + {74, 8}, // idx == 330 + {75, 8}, // idx == 331 + {76, 8}, // idx == 332 + {77, 8}, // idx == 333 + {78, 8}, // idx == 334 + {79, 8}, // idx == 335 + {80, 8}, // idx == 336 + {81, 8}, // idx == 337 + {82, 8}, // idx == 338 + {83, 8}, // idx == 339 + {84, 8}, // idx == 340 + {85, 8}, // idx == 341 + {86, 8}, // idx == 342 + {87, 8}, // idx == 343 + {88, 8}, // idx == 344 + {89, 8}, // idx == 345 + {90, 8}, // idx == 346 + {91, 8}, // idx == 347 + {92, 8}, // idx == 348 + {93, 8}, // idx == 349 + {94, 8}, // idx == 350 + {95, 8}, // idx == 351 + {96, 8}, // idx == 352 + {97, 8}, // idx == 353 + {98, 8}, // idx == 354 + {99, 8}, // idx == 355 + {100, 8}, // idx == 356 + {101, 8}, // idx == 357 + {102, 8}, // idx == 358 + {103, 8}, // idx == 359 + {104, 8}, // idx == 360 + {105, 8}, // idx == 361 + {106, 8}, // idx == 362 + {107, 8}, // idx == 363 + {108, 8}, // idx == 364 + {109, 8}, // idx == 365 + {110, 8}, // idx == 366 + {111, 8}, // idx == 367 + {112, 8}, // idx == 368 + {113, 8}, // idx == 369 + {114, 8}, // idx == 370 + {115, 8}, // idx == 371 + {116, 8}, // idx == 372 + {117, 8}, // idx == 373 + {118, 8}, // idx == 374 + {119, 8}, // idx == 375 + {120, 8}, // idx == 376 + {121, 8}, // idx == 377 + {122, 8}, // idx == 378 + {123, 8}, // idx == 379 + {124, 8}, // idx == 380 + {125, 8}, // idx == 381 + {126, 8}, // idx == 382 + {127, 8}, // idx == 383 + {128, 8}, // idx == 384 + {129, 8}, // idx == 385 + {130, 8}, // idx == 386 + {131, 8}, // idx == 387 + {132, 8}, // idx == 388 + {133, 8}, // idx == 389 + {134, 8}, // idx == 390 + {135, 8}, // idx == 391 + {136, 8}, // idx == 392 + {137, 8}, // idx == 393 + {138, 8}, // idx == 394 + {139, 8}, // idx == 395 + {140, 8}, // idx == 396 + {141, 8}, // idx == 397 + {142, 8}, // idx == 398 + {143, 8}, // idx == 399 + {144, 8}, // idx == 400 + {145, 8}, // idx == 401 + {146, 8}, // idx == 402 + {147, 8}, // idx == 403 + {148, 8}, // idx == 404 + {149, 8}, // idx == 405 + {150, 8}, // idx == 406 + {151, 8}, // idx == 407 + {152, 8}, // idx == 408 + {153, 8}, // idx == 409 + {154, 8}, // idx == 410 + {155, 8}, // idx == 411 + {156, 8}, // idx == 412 + {157, 8}, // idx == 413 + {158, 8}, // idx == 414 + {159, 8}, // idx == 415 + {160, 8}, // idx == 416 + {161, 8}, // idx == 417 + {162, 8}, // idx == 418 + {163, 8}, // idx == 419 + {164, 8}, // idx == 420 + {165, 8}, // idx == 421 + {166, 8}, // idx == 422 + {167, 8}, // idx == 423 + {168, 8}, // idx == 424 + {169, 8}, // idx == 425 + {170, 8}, // idx == 426 + {171, 8}, // idx == 427 + {172, 8}, // idx == 428 + {173, 8}, // idx == 429 + {174, 8}, // idx == 430 + {175, 8}, // idx == 431 + {176, 8}, // idx == 432 + {177, 8}, // idx == 433 + {178, 8}, // idx == 434 + {179, 8}, // idx == 435 + {180, 8}, // idx == 436 + {181, 8}, // idx == 437 + {182, 8}, // idx == 438 + {183, 8}, // idx == 439 + {184, 8}, // idx == 440 + {185, 8}, // idx == 441 + {186, 8}, // idx == 442 + {187, 8}, // idx == 443 + {188, 8}, // idx == 444 + {189, 8}, // idx == 445 + {190, 8}, // idx == 446 + {191, 8}, // idx == 447 + {192, 8}, // idx == 448 + {193, 8}, // idx == 449 + {194, 8}, // idx == 450 + {195, 8}, // idx == 451 + {196, 8}, // idx == 452 + {197, 8}, // idx == 453 + {198, 8}, // idx == 454 + {199, 8}, // idx == 455 + {200, 8}, // idx == 456 + {201, 8}, // idx == 457 + {202, 8}, // idx == 458 + {203, 8}, // idx == 459 + {204, 8}, // idx == 460 + {205, 8}, // idx == 461 + {206, 8}, // idx == 462 + {207, 8}, // idx == 463 + {208, 8}, // idx == 464 + {209, 8}, // idx == 465 + {210, 8}, // idx == 466 + {211, 8}, // idx == 467 + {212, 8}, // idx == 468 + {213, 8}, // idx == 469 + {214, 8}, // idx == 470 + {215, 8}, // idx == 471 + {216, 8}, // idx == 472 + {217, 8}, // idx == 473 + {218, 8}, // idx == 474 + {219, 8}, // idx == 475 + {220, 8}, // idx == 476 + {221, 8}, // idx == 477 + {222, 8}, // idx == 478 + {223, 8}, // idx == 479 + {224, 8}, // idx == 480 + {225, 8}, // idx == 481 + {226, 8}, // idx == 482 + {227, 8}, // idx == 483 + {228, 8}, // idx == 484 + {229, 8}, // idx == 485 + {230, 8}, // idx == 486 + {231, 8}, // idx == 487 + {232, 8}, // idx == 488 + {233, 8}, // idx == 489 + {234, 8}, // idx == 490 + {235, 8}, // idx == 491 + {236, 8}, // idx == 492 + {237, 8}, // idx == 493 + {238, 8}, // idx == 494 + {239, 8}, // idx == 495 + {240, 8}, // idx == 496 + {241, 8}, // idx == 497 + {242, 8}, // idx == 498 + {243, 8}, // idx == 499 + {244, 8}, // idx == 500 + {245, 8}, // idx == 501 + {246, 8}, // idx == 502 + {247, 8}, // idx == 503 + {248, 8}, // idx == 504 + {249, 8}, // idx == 505 + {250, 8}, // idx == 506 + {251, 8}, // idx == 507 + {252, 8}, // idx == 508 + {253, 8}, // idx == 509 + {254, 8}, // idx == 510 + {255, 8}, // idx == 511 } diff --git a/vendor/github.com/gaissmai/bart/dumper.go b/vendor/github.com/gaissmai/bart/dumper.go index 2f7c23d..97e15b7 100644 --- a/vendor/github.com/gaissmai/bart/dumper.go +++ b/vendor/github.com/gaissmai/bart/dumper.go @@ -14,9 +14,9 @@ type nodeType byte const ( nullNode nodeType = iota // empty node - fullNode // prefixes and children - leafNode // only prefixes - intermediateNode // only children + fullNode // prefixes and children or path-compressed prefixes + leafNode // no children, only prefixes or path-compressed prefixes + intermediateNode // only children, no prefix nor path-compressed prefixes ) // ################################################## @@ -27,65 +27,47 @@ const ( func (t *Table[V]) dumpString() string { w := new(strings.Builder) t.dump(w) + return w.String() } // dump the table structure and all the nodes to w. -// -// Output: -// -// [FULL] depth: 0 path: [] / 0 -// indexs(#6): 1 66 128 133 266 383 -// prefxs(#6): 0/0 8/6 0/7 10/7 10/8 127/8 -// childs(#3): 10 127 192 -// -// .[IMED] depth: 1 path: [10] / 8 -// .childs(#1): 0 -// -// ..[LEAF] depth: 2 path: [10.0] / 16 -// ..indexs(#2): 256 257 -// ..prefxs(#2): 0/8 1/8 -// -// .[IMED] depth: 1 path: [127] / 8 -// .childs(#1): 0 -// -// ..[IMED] depth: 2 path: [127.0] / 16 -// ..childs(#1): 0 -// -// ...[LEAF] depth: 3 path: [127.0.0] / 24 -// ...indexs(#1): 257 -// ...prefxs(#1): 1/8 -// -// ... func (t *Table[V]) dump(w io.Writer) { - t.init() + if t == nil { + return + } - fmt.Fprint(w, "### IPv4:") - t.rootV4.dumpRec(w, zeroPath, 0, true) + if t.size4 > 0 { + fmt.Fprintln(w) + fmt.Fprintf(w, "### IPv4: size(%d), nodes(%d)", t.size4, t.root4.nodeStatsRec().nodes) + t.root4.dumpRec(w, stridePath{}, 0, true) + } - fmt.Fprint(w, "### IPv6:") - t.rootV6.dumpRec(w, zeroPath, 0, false) + if t.size6 > 0 { + fmt.Fprintln(w) + fmt.Fprintf(w, "### IPv6: size(%d), nodes(%d)", t.size6, t.root6.nodeStatsRec().nodes) + t.root6.dumpRec(w, stridePath{}, 0, false) + } } // dumpRec, rec-descent the trie. -func (n *node[V]) dumpRec(w io.Writer, path [16]byte, depth int, is4 bool) { +func (n *node[V]) dumpRec(w io.Writer, path stridePath, depth int, is4 bool) { + // dump this node n.dump(w, path, depth, is4) - // make backing arrays, no heap allocs - addrBackingArray := [maxNodeChildren]uint{} - - // the node may have childs, the rec-descent monster starts - for i, addr := range n.allChildAddrs(addrBackingArray[:]) { + // the node may have childs, rec-descent down + for i, addr := range n.children.All() { octet := byte(addr) - child := n.children[i] path[depth] = octet - child.dumpRec(w, path, depth+1, is4) + if child, ok := n.children.Items[i].(*node[V]); ok { + child.dumpRec(w, path, depth+1, is4) + } } } // dump the node to w. -func (n *node[V]) dump(w io.Writer, path [16]byte, depth int, is4 bool) { +func (n *node[V]) dump(w io.Writer, path stridePath, depth int, is4 bool) { bits := depth * strideLen indent := strings.Repeat(".", depth) @@ -93,42 +75,97 @@ func (n *node[V]) dump(w io.Writer, path [16]byte, depth int, is4 bool) { fmt.Fprintf(w, "\n%s[%s] depth: %d path: [%s] / %d\n", indent, n.hasType(), depth, ipStridePath(path, depth, is4), bits) - if nPfxLen := len(n.prefixes); nPfxLen != 0 { - // make backing arrays, no heap allocs - idxBackingArray := [maxNodePrefixes]uint{} - allIndices := n.allStrideIndexes(idxBackingArray[:]) + if nPfxCount := n.prefixes.Len(); nPfxCount != 0 { + // no heap allocs + allIndices := n.prefixes.All() // print the baseIndices for this node. - fmt.Fprintf(w, "%sindexs(#%d): %v\n", indent, nPfxLen, allIndices) + fmt.Fprintf(w, "%sindexs(#%d): %v\n", indent, nPfxCount, allIndices) // print the prefixes for this node - fmt.Fprintf(w, "%sprefxs(#%d):", indent, nPfxLen) + fmt.Fprintf(w, "%sprefxs(#%d):", indent, nPfxCount) for _, idx := range allIndices { - octet, bits := baseIndexToPrefix(idx) - fmt.Fprintf(w, " %s/%d", octetFmt(octet, is4), bits) + octet, pfxLen := idxToPfx(idx) + fmt.Fprintf(w, " %s/%d", octetFmt(octet, is4), pfxLen) } + fmt.Fprintln(w) // print the values for this node - fmt.Fprintf(w, "%svalues(#%d):", indent, nPfxLen) + fmt.Fprintf(w, "%svalues(#%d):", indent, nPfxCount) - for _, val := range n.prefixes { + for _, val := range n.prefixes.Items { fmt.Fprintf(w, " %v", val) } + fmt.Fprintln(w) } - if childs := len(n.children); childs != 0 { - // print the childs for this node - fmt.Fprintf(w, "%schilds(#%d):", indent, childs) + if n.children.Len() != 0 { - addrBackingArray := [maxNodeChildren]uint{} - for _, addr := range n.allChildAddrs(addrBackingArray[:]) { - octet := byte(addr) - fmt.Fprintf(w, " %s", octetFmt(octet, is4)) + nodeAddrs := make([]uint, 0, maxNodeChildren) + leafAddrs := make([]uint, 0, maxNodeChildren) + + // the node has recursive child nodes or path-compressed leaves + for i, addr := range n.children.All() { + switch n.children.Items[i].(type) { + case *node[V]: + nodeAddrs = append(nodeAddrs, addr) + continue + + case *leaf[V]: + leafAddrs = append(leafAddrs, addr) + + default: + panic("logic error, wrong node type") + } } - fmt.Fprintln(w) + + if nodeCount := len(nodeAddrs); nodeCount > 0 { + // print the childs for this node + fmt.Fprintf(w, "%schilds(#%d):", indent, nodeCount) + + for _, addr := range nodeAddrs { + octet := byte(addr) + fmt.Fprintf(w, " %s", octetFmt(octet, is4)) + } + + fmt.Fprintln(w) + } + + if leafCount := len(leafAddrs); leafCount > 0 { + // print the pathcomp prefixes for this node + fmt.Fprintf(w, "%sleaves(#%d):", indent, leafCount) + + for _, addr := range leafAddrs { + octet := byte(addr) + k := n.children.MustGet(addr) + pc := k.(*leaf[V]) + + fmt.Fprintf(w, " %s:{%s, %v}", octetFmt(octet, is4), pc.prefix, pc.value) + } + fmt.Fprintln(w) + } + } +} + +// hasType returns the nodeType. +func (n *node[V]) hasType() nodeType { + s := n.nodeStats() + + switch { + case s.pfxs == 0 && s.childs == 0: + return nullNode + case s.nodes == 0: + return leafNode + case (s.pfxs > 0 || s.leaves > 0) && s.nodes > 0: + return fullNode + case (s.pfxs == 0 && s.leaves == 0) && s.nodes > 0: + return intermediateNode + default: + panic(fmt.Sprintf("UNREACHABLE: pfx: %d, chld: %d, node: %d, leaf: %d", + s.pfxs, s.childs, s.nodes, s.leaves)) } } @@ -137,6 +174,7 @@ func octetFmt(octet byte, is4 bool) string { if is4 { return fmt.Sprintf("%d", octet) } + return fmt.Sprintf("0x%02x", octet) } @@ -144,7 +182,7 @@ func octetFmt(octet byte, is4 bool) string { // // 127.0.0 // 2001:0d -func ipStridePath(path [16]byte, depth int, is4 bool) string { +func ipStridePath(path stridePath, depth int, is4 bool) string { buf := new(strings.Builder) if is4 { @@ -152,8 +190,10 @@ func ipStridePath(path [16]byte, depth int, is4 bool) string { if i != 0 { buf.WriteString(".") } + buf.WriteString(strconv.Itoa(int(b))) } + return buf.String() } @@ -161,8 +201,10 @@ func ipStridePath(path [16]byte, depth int, is4 bool) string { if i != 0 && i%2 == 0 { buf.WriteString(":") } + buf.WriteString(fmt.Sprintf("%02x", b)) } + return buf.String() } @@ -177,29 +219,72 @@ func (nt nodeType) String() string { return "LEAF" case intermediateNode: return "IMED" + default: + return "unreachable" } - panic("unreachable") } -// hasType returns the nodeType. -func (n *node[V]) hasType() nodeType { - lenPefixes := len(n.prefixes) - lenChilds := len(n.children) - - if lenPefixes == 0 && lenChilds != 0 { - return intermediateNode - } - - if lenPefixes == 0 && lenChilds == 0 { - return nullNode - } - - if lenPefixes != 0 && lenChilds == 0 { - return leafNode - } - - if lenPefixes != 0 && lenChilds != 0 { - return fullNode - } - panic("unreachable") +// stats, only used for dump, tests and benchmarks +type stats struct { + pfxs int + childs int + nodes int + leaves int +} + +// node statistics for this single node +func (n *node[V]) nodeStats() stats { + var s stats + + s.pfxs = n.prefixes.Len() + s.childs = n.children.Len() + + for i := range n.children.All() { + switch n.children.Items[i].(type) { + case *node[V]: + s.nodes++ + + case *leaf[V]: + s.leaves++ + + default: + panic("logic error, wrong node type") + } + } + + return s +} + +// nodeStatsRec, calculate the number of pfxs, nodes and leaves under n, rec-descent. +func (n *node[V]) nodeStatsRec() stats { + var s stats + if n == nil || n.isEmpty() { + return s + } + + s.pfxs = n.prefixes.Len() + s.childs = n.children.Len() + s.nodes = 1 // this node + s.leaves = 0 + + for _, kidAny := range n.children.Items { + switch kid := kidAny.(type) { + case *node[V]: + // rec-descent + rs := kid.nodeStatsRec() + + s.pfxs += rs.pfxs + s.childs += rs.childs + s.nodes += rs.nodes + s.leaves += rs.leaves + + case *leaf[V]: + s.leaves++ + + default: + panic("logic error, wrong node type") + } + } + + return s } diff --git a/vendor/github.com/gaissmai/bart/internal/bitset/bitset.go b/vendor/github.com/gaissmai/bart/internal/bitset/bitset.go new file mode 100644 index 0000000..37da871 --- /dev/null +++ b/vendor/github.com/gaissmai/bart/internal/bitset/bitset.go @@ -0,0 +1,326 @@ +// Copyright (c) 2024 Karl Gaissmaier +// SPDX-License-Identifier: MIT + +// Package bitset implements bitsets, a mapping +// between non-negative integers and boolean values. +// +// Studied [github.com/bits-and-blooms/bitset] inside out +// and rewrote needed parts from scratch for this project. +// +// This implementation is smaller and faster as the more +// general [github.com/bits-and-blooms/bitset]. +// +// All functions can be inlined! +// +// can inline BitSet.Set with cost 63 +// can inline BitSet.Clear with cost 24 +// can inline BitSet.Test with cost 26 +// can inline BitSet.Rank0 with cost 66 +// can inline BitSet.Clone with cost 7 +// can inline BitSet.Compact with cost 35 +// can inline BitSet.FirstSet with cost 25 +// can inline BitSet.NextSet with cost 71 +// can inline BitSet.AsSlice with cost 50 +// can inline BitSet.All with cost 62 +// can inline BitSet.IntersectsAny with cost 42 +// can inline BitSet.IntersectionTop with cost 56 +// can inline BitSet.IntersectionCardinality with cost 35 +// can inline (*BitSet).InPlaceIntersection with cost 71 +// can inline (*BitSet).InPlaceUnion with cost 77 +// can inline BitSet.Size with cost 16 +// can inline popcount with cost 12 +// can inline popcountAnd with cost 30 +package bitset + +import ( + "math/bits" +) + +// A BitSet is a slice of words. This is an internal package +// with a wide open public API. +type BitSet []uint64 + +// xIdx calculates the index of i in a []uint64 +// func wIdx(i uint) int { +// return int(i >> 6) // like (i / 64) but faster +// } + +// bIdx calculates the index of i in a `uint64` +// func bIdx(i uint) uint { +// return i & 63 // like (i % 64) but faster +// } +// +// just as an explanation of the expressions, +// +// i>>6 or i<<6 and i&63 +// +// not factored out as functions to make most of the methods +// inlineable with minimal costs. + +// Set bit i to 1, the capacity of the bitset is increased accordingly. +func (b BitSet) Set(i uint) BitSet { + // grow? + if i >= uint(len(b)<<6) { + words := int((i + 64) >> 6) + switch { + case b == nil: + b = make([]uint64, words) + case cap(b) >= words: + b = b[:words] + default: + // be exact, don't use append! + // max 512 prefixes/node (8*uint64), and a cache line has 64 Bytes + newset := make([]uint64, words) + copy(newset, b) + b = newset + } + } + + b[i>>6] |= 1 << (i & 63) + return b +} + +// Clear bit i to 0. +func (b BitSet) Clear(i uint) BitSet { + if x := int(i >> 6); x < len(b) { + b[x] &^= 1 << (i & 63) + } + return b +} + +// Test if bit i is set. +func (b BitSet) Test(i uint) (ok bool) { + if x := int(i >> 6); x < len(b) { + return b[x]&(1<<(i&63)) != 0 + } + return +} + +// Clone this BitSet, returning a new BitSet that has the same bits set. +func (b BitSet) Clone() BitSet { + return append(b[:0:0], b...) +} + +// Compact, preserve all set bits, while minimizing memory usage. +func (b BitSet) Compact() BitSet { + last := len(b) - 1 + + // find last word with at least one bit set. + for ; last >= 0; last-- { + if b[last] != 0 { + b = b[: last+1 : last+1] + return b + } + } + + // BitSet was empty, shrink to nil + return nil +} + +// FirstSet returns the first bit set along with an ok code. +func (b BitSet) FirstSet() (uint, bool) { + for x, word := range b { + if word != 0 { + return uint(x<<6 + bits.TrailingZeros64(word)), true + } + } + return 0, false +} + +// NextSet returns the next bit set from the specified index, +// including possibly the current index along with an ok code. +func (b BitSet) NextSet(i uint) (uint, bool) { + x := int(i >> 6) + if x >= len(b) { + return 0, false + } + + // process the first (maybe partial) word + first := b[x] >> (i & 63) // i % 64 + if first != 0 { + return i + uint(bits.TrailingZeros64(first)), true + } + + // process the following words until next bit is set + // x < len(b), no out-of-bounds panic in following slice expression + x++ + for j, word := range b[x:] { + if word != 0 { + return uint((x+j)<<6 + bits.TrailingZeros64(word)), true + } + } + return 0, false +} + +// AsSlice returns all set bits as slice of uint without +// heap allocations. +// +// This is faster than All, but also more dangerous, +// it panics if the capacity of buf is < b.Size() +func (b BitSet) AsSlice(buf []uint) []uint { + buf = buf[:cap(buf)] // len = cap + + size := 0 + for idx, word := range b { + for ; word != 0; size++ { + // panics if capacity of buf is exceeded. + buf[size] = uint(idx<<6 + bits.TrailingZeros64(word)) + + // clear the rightmost set bit + word &= word - 1 + } + } + + buf = buf[:size] + return buf +} + +// All returns all set bits. This is simpler but slower than AsSlice. +func (b BitSet) All() []uint { + buf := make([]uint, b.Size()) + + slot := 0 + for idx, word := range b { + for word != 0 { + buf[slot] = uint(idx<<6 + bits.TrailingZeros64(word)) + slot++ + + // clear the rightmost set bit + word &= word - 1 + } + } + + return buf +} + +// IntersectsAny returns true if the intersection of base set with the compare set +// is not the empty set. +func (b BitSet) IntersectsAny(c BitSet) bool { + i := min(len(b), len(c)) - 1 + // bounds check eliminated (BCE) + for ; i >= 0 && i < len(b) && i < len(c); i-- { + if b[i]&c[i] != 0 { + return true + } + } + return false +} + +// IntersectionTop computes the intersection of base set with the compare set. +// If the result set isn't empty, it returns the top most set bit and true. +func (b BitSet) IntersectionTop(c BitSet) (top uint, ok bool) { + i := min(len(b), len(c)) - 1 + // bounds check eliminated (BCE) + for ; i >= 0 && i < len(b) && i < len(c); i-- { + if word := b[i] & c[i]; word != 0 { + return uint(i<<6+bits.Len64(word)) - 1, true + } + } + return +} + +// IntersectionCardinality computes the popcount of the intersection. +func (b BitSet) IntersectionCardinality(c BitSet) int { + return popcntAnd(b, c) +} + +// InPlaceIntersection overwrites and computes the intersection of +// base set with the compare set. This is the BitSet equivalent of & (and). +// If len(c) > len(b), new memory is allocated. +func (b *BitSet) InPlaceIntersection(c BitSet) { + // bounds check eliminated, range until minLen(b,c) + for i := 0; i < len(*b) && i < len(c); i++ { + (*b)[i] &= c[i] + } + + // b >= c + if len(*b) >= len(c) { + // bounds check eliminated + for i := len(c); i < len(*b); i++ { + (*b)[i] = 0 + } + return + } + + // b < c + newset := make([]uint64, len(c)) + copy(newset, *b) + *b = newset +} + +// InPlaceUnion creates the destructive union of base set with compare set. +// This is the BitSet equivalent of | (or). +// If len(c) > len(b), new memory is allocated. +func (b *BitSet) InPlaceUnion(c BitSet) { + // b >= c + if len(*b) >= len(c) { + // bounds check eliminated + for i := 0; i < len(*b) && i < len(c); i++ { + (*b)[i] |= c[i] + } + + return + } + + // b < c + newset := make([]uint64, len(c)) + copy(newset, *b) + *b = newset + + // bounds check eliminated + for i := 0; i < len(*b) && i < len(c); i++ { + (*b)[i] |= c[i] + } +} + +// Size (number of set bits). +func (b BitSet) Size() int { + return popcntSlice(b) +} + +// Rank0 is equal to Rank(i) - 1 +// +// With inlined popcount to make Rank0 itself inlineable. +func (b BitSet) Rank0(i uint) (rnk int) { + // Rank count is inclusive + i++ + + if wordIdx := int(i >> 6); wordIdx >= len(b) { + // inlined popcount, whole slice + for _, x := range b { + rnk += bits.OnesCount64(x) + } + } else { + // inlined popcount, partial slice ... + for _, x := range b[:wordIdx] { + rnk += bits.OnesCount64(x) + } + + // ... plus partial word? + if bitsIdx := i & 63; bitsIdx != 0 { + rnk += bits.OnesCount64(b[wordIdx] << (64 - bitsIdx)) + } + + } + + // correct for offset by one + return rnk - 1 +} + +// popcntSlice +func popcntSlice(s []uint64) (cnt int) { + for _, x := range s { + // count all the bits set in slice. + cnt += bits.OnesCount64(x) + } + return +} + +// popcntAnd +func popcntAnd(s, m []uint64) (cnt int) { + for j := 0; j < len(s) && j < len(m); j++ { + // words are bitwise & followed by popcount. + cnt += bits.OnesCount64(s[j] & m[j]) + } + return +} diff --git a/vendor/github.com/gaissmai/bart/internal/sparse/array.go b/vendor/github.com/gaissmai/bart/internal/sparse/array.go new file mode 100644 index 0000000..5c32e9f --- /dev/null +++ b/vendor/github.com/gaissmai/bart/internal/sparse/array.go @@ -0,0 +1,160 @@ +// Copyright (c) 2024 Karl Gaissmaier +// SPDX-License-Identifier: MIT + +// package sparse implements a generic sparse array +// with popcount compression. +package sparse + +import ( + "github.com/gaissmai/bart/internal/bitset" +) + +// Array, a generic implementation of a sparse array +// with popcount compression and payload T. +type Array[T any] struct { + bitset.BitSet + Items []T +} + +// Get the value at i from sparse array. +// +// example: Array.Get(5) -> Array.Items[1] +// +// ⬇ +// BitSet: [0|0|1|0|0|1|0|1|...] <- 3 bits set +// Items: [*|*|*] <- len(Items) = 3 +// ⬆ +// +// BitSet.Test(5): true +// BitSet.popcount(5): 2, for interval [0,5] +// BitSet.Rank0(5): 1, equal popcount(5)-1 +func (s *Array[T]) Get(i uint) (value T, ok bool) { + if s.Test(i) { + return s.Items[s.Rank0(i)], true + } + return +} + +// MustGet, use it only after a successful test +// or the behavior is undefined, maybe it panics. +func (s *Array[T]) MustGet(i uint) T { + return s.Items[s.Rank0(i)] +} + +// UpdateAt or set the value at i via callback. The new value is returned +// and true if the value was already present. +func (s *Array[T]) UpdateAt(i uint, cb func(T, bool) T) (newValue T, wasPresent bool) { + var rank0 int + + // if already set, get current value + var oldValue T + + if wasPresent = s.Test(i); wasPresent { + rank0 = s.Rank0(i) + oldValue = s.Items[rank0] + } + + // callback function to get updated or new value + newValue = cb(oldValue, wasPresent) + + // already set, update and return value + if wasPresent { + s.Items[rank0] = newValue + + return newValue, wasPresent + } + + // new value, insert into bitset ... + s.BitSet = s.Set(i) + + // bitset has changed, recalc rank + rank0 = s.Rank0(i) + + // ... and insert value into slice + s.insertItem(rank0, newValue) + + return newValue, wasPresent +} + +// Len returns the number of items in sparse array. +func (s *Array[T]) Len() int { + return len(s.Items) +} + +// Copy returns a shallow copy of the Array. +// The elements are copied using assignment, this is no deep clone. +func (s *Array[T]) Copy() *Array[T] { + if s == nil { + return nil + } + + return &Array[T]{ + BitSet: s.BitSet.Clone(), + Items: append(s.Items[:0:0], s.Items...), + } +} + +// InsertAt a value at i into the sparse array. +// If the value already exists, overwrite it with val and return true. +func (s *Array[T]) InsertAt(i uint, value T) (exists bool) { + // slot exists, overwrite value + if s.Len() != 0 && s.Test(i) { + s.Items[s.Rank0(i)] = value + + return true + } + + // new, insert into bitset ... + s.BitSet = s.Set(i) + + // ... and slice + s.insertItem(s.Rank0(i), value) + + return false +} + +// DeleteAt a value at i from the sparse array, zeroes the tail. +func (s *Array[T]) DeleteAt(i uint) (value T, exists bool) { + if s.Len() == 0 || !s.Test(i) { + return + } + + rank0 := s.Rank0(i) + value = s.Items[rank0] + + // delete from slice + s.deleteItem(rank0) + + // delete from bitset + s.BitSet = s.Clear(i) + + return value, true +} + +// insertItem inserts the item at index i, shift the rest one pos right +// +// It panics if i is out of range. +func (s *Array[T]) insertItem(i int, item T) { + if len(s.Items) < cap(s.Items) { + s.Items = s.Items[:len(s.Items)+1] // fast resize, no alloc + } else { + var zero T + s.Items = append(s.Items, zero) // append one item, mostly enlarge cap by more than one item + } + + copy(s.Items[i+1:], s.Items[i:]) + s.Items[i] = item +} + +// deleteItem at index i, shift the rest one pos left and clears the tail item +// +// It panics if i is out of range. +func (s *Array[T]) deleteItem(i int) { + var zero T + + nl := len(s.Items) - 1 // new len + copy(s.Items[i:], s.Items[i+1:]) // overwrite item at [i] + + s.Items[nl] = zero // clear the tail item + s.Items = s.Items[:nl] // new len, keep cap is unchanged +} diff --git a/vendor/github.com/gaissmai/bart/jsonify.go b/vendor/github.com/gaissmai/bart/jsonify.go index a888770..8e37038 100644 --- a/vendor/github.com/gaissmai/bart/jsonify.go +++ b/vendor/github.com/gaissmai/bart/jsonify.go @@ -1,8 +1,8 @@ +package bart + // Copyright (c) 2024 Karl Gaissmaier // SPDX-License-Identifier: MIT -package bart - import ( "encoding/json" "net/netip" @@ -19,7 +19,9 @@ type DumpListNode[V any] struct { // MarshalJSON dumps the table into two sorted lists: for ipv4 and ipv6. // Every root and subnet is an array, not a map, because the order matters. func (t *Table[V]) MarshalJSON() ([]byte, error) { - t.init() + if t == nil { + return nil, nil + } result := struct { Ipv4 []DumpListNode[V] `json:"ipv4,omitempty"` @@ -40,24 +42,27 @@ func (t *Table[V]) MarshalJSON() ([]byte, error) { // DumpList4 dumps the ipv4 tree into a list of roots and their subnets. // It can be used to analyze the tree or build custom json representation. func (t *Table[V]) DumpList4() []DumpListNode[V] { - t.init() - if t.rootV4 == nil { + if t == nil { return nil } - return t.rootV4.dumpListRec(0, zeroPath, 0, true) + return t.root4.dumpListRec(0, stridePath{}, 0, true) } // DumpList6 dumps the ipv6 tree into a list of roots and their subnets. // It can be used to analyze the tree or build custom json representation. func (t *Table[V]) DumpList6() []DumpListNode[V] { - t.init() - if t.rootV6 == nil { + if t == nil { return nil } - return t.rootV6.dumpListRec(0, zeroPath, 0, false) + return t.root6.dumpListRec(0, stridePath{}, 0, false) } -func (n *node[V]) dumpListRec(parentIdx uint, path [16]byte, depth int, is4 bool) []DumpListNode[V] { +func (n *node[V]) dumpListRec(parentIdx uint, path stridePath, depth int, is4 bool) []DumpListNode[V] { + // recursion stop condition + if n == nil { + return nil + } + directKids := n.getKidsRec(parentIdx, path, depth, is4) slices.SortFunc(directKids, cmpKidByPrefix[V]) diff --git a/vendor/github.com/gaissmai/bart/lpm_lookuptbl.go b/vendor/github.com/gaissmai/bart/lpm_lookuptbl.go new file mode 100644 index 0000000..751a8d5 --- /dev/null +++ b/vendor/github.com/gaissmai/bart/lpm_lookuptbl.go @@ -0,0 +1,538 @@ +package bart + +import "github.com/gaissmai/bart/internal/bitset" + +// lpmLookupTbl is the backtracking sequence in the complete binary tree as bitstring. +// +// for idx := 1; idx > 0; idx >>= 1 { b.Set(idx) } +// +// allows a one shot bitset intersection algorithm: +// +// func (n *node[V]) lpmTest(idx uint) bool { +// return n.prefixes.IntersectsAny(lpmLookupTbl[idx]) +// } +// +// instead of a sequence of single bitset tests: +// +// func (n *node[V]) lpmTest(idx uint) bool { +// for ; idx > 0; idx >>= 1 { +// if n.prefixes.Test(idx) { +// return true +// } +// } +// return false +// } +var lpmLookupTbl = [512]bitset.BitSet{ + /* idx: 0 */ {}, // invalid + /* idx: 1 */ {0x2}, // 0b0000_0010 + /* idx: 2 */ {0x6}, // 0b0000_0110 + /* idx: 3 */ {0xa}, // 0b0000_1010 + /* idx: 4 */ {0x16}, // ... + /* idx: 5 */ {0x26}, + /* idx: 6 */ {0x4a}, + /* idx: 7 */ {0x8a}, + /* idx: 8 */ {0x116}, + /* idx: 9 */ {0x216}, + /* idx: 10 */ {0x426}, + /* idx: 11 */ {0x826}, + /* idx: 12 */ {0x104a}, + /* idx: 13 */ {0x204a}, + /* idx: 14 */ {0x408a}, + /* idx: 15 */ {0x808a}, + /* idx: 16 */ {0x10116}, + /* idx: 17 */ {0x20116}, + /* idx: 18 */ {0x40216}, + /* idx: 19 */ {0x80216}, + /* idx: 20 */ {0x100426}, + /* idx: 21 */ {0x200426}, + /* idx: 22 */ {0x400826}, + /* idx: 23 */ {0x800826}, + /* idx: 24 */ {0x100104a}, + /* idx: 25 */ {0x200104a}, + /* idx: 26 */ {0x400204a}, + /* idx: 27 */ {0x800204a}, + /* idx: 28 */ {0x1000408a}, + /* idx: 29 */ {0x2000408a}, + /* idx: 30 */ {0x4000808a}, + /* idx: 31 */ {0x8000808a}, + /* idx: 32 */ {0x100010116}, + /* idx: 33 */ {0x200010116}, + /* idx: 34 */ {0x400020116}, + /* idx: 35 */ {0x800020116}, + /* idx: 36 */ {0x1000040216}, + /* idx: 37 */ {0x2000040216}, + /* idx: 38 */ {0x4000080216}, + /* idx: 39 */ {0x8000080216}, + /* idx: 40 */ {0x10000100426}, + /* idx: 41 */ {0x20000100426}, + /* idx: 42 */ {0x40000200426}, + /* idx: 43 */ {0x80000200426}, + /* idx: 44 */ {0x100000400826}, + /* idx: 45 */ {0x200000400826}, + /* idx: 46 */ {0x400000800826}, + /* idx: 47 */ {0x800000800826}, + /* idx: 48 */ {0x100000100104a}, + /* idx: 49 */ {0x200000100104a}, + /* idx: 50 */ {0x400000200104a}, + /* idx: 51 */ {0x800000200104a}, + /* idx: 52 */ {0x1000000400204a}, + /* idx: 53 */ {0x2000000400204a}, + /* idx: 54 */ {0x4000000800204a}, + /* idx: 55 */ {0x8000000800204a}, + /* idx: 56 */ {0x10000001000408a}, + /* idx: 57 */ {0x20000001000408a}, + /* idx: 58 */ {0x40000002000408a}, + /* idx: 59 */ {0x80000002000408a}, + /* idx: 60 */ {0x100000004000808a}, + /* idx: 61 */ {0x200000004000808a}, + /* idx: 62 */ {0x400000008000808a}, + /* idx: 63 */ {0x800000008000808a}, + /* idx: 64 */ {0x100010116, 0x1}, + /* idx: 65 */ {0x100010116, 0x2}, + /* idx: 66 */ {0x200010116, 0x4}, + /* idx: 67 */ {0x200010116, 0x8}, + /* idx: 68 */ {0x400020116, 0x10}, + /* idx: 69 */ {0x400020116, 0x20}, + /* idx: 70 */ {0x800020116, 0x40}, + /* idx: 71 */ {0x800020116, 0x80}, + /* idx: 72 */ {0x1000040216, 0x100}, + /* idx: 73 */ {0x1000040216, 0x200}, + /* idx: 74 */ {0x2000040216, 0x400}, + /* idx: 75 */ {0x2000040216, 0x800}, + /* idx: 76 */ {0x4000080216, 0x1000}, + /* idx: 77 */ {0x4000080216, 0x2000}, + /* idx: 78 */ {0x8000080216, 0x4000}, + /* idx: 79 */ {0x8000080216, 0x8000}, + /* idx: 80 */ {0x10000100426, 0x10000}, + /* idx: 81 */ {0x10000100426, 0x20000}, + /* idx: 82 */ {0x20000100426, 0x40000}, + /* idx: 83 */ {0x20000100426, 0x80000}, + /* idx: 84 */ {0x40000200426, 0x100000}, + /* idx: 85 */ {0x40000200426, 0x200000}, + /* idx: 86 */ {0x80000200426, 0x400000}, + /* idx: 87 */ {0x80000200426, 0x800000}, + /* idx: 88 */ {0x100000400826, 0x1000000}, + /* idx: 89 */ {0x100000400826, 0x2000000}, + /* idx: 90 */ {0x200000400826, 0x4000000}, + /* idx: 91 */ {0x200000400826, 0x8000000}, + /* idx: 92 */ {0x400000800826, 0x10000000}, + /* idx: 93 */ {0x400000800826, 0x20000000}, + /* idx: 94 */ {0x800000800826, 0x40000000}, + /* idx: 95 */ {0x800000800826, 0x80000000}, + /* idx: 96 */ {0x100000100104a, 0x100000000}, + /* idx: 97 */ {0x100000100104a, 0x200000000}, + /* idx: 98 */ {0x200000100104a, 0x400000000}, + /* idx: 99 */ {0x200000100104a, 0x800000000}, + /* idx: 100 */ {0x400000200104a, 0x1000000000}, + /* idx: 101 */ {0x400000200104a, 0x2000000000}, + /* idx: 102 */ {0x800000200104a, 0x4000000000}, + /* idx: 103 */ {0x800000200104a, 0x8000000000}, + /* idx: 104 */ {0x1000000400204a, 0x10000000000}, + /* idx: 105 */ {0x1000000400204a, 0x20000000000}, + /* idx: 106 */ {0x2000000400204a, 0x40000000000}, + /* idx: 107 */ {0x2000000400204a, 0x80000000000}, + /* idx: 108 */ {0x4000000800204a, 0x100000000000}, + /* idx: 109 */ {0x4000000800204a, 0x200000000000}, + /* idx: 110 */ {0x8000000800204a, 0x400000000000}, + /* idx: 111 */ {0x8000000800204a, 0x800000000000}, + /* idx: 112 */ {0x10000001000408a, 0x1000000000000}, + /* idx: 113 */ {0x10000001000408a, 0x2000000000000}, + /* idx: 114 */ {0x20000001000408a, 0x4000000000000}, + /* idx: 115 */ {0x20000001000408a, 0x8000000000000}, + /* idx: 116 */ {0x40000002000408a, 0x10000000000000}, + /* idx: 117 */ {0x40000002000408a, 0x20000000000000}, + /* idx: 118 */ {0x80000002000408a, 0x40000000000000}, + /* idx: 119 */ {0x80000002000408a, 0x80000000000000}, + /* idx: 120 */ {0x100000004000808a, 0x100000000000000}, + /* idx: 121 */ {0x100000004000808a, 0x200000000000000}, + /* idx: 122 */ {0x200000004000808a, 0x400000000000000}, + /* idx: 123 */ {0x200000004000808a, 0x800000000000000}, + /* idx: 124 */ {0x400000008000808a, 0x1000000000000000}, + /* idx: 125 */ {0x400000008000808a, 0x2000000000000000}, + /* idx: 126 */ {0x800000008000808a, 0x4000000000000000}, + /* idx: 127 */ {0x800000008000808a, 0x8000000000000000}, + /* idx: 128 */ {0x100010116, 0x1, 0x1}, + /* idx: 129 */ {0x100010116, 0x1, 0x2}, + /* idx: 130 */ {0x100010116, 0x2, 0x4}, + /* idx: 131 */ {0x100010116, 0x2, 0x8}, + /* idx: 132 */ {0x200010116, 0x4, 0x10}, + /* idx: 133 */ {0x200010116, 0x4, 0x20}, + /* idx: 134 */ {0x200010116, 0x8, 0x40}, + /* idx: 135 */ {0x200010116, 0x8, 0x80}, + /* idx: 136 */ {0x400020116, 0x10, 0x100}, + /* idx: 137 */ {0x400020116, 0x10, 0x200}, + /* idx: 138 */ {0x400020116, 0x20, 0x400}, + /* idx: 139 */ {0x400020116, 0x20, 0x800}, + /* idx: 140 */ {0x800020116, 0x40, 0x1000}, + /* idx: 141 */ {0x800020116, 0x40, 0x2000}, + /* idx: 142 */ {0x800020116, 0x80, 0x4000}, + /* idx: 143 */ {0x800020116, 0x80, 0x8000}, + /* idx: 144 */ {0x1000040216, 0x100, 0x10000}, + /* idx: 145 */ {0x1000040216, 0x100, 0x20000}, + /* idx: 146 */ {0x1000040216, 0x200, 0x40000}, + /* idx: 147 */ {0x1000040216, 0x200, 0x80000}, + /* idx: 148 */ {0x2000040216, 0x400, 0x100000}, + /* idx: 149 */ {0x2000040216, 0x400, 0x200000}, + /* idx: 150 */ {0x2000040216, 0x800, 0x400000}, + /* idx: 151 */ {0x2000040216, 0x800, 0x800000}, + /* idx: 152 */ {0x4000080216, 0x1000, 0x1000000}, + /* idx: 153 */ {0x4000080216, 0x1000, 0x2000000}, + /* idx: 154 */ {0x4000080216, 0x2000, 0x4000000}, + /* idx: 155 */ {0x4000080216, 0x2000, 0x8000000}, + /* idx: 156 */ {0x8000080216, 0x4000, 0x10000000}, + /* idx: 157 */ {0x8000080216, 0x4000, 0x20000000}, + /* idx: 158 */ {0x8000080216, 0x8000, 0x40000000}, + /* idx: 159 */ {0x8000080216, 0x8000, 0x80000000}, + /* idx: 160 */ {0x10000100426, 0x10000, 0x100000000}, + /* idx: 161 */ {0x10000100426, 0x10000, 0x200000000}, + /* idx: 162 */ {0x10000100426, 0x20000, 0x400000000}, + /* idx: 163 */ {0x10000100426, 0x20000, 0x800000000}, + /* idx: 164 */ {0x20000100426, 0x40000, 0x1000000000}, + /* idx: 165 */ {0x20000100426, 0x40000, 0x2000000000}, + /* idx: 166 */ {0x20000100426, 0x80000, 0x4000000000}, + /* idx: 167 */ {0x20000100426, 0x80000, 0x8000000000}, + /* idx: 168 */ {0x40000200426, 0x100000, 0x10000000000}, + /* idx: 169 */ {0x40000200426, 0x100000, 0x20000000000}, + /* idx: 170 */ {0x40000200426, 0x200000, 0x40000000000}, + /* idx: 171 */ {0x40000200426, 0x200000, 0x80000000000}, + /* idx: 172 */ {0x80000200426, 0x400000, 0x100000000000}, + /* idx: 173 */ {0x80000200426, 0x400000, 0x200000000000}, + /* idx: 174 */ {0x80000200426, 0x800000, 0x400000000000}, + /* idx: 175 */ {0x80000200426, 0x800000, 0x800000000000}, + /* idx: 176 */ {0x100000400826, 0x1000000, 0x1000000000000}, + /* idx: 177 */ {0x100000400826, 0x1000000, 0x2000000000000}, + /* idx: 178 */ {0x100000400826, 0x2000000, 0x4000000000000}, + /* idx: 179 */ {0x100000400826, 0x2000000, 0x8000000000000}, + /* idx: 180 */ {0x200000400826, 0x4000000, 0x10000000000000}, + /* idx: 181 */ {0x200000400826, 0x4000000, 0x20000000000000}, + /* idx: 182 */ {0x200000400826, 0x8000000, 0x40000000000000}, + /* idx: 183 */ {0x200000400826, 0x8000000, 0x80000000000000}, + /* idx: 184 */ {0x400000800826, 0x10000000, 0x100000000000000}, + /* idx: 185 */ {0x400000800826, 0x10000000, 0x200000000000000}, + /* idx: 186 */ {0x400000800826, 0x20000000, 0x400000000000000}, + /* idx: 187 */ {0x400000800826, 0x20000000, 0x800000000000000}, + /* idx: 188 */ {0x800000800826, 0x40000000, 0x1000000000000000}, + /* idx: 189 */ {0x800000800826, 0x40000000, 0x2000000000000000}, + /* idx: 190 */ {0x800000800826, 0x80000000, 0x4000000000000000}, + /* idx: 191 */ {0x800000800826, 0x80000000, 0x8000000000000000}, + /* idx: 192 */ {0x100000100104a, 0x100000000, 0x0, 0x1}, + /* idx: 193 */ {0x100000100104a, 0x100000000, 0x0, 0x2}, + /* idx: 194 */ {0x100000100104a, 0x200000000, 0x0, 0x4}, + /* idx: 195 */ {0x100000100104a, 0x200000000, 0x0, 0x8}, + /* idx: 196 */ {0x200000100104a, 0x400000000, 0x0, 0x10}, + /* idx: 197 */ {0x200000100104a, 0x400000000, 0x0, 0x20}, + /* idx: 198 */ {0x200000100104a, 0x800000000, 0x0, 0x40}, + /* idx: 199 */ {0x200000100104a, 0x800000000, 0x0, 0x80}, + /* idx: 200 */ {0x400000200104a, 0x1000000000, 0x0, 0x100}, + /* idx: 201 */ {0x400000200104a, 0x1000000000, 0x0, 0x200}, + /* idx: 202 */ {0x400000200104a, 0x2000000000, 0x0, 0x400}, + /* idx: 203 */ {0x400000200104a, 0x2000000000, 0x0, 0x800}, + /* idx: 204 */ {0x800000200104a, 0x4000000000, 0x0, 0x1000}, + /* idx: 205 */ {0x800000200104a, 0x4000000000, 0x0, 0x2000}, + /* idx: 206 */ {0x800000200104a, 0x8000000000, 0x0, 0x4000}, + /* idx: 207 */ {0x800000200104a, 0x8000000000, 0x0, 0x8000}, + /* idx: 208 */ {0x1000000400204a, 0x10000000000, 0x0, 0x10000}, + /* idx: 209 */ {0x1000000400204a, 0x10000000000, 0x0, 0x20000}, + /* idx: 210 */ {0x1000000400204a, 0x20000000000, 0x0, 0x40000}, + /* idx: 211 */ {0x1000000400204a, 0x20000000000, 0x0, 0x80000}, + /* idx: 212 */ {0x2000000400204a, 0x40000000000, 0x0, 0x100000}, + /* idx: 213 */ {0x2000000400204a, 0x40000000000, 0x0, 0x200000}, + /* idx: 214 */ {0x2000000400204a, 0x80000000000, 0x0, 0x400000}, + /* idx: 215 */ {0x2000000400204a, 0x80000000000, 0x0, 0x800000}, + /* idx: 216 */ {0x4000000800204a, 0x100000000000, 0x0, 0x1000000}, + /* idx: 217 */ {0x4000000800204a, 0x100000000000, 0x0, 0x2000000}, + /* idx: 218 */ {0x4000000800204a, 0x200000000000, 0x0, 0x4000000}, + /* idx: 219 */ {0x4000000800204a, 0x200000000000, 0x0, 0x8000000}, + /* idx: 220 */ {0x8000000800204a, 0x400000000000, 0x0, 0x10000000}, + /* idx: 221 */ {0x8000000800204a, 0x400000000000, 0x0, 0x20000000}, + /* idx: 222 */ {0x8000000800204a, 0x800000000000, 0x0, 0x40000000}, + /* idx: 223 */ {0x8000000800204a, 0x800000000000, 0x0, 0x80000000}, + /* idx: 224 */ {0x10000001000408a, 0x1000000000000, 0x0, 0x100000000}, + /* idx: 225 */ {0x10000001000408a, 0x1000000000000, 0x0, 0x200000000}, + /* idx: 226 */ {0x10000001000408a, 0x2000000000000, 0x0, 0x400000000}, + /* idx: 227 */ {0x10000001000408a, 0x2000000000000, 0x0, 0x800000000}, + /* idx: 228 */ {0x20000001000408a, 0x4000000000000, 0x0, 0x1000000000}, + /* idx: 229 */ {0x20000001000408a, 0x4000000000000, 0x0, 0x2000000000}, + /* idx: 230 */ {0x20000001000408a, 0x8000000000000, 0x0, 0x4000000000}, + /* idx: 231 */ {0x20000001000408a, 0x8000000000000, 0x0, 0x8000000000}, + /* idx: 232 */ {0x40000002000408a, 0x10000000000000, 0x0, 0x10000000000}, + /* idx: 233 */ {0x40000002000408a, 0x10000000000000, 0x0, 0x20000000000}, + /* idx: 234 */ {0x40000002000408a, 0x20000000000000, 0x0, 0x40000000000}, + /* idx: 235 */ {0x40000002000408a, 0x20000000000000, 0x0, 0x80000000000}, + /* idx: 236 */ {0x80000002000408a, 0x40000000000000, 0x0, 0x100000000000}, + /* idx: 237 */ {0x80000002000408a, 0x40000000000000, 0x0, 0x200000000000}, + /* idx: 238 */ {0x80000002000408a, 0x80000000000000, 0x0, 0x400000000000}, + /* idx: 239 */ {0x80000002000408a, 0x80000000000000, 0x0, 0x800000000000}, + /* idx: 240 */ {0x100000004000808a, 0x100000000000000, 0x0, 0x1000000000000}, + /* idx: 241 */ {0x100000004000808a, 0x100000000000000, 0x0, 0x2000000000000}, + /* idx: 242 */ {0x100000004000808a, 0x200000000000000, 0x0, 0x4000000000000}, + /* idx: 243 */ {0x100000004000808a, 0x200000000000000, 0x0, 0x8000000000000}, + /* idx: 244 */ {0x200000004000808a, 0x400000000000000, 0x0, 0x10000000000000}, + /* idx: 245 */ {0x200000004000808a, 0x400000000000000, 0x0, 0x20000000000000}, + /* idx: 246 */ {0x200000004000808a, 0x800000000000000, 0x0, 0x40000000000000}, + /* idx: 247 */ {0x200000004000808a, 0x800000000000000, 0x0, 0x80000000000000}, + /* idx: 248 */ {0x400000008000808a, 0x1000000000000000, 0x0, 0x100000000000000}, + /* idx: 249 */ {0x400000008000808a, 0x1000000000000000, 0x0, 0x200000000000000}, + /* idx: 250 */ {0x400000008000808a, 0x2000000000000000, 0x0, 0x400000000000000}, + /* idx: 251 */ {0x400000008000808a, 0x2000000000000000, 0x0, 0x800000000000000}, + /* idx: 252 */ {0x800000008000808a, 0x4000000000000000, 0x0, 0x1000000000000000}, + /* idx: 253 */ {0x800000008000808a, 0x4000000000000000, 0x0, 0x2000000000000000}, + /* idx: 254 */ {0x800000008000808a, 0x8000000000000000, 0x0, 0x4000000000000000}, + /* idx: 255 */ {0x800000008000808a, 0x8000000000000000, 0x0, 0x8000000000000000}, + /* idx: 256 */ {0x100010116, 0x1, 0x1, 0x0, 0x1}, + /* idx: 257 */ {0x100010116, 0x1, 0x1, 0x0, 0x2}, + /* idx: 258 */ {0x100010116, 0x1, 0x2, 0x0, 0x4}, + /* idx: 259 */ {0x100010116, 0x1, 0x2, 0x0, 0x8}, + /* idx: 260 */ {0x100010116, 0x2, 0x4, 0x0, 0x10}, + /* idx: 261 */ {0x100010116, 0x2, 0x4, 0x0, 0x20}, + /* idx: 262 */ {0x100010116, 0x2, 0x8, 0x0, 0x40}, + /* idx: 263 */ {0x100010116, 0x2, 0x8, 0x0, 0x80}, + /* idx: 264 */ {0x200010116, 0x4, 0x10, 0x0, 0x100}, + /* idx: 265 */ {0x200010116, 0x4, 0x10, 0x0, 0x200}, + /* idx: 266 */ {0x200010116, 0x4, 0x20, 0x0, 0x400}, + /* idx: 267 */ {0x200010116, 0x4, 0x20, 0x0, 0x800}, + /* idx: 268 */ {0x200010116, 0x8, 0x40, 0x0, 0x1000}, + /* idx: 269 */ {0x200010116, 0x8, 0x40, 0x0, 0x2000}, + /* idx: 270 */ {0x200010116, 0x8, 0x80, 0x0, 0x4000}, + /* idx: 271 */ {0x200010116, 0x8, 0x80, 0x0, 0x8000}, + /* idx: 272 */ {0x400020116, 0x10, 0x100, 0x0, 0x10000}, + /* idx: 273 */ {0x400020116, 0x10, 0x100, 0x0, 0x20000}, + /* idx: 274 */ {0x400020116, 0x10, 0x200, 0x0, 0x40000}, + /* idx: 275 */ {0x400020116, 0x10, 0x200, 0x0, 0x80000}, + /* idx: 276 */ {0x400020116, 0x20, 0x400, 0x0, 0x100000}, + /* idx: 277 */ {0x400020116, 0x20, 0x400, 0x0, 0x200000}, + /* idx: 278 */ {0x400020116, 0x20, 0x800, 0x0, 0x400000}, + /* idx: 279 */ {0x400020116, 0x20, 0x800, 0x0, 0x800000}, + /* idx: 280 */ {0x800020116, 0x40, 0x1000, 0x0, 0x1000000}, + /* idx: 281 */ {0x800020116, 0x40, 0x1000, 0x0, 0x2000000}, + /* idx: 282 */ {0x800020116, 0x40, 0x2000, 0x0, 0x4000000}, + /* idx: 283 */ {0x800020116, 0x40, 0x2000, 0x0, 0x8000000}, + /* idx: 284 */ {0x800020116, 0x80, 0x4000, 0x0, 0x10000000}, + /* idx: 285 */ {0x800020116, 0x80, 0x4000, 0x0, 0x20000000}, + /* idx: 286 */ {0x800020116, 0x80, 0x8000, 0x0, 0x40000000}, + /* idx: 287 */ {0x800020116, 0x80, 0x8000, 0x0, 0x80000000}, + /* idx: 288 */ {0x1000040216, 0x100, 0x10000, 0x0, 0x100000000}, + /* idx: 289 */ {0x1000040216, 0x100, 0x10000, 0x0, 0x200000000}, + /* idx: 290 */ {0x1000040216, 0x100, 0x20000, 0x0, 0x400000000}, + /* idx: 291 */ {0x1000040216, 0x100, 0x20000, 0x0, 0x800000000}, + /* idx: 292 */ {0x1000040216, 0x200, 0x40000, 0x0, 0x1000000000}, + /* idx: 293 */ {0x1000040216, 0x200, 0x40000, 0x0, 0x2000000000}, + /* idx: 294 */ {0x1000040216, 0x200, 0x80000, 0x0, 0x4000000000}, + /* idx: 295 */ {0x1000040216, 0x200, 0x80000, 0x0, 0x8000000000}, + /* idx: 296 */ {0x2000040216, 0x400, 0x100000, 0x0, 0x10000000000}, + /* idx: 297 */ {0x2000040216, 0x400, 0x100000, 0x0, 0x20000000000}, + /* idx: 298 */ {0x2000040216, 0x400, 0x200000, 0x0, 0x40000000000}, + /* idx: 299 */ {0x2000040216, 0x400, 0x200000, 0x0, 0x80000000000}, + /* idx: 300 */ {0x2000040216, 0x800, 0x400000, 0x0, 0x100000000000}, + /* idx: 301 */ {0x2000040216, 0x800, 0x400000, 0x0, 0x200000000000}, + /* idx: 302 */ {0x2000040216, 0x800, 0x800000, 0x0, 0x400000000000}, + /* idx: 303 */ {0x2000040216, 0x800, 0x800000, 0x0, 0x800000000000}, + /* idx: 304 */ {0x4000080216, 0x1000, 0x1000000, 0x0, 0x1000000000000}, + /* idx: 305 */ {0x4000080216, 0x1000, 0x1000000, 0x0, 0x2000000000000}, + /* idx: 306 */ {0x4000080216, 0x1000, 0x2000000, 0x0, 0x4000000000000}, + /* idx: 307 */ {0x4000080216, 0x1000, 0x2000000, 0x0, 0x8000000000000}, + /* idx: 308 */ {0x4000080216, 0x2000, 0x4000000, 0x0, 0x10000000000000}, + /* idx: 309 */ {0x4000080216, 0x2000, 0x4000000, 0x0, 0x20000000000000}, + /* idx: 310 */ {0x4000080216, 0x2000, 0x8000000, 0x0, 0x40000000000000}, + /* idx: 311 */ {0x4000080216, 0x2000, 0x8000000, 0x0, 0x80000000000000}, + /* idx: 312 */ {0x8000080216, 0x4000, 0x10000000, 0x0, 0x100000000000000}, + /* idx: 313 */ {0x8000080216, 0x4000, 0x10000000, 0x0, 0x200000000000000}, + /* idx: 314 */ {0x8000080216, 0x4000, 0x20000000, 0x0, 0x400000000000000}, + /* idx: 315 */ {0x8000080216, 0x4000, 0x20000000, 0x0, 0x800000000000000}, + /* idx: 316 */ {0x8000080216, 0x8000, 0x40000000, 0x0, 0x1000000000000000}, + /* idx: 317 */ {0x8000080216, 0x8000, 0x40000000, 0x0, 0x2000000000000000}, + /* idx: 318 */ {0x8000080216, 0x8000, 0x80000000, 0x0, 0x4000000000000000}, + /* idx: 319 */ {0x8000080216, 0x8000, 0x80000000, 0x0, 0x8000000000000000}, + /* idx: 320 */ {0x10000100426, 0x10000, 0x100000000, 0x0, 0x0, 0x1}, + /* idx: 321 */ {0x10000100426, 0x10000, 0x100000000, 0x0, 0x0, 0x2}, + /* idx: 322 */ {0x10000100426, 0x10000, 0x200000000, 0x0, 0x0, 0x4}, + /* idx: 323 */ {0x10000100426, 0x10000, 0x200000000, 0x0, 0x0, 0x8}, + /* idx: 324 */ {0x10000100426, 0x20000, 0x400000000, 0x0, 0x0, 0x10}, + /* idx: 325 */ {0x10000100426, 0x20000, 0x400000000, 0x0, 0x0, 0x20}, + /* idx: 326 */ {0x10000100426, 0x20000, 0x800000000, 0x0, 0x0, 0x40}, + /* idx: 327 */ {0x10000100426, 0x20000, 0x800000000, 0x0, 0x0, 0x80}, + /* idx: 328 */ {0x20000100426, 0x40000, 0x1000000000, 0x0, 0x0, 0x100}, + /* idx: 329 */ {0x20000100426, 0x40000, 0x1000000000, 0x0, 0x0, 0x200}, + /* idx: 330 */ {0x20000100426, 0x40000, 0x2000000000, 0x0, 0x0, 0x400}, + /* idx: 331 */ {0x20000100426, 0x40000, 0x2000000000, 0x0, 0x0, 0x800}, + /* idx: 332 */ {0x20000100426, 0x80000, 0x4000000000, 0x0, 0x0, 0x1000}, + /* idx: 333 */ {0x20000100426, 0x80000, 0x4000000000, 0x0, 0x0, 0x2000}, + /* idx: 334 */ {0x20000100426, 0x80000, 0x8000000000, 0x0, 0x0, 0x4000}, + /* idx: 335 */ {0x20000100426, 0x80000, 0x8000000000, 0x0, 0x0, 0x8000}, + /* idx: 336 */ {0x40000200426, 0x100000, 0x10000000000, 0x0, 0x0, 0x10000}, + /* idx: 337 */ {0x40000200426, 0x100000, 0x10000000000, 0x0, 0x0, 0x20000}, + /* idx: 338 */ {0x40000200426, 0x100000, 0x20000000000, 0x0, 0x0, 0x40000}, + /* idx: 339 */ {0x40000200426, 0x100000, 0x20000000000, 0x0, 0x0, 0x80000}, + /* idx: 340 */ {0x40000200426, 0x200000, 0x40000000000, 0x0, 0x0, 0x100000}, + /* idx: 341 */ {0x40000200426, 0x200000, 0x40000000000, 0x0, 0x0, 0x200000}, + /* idx: 342 */ {0x40000200426, 0x200000, 0x80000000000, 0x0, 0x0, 0x400000}, + /* idx: 343 */ {0x40000200426, 0x200000, 0x80000000000, 0x0, 0x0, 0x800000}, + /* idx: 344 */ {0x80000200426, 0x400000, 0x100000000000, 0x0, 0x0, 0x1000000}, + /* idx: 345 */ {0x80000200426, 0x400000, 0x100000000000, 0x0, 0x0, 0x2000000}, + /* idx: 346 */ {0x80000200426, 0x400000, 0x200000000000, 0x0, 0x0, 0x4000000}, + /* idx: 347 */ {0x80000200426, 0x400000, 0x200000000000, 0x0, 0x0, 0x8000000}, + /* idx: 348 */ {0x80000200426, 0x800000, 0x400000000000, 0x0, 0x0, 0x10000000}, + /* idx: 349 */ {0x80000200426, 0x800000, 0x400000000000, 0x0, 0x0, 0x20000000}, + /* idx: 350 */ {0x80000200426, 0x800000, 0x800000000000, 0x0, 0x0, 0x40000000}, + /* idx: 351 */ {0x80000200426, 0x800000, 0x800000000000, 0x0, 0x0, 0x80000000}, + /* idx: 352 */ {0x100000400826, 0x1000000, 0x1000000000000, 0x0, 0x0, 0x100000000}, + /* idx: 353 */ {0x100000400826, 0x1000000, 0x1000000000000, 0x0, 0x0, 0x200000000}, + /* idx: 354 */ {0x100000400826, 0x1000000, 0x2000000000000, 0x0, 0x0, 0x400000000}, + /* idx: 355 */ {0x100000400826, 0x1000000, 0x2000000000000, 0x0, 0x0, 0x800000000}, + /* idx: 356 */ {0x100000400826, 0x2000000, 0x4000000000000, 0x0, 0x0, 0x1000000000}, + /* idx: 357 */ {0x100000400826, 0x2000000, 0x4000000000000, 0x0, 0x0, 0x2000000000}, + /* idx: 358 */ {0x100000400826, 0x2000000, 0x8000000000000, 0x0, 0x0, 0x4000000000}, + /* idx: 359 */ {0x100000400826, 0x2000000, 0x8000000000000, 0x0, 0x0, 0x8000000000}, + /* idx: 360 */ {0x200000400826, 0x4000000, 0x10000000000000, 0x0, 0x0, 0x10000000000}, + /* idx: 361 */ {0x200000400826, 0x4000000, 0x10000000000000, 0x0, 0x0, 0x20000000000}, + /* idx: 362 */ {0x200000400826, 0x4000000, 0x20000000000000, 0x0, 0x0, 0x40000000000}, + /* idx: 363 */ {0x200000400826, 0x4000000, 0x20000000000000, 0x0, 0x0, 0x80000000000}, + /* idx: 364 */ {0x200000400826, 0x8000000, 0x40000000000000, 0x0, 0x0, 0x100000000000}, + /* idx: 365 */ {0x200000400826, 0x8000000, 0x40000000000000, 0x0, 0x0, 0x200000000000}, + /* idx: 366 */ {0x200000400826, 0x8000000, 0x80000000000000, 0x0, 0x0, 0x400000000000}, + /* idx: 367 */ {0x200000400826, 0x8000000, 0x80000000000000, 0x0, 0x0, 0x800000000000}, + /* idx: 368 */ {0x400000800826, 0x10000000, 0x100000000000000, 0x0, 0x0, 0x1000000000000}, + /* idx: 369 */ {0x400000800826, 0x10000000, 0x100000000000000, 0x0, 0x0, 0x2000000000000}, + /* idx: 370 */ {0x400000800826, 0x10000000, 0x200000000000000, 0x0, 0x0, 0x4000000000000}, + /* idx: 371 */ {0x400000800826, 0x10000000, 0x200000000000000, 0x0, 0x0, 0x8000000000000}, + /* idx: 372 */ {0x400000800826, 0x20000000, 0x400000000000000, 0x0, 0x0, 0x10000000000000}, + /* idx: 373 */ {0x400000800826, 0x20000000, 0x400000000000000, 0x0, 0x0, 0x20000000000000}, + /* idx: 374 */ {0x400000800826, 0x20000000, 0x800000000000000, 0x0, 0x0, 0x40000000000000}, + /* idx: 375 */ {0x400000800826, 0x20000000, 0x800000000000000, 0x0, 0x0, 0x80000000000000}, + /* idx: 376 */ {0x800000800826, 0x40000000, 0x1000000000000000, 0x0, 0x0, 0x100000000000000}, + /* idx: 377 */ {0x800000800826, 0x40000000, 0x1000000000000000, 0x0, 0x0, 0x200000000000000}, + /* idx: 378 */ {0x800000800826, 0x40000000, 0x2000000000000000, 0x0, 0x0, 0x400000000000000}, + /* idx: 379 */ {0x800000800826, 0x40000000, 0x2000000000000000, 0x0, 0x0, 0x800000000000000}, + /* idx: 380 */ {0x800000800826, 0x80000000, 0x4000000000000000, 0x0, 0x0, 0x1000000000000000}, + /* idx: 381 */ {0x800000800826, 0x80000000, 0x4000000000000000, 0x0, 0x0, 0x2000000000000000}, + /* idx: 382 */ {0x800000800826, 0x80000000, 0x8000000000000000, 0x0, 0x0, 0x4000000000000000}, + /* idx: 383 */ {0x800000800826, 0x80000000, 0x8000000000000000, 0x0, 0x0, 0x8000000000000000}, + /* idx: 384 */ {0x100000100104a, 0x100000000, 0x0, 0x1, 0x0, 0x0, 0x1}, + /* idx: 385 */ {0x100000100104a, 0x100000000, 0x0, 0x1, 0x0, 0x0, 0x2}, + /* idx: 386 */ {0x100000100104a, 0x100000000, 0x0, 0x2, 0x0, 0x0, 0x4}, + /* idx: 387 */ {0x100000100104a, 0x100000000, 0x0, 0x2, 0x0, 0x0, 0x8}, + /* idx: 388 */ {0x100000100104a, 0x200000000, 0x0, 0x4, 0x0, 0x0, 0x10}, + /* idx: 389 */ {0x100000100104a, 0x200000000, 0x0, 0x4, 0x0, 0x0, 0x20}, + /* idx: 390 */ {0x100000100104a, 0x200000000, 0x0, 0x8, 0x0, 0x0, 0x40}, + /* idx: 391 */ {0x100000100104a, 0x200000000, 0x0, 0x8, 0x0, 0x0, 0x80}, + /* idx: 392 */ {0x200000100104a, 0x400000000, 0x0, 0x10, 0x0, 0x0, 0x100}, + /* idx: 393 */ {0x200000100104a, 0x400000000, 0x0, 0x10, 0x0, 0x0, 0x200}, + /* idx: 394 */ {0x200000100104a, 0x400000000, 0x0, 0x20, 0x0, 0x0, 0x400}, + /* idx: 395 */ {0x200000100104a, 0x400000000, 0x0, 0x20, 0x0, 0x0, 0x800}, + /* idx: 396 */ {0x200000100104a, 0x800000000, 0x0, 0x40, 0x0, 0x0, 0x1000}, + /* idx: 397 */ {0x200000100104a, 0x800000000, 0x0, 0x40, 0x0, 0x0, 0x2000}, + /* idx: 398 */ {0x200000100104a, 0x800000000, 0x0, 0x80, 0x0, 0x0, 0x4000}, + /* idx: 399 */ {0x200000100104a, 0x800000000, 0x0, 0x80, 0x0, 0x0, 0x8000}, + /* idx: 400 */ {0x400000200104a, 0x1000000000, 0x0, 0x100, 0x0, 0x0, 0x10000}, + /* idx: 401 */ {0x400000200104a, 0x1000000000, 0x0, 0x100, 0x0, 0x0, 0x20000}, + /* idx: 402 */ {0x400000200104a, 0x1000000000, 0x0, 0x200, 0x0, 0x0, 0x40000}, + /* idx: 403 */ {0x400000200104a, 0x1000000000, 0x0, 0x200, 0x0, 0x0, 0x80000}, + /* idx: 404 */ {0x400000200104a, 0x2000000000, 0x0, 0x400, 0x0, 0x0, 0x100000}, + /* idx: 405 */ {0x400000200104a, 0x2000000000, 0x0, 0x400, 0x0, 0x0, 0x200000}, + /* idx: 406 */ {0x400000200104a, 0x2000000000, 0x0, 0x800, 0x0, 0x0, 0x400000}, + /* idx: 407 */ {0x400000200104a, 0x2000000000, 0x0, 0x800, 0x0, 0x0, 0x800000}, + /* idx: 408 */ {0x800000200104a, 0x4000000000, 0x0, 0x1000, 0x0, 0x0, 0x1000000}, + /* idx: 409 */ {0x800000200104a, 0x4000000000, 0x0, 0x1000, 0x0, 0x0, 0x2000000}, + /* idx: 410 */ {0x800000200104a, 0x4000000000, 0x0, 0x2000, 0x0, 0x0, 0x4000000}, + /* idx: 411 */ {0x800000200104a, 0x4000000000, 0x0, 0x2000, 0x0, 0x0, 0x8000000}, + /* idx: 412 */ {0x800000200104a, 0x8000000000, 0x0, 0x4000, 0x0, 0x0, 0x10000000}, + /* idx: 413 */ {0x800000200104a, 0x8000000000, 0x0, 0x4000, 0x0, 0x0, 0x20000000}, + /* idx: 414 */ {0x800000200104a, 0x8000000000, 0x0, 0x8000, 0x0, 0x0, 0x40000000}, + /* idx: 415 */ {0x800000200104a, 0x8000000000, 0x0, 0x8000, 0x0, 0x0, 0x80000000}, + /* idx: 416 */ {0x1000000400204a, 0x10000000000, 0x0, 0x10000, 0x0, 0x0, 0x100000000}, + /* idx: 417 */ {0x1000000400204a, 0x10000000000, 0x0, 0x10000, 0x0, 0x0, 0x200000000}, + /* idx: 418 */ {0x1000000400204a, 0x10000000000, 0x0, 0x20000, 0x0, 0x0, 0x400000000}, + /* idx: 419 */ {0x1000000400204a, 0x10000000000, 0x0, 0x20000, 0x0, 0x0, 0x800000000}, + /* idx: 420 */ {0x1000000400204a, 0x20000000000, 0x0, 0x40000, 0x0, 0x0, 0x1000000000}, + /* idx: 421 */ {0x1000000400204a, 0x20000000000, 0x0, 0x40000, 0x0, 0x0, 0x2000000000}, + /* idx: 422 */ {0x1000000400204a, 0x20000000000, 0x0, 0x80000, 0x0, 0x0, 0x4000000000}, + /* idx: 423 */ {0x1000000400204a, 0x20000000000, 0x0, 0x80000, 0x0, 0x0, 0x8000000000}, + /* idx: 424 */ {0x2000000400204a, 0x40000000000, 0x0, 0x100000, 0x0, 0x0, 0x10000000000}, + /* idx: 425 */ {0x2000000400204a, 0x40000000000, 0x0, 0x100000, 0x0, 0x0, 0x20000000000}, + /* idx: 426 */ {0x2000000400204a, 0x40000000000, 0x0, 0x200000, 0x0, 0x0, 0x40000000000}, + /* idx: 427 */ {0x2000000400204a, 0x40000000000, 0x0, 0x200000, 0x0, 0x0, 0x80000000000}, + /* idx: 428 */ {0x2000000400204a, 0x80000000000, 0x0, 0x400000, 0x0, 0x0, 0x100000000000}, + /* idx: 429 */ {0x2000000400204a, 0x80000000000, 0x0, 0x400000, 0x0, 0x0, 0x200000000000}, + /* idx: 430 */ {0x2000000400204a, 0x80000000000, 0x0, 0x800000, 0x0, 0x0, 0x400000000000}, + /* idx: 431 */ {0x2000000400204a, 0x80000000000, 0x0, 0x800000, 0x0, 0x0, 0x800000000000}, + /* idx: 432 */ {0x4000000800204a, 0x100000000000, 0x0, 0x1000000, 0x0, 0x0, 0x1000000000000}, + /* idx: 433 */ {0x4000000800204a, 0x100000000000, 0x0, 0x1000000, 0x0, 0x0, 0x2000000000000}, + /* idx: 434 */ {0x4000000800204a, 0x100000000000, 0x0, 0x2000000, 0x0, 0x0, 0x4000000000000}, + /* idx: 435 */ {0x4000000800204a, 0x100000000000, 0x0, 0x2000000, 0x0, 0x0, 0x8000000000000}, + /* idx: 436 */ {0x4000000800204a, 0x200000000000, 0x0, 0x4000000, 0x0, 0x0, 0x10000000000000}, + /* idx: 437 */ {0x4000000800204a, 0x200000000000, 0x0, 0x4000000, 0x0, 0x0, 0x20000000000000}, + /* idx: 438 */ {0x4000000800204a, 0x200000000000, 0x0, 0x8000000, 0x0, 0x0, 0x40000000000000}, + /* idx: 439 */ {0x4000000800204a, 0x200000000000, 0x0, 0x8000000, 0x0, 0x0, 0x80000000000000}, + /* idx: 440 */ {0x8000000800204a, 0x400000000000, 0x0, 0x10000000, 0x0, 0x0, 0x100000000000000}, + /* idx: 441 */ {0x8000000800204a, 0x400000000000, 0x0, 0x10000000, 0x0, 0x0, 0x200000000000000}, + /* idx: 442 */ {0x8000000800204a, 0x400000000000, 0x0, 0x20000000, 0x0, 0x0, 0x400000000000000}, + /* idx: 443 */ {0x8000000800204a, 0x400000000000, 0x0, 0x20000000, 0x0, 0x0, 0x800000000000000}, + /* idx: 444 */ {0x8000000800204a, 0x800000000000, 0x0, 0x40000000, 0x0, 0x0, 0x1000000000000000}, + /* idx: 445 */ {0x8000000800204a, 0x800000000000, 0x0, 0x40000000, 0x0, 0x0, 0x2000000000000000}, + /* idx: 446 */ {0x8000000800204a, 0x800000000000, 0x0, 0x80000000, 0x0, 0x0, 0x4000000000000000}, + /* idx: 447 */ {0x8000000800204a, 0x800000000000, 0x0, 0x80000000, 0x0, 0x0, 0x8000000000000000}, + /* idx: 448 */ {0x10000001000408a, 0x1000000000000, 0x0, 0x100000000, 0x0, 0x0, 0x0, 0x1}, + /* idx: 449 */ {0x10000001000408a, 0x1000000000000, 0x0, 0x100000000, 0x0, 0x0, 0x0, 0x2}, + /* idx: 450 */ {0x10000001000408a, 0x1000000000000, 0x0, 0x200000000, 0x0, 0x0, 0x0, 0x4}, + /* idx: 451 */ {0x10000001000408a, 0x1000000000000, 0x0, 0x200000000, 0x0, 0x0, 0x0, 0x8}, + /* idx: 452 */ {0x10000001000408a, 0x2000000000000, 0x0, 0x400000000, 0x0, 0x0, 0x0, 0x10}, + /* idx: 453 */ {0x10000001000408a, 0x2000000000000, 0x0, 0x400000000, 0x0, 0x0, 0x0, 0x20}, + /* idx: 454 */ {0x10000001000408a, 0x2000000000000, 0x0, 0x800000000, 0x0, 0x0, 0x0, 0x40}, + /* idx: 455 */ {0x10000001000408a, 0x2000000000000, 0x0, 0x800000000, 0x0, 0x0, 0x0, 0x80}, + /* idx: 456 */ {0x20000001000408a, 0x4000000000000, 0x0, 0x1000000000, 0x0, 0x0, 0x0, 0x100}, + /* idx: 457 */ {0x20000001000408a, 0x4000000000000, 0x0, 0x1000000000, 0x0, 0x0, 0x0, 0x200}, + /* idx: 458 */ {0x20000001000408a, 0x4000000000000, 0x0, 0x2000000000, 0x0, 0x0, 0x0, 0x400}, + /* idx: 459 */ {0x20000001000408a, 0x4000000000000, 0x0, 0x2000000000, 0x0, 0x0, 0x0, 0x800}, + /* idx: 460 */ {0x20000001000408a, 0x8000000000000, 0x0, 0x4000000000, 0x0, 0x0, 0x0, 0x1000}, + /* idx: 461 */ {0x20000001000408a, 0x8000000000000, 0x0, 0x4000000000, 0x0, 0x0, 0x0, 0x2000}, + /* idx: 462 */ {0x20000001000408a, 0x8000000000000, 0x0, 0x8000000000, 0x0, 0x0, 0x0, 0x4000}, + /* idx: 463 */ {0x20000001000408a, 0x8000000000000, 0x0, 0x8000000000, 0x0, 0x0, 0x0, 0x8000}, + /* idx: 464 */ {0x40000002000408a, 0x10000000000000, 0x0, 0x10000000000, 0x0, 0x0, 0x0, 0x10000}, + /* idx: 465 */ {0x40000002000408a, 0x10000000000000, 0x0, 0x10000000000, 0x0, 0x0, 0x0, 0x20000}, + /* idx: 466 */ {0x40000002000408a, 0x10000000000000, 0x0, 0x20000000000, 0x0, 0x0, 0x0, 0x40000}, + /* idx: 467 */ {0x40000002000408a, 0x10000000000000, 0x0, 0x20000000000, 0x0, 0x0, 0x0, 0x80000}, + /* idx: 468 */ {0x40000002000408a, 0x20000000000000, 0x0, 0x40000000000, 0x0, 0x0, 0x0, 0x100000}, + /* idx: 469 */ {0x40000002000408a, 0x20000000000000, 0x0, 0x40000000000, 0x0, 0x0, 0x0, 0x200000}, + /* idx: 470 */ {0x40000002000408a, 0x20000000000000, 0x0, 0x80000000000, 0x0, 0x0, 0x0, 0x400000}, + /* idx: 471 */ {0x40000002000408a, 0x20000000000000, 0x0, 0x80000000000, 0x0, 0x0, 0x0, 0x800000}, + /* idx: 472 */ {0x80000002000408a, 0x40000000000000, 0x0, 0x100000000000, 0x0, 0x0, 0x0, 0x1000000}, + /* idx: 473 */ {0x80000002000408a, 0x40000000000000, 0x0, 0x100000000000, 0x0, 0x0, 0x0, 0x2000000}, + /* idx: 474 */ {0x80000002000408a, 0x40000000000000, 0x0, 0x200000000000, 0x0, 0x0, 0x0, 0x4000000}, + /* idx: 475 */ {0x80000002000408a, 0x40000000000000, 0x0, 0x200000000000, 0x0, 0x0, 0x0, 0x8000000}, + /* idx: 476 */ {0x80000002000408a, 0x80000000000000, 0x0, 0x400000000000, 0x0, 0x0, 0x0, 0x10000000}, + /* idx: 477 */ {0x80000002000408a, 0x80000000000000, 0x0, 0x400000000000, 0x0, 0x0, 0x0, 0x20000000}, + /* idx: 478 */ {0x80000002000408a, 0x80000000000000, 0x0, 0x800000000000, 0x0, 0x0, 0x0, 0x40000000}, + /* idx: 479 */ {0x80000002000408a, 0x80000000000000, 0x0, 0x800000000000, 0x0, 0x0, 0x0, 0x80000000}, + /* idx: 480 */ {0x100000004000808a, 0x100000000000000, 0x0, 0x1000000000000, 0x0, 0x0, 0x0, 0x100000000}, + /* idx: 481 */ {0x100000004000808a, 0x100000000000000, 0x0, 0x1000000000000, 0x0, 0x0, 0x0, 0x200000000}, + /* idx: 482 */ {0x100000004000808a, 0x100000000000000, 0x0, 0x2000000000000, 0x0, 0x0, 0x0, 0x400000000}, + /* idx: 483 */ {0x100000004000808a, 0x100000000000000, 0x0, 0x2000000000000, 0x0, 0x0, 0x0, 0x800000000}, + /* idx: 484 */ {0x100000004000808a, 0x200000000000000, 0x0, 0x4000000000000, 0x0, 0x0, 0x0, 0x1000000000}, + /* idx: 485 */ {0x100000004000808a, 0x200000000000000, 0x0, 0x4000000000000, 0x0, 0x0, 0x0, 0x2000000000}, + /* idx: 486 */ {0x100000004000808a, 0x200000000000000, 0x0, 0x8000000000000, 0x0, 0x0, 0x0, 0x4000000000}, + /* idx: 487 */ {0x100000004000808a, 0x200000000000000, 0x0, 0x8000000000000, 0x0, 0x0, 0x0, 0x8000000000}, + /* idx: 488 */ {0x200000004000808a, 0x400000000000000, 0x0, 0x10000000000000, 0x0, 0x0, 0x0, 0x10000000000}, + /* idx: 489 */ {0x200000004000808a, 0x400000000000000, 0x0, 0x10000000000000, 0x0, 0x0, 0x0, 0x20000000000}, + /* idx: 490 */ {0x200000004000808a, 0x400000000000000, 0x0, 0x20000000000000, 0x0, 0x0, 0x0, 0x40000000000}, + /* idx: 491 */ {0x200000004000808a, 0x400000000000000, 0x0, 0x20000000000000, 0x0, 0x0, 0x0, 0x80000000000}, + /* idx: 492 */ {0x200000004000808a, 0x800000000000000, 0x0, 0x40000000000000, 0x0, 0x0, 0x0, 0x100000000000}, + /* idx: 493 */ {0x200000004000808a, 0x800000000000000, 0x0, 0x40000000000000, 0x0, 0x0, 0x0, 0x200000000000}, + /* idx: 494 */ {0x200000004000808a, 0x800000000000000, 0x0, 0x80000000000000, 0x0, 0x0, 0x0, 0x400000000000}, + /* idx: 495 */ {0x200000004000808a, 0x800000000000000, 0x0, 0x80000000000000, 0x0, 0x0, 0x0, 0x800000000000}, + /* idx: 496 */ {0x400000008000808a, 0x1000000000000000, 0x0, 0x100000000000000, 0x0, 0x0, 0x0, 0x1000000000000}, + /* idx: 497 */ {0x400000008000808a, 0x1000000000000000, 0x0, 0x100000000000000, 0x0, 0x0, 0x0, 0x2000000000000}, + /* idx: 498 */ {0x400000008000808a, 0x1000000000000000, 0x0, 0x200000000000000, 0x0, 0x0, 0x0, 0x4000000000000}, + /* idx: 499 */ {0x400000008000808a, 0x1000000000000000, 0x0, 0x200000000000000, 0x0, 0x0, 0x0, 0x8000000000000}, + /* idx: 500 */ {0x400000008000808a, 0x2000000000000000, 0x0, 0x400000000000000, 0x0, 0x0, 0x0, 0x10000000000000}, + /* idx: 501 */ {0x400000008000808a, 0x2000000000000000, 0x0, 0x400000000000000, 0x0, 0x0, 0x0, 0x20000000000000}, + /* idx: 502 */ {0x400000008000808a, 0x2000000000000000, 0x0, 0x800000000000000, 0x0, 0x0, 0x0, 0x40000000000000}, + /* idx: 503 */ {0x400000008000808a, 0x2000000000000000, 0x0, 0x800000000000000, 0x0, 0x0, 0x0, 0x80000000000000}, + /* idx: 504 */ {0x800000008000808a, 0x4000000000000000, 0x0, 0x1000000000000000, 0x0, 0x0, 0x0, 0x100000000000000}, + /* idx: 505 */ {0x800000008000808a, 0x4000000000000000, 0x0, 0x1000000000000000, 0x0, 0x0, 0x0, 0x200000000000000}, + /* idx: 506 */ {0x800000008000808a, 0x4000000000000000, 0x0, 0x2000000000000000, 0x0, 0x0, 0x0, 0x400000000000000}, + /* idx: 507 */ {0x800000008000808a, 0x4000000000000000, 0x0, 0x2000000000000000, 0x0, 0x0, 0x0, 0x800000000000000}, + /* idx: 508 */ {0x800000008000808a, 0x8000000000000000, 0x0, 0x4000000000000000, 0x0, 0x0, 0x0, 0x1000000000000000}, + /* idx: 509 */ {0x800000008000808a, 0x8000000000000000, 0x0, 0x4000000000000000, 0x0, 0x0, 0x0, 0x2000000000000000}, + /* idx: 510 */ {0x800000008000808a, 0x8000000000000000, 0x0, 0x8000000000000000, 0x0, 0x0, 0x0, 0x4000000000000000}, + /* idx: 511 */ {0x800000008000808a, 0x8000000000000000, 0x0, 0x8000000000000000, 0x0, 0x0, 0x0, 0x8000000000000000}, +} diff --git a/vendor/github.com/gaissmai/bart/node.go b/vendor/github.com/gaissmai/bart/node.go index 877edf3..15bf12c 100644 --- a/vendor/github.com/gaissmai/bart/node.go +++ b/vendor/github.com/gaissmai/bart/node.go @@ -4,569 +4,358 @@ package bart import ( - "cmp" "net/netip" "slices" - "github.com/bits-and-blooms/bitset" + "github.com/gaissmai/bart/internal/sparse" ) const ( - strideLen = 8 // octet - maxTreeDepth = 128 / strideLen // 16 - maxNodeChildren = 1 << strideLen // 256 - maxNodePrefixes = 1 << (strideLen + 1) // 512 + strideLen = 8 // octet + maxTreeDepth = 16 // 16 for IPv6 + maxNodeChildren = 256 // 256 + maxNodePrefixes = 512 // 512 ) -// zero value, used manifold -var zeroPath [16]byte +// stridePath, max 16 octets deep +type stridePath [maxTreeDepth]uint8 // node is a level node in the multibit-trie. -// A node has prefixes and children. +// A node has prefixes and children, forming the multibit trie. // // The prefixes form a complete binary tree, see the artlookup.pdf // paper in the doc folder to understand the data structure. // -// In contrast to the ART algorithm, popcount-compressed slices are used -// instead of fixed-size arrays. +// In contrast to the ART algorithm, sparse arrays +// (popcount-compressed slices) are used instead of fixed-size arrays. // -// The array slots are also not pre-allocated as in the ART algorithm, -// but backtracking is used for the longest-prefix-match. +// The array slots are also not pre-allocated (alloted) as described +// in the ART algorithm, fast backtracking with a bitset vector is used +// to get the longest-prefix-match. // -// The lookup is then slower by a factor of about 2, but this is -// the intended trade-off to prevent memory consumption from exploding. +// The sparse child array recursively spans the trie with a branching factor of 256 +// and also records path-compressed leaves in the free node slots. type node[V any] struct { - prefixesBitset *bitset.BitSet - childrenBitset *bitset.BitSet + // prefixes contains the routes indexed as a complete binary tree with payload V + // with the help of the baseIndex function from the ART algorithm. + prefixes sparse.Array[V] - // popcount compressed slices - prefixes []V - children []*node[V] + // children, recursively spans the trie with a branching factor of 256. + // + // Sorry, here we have to use a mixture of generics and interfaces: + // + // Without path compression, the definition would naturally be: + // children sparse.Array[*node[V]] + // + // ... but with path compression the child can now be a node or a path compressed leaf. + // + // With path compression we could define: + // type noder[V any] interface { + // isLeaf[V]() bool + // } + // + // and: + // children sparse.Array[noder[V]] + // + // But we use the empty interface{} instead, by intention, see below! + // + // The empty interface{} consumes less memory and type assertions are faster than + // indirect method calls like node.isLeaf() + children sparse.Array[interface{}] } -// newNode, BitSets have to be initialized. -func newNode[V any]() *node[V] { - return &node[V]{ - prefixesBitset: bitset.New(0), // init BitSet - childrenBitset: bitset.New(0), // init BitSet - } -} - -// isEmpty returns true if node has neither prefixes nor children. +// isEmpty returns true if node has neither prefixes nor children func (n *node[V]) isEmpty() bool { - return len(n.prefixes) == 0 && len(n.children) == 0 + return n.prefixes.Len() == 0 && n.children.Len() == 0 } -// ################## prefixes ################################ - -// prefixRank, Rank() is the key of the popcount compression algorithm, -// mapping between bitset index and slice index. -func (n *node[V]) prefixRank(baseIdx uint) int { - // adjust offset by one to slice index - return int(n.prefixesBitset.Rank(baseIdx)) - 1 +// leaf is a prefix with value, used as a path compressed child +type leaf[V any] struct { + prefix netip.Prefix + value V } -// insertPrefix adds the route for baseIdx, with value val. -// If the value already exists, overwrite it with val and return false. -func (n *node[V]) insertPrefix(baseIdx uint, val V) (ok bool) { - // prefix exists, overwrite val - if n.prefixesBitset.Test(baseIdx) { - n.prefixes[n.prefixRank(baseIdx)] = val - return false +// cloneOrCopy, helper function, +// deep copy if v implements the Cloner interface. +func cloneOrCopy[V any](val V) V { + if cloner, ok := any(val).(Cloner[V]); ok { + return cloner.Clone() + } + // just a shallow copy + return val +} + +// cloneLeaf returns a clone of the leaf +// if the value implements the Cloner interface. +func (l *leaf[V]) cloneLeaf() *leaf[V] { + return &leaf[V]{l.prefix, cloneOrCopy(l.value)} +} + +// insertAtDepth insert a prefix/val into a node tree at depth. +// n must not be nil, prefix must be valid and already in canonical form. +// +// If a path compression has to be resolved because a new value is added +// that collides with a leaf, the compressed leaf is then reinserted +// one depth down in the node trie. +func (n *node[V]) insertAtDepth(pfx netip.Prefix, val V, depth int) (exists bool) { + ip := pfx.Addr() + bits := pfx.Bits() + + lastIdx, lastBits := lastOctetIdxAndBits(bits) + + octets := ip.AsSlice() + octets = octets[:lastIdx+1] + + // find the proper trie node to insert prefix + // start with prefix octet at depth + for ; depth < len(octets); depth++ { + octet := octets[depth] + addr := uint(octet) + + // last significant octet: insert/override prefix/val into node + if depth == lastIdx { + return n.prefixes.InsertAt(pfxToIdx(octet, lastBits), val) + } + + if !n.children.Test(addr) { + // insert prefix path compressed + return n.children.InsertAt(addr, &leaf[V]{pfx, val}) + } + + // get the child: node or leaf + switch kid := n.children.MustGet(addr).(type) { + case *node[V]: + n = kid + continue // descend down to next trie level + + case *leaf[V]: + // reached a path compressed prefix + // override value in slot if prefixes are equal + if kid.prefix == pfx { + kid.value = val + // exists + return true + } + + // create new node + // push the leaf down + // insert new child at current leaf position (addr) + // descend down, replace n with new child + newNode := new(node[V]) + newNode.insertAtDepth(kid.prefix, kid.value, depth+1) + + n.children.InsertAt(addr, newNode) + n = newNode + + default: + panic("logic error, wrong node type") + } } - // new, insert into bitset and slice - n.prefixesBitset.Set(baseIdx) - n.prefixes = slices.Insert(n.prefixes, n.prefixRank(baseIdx), val) - return true + panic("unreachable") } -// deletePrefix removes the route octet/prefixLen. -// Returns false if there was no prefix to delete. -func (n *node[V]) deletePrefix(octet byte, prefixLen int) (ok bool) { - baseIdx := prefixToBaseIndex(octet, prefixLen) +// insertAtDepthPersist is the immutable version of insertAtDepth. +// All visited nodes are cloned during insertion. +func (n *node[V]) insertAtDepthPersist(pfx netip.Prefix, val V, depth int) (exists bool) { + ip := pfx.Addr() + bits := pfx.Bits() - // no route entry - if !n.prefixesBitset.Test(baseIdx) { - return false + lastIdx, lastBits := lastOctetIdxAndBits(bits) + + octets := ip.AsSlice() + octets = octets[:lastIdx+1] + + // find the proper trie node to insert prefix + // start with prefix octet at depth + for ; depth < len(octets); depth++ { + + octet := octets[depth] + addr := uint(octet) + + // last significant octet: insert/override prefix/val into node + if depth == lastIdx { + return n.prefixes.InsertAt(pfxToIdx(octet, lastBits), val) + } + + if !n.children.Test(addr) { + // insert new prefix path compressed + return n.children.InsertAt(addr, &leaf[V]{pfx, val}) + } + + // get the child: node or leaf, but clone the path down + switch kid := n.children.MustGet(addr).(type) { + case *node[V]: + // proceed to next level + kid = kid.cloneFlat() + n.children.InsertAt(addr, kid) + n = kid + continue // descend down to next trie level + + case *leaf[V]: + kid = kid.cloneLeaf() + + // override value in slot if prefixes are equal + if kid.prefix == pfx { + // exists + return n.children.InsertAt(addr, &leaf[V]{pfx, val}) + } + + // create new node + // push the leaf down + // insert new child at current leaf position (addr) + // descend down, replace n with new child + newNode := new(node[V]) + newNode.insertAtDepth(kid.prefix, kid.value, depth+1) + + n.children.InsertAt(addr, newNode) + n = newNode + + default: + panic("logic error, wrong node type") + } } - rnk := n.prefixRank(baseIdx) - - // delete from slice - n.prefixes = slices.Delete(n.prefixes, rnk, rnk+1) - - // delete from bitset, followed by Compact to reduce memory consumption - n.prefixesBitset.Clear(baseIdx) - n.prefixesBitset.Compact() - - return true + panic("unreachable") } -// updatePrefix, update or set the value at prefix via callback. The new value returned -// and a bool wether the prefix was already present in the node. -func (n *node[V]) updatePrefix(octet byte, prefixLen int, cb func(V, bool) V) (newVal V, wasPresent bool) { - // calculate idx once - baseIdx := prefixToBaseIndex(octet, prefixLen) +// purgeAndCompress, purge empty nodes or compress nodes with single prefix or leaf. +func (n *node[V]) purgeAndCompress(parentStack []*node[V], childPath []uint8, is4 bool) { + // unwind the stack + for i := len(parentStack) - 1; i >= 0; i-- { + parent := parentStack[i] + addr := uint(childPath[i]) - var rnk int + pfxCount := n.prefixes.Len() + childCount := n.children.Len() - // if prefix is set, get current value - var oldVal V - if wasPresent = n.prefixesBitset.Test(baseIdx); wasPresent { - rnk = n.prefixRank(baseIdx) - oldVal = n.prefixes[rnk] + switch { + case n.isEmpty(): + // purge empty node + parent.children.DeleteAt(addr) + + case pfxCount == 1 && childCount == 0: + // make leaf from prefix idx, shift leaf one level up + // and override current node with new leaf + idx, _ := n.prefixes.FirstSet() + val := n.prefixes.Items[0] + + path := stridePath{} + copy(path[:], childPath) + pfx := cidrFromPath(path, i+1, is4, idx) + + parent.children.InsertAt(addr, &leaf[V]{pfx, val}) + + case pfxCount == 0 && childCount == 1: + // if single child is a leaf, shift it up one level + // and override current node with this leaf + if leafPtr, ok := n.children.Items[0].(*leaf[V]); ok { + parent.children.InsertAt(addr, leafPtr) + } + } + + n = parent } - - // callback function to get updated or new value - newVal = cb(oldVal, wasPresent) - - // prefix is already set, update and return value - if wasPresent { - n.prefixes[rnk] = newVal - return - } - - // new prefix, insert into bitset ... - n.prefixesBitset.Set(baseIdx) - - // bitset has changed, recalc rank - rnk = n.prefixRank(baseIdx) - - // ... and insert value into slice - n.prefixes = slices.Insert(n.prefixes, rnk, newVal) - - return } -// lpm does a route lookup for idx in the 8-bit (stride) routing table +// lpmGet does a route lookup for idx in the 8-bit (stride) routing table // at this depth and returns (baseIdx, value, true) if a matching // longest prefix exists, or ok=false otherwise. // -// backtracking is fast, it's just a bitset test and, if found, one popcount. -// max steps in backtracking is the stride length. -func (n *node[V]) lpm(idx uint) (baseIdx uint, val V, ok bool) { - for baseIdx = idx; baseIdx > 0; baseIdx >>= 1 { - if n.prefixesBitset.Test(baseIdx) { - // longest prefix match - return baseIdx, n.prefixes[n.prefixRank(baseIdx)], true - } +// The prefixes in the stride form a complete binary tree (CBT) using the baseIndex function. +// In contrast to the ART algorithm, I do not use an allotment approach but map +// the backtracking in the CBT by a bitset operation with a precalculated backtracking path +// for the respective idx. +func (n *node[V]) lpmGet(idx uint) (baseIdx uint, val V, ok bool) { + // top is the idx of the longest-prefix-match + if top, ok := n.prefixes.IntersectionTop(lpmLookupTbl[idx]); ok { + return top, n.prefixes.MustGet(top), true } // not found (on this level) return 0, val, false } -// lpmTest for internal use in overlap tests, just return true or false, no value needed. -func (n *node[V]) lpmTest(baseIdx uint) bool { - for idx := baseIdx; idx > 0; idx >>= 1 { - if n.prefixesBitset.Test(idx) { - return true - } - } - - return false -} - -// getValue for baseIdx. -func (n *node[V]) getValue(baseIdx uint) (val V, ok bool) { - if n.prefixesBitset.Test(baseIdx) { - return n.prefixes[n.prefixRank(baseIdx)], true - } - return -} - -// allStrideIndexes returns all baseIndexes set in this stride node in ascending order. -func (n *node[V]) allStrideIndexes(buffer []uint) []uint { - if len(n.prefixes) > len(buffer) { - panic("logic error, buffer is too small") - } - - _, buffer = n.prefixesBitset.NextSetMany(0, buffer) - return buffer -} - -// ################## children ################################ - -// childRank, Rank() is the key of the popcount compression algorithm, -// mapping between bitset index and slice index. -func (n *node[V]) childRank(octet byte) int { - // adjust offset by one to slice index - return int(n.childrenBitset.Rank(uint(octet))) - 1 -} - -// insertChild, insert the child -func (n *node[V]) insertChild(octet byte, child *node[V]) { - // child exists, overwrite it - if n.childrenBitset.Test(uint(octet)) { - n.children[n.childRank(octet)] = child - return - } - - // new insert into bitset and slice - n.childrenBitset.Set(uint(octet)) - n.children = slices.Insert(n.children, n.childRank(octet), child) -} - -// deleteChild, delete the child at octet. It is valid to delete a non-existent child. -func (n *node[V]) deleteChild(octet byte) { - if !n.childrenBitset.Test(uint(octet)) { - return - } - - rnk := n.childRank(octet) - - // delete from slice - n.children = slices.Delete(n.children, rnk, rnk+1) - - // delete from bitset, followed by Compact to reduce memory consumption - n.childrenBitset.Clear(uint(octet)) - n.childrenBitset.Compact() -} - -// getChild returns the child pointer for octet, or nil if none. -func (n *node[V]) getChild(octet byte) *node[V] { - if !n.childrenBitset.Test(uint(octet)) { - return nil - } - - return n.children[n.childRank(octet)] -} - -// allChildAddrs fills the buffer with the octets of all child nodes in ascending order, -// panics if the buffer isn't big enough. -func (n *node[V]) allChildAddrs(buffer []uint) []uint { - if len(n.children) > len(buffer) { - panic("logic error, buffer is too small") - } - - _, buffer = n.childrenBitset.NextSetMany(0, buffer) - return buffer -} - -// #################### nodes ############################################# - -// eachLookupPrefix does an all prefix match in the 8-bit (stride) routing table -// at this depth and calls yield() for any matching CIDR. -func (n *node[V]) eachLookupPrefix(path [16]byte, depth int, is4 bool, octet byte, bits int, yield func(pfx netip.Prefix, val V) bool) bool { - for idx := prefixToBaseIndex(octet, bits); idx > 0; idx >>= 1 { - if n.prefixesBitset.Test(idx) { - cidr, _ := cidrFromPath(path, depth, is4, idx) - val, _ := n.getValue(idx) - - if !yield(cidr, val) { - // early exit - return false - } - } - } - - return true -} - -// overlapsRec returns true if any IP in the nodes n or o overlaps. -func (n *node[V]) overlapsRec(o *node[V]) bool { - // ############################## - // 1. test if any routes overlaps - // ############################## - - nPfxLen := len(n.prefixes) - oPfxLen := len(o.prefixes) - - if oPfxLen > 0 && nPfxLen > 0 { - - // some prefixes are identical - if n.prefixesBitset.IntersectionCardinality(o.prefixesBitset) > 0 { - return true - } - - var nIdx, oIdx uint - - nOK := nPfxLen > 0 - oOK := oPfxLen > 0 - - // zip, range over n and o at the same time to help chance on its way - for nOK || oOK { - - if nOK { - // does any route in o overlap this prefix from n - if nIdx, nOK = n.prefixesBitset.NextSet(nIdx); nOK { - if o.lpmTest(nIdx) { - return true - } - } - nIdx++ - } - - if oOK { - // does any route in n overlap this prefix from o - if oIdx, oOK = o.prefixesBitset.NextSet(oIdx); oOK { - if n.lpmTest(oIdx) { - return true - } - } - oIdx++ - } - } - } - - // #################################### - // 2. test if routes overlaps any child - // #################################### - - nChildLen := len(n.children) - oChildLen := len(o.children) - - var nAddr, oAddr uint - - nOK := nChildLen > 0 && oPfxLen > 0 // test the childs in n against the routes in o - oOK := oChildLen > 0 && nPfxLen > 0 // test the childs in o against the routes in n - - // zip, range over n and o at the same time to help chance on its way - for nOK || oOK { - - if nOK { - // does any route in o overlap this child from n - if nAddr, nOK = n.childrenBitset.NextSet(nAddr); nOK { - if o.lpmTest(octetToBaseIndex(byte(nAddr))) { - return true - } - } - nAddr++ - } - - if oOK { - // does any route in n overlap this child from o - if oAddr, oOK = o.childrenBitset.NextSet(oAddr); oOK { - if n.lpmTest(octetToBaseIndex(byte(oAddr))) { - return true - } - } - oAddr++ - } - } - - // ################################################################ - // 3. rec-descent call for childs with same octet in nodes n and o - // ################################################################ - - // stop condition, n or o have no childs - if nChildLen == 0 || oChildLen == 0 { - return false - } - - // stop condition, no child with identical octet in n and o - if n.childrenBitset.IntersectionCardinality(o.childrenBitset) == 0 { - return false - } - - // swap the nodes, range over shorter bitset - if nChildLen > oChildLen { - n, o = o, n - } - - addrBackingArray := [maxNodeChildren]uint{} - for i, addr := range n.allChildAddrs(addrBackingArray[:]) { - oChild := o.getChild(byte(addr)) - if oChild == nil { - // no child in o with this octet - continue - } - - // we have the slice index for n - nChild := n.children[i] - - // rec-descent - if nChild.overlapsRec(oChild) { - return true - } - } - - return false -} - -// overlapsPrefix returns true if node overlaps with prefix. -func (n *node[V]) overlapsPrefix(octet byte, pfxLen int) bool { - // ################################################## - // 1. test if any route in this node overlaps prefix? - // ################################################## - - pfxIdx := prefixToBaseIndex(octet, pfxLen) - if n.lpmTest(pfxIdx) { - return true - } - - // ################################################# - // 2. test if prefix overlaps any route in this node - // ################################################# - - // lower/upper boundary for host routes - pfxLower, pfxUpper := hostRoutesByIndex(pfxIdx) - - // increment to 'next' routeIdx for start in bitset search - // since pfxIdx already testet by lpm in other direction - routeIdx := pfxIdx * 2 - var ok bool - for { - if routeIdx, ok = n.prefixesBitset.NextSet(routeIdx); !ok { - break - } - - routeLower, routeUpper := hostRoutesByIndex(routeIdx) - if routeLower >= pfxLower && routeUpper <= pfxUpper { - return true - } - - // next route - routeIdx++ - } - - // ################################################# - // 3. test if prefix overlaps any child in this node - // ################################################# - - // set start octet in bitset search with prefix octet - addr := uint(octet) - for { - if addr, ok = n.childrenBitset.NextSet(addr); !ok { - break - } - - idx := addr + firstHostIndex - if idx >= pfxLower && idx <= pfxUpper { - return true - } - - // next round - addr++ - } - - return false -} - -// eachSubnet calls yield() for any covered CIDR by parent prefix. -func (n *node[V]) eachSubnet(path [16]byte, depth int, is4 bool, parentOctet byte, pfxLen int, yield func(pfx netip.Prefix, val V) bool) bool { - // collect all routes covered by this pfx - // see also algorithm in overlapsPrefix - - // can't use lpm, search prefix has no node - parentIdx := prefixToBaseIndex(parentOctet, pfxLen) - parentLower, parentUpper := hostRoutesByIndex(parentIdx) - - // start bitset search at parentIdx - idx := parentIdx - var ok bool - for { - if idx, ok = n.prefixesBitset.NextSet(idx); !ok { - break - } - - // can't use lpm, search prefix has no node - lower, upper := hostRoutesByIndex(idx) - - // idx is covered by parentIdx? - if lower >= parentLower && upper <= parentUpper { - val, _ := n.getValue(idx) - cidr, _ := cidrFromPath(path, depth, is4, idx) - - if !yield(cidr, val) { - // early exit - return false - } - - } - - idx++ - } - - // collect all children covered - var addr uint - for { - if addr, ok = n.childrenBitset.NextSet(addr); !ok { - break - } - octet := byte(addr) - - // make host route for comparison with lower, upper - idx := octetToBaseIndex(octet) - - // is child covered? - if idx >= parentLower && idx <= parentUpper { - c := n.getChild(octet) - - // add (set) this octet to path - path[depth] = octet - - // all cidrs under this child are covered by pfx - if !c.allRec(path, depth+1, is4, yield) { - // early exit - return false - } - } - - addr++ - } - - return true -} - -// unionRec combines two nodes, changing the receiver node. -// If there are duplicate entries, the value is taken from the other node. -// Count duplicate entries to adjust the t.size struct members. -func (n *node[V]) unionRec(o *node[V]) (duplicates int) { - // make backing arrays, no heap allocs - idxBackingArray := [maxNodePrefixes]uint{} - - // for all prefixes in other node do ... - for _, oIdx := range o.allStrideIndexes(idxBackingArray[:]) { - // insert/overwrite prefix/value from oNode to nNode - oVal, _ := o.getValue(oIdx) - if !n.insertPrefix(oIdx, oVal) { - duplicates++ - } - } - - // make backing arrays, no heap allocs - addrBackingArray := [maxNodeChildren]uint{} - - // for all children in other node do ... - for i, oOctet := range o.allChildAddrs(addrBackingArray[:]) { - octet := byte(oOctet) - - // we know the slice index, faster as o.getChild(octet) - oc := o.children[i] - - // get n child with same octet, - // we don't know the slice index in n.children - nc := n.getChild(octet) - - if nc == nil { - // insert cloned child from oNode into nNode - n.insertChild(octet, oc.cloneRec()) - } else { - // both nodes have child with octet, call union rec-descent - duplicates += nc.unionRec(oc) - } - } - return duplicates +// lpmTest for faster lpm tests without value returns. +func (n *node[V]) lpmTest(idx uint) bool { + return n.prefixes.IntersectsAny(lpmLookupTbl[idx]) } // cloneRec, clones the node recursive. func (n *node[V]) cloneRec() *node[V] { - c := newNode[V]() + if n == nil { + return nil + } + + c := new(node[V]) if n.isEmpty() { return c } - c.prefixesBitset = n.prefixesBitset.Clone() // deep - c.prefixes = slices.Clone(n.prefixes) // shallow values + // shallow + c.prefixes = *(n.prefixes.Copy()) - c.childrenBitset = n.childrenBitset.Clone() // deep - c.children = slices.Clone(n.children) // shallow + _, isCloner := any(*new(V)).(Cloner[V]) - // now clone the children deep - for i, child := range c.children { - c.children[i] = child.cloneRec() + // deep copy if V implements Cloner[V] + if isCloner { + for i, val := range c.prefixes.Items { + c.prefixes.Items[i] = cloneOrCopy(val) + } + } + + // shallow + c.children = *(n.children.Copy()) + + // deep copy of nodes and leaves + for i, kidAny := range c.children.Items { + switch kid := kidAny.(type) { + case *node[V]: + // clone the child node rec-descent + c.children.Items[i] = kid.cloneRec() + case *leaf[V]: + // deep copy if V implements Cloner[V] + c.children.Items[i] = kid.cloneLeaf() + + default: + panic("logic error, wrong node type") + } + } + + return c +} + +// cloneFlat, copies the node and clone the values in prefixes and path compressed leaves +// if V implements Cloner. Used in the various ...Persist functions. +func (n *node[V]) cloneFlat() *node[V] { + if n == nil { + return nil + } + + c := new(node[V]) + if n.isEmpty() { + return c + } + + // shallow copy + c.prefixes = *(n.prefixes.Copy()) + c.children = *(n.children.Copy()) + + if _, ok := any(*new(V)).(Cloner[V]); !ok { + // if V doesn't implement Cloner[V], return early + return c + } + + // deep copy of values in prefixes + for i, val := range c.prefixes.Items { + c.prefixes.Items[i] = cloneOrCopy(val) + } + + // deep copy of values in path compressed leaves + for i, kidAny := range c.children.Items { + if kidLeaf, ok := kidAny.(*leaf[V]); ok { + c.children.Items[i] = kidLeaf.cloneLeaf() + } } return c @@ -578,29 +367,39 @@ func (n *node[V]) cloneRec() *node[V] { // false value is propagated. // // The iteration order is not defined, just the simplest and fastest recursive implementation. -func (n *node[V]) allRec(path [16]byte, depth int, is4 bool, yield func(netip.Prefix, V) bool) bool { +func (n *node[V]) allRec(path stridePath, depth int, is4 bool, yield func(netip.Prefix, V) bool) bool { // for all prefixes in this node do ... - idxBackingArray := [maxNodePrefixes]uint{} - for _, idx := range n.allStrideIndexes(idxBackingArray[:]) { - val, _ := n.getValue(idx) - cidr, _ := cidrFromPath(path, depth, is4, idx) + allIndices := n.prefixes.AsSlice(make([]uint, 0, maxNodePrefixes)) + for _, idx := range allIndices { + cidr := cidrFromPath(path, depth, is4, idx) - // make the callback for this prefix - if !yield(cidr, val) { + // callback for this prefix and val + if !yield(cidr, n.prefixes.MustGet(idx)) { // early exit return false } } - // for all children in this node do ... - addrBackingArray := [maxNodeChildren]uint{} - for i, addr := range n.allChildAddrs(addrBackingArray[:]) { - child := n.children[i] - path[depth] = byte(addr) + // for all children (nodes and leaves) in this node do ... + allChildAddrs := n.children.AsSlice(make([]uint, 0, maxNodeChildren)) + for i, addr := range allChildAddrs { + switch kid := n.children.Items[i].(type) { + case *node[V]: + // rec-descent with this node + path[depth] = byte(addr) + if !kid.allRec(path, depth+1, is4, yield) { + // early exit + return false + } + case *leaf[V]: + // callback for this leaf + if !yield(kid.prefix, kid.value) { + // early exit + return false + } - if !child.allRec(path, depth+1, is4, yield) { - // early exit - return false + default: + panic("logic error, wrong node type") } } @@ -609,192 +408,322 @@ func (n *node[V]) allRec(path [16]byte, depth int, is4 bool, yield func(netip.Pr // allRecSorted runs recursive the trie, starting at node and // the yield function is called for each route entry with prefix and value. +// The iteration is in prefix sort order. +// // If the yield function returns false the recursion ends prematurely and the // false value is propagated. -// -// The iteration is in prefix sort order, it's a very complex implemenation compared with allRec. -func (n *node[V]) allRecSorted(path [16]byte, depth int, is4 bool, yield func(netip.Prefix, V) bool) bool { - // make backing arrays, no heap allocs - addrBackingArray := [maxNodeChildren]uint{} - idxBackingArray := [maxNodePrefixes]uint{} - +func (n *node[V]) allRecSorted(path stridePath, depth int, is4 bool, yield func(netip.Prefix, V) bool) bool { // get slice of all child octets, sorted by addr - childAddrs := n.allChildAddrs(addrBackingArray[:]) - childCursor := 0 + allChildAddrs := n.children.AsSlice(make([]uint, 0, maxNodeChildren)) // get slice of all indexes, sorted by idx - allIndices := n.allStrideIndexes(idxBackingArray[:]) + allIndices := n.prefixes.AsSlice(make([]uint, 0, maxNodePrefixes)) - // re-sort indexes by prefix in place + // sort indices in CIDR sort order slices.SortFunc(allIndices, cmpIndexRank) - // example for entry with root node: - // - // ▼ - // ├─ 0.0.0.1/32 <-- FOOTNOTE A: child 0 in first node - // ├─ 10.0.0.0/7 <-- FOOTNOTE B: prefix 10/7 in first node - // │ └─ 10.0.0.0/8 <-- FOOTNOTE C: prefix 10/8 in first node - // │ └─ 10.0.0.1/32 <-- FOOTNOTE D: child 10 in first node - // ├─ 127.0.0.0/8 <-- FOOTNOTE E: prefix 127/8 in first node - // └─ 192.168.0.0/16 <-- FOOTNOTE F: child 192 in first node + childCursor := 0 - // range over all indexes in this node, now in prefix sort order - // FOOTNOTE: B, C, E - for i, idx := range allIndices { - // get the host routes for this index - lower, upper := hostRoutesByIndex(idx) + // yield indices and childs in CIDR sort order + for _, pfxIdx := range allIndices { + pfxOctet, _ := idxToPfx(pfxIdx) - // adjust host routes for this idx in case the host routes - // of the following idx overlaps - // FOOTNOTE: B and C have overlaps in host routes - // FOOTNOTE: C, E don't overlap in host routes - // FOOTNOTE: E has no following prefix in this node - if i+1 < len(allIndices) { - lower, upper = adjustHostRoutes(idx, allIndices[i+1]) - } + // yield all childs before idx + for j := childCursor; j < len(allChildAddrs); j++ { + childAddr := allChildAddrs[j] - // handle childs before the host routes of idx - // FOOTNOTE: A - for j := childCursor; j < len(childAddrs); j++ { - addr := childAddrs[j] - octet := byte(addr) - - if octetToBaseIndex(octet) >= lower { - // lower border of host routes + if childAddr >= uint(pfxOctet) { break } - // we know the slice index, faster as n.getChild(octet) - c := n.children[j] + // yield the node (rec-descent) or leaf + switch kid := n.children.Items[j].(type) { + case *node[V]: + path[depth] = byte(childAddr) + if !kid.allRecSorted(path, depth+1, is4, yield) { + return false + } + case *leaf[V]: + if !yield(kid.prefix, kid.value) { + return false + } - // add (set) this octet to path - path[depth] = octet - - if !c.allRecSorted(path, depth+1, is4, yield) { - // early exit - return false + default: + panic("logic error, wrong node type") } childCursor++ } - // FOOTNOTE: B, C, F - // now handle prefix for idx - val, _ := n.getValue(idx) - cidr, _ := cidrFromPath(path, depth, is4, idx) - - if !yield(cidr, val) { - // early exit + // yield the prefix for this idx + cidr := cidrFromPath(path, depth, is4, pfxIdx) + // n.prefixes.Items[i] not possible after sorting allIndices + if !yield(cidr, n.prefixes.MustGet(pfxIdx)) { return false } - - // handle the children in host routes for this prefix - // FOOTNOTE: D - for j := childCursor; j < len(childAddrs); j++ { - addr := childAddrs[j] - octet := byte(addr) - if octetToBaseIndex(octet) > upper { - // out of host routes - break - } - - // we know the slice index, faster as n.getChild(octet) - c := n.children[j] - - // add (set) this octet to path - path[depth] = octet - - if !c.allRecSorted(path, depth+1, is4, yield) { - // early exit - return false - } - - childCursor++ - } } - // FOOTNOTE: F - // handle all the rest of the children - for j := childCursor; j < len(childAddrs); j++ { - addr := childAddrs[j] - octet := byte(addr) + // yield the rest of leaves and nodes (rec-descent) + for j := childCursor; j < len(allChildAddrs); j++ { + addr := allChildAddrs[j] + switch kid := n.children.Items[j].(type) { + case *node[V]: + path[depth] = byte(addr) + if !kid.allRecSorted(path, depth+1, is4, yield) { + return false + } + case *leaf[V]: + if !yield(kid.prefix, kid.value) { + return false + } - // we know the slice index, faster as n.getChild(octet) - c := n.children[j] - - // add (set) this octet to path - path[depth] = octet - - if !c.allRecSorted(path, depth+1, is4, yield) { - // early exit - return false + default: + panic("logic error, wrong node type") } } return true } -// adjustHostRoutes, helper function to adjust the lower, upper bounds of the -// host routes in case the host routes of the next idx overlaps -func adjustHostRoutes(idx, next uint) (lower, upper uint) { - lower, upper = hostRoutesByIndex(idx) +// unionRec combines two nodes, changing the receiver node. +// If there are duplicate entries, the value is taken from the other node. +// Count duplicate entries to adjust the t.size struct members. +func (n *node[V]) unionRec(o *node[V], depth int) (duplicates int) { + // for all prefixes in other node do ... + allIndices := o.prefixes.AsSlice(make([]uint, 0, maxNodePrefixes)) + for i, oIdx := range allIndices { + // insert/overwrite prefix/value from oNode to nNode + exists := n.prefixes.InsertAt(oIdx, o.prefixes.Items[i]) - // get the lower host route border of the next idx - nextLower, _ := hostRoutesByIndex(next) - - // is there an overlap? - switch { - case nextLower == lower: - upper = 0 - - // [------------] idx - // [-----] next - // make host routes for this idx invalid - // - // ][ idx - // [-----]^^^^^^] next - // - // these ^^^^^^ children are handled before next prefix - // - // sorry, I know, it's completely confusing - - case nextLower <= upper: - upper = nextLower - 1 - - // [------------] idx - // [------] next - // - // shrink host routes for this idx - // [----][------] idx, next - // ^ + // this prefix is duplicate in n and o + if exists { + duplicates++ + } } - return lower, upper + // for all child addrs in other node do ... + allOtherChildAddrs := o.children.AsSlice(make([]uint, 0, maxNodeChildren)) +LOOP: + for i, addr := range allOtherChildAddrs { + // 6 possible combinations for this child and other child child + // + // THIS, OTHER: + // ---------- + // NULL, node <-- easy, insert at cloned node + // NULL, leaf <-- easy, insert at cloned leaf + // node, node <-- easy, union rec-descent + // node, leaf <-- easy, insert other cloned leaf at depth+1 + // leaf, node <-- complex, push this leaf down, union rec-descent + // leaf, leaf <-- complex, push this leaf down, insert other cloned leaf at depth+1 + // + // try to get child at same addr from n + thisChild, thisExists := n.children.Get(addr) + if !thisExists { + switch otherChild := o.children.Items[i].(type) { + + case *node[V]: // NULL, node + if !thisExists { + n.children.InsertAt(addr, otherChild.cloneRec()) + continue LOOP + } + + case *leaf[V]: // NULL, leaf + if !thisExists { + n.children.InsertAt(addr, otherChild.cloneLeaf()) + continue LOOP + } + + default: + panic("logic error, wrong node type") + } + } + + switch otherChild := o.children.Items[i].(type) { + + case *node[V]: + switch this := thisChild.(type) { + + case *node[V]: // node, node + // both childs have node in octet, call union rec-descent on child nodes + duplicates += this.unionRec(otherChild, depth+1) + continue LOOP + + case *leaf[V]: // leaf, node + // create new node + nc := new(node[V]) + + // push this leaf down + nc.insertAtDepth(this.prefix, this.value, depth+1) + + // insert new node at current addr + n.children.InsertAt(addr, nc) + + // union rec-descent new node with other node + duplicates += nc.unionRec(otherChild, depth+1) + continue LOOP + } + + case *leaf[V]: + switch this := thisChild.(type) { + + case *node[V]: // node, leaf + clonedLeaf := otherChild.cloneLeaf() + if this.insertAtDepth(clonedLeaf.prefix, clonedLeaf.value, depth+1) { + duplicates++ + } + continue LOOP + + case *leaf[V]: // leaf, leaf + // create new node + nc := new(node[V]) + + // push this leaf down + nc.insertAtDepth(this.prefix, this.value, depth+1) + + // insert at depth cloned leaf + clonedLeaf := otherChild.cloneLeaf() + if nc.insertAtDepth(clonedLeaf.prefix, clonedLeaf.value, depth+1) { + duplicates++ + } + + // insert the new node at current addr + n.children.InsertAt(addr, nc) + continue LOOP + } + + default: + panic("logic error, wrong node type") + } + } + + return duplicates } -// numPrefixesRec, calculate the number of prefixes under n. -func (n *node[V]) numPrefixesRec() int { - size := len(n.prefixes) // this node - for _, c := range n.children { - size += c.numPrefixesRec() +// eachLookupPrefix does an all prefix match in the 8-bit (stride) routing table +// at this depth and calls yield() for any matching CIDR. +func (n *node[V]) eachLookupPrefix(octets []byte, depth int, is4 bool, pfxLen int, yield func(netip.Prefix, V) bool) (ok bool) { + if n.prefixes.Len() == 0 { + return true } - return size + + // octets as array, needed below more than once + var path stridePath + copy(path[:], octets) + + // backtracking the CBT + for idx := pfxToIdx(octets[depth], pfxLen); idx > 0; idx >>= 1 { + if n.prefixes.Test(idx) { + val := n.prefixes.MustGet(idx) + cidr := cidrFromPath(path, depth, is4, idx) + + if !yield(cidr, val) { + return false + } + } + } + + return true } -// numNodesRec, calculate the number of nodes under n. -func (n *node[V]) numNodesRec() int { - size := 1 // this node - for _, c := range n.children { - size += c.numNodesRec() - } - return size -} +// eachSubnet calls yield() for any covered CIDR by parent prefix in natural CIDR sort order. +func (n *node[V]) eachSubnet(octets []byte, depth int, is4 bool, pfxLen int, yield func(netip.Prefix, V) bool) bool { + // octets as array, needed below more than once + var path stridePath + copy(path[:], octets) -// cmpPrefix, compare func for prefix sort, -// all cidrs are already normalized -func cmpPrefix(a, b netip.Prefix) int { - if cmp := a.Addr().Compare(b.Addr()); cmp != 0 { - return cmp + pfxFirstAddr := uint(octets[depth]) + pfxLastAddr := uint(octets[depth] | ^netMask(pfxLen)) + + // 1. collect all indices in n covered by prefix + + allCoveredIndices := make([]uint, 0, maxNodePrefixes) + for _, idx := range n.prefixes.AsSlice(make([]uint, 0, maxNodePrefixes)) { + thisOctet, thisPfxLen := idxToPfx(idx) + + thisFirstAddr := uint(thisOctet) + thisLastAddr := uint(thisOctet | ^netMask(thisPfxLen)) + + if thisFirstAddr >= pfxFirstAddr && thisLastAddr <= pfxLastAddr { + allCoveredIndices = append(allCoveredIndices, idx) + } } - return cmp.Compare(a.Bits(), b.Bits()) + + // sort indices in CIDR sort order + slices.SortFunc(allCoveredIndices, cmpIndexRank) + + // 2. collect all covered child addrs by prefix + + allCoveredChildAddrs := make([]uint, 0, maxNodeChildren) + for _, addr := range n.children.AsSlice(make([]uint, 0, maxNodeChildren)) { + if addr >= pfxFirstAddr && addr <= pfxLastAddr { + allCoveredChildAddrs = append(allCoveredChildAddrs, addr) + } + } + + // 3. yield covered indices, pathcomp prefixes and childs in CIDR sort order + + addrCursor := 0 + + // yield indices and childs in CIDR sort order + for _, pfxIdx := range allCoveredIndices { + pfxOctet, _ := idxToPfx(pfxIdx) + + // yield all childs before idx + for j := addrCursor; j < len(allCoveredChildAddrs); j++ { + addr := allCoveredChildAddrs[j] + if addr >= uint(pfxOctet) { + break + } + + // yield the node or leaf? + switch kid := n.children.MustGet(addr).(type) { + + case *node[V]: + path[depth] = byte(addr) + if !kid.allRecSorted(path, depth+1, is4, yield) { + return false + } + + case *leaf[V]: + if !yield(kid.prefix, kid.value) { + return false + } + + default: + panic("logic error, wrong node type") + } + + addrCursor++ + } + + // yield the prefix for this idx + cidr := cidrFromPath(path, depth, is4, pfxIdx) + // n.prefixes.Items[i] not possible after sorting allIndices + if !yield(cidr, n.prefixes.MustGet(pfxIdx)) { + return false + } + } + + // yield the rest of leaves and nodes (rec-descent) + for _, addr := range allCoveredChildAddrs[addrCursor:] { + // yield the node or leaf? + switch kid := n.children.MustGet(addr).(type) { + + case *node[V]: + path[depth] = byte(addr) + if !kid.allRecSorted(path, depth+1, is4, yield) { + return false + } + + case *leaf[V]: + if !yield(kid.prefix, kid.value) { + return false + } + + default: + panic("logic error, wrong node type") + } + } + + return true } diff --git a/vendor/github.com/gaissmai/bart/overlaps.go b/vendor/github.com/gaissmai/bart/overlaps.go new file mode 100644 index 0000000..f0ce66f --- /dev/null +++ b/vendor/github.com/gaissmai/bart/overlaps.go @@ -0,0 +1,305 @@ +package bart + +import ( + "net/netip" + + "github.com/gaissmai/bart/internal/bitset" +) + +// overlaps returns true if any IP in the nodes n or o overlaps. +func (n *node[V]) overlaps(o *node[V], depth int) bool { + nPfxCount := n.prefixes.Len() + oPfxCount := o.prefixes.Len() + + nChildCount := n.children.Len() + oChildCount := o.children.Len() + + // ############################## + // 1. Test if any routes overlaps + // ############################## + + // full cross check + if nPfxCount > 0 && oPfxCount > 0 { + if n.overlapsRoutes(o) { + return true + } + } + + // #################################### + // 2. Test if routes overlaps any child + // #################################### + + // swap nodes to help chance on its way, + // if the first call to expensive overlapsChildrenIn() is already true, + // if both orders are false it doesn't help either + if nChildCount > oChildCount { + n, o = o, n + + nPfxCount = n.prefixes.Len() + oPfxCount = o.prefixes.Len() + + nChildCount = n.children.Len() + oChildCount = o.children.Len() + } + + if nPfxCount > 0 && oChildCount > 0 { + if n.overlapsChildrenIn(o) { + return true + } + } + + // symmetric reverse + if oPfxCount > 0 && nChildCount > 0 { + if o.overlapsChildrenIn(n) { + return true + } + } + + // ########################################### + // 3. childs with same octet in nodes n and o + // ########################################### + + // stop condition, n or o have no childs + if nChildCount == 0 || oChildCount == 0 { + return false + } + + // stop condition, no child with identical octet in n and o + if !n.children.IntersectsAny(o.children.BitSet) { + return false + } + + return n.overlapsSameChildren(o, depth) +} + +// overlapsRoutes, test if n overlaps o prefixes and vice versa +func (n *node[V]) overlapsRoutes(o *node[V]) bool { + // some prefixes are identical, trivial overlap + if n.prefixes.IntersectsAny(o.prefixes.BitSet) { + return true + } + + // get the lowest idx (biggest prefix) + nFirstIdx, _ := n.prefixes.FirstSet() + oFirstIdx, _ := o.prefixes.FirstSet() + + // start with other min value, see ART algo + nIdx := oFirstIdx + oIdx := nFirstIdx + + // make full cross check + nOK := true + oOK := true + + // zip, range over n and o together to help chance on its way + for nOK || oOK { + if nOK { + // does any route in o overlap this prefix from n + if nIdx, nOK = n.prefixes.NextSet(nIdx); nOK { + if o.lpmTest(nIdx) { + return true + } + + nIdx++ + } + } + + if oOK { + // does any route in n overlap this prefix from o + if oIdx, oOK = o.prefixes.NextSet(oIdx); oOK { + if n.lpmTest(oIdx) { + return true + } + + oIdx++ + } + } + } + + return false +} + +// overlapsChildrenIn, test if prefixes in n overlaps child octets in o. +func (n *node[V]) overlapsChildrenIn(o *node[V]) bool { + pfxCount := n.prefixes.Len() + childCount := o.children.Len() + + // heuristic, compare benchmarks + // when will we range over the children and when will we do bitset calc? + magicNumber := 15 + doRange := childCount < magicNumber || pfxCount > magicNumber + + // do range over, not so many childs and maybe to many prefixes for other algo below + if doRange { + lowerBound, _ := n.prefixes.FirstSet() + for _, addr := range o.children.AsSlice(make([]uint, 0, maxNodeChildren)) { + idx := hostIndex(addr) + if idx < lowerBound { // lpm match impossible + continue + } + if n.lpmTest(idx) { + return true + } + } + + return false + } + + // do bitset intersection, alloted route table with child octets + // maybe to many childs for range over or not so many prefixes to + // build the alloted routing table from them + + // make allot table with prefixes as bitsets, bitsets are precalculated + // just union the bitsets to one bitset (allot table) for all prefixes + // in this node + prefixRoutes := bitset.BitSet(make([]uint64, 8)) + + allIndices := n.prefixes.AsSlice(make([]uint, 0, maxNodePrefixes)) + + for _, idx := range allIndices { + // get pre alloted bitset for idx + prefixRoutes.InPlaceUnion(allotLookupTbl[idx]) + } + + // clone a bitset without heap allocation + // shift-right children bitset by 256 (firstHostIndex) + c8 := make([]uint64, 8) + copy(c8[4:], o.children.BitSet) // 4*64= 256 + hostRoutes := bitset.BitSet(c8) + + return prefixRoutes.IntersectsAny(hostRoutes) +} + +// overlapsSameChildren, find same octets with bitset intersection. +func (n *node[V]) overlapsSameChildren(o *node[V], depth int) bool { + // clone a bitset without heap allocation + c4 := [4]uint64{} + copy(c4[:], n.children.BitSet) + nChildrenBitsetCloned := bitset.BitSet(c4[:]) + + // intersect in place the cloned child bitset from n with o + nChildrenBitsetCloned.InPlaceIntersection(o.children.BitSet) + + allCommonChildren := nChildrenBitsetCloned.AsSlice(make([]uint, 0, maxNodeChildren)) + + // range over all child addrs, common in n and o + for _, addr := range allCommonChildren { + nChild := n.children.MustGet(addr) + oChild := o.children.MustGet(addr) + + if overlapsTwoChilds[V](nChild, oChild, depth+1) { + return true + } + } + + return false +} + +// overlapsTwoChilds, childs can be node or leaf. +func overlapsTwoChilds[V any](nChild, oChild any, depth int) bool { + // 4 possible different combinations for n and o + // + // node, node --> overlapsRec + // node, leaf --> overlapsPrefixAtDepth + // leaf, node --> overlapsPrefixAtDepth + // leaf, leaf --> netip.Prefix.Overlaps + // + switch nKind := nChild.(type) { + + case *node[V]: + switch oKind := oChild.(type) { + case *node[V]: // node, node + return nKind.overlaps(oKind, depth) + case *leaf[V]: // node, leaf + return nKind.overlapsPrefixAtDepth(oKind.prefix, depth) + } + + case *leaf[V]: + switch oKind := oChild.(type) { + case *node[V]: // leaf, node + return oKind.overlapsPrefixAtDepth(nKind.prefix, depth) + case *leaf[V]: // leaf, leaf + return oKind.prefix.Overlaps(nKind.prefix) + } + + default: + panic("logic error, wrong node type") + } + + return false +} + +// overlapsPrefixAtDepth, returns true if node overlaps with prefix +// starting with prefix octet at depth. +// +// Needed for path compressed prefix some level down in the node trie. +func (n *node[V]) overlapsPrefixAtDepth(pfx netip.Prefix, depth int) bool { + ip := pfx.Addr() + bits := pfx.Bits() + + lastIdx, lastBits := lastOctetIdxAndBits(bits) + + octets := ip.AsSlice() + octets = octets[:lastIdx+1] + + for ; depth < len(octets); depth++ { + octet := octets[depth] + addr := uint(octet) + + // full octet path in node trie, check overlap with last prefix octet + if depth == lastIdx { + return n.overlapsIdx(pfxToIdx(octet, lastBits)) + } + + // test if any route overlaps prefix´ so far + // no best match needed, forward tests without backtracking + if n.prefixes.Len() != 0 && n.lpmTest(hostIndex(addr)) { + return true + } + + if !n.children.Test(addr) { + return false + } + + // next child, node or leaf + switch kid := n.children.MustGet(addr).(type) { + case *node[V]: + n = kid + continue + case *leaf[V]: + return kid.prefix.Overlaps(pfx) + + default: + panic("logic error, wrong node type") + } + } + + panic("unreachable: " + pfx.String()) +} + +// overlapsIdx returns true if node overlaps with prefix. +func (n *node[V]) overlapsIdx(idx uint) bool { + // 1. Test if any route in this node overlaps prefix? + if n.lpmTest(idx) { + return true + } + + // 2. Test if prefix overlaps any route in this node + + // use bitset intersections instead of range loops + // shallow copy pre alloted bitset for idx + allotedPrefixRoutes := allotLookupTbl[idx] + if allotedPrefixRoutes.IntersectsAny(n.prefixes.BitSet) { + return true + } + + // 3. Test if prefix overlaps any child in this node + + // shift-right children bitset by 256 (firstHostIndex) + c8 := [8]uint64{} + copy(c8[4:], n.children.BitSet) // 4*64= 256 + hostRoutes := bitset.BitSet(c8[:]) + + // use bitsets intersection instead of range loops + return allotedPrefixRoutes.IntersectsAny(hostRoutes) +} diff --git a/vendor/github.com/gaissmai/bart/stringify.go b/vendor/github.com/gaissmai/bart/stringify.go index c41361a..68b7dc0 100644 --- a/vendor/github.com/gaissmai/bart/stringify.go +++ b/vendor/github.com/gaissmai/bart/stringify.go @@ -5,6 +5,7 @@ package bart import ( "bytes" + "cmp" "fmt" "io" "net/netip" @@ -18,7 +19,8 @@ import ( type kid[V any] struct { // for traversing n *node[V] - path [16]byte + is4 bool + path stridePath depth int idx uint @@ -27,14 +29,14 @@ type kid[V any] struct { val V } -// MarshalText implements the encoding.TextMarshaler interface, +// MarshalText implements the [encoding.TextMarshaler] interface, // just a wrapper for [Table.Fprint]. func (t *Table[V]) MarshalText() ([]byte, error) { - t.init() w := new(bytes.Buffer) if err := t.Fprint(w); err != nil { return nil, err } + return w.Bytes(), nil } @@ -42,46 +44,47 @@ func (t *Table[V]) MarshalText() ([]byte, error) { // as string, just a wrapper for [Table.Fprint]. // If Fprint returns an error, String panics. func (t *Table[V]) String() string { - t.init() w := new(strings.Builder) if err := t.Fprint(w); err != nil { panic(err) } + return w.String() } -// Fprint writes a hierarchical tree diagram of the ordered CIDRs to w. -// If w is nil, Fprint panics. +// Fprint writes a hierarchical tree diagram of the ordered CIDRs +// with default formatted payload V to w. If w is nil, Fprint panics. // // The order from top to bottom is in ascending order of the prefix address // and the subtree structure is determined by the CIDRs coverage. // // ▼ -// ├─ 10.0.0.0/8 (9.9.9.9) -// │ ├─ 10.0.0.0/24 (8.8.8.8) -// │ └─ 10.0.1.0/24 (10.0.0.0) -// ├─ 127.0.0.0/8 (127.0.0.1) -// │ └─ 127.0.0.1/32 (127.0.0.1) -// ├─ 169.254.0.0/16 (10.0.0.0) -// ├─ 172.16.0.0/12 (8.8.8.8) -// └─ 192.168.0.0/16 (9.9.9.9) -// └─ 192.168.1.0/24 (127.0.0.1) +// ├─ 10.0.0.0/8 (V) +// │ ├─ 10.0.0.0/24 (V) +// │ └─ 10.0.1.0/24 (V) +// ├─ 127.0.0.0/8 (V) +// │ └─ 127.0.0.1/32 (V) +// ├─ 169.254.0.0/16 (V) +// ├─ 172.16.0.0/12 (V) +// └─ 192.168.0.0/16 (V) +// └─ 192.168.1.0/24 (V) // ▼ -// └─ ::/0 (2001:db8::1) -// ├─ ::1/128 (::1%lo) -// ├─ 2000::/3 (2001:db8::1) -// │ └─ 2001:db8::/32 (2001:db8::1) -// └─ fe80::/10 (::1%eth0) +// └─ ::/0 (V) +// ├─ ::1/128 (V) +// ├─ 2000::/3 (V) +// │ └─ 2001:db8::/32 (V) +// └─ fe80::/10 (V) func (t *Table[V]) Fprint(w io.Writer) error { - t.init() - + // v4 if err := t.fprint(w, true); err != nil { return err } + // v6 if err := t.fprint(w, false); err != nil { return err } + return nil } @@ -95,16 +98,30 @@ func (t *Table[V]) fprint(w io.Writer, is4 bool) error { if _, err := fmt.Fprint(w, "▼\n"); err != nil { return err } - if err := n.fprintRec(w, 0, zeroPath, 0, is4, ""); err != nil { + + startKid := kid[V]{ + n: nil, + idx: 0, + path: stridePath{}, + is4: is4, + } + + if err := n.fprintRec(w, startKid, ""); err != nil { return err } + return nil } -// fprintRec, the output is a hierarchical CIDR tree starting with parentIdx and byte path. -func (n *node[V]) fprintRec(w io.Writer, parentIdx uint, path [16]byte, depth int, is4 bool, pad string) error { - // get direct childs for this parentIdx ... - directKids := n.getKidsRec(parentIdx, path, depth, is4) +// fprintRec, the output is a hierarchical CIDR tree starting with this kid. +func (n *node[V]) fprintRec(w io.Writer, parent kid[V], pad string) error { + // recursion stop condition + if n == nil { + return nil + } + + // get direct childs for this kid ... + directKids := n.getKidsRec(parent.idx, parent.path, parent.depth, parent.is4) // sort them by netip.Prefix, not by baseIndex slices.SortFunc(directKids, cmpKidByPrefix[V]) @@ -129,7 +146,7 @@ func (n *node[V]) fprintRec(w io.Writer, parentIdx uint, path [16]byte, depth in // rec-descent with this prefix as parentIdx. // hierarchical nested tree view, two rec-descent functions // work together to spoil the reader. - if err := kid.n.fprintRec(w, kid.idx, kid.path, kid.depth, is4, pad+spacer); err != nil { + if err := kid.n.fprintRec(w, kid, pad+spacer); err != nil { return err } } @@ -143,71 +160,104 @@ func (n *node[V]) fprintRec(w io.Writer, parentIdx uint, path [16]byte, depth in // // See the artlookup.pdf paper in the doc folder, // the baseIndex function is the key. -func (n *node[V]) getKidsRec(parentIdx uint, path [16]byte, depth int, is4 bool) []kid[V] { - directKids := []kid[V]{} +func (n *node[V]) getKidsRec(parentIdx uint, path stridePath, depth int, is4 bool) []kid[V] { + // recursion stop condition + if n == nil { + return nil + } - // make backing arrays, no heap allocs - idxBackingArray := [maxNodePrefixes]uint{} - for _, idx := range n.allStrideIndexes(idxBackingArray[:]) { + var directKids []kid[V] + + for _, idx := range n.prefixes.All() { // parent or self, handled alreday in an upper stack frame. if idx <= parentIdx { continue } // check if lpmIdx for this idx' parent is equal to parentIdx - lpmIdx, _, _ := n.lpm(idx >> 1) - if lpmIdx == parentIdx { - // idx is directKid - val, _ := n.getValue(idx) - cidr, _ := cidrFromPath(path, depth, is4, idx) + lpmIdx, _, _ := n.lpmGet(idx >> 1) - directKids = append(directKids, kid[V]{n, path, depth, idx, cidr, val}) + // if idx is directKid? + if lpmIdx == parentIdx { + cidr := cidrFromPath(path, depth, is4, idx) + + kid := kid[V]{ + n: n, + is4: is4, + path: path, + depth: depth, + idx: idx, + cidr: cidr, + val: n.prefixes.MustGet(idx), + } + + directKids = append(directKids, kid) } } - // the node may have childs, the rec-descent monster starts - addrBackingArray := [maxNodeChildren]uint{} - for i, addr := range n.allChildAddrs(addrBackingArray[:]) { - octet := byte(addr) + // the node may have childs and leaves, the rec-descent monster starts + for i, addr := range n.children.All() { // do a longest-prefix-match - lpmIdx, _, _ := n.lpm(octetToBaseIndex(octet)) + lpmIdx, _, _ := n.lpmGet(hostIndex(addr)) if lpmIdx == parentIdx { - c := n.children[i] - path[depth] = octet + switch k := n.children.Items[i].(type) { + case *node[V]: + path[depth] = byte(addr) - // traverse, rec-descent call with next child node - directKids = append(directKids, c.getKidsRec(0, path, depth+1, is4)...) + // traverse, rec-descent call with next child node + directKids = append(directKids, k.getKidsRec(0, path, depth+1, is4)...) + case *leaf[V]: + kid := kid[V]{ + n: nil, // path compressed item, stop recursion + is4: is4, + cidr: k.prefix, + val: k.value, + } + + directKids = append(directKids, kid) + } } } return directKids } -// cidrFromPath, get prefix back from byte path, depth, octet and pfxLen. -func cidrFromPath(path [16]byte, depth int, is4 bool, idx uint) (netip.Prefix, error) { - octet, pfxLen := baseIndexToPrefix(idx) +// cmpKidByPrefix, all prefixes are already normalized (Masked). +func cmpKidByPrefix[V any](a, b kid[V]) int { + return cmpPrefix(a.cidr, b.cidr) +} - // set (partially) masked byte in path at depth +// cmpPrefix, compare func for prefix sort, +// all cidrs are already normalized +func cmpPrefix(a, b netip.Prefix) int { + if cmp := a.Addr().Compare(b.Addr()); cmp != 0 { + return cmp + } + + return cmp.Compare(a.Bits(), b.Bits()) +} + +// cidrFromPath, get prefix back from byte path, depth, octet and pfxLen. +func cidrFromPath(path stridePath, depth int, is4 bool, idx uint) netip.Prefix { + octet, pfxLen := idxToPfx(idx) + + // set masked byte in path at depth path[depth] = octet + // zero/mask the bytes after prefix bits + clear(path[depth+1:]) + // make ip addr from octets var ip netip.Addr if is4 { - b4 := [4]byte{} - copy(b4[:], path[:4]) - ip = netip.AddrFrom4(b4) + ip = netip.AddrFrom4([4]byte(path[:4])) } else { ip = netip.AddrFrom16(path) } // calc bits with pathLen and pfxLen - bits := depth*strideLen + pfxLen + bits := depth<<3 + pfxLen - // make a normalized prefix from ip/bits - return ip.Prefix(bits) -} - -// cmpKidByPrefix, all prefixes are already normalized (Masked). -func cmpKidByPrefix[V any](a, b kid[V]) int { - return cmpPrefix(a.cidr, b.cidr) + // return a normalized prefix from ip/bits + return netip.PrefixFrom(ip, bits) } diff --git a/vendor/github.com/gaissmai/bart/table.go b/vendor/github.com/gaissmai/bart/table.go index 19f2cec..d9d356c 100644 --- a/vendor/github.com/gaissmai/bart/table.go +++ b/vendor/github.com/gaissmai/bart/table.go @@ -1,152 +1,141 @@ -// Copyright (c) 2024 Karl Gaissmaier // SPDX-License-Identifier: MIT // package bart provides a Balanced-Routing-Table (BART). // -// BART is balanced in terms of memory consumption versus -// lookup time. -// -// The lookup time is by a factor of ~2 slower on average as the -// routing algorithms ART, SMART, CPE, ... but reduces the memory -// consumption by an order of magnitude in comparison. +// BART is balanced in terms of memory usage and lookup time +// for the longest-prefix match. // // BART is a multibit-trie with fixed stride length of 8 bits, // using the _baseIndex_ function from the ART algorithm to // build the complete-binary-tree (CBT) of prefixes for each stride. // -// The second key factor is popcount array compression at each stride level -// of the CBT prefix tree and backtracking along the CBT in O(k). -// -// The CBT is implemented as a bitvector, backtracking is just +// The CBT is implemented as a bit-vector, backtracking is just // a matter of fast cache friendly bitmask operations. // -// The child array at each stride level is also popcount compressed. +// The routing table is implemented with popcount compressed sparse arrays +// together with path compression. This reduces storage consumption +// by almost two orders of magnitude in comparison to ART with +// similar lookup times for the longest prefix match. package bart import ( + "iter" "net/netip" - "sync" ) // Table is an IPv4 and IPv6 routing table with payload V. // The zero value is ready to use. // -// The Table is safe for concurrent readers but not for -// concurrent readers and/or writers. +// The Table is safe for concurrent readers but not for concurrent readers +// and/or writers. Either the update operations must be protected by an +// external lock mechanism or the various ...Persist functions must be used +// which return a modified routing table by leaving the original unchanged +// +// A Table must not be copied by value, see [Table.Clone]. type Table[V any] struct { - rootV4 *node[V] - rootV6 *node[V] + // used by -copylocks checker from `go vet`. + _ noCopy + // the root nodes, implemented as popcount compressed multibit tries + root4 node[V] + root6 node[V] + + // the number of prefixes in the routing table size4 int size6 int - - // BitSets have to be initialized. - initOnce sync.Once } -// init BitSets once, so no constructor is needed -func (t *Table[V]) init() { - // upfront nil test, faster than the atomic load in sync.Once.Do - // this makes bulk inserts 5% faster and the table is not safe - // for concurrent writers anyway - if t.rootV6 != nil { - return - } - - t.initOnce.Do(func() { - t.rootV4 = newNode[V]() - t.rootV6 = newNode[V]() - }) -} - -// rootNodeByVersion, select root node for ip version. +// rootNodeByVersion, root node getter for ip version. func (t *Table[V]) rootNodeByVersion(is4 bool) *node[V] { if is4 { - return t.rootV4 + return &t.root4 } - return t.rootV6 + + return &t.root6 } -// Insert adds pfx to the tree, with value val. +// Insert adds pfx to the tree, with given val. // If pfx is already present in the tree, its value is set to val. func (t *Table[V]) Insert(pfx netip.Prefix, val V) { - t.init() - if !pfx.IsValid() { return } - // values derived from pfx - ip := pfx.Addr() - is4 := ip.Is4() - bits := pfx.Bits() + // canonicalize prefix + pfx = pfx.Masked() - // get the root node of the routing table + is4 := pfx.Addr().Is4() n := t.rootNodeByVersion(is4) - // Do not allocate! - // As16() is inlined, the prefered AsSlice() is too complex for inlining. - // starting with go1.23 we can use AsSlice(), - // see https://github.com/golang/go/issues/56136 - - a16 := ip.As16() - octets := a16[:] - if is4 { - octets = octets[12:] + if n.insertAtDepth(pfx, val, 0) { + return } - // 10.0.0.0/8 -> 0 - // 10.12.0.0/15 -> 1 - // 10.12.0.0/16 -> 1 - // 10.12.10.9/32 -> 3 - lastOctetIdx := (bits - 1) / strideLen + // true insert, update size + t.sizeUpdate(is4, 1) +} - // 10.0.0.0/8 -> 10 - // 10.12.0.0/15 -> 12 - // 10.12.0.0/16 -> 12 - // 10.12.10.9/32 -> 9 - lastOctet := octets[lastOctetIdx] - - // 10.0.0.0/8 -> 8 - // 10.12.0.0/15 -> 7 - // 10.12.0.0/16 -> 8 - // 10.12.10.9/32 -> 8 - lastOctetBits := bits - (lastOctetIdx * strideLen) - - // mask the prefix, this is faster than netip.Prefix.Masked() - lastOctet = lastOctet & netMask(lastOctetBits) - - // find the proper trie node to insert prefix - for _, octet := range octets[:lastOctetIdx] { - // descend down to next trie level - c := n.getChild(octet) - if c == nil { - // create and insert missing intermediate child - c = newNode[V]() - n.insertChild(octet, c) - } - - // proceed with next level - n = c +// InsertPersist is similar to Insert but the receiver isn't modified. +// +// All nodes touched during insert are cloned and a new Table is returned. +// This is not a full [Table.Clone], all untouched nodes are still referenced +// from both Tables. +// +// If the payload V is a pointer or contains a pointer, it should +// implement the cloner interface. +// +// This is orders of magnitude slower than Insert (μsec versus nsec). +// +// The bulk table load should be done with [Table.Insert] and then you can +// use InsertPersist, [Table.UpdatePersist] and [Table.DeletePersist] for lock-free updates. +func (t *Table[V]) InsertPersist(pfx netip.Prefix, val V) *Table[V] { + if !pfx.IsValid() { + return t } - // insert prefix/val into node - if n.insertPrefix(prefixToBaseIndex(lastOctet, lastOctetBits), val) { - t.sizeUpdate(is4, 1) + pt := &Table[V]{ + root4: t.root4, + root6: t.root6, + size4: t.size4, + size6: t.size6, } + + // canonicalize prefix + pfx = pfx.Masked() + + is4 := pfx.Addr().Is4() + + n := pt.rootNodeByVersion(is4) + + // clone the root of insertion path + *n = *n.cloneFlat() + + // clone nodes along the insertion path + if n.insertAtDepthPersist(pfx, val, 0) { + // prefix existed, no size increment + return pt + } + + // true insert, update size + pt.sizeUpdate(is4, 1) + + return pt } // Update or set the value at pfx with a callback function. -// The callback function is called with (value, ok) and returns a new value.. +// The callback function is called with (value, ok) and returns a new value. // // If the pfx does not already exist, it is set with the new value. func (t *Table[V]) Update(pfx netip.Prefix, cb func(val V, ok bool) V) (newVal V) { - t.init() + var zero V + if !pfx.IsValid() { - var zero V return zero } + // canonicalize prefix + pfx = pfx.Masked() + // values derived from pfx ip := pfx.Addr() is4 := ip.Is4() @@ -154,226 +143,542 @@ func (t *Table[V]) Update(pfx netip.Prefix, cb func(val V, ok bool) V) (newVal V n := t.rootNodeByVersion(is4) - // do not allocate - a16 := ip.As16() - octets := a16[:] - if is4 { - octets = octets[12:] - } + lastIdx, lastBits := lastOctetIdxAndBits(bits) - // see comment in Insert() - lastOctetIdx := (bits - 1) / strideLen - lastOctet := octets[lastOctetIdx] - lastOctetBits := bits - (lastOctetIdx * strideLen) - - // mask the prefix - lastOctet = lastOctet & netMask(lastOctetBits) + octets := ip.AsSlice() + octets = octets[:lastIdx+1] // find the proper trie node to update prefix - for _, octet := range octets[:lastOctetIdx] { - // descend down to next trie level - c := n.getChild(octet) - if c == nil { - // create and insert missing intermediate child - c = newNode[V]() - n.insertChild(octet, c) + for depth, octet := range octets { + // last octet from prefix, update/insert prefix into node + if depth == lastIdx { + newVal, exists := n.prefixes.UpdateAt(pfxToIdx(octet, lastBits), cb) + if !exists { + t.sizeUpdate(is4, 1) + } + return newVal } - // proceed with next level - n = c + addr := uint(octet) + + // go down in tight loop to last octet + if !n.children.Test(addr) { + // insert prefix path compressed + newVal := cb(zero, false) + n.children.InsertAt(addr, &leaf[V]{pfx, newVal}) + t.sizeUpdate(is4, 1) + return newVal + } + + // get node or leaf for octet + switch kid := n.children.MustGet(addr).(type) { + case *node[V]: + n = kid + continue // descend down to next trie level + + case *leaf[V]: + // update existing value if prefixes are equal + if kid.prefix == pfx { + kid.value = cb(kid.value, true) + return kid.value + } + + // create new node + // push the leaf down + // insert new child at current leaf position (addr) + // descend down, replace n with new child + newNode := new(node[V]) + newNode.insertAtDepth(kid.prefix, kid.value, depth+1) + + n.children.InsertAt(addr, newNode) + n = newNode + + default: + panic("logic error, wrong node type") + } } - // update/insert prefix into node - var wasPresent bool - newVal, wasPresent = n.updatePrefix(lastOctet, lastOctetBits, cb) - if !wasPresent { - t.sizeUpdate(is4, 1) + panic("unreachable") +} + +// UpdatePersist is similar to Update but the receiver isn't modified. +// +// All nodes touched during update are cloned and a new Table is returned. +// This is not a full [Table.Clone], all untouched nodes are still referenced +// from both Tables. +// +// If the payload V is a pointer or contains a pointer, it should +// implement the cloner interface. +// +// This is orders of magnitude slower than Update (μsec versus nsec). +func (t *Table[V]) UpdatePersist(pfx netip.Prefix, cb func(val V, ok bool) V) (pt *Table[V], newVal V) { + var zero V + + if !pfx.IsValid() { + return t, zero } - return newVal + // canonicalize prefix + pfx = pfx.Masked() + + // values derived from pfx + ip := pfx.Addr() + is4 := ip.Is4() + bits := pfx.Bits() + + pt = &Table[V]{ + root4: t.root4, + root6: t.root6, + size4: t.size4, + size6: t.size6, + } + + n := pt.rootNodeByVersion(is4) + + // clone the root of insertion path + *n = *(n.cloneFlat()) + + lastIdx, lastBits := lastOctetIdxAndBits(bits) + + octets := ip.AsSlice() + octets = octets[:lastIdx+1] + + // find the proper trie node to update prefix + for depth, octet := range octets { + // last octet from prefix, update/insert prefix into node + if depth == lastIdx { + newVal, exists := n.prefixes.UpdateAt(pfxToIdx(octet, lastBits), cb) + if !exists { + pt.sizeUpdate(is4, 1) + } + return pt, newVal + } + + addr := uint(octet) + + // go down in tight loop to last octet + if !n.children.Test(addr) { + // insert prefix path compressed + newVal := cb(zero, false) + n.children.InsertAt(addr, &leaf[V]{pfx, newVal}) + + pt.sizeUpdate(is4, 1) + return pt, newVal + } + + // get node or leaf for octet + switch kid := n.children.MustGet(addr).(type) { + case *node[V]: + // proceed to next level + kid = kid.cloneFlat() + n.children.InsertAt(addr, kid) + n = kid + continue // descend down to next trie level + + case *leaf[V]: + kid = kid.cloneLeaf() + + // update existing value if prefixes are equal + if kid.prefix == pfx { + newVal = cb(kid.value, true) + n.children.InsertAt(addr, &leaf[V]{pfx, newVal}) + return pt, newVal + } + + // create new node + // push the leaf down + // insert new child at current leaf position (addr) + // descend down, replace n with new child + newNode := new(node[V]) + newNode.insertAtDepth(kid.prefix, kid.value, depth+1) + + n.children.InsertAt(addr, newNode) + n = newNode + + default: + panic("logic error, wrong node type") + } + } + + panic("unreachable") +} + +// Delete removes pfx from the tree, pfx does not have to be present. +func (t *Table[V]) Delete(pfx netip.Prefix) { + _, _ = t.getAndDelete(pfx) +} + +// DeletePersist is similar to Delete but the receiver isn't modified. +// All nodes touched during delete are cloned and a new Table is returned. +// +// This is orders of magnitude slower than Delete (μsec versus nsec). +func (t *Table[V]) DeletePersist(pfx netip.Prefix) *Table[V] { + pt, _, _ := t.getAndDeletePersist(pfx) + return pt +} + +// GetAndDelete deletes the prefix and returns the associated payload for prefix and true, +// or the zero value and false if prefix is not set in the routing table. +func (t *Table[V]) GetAndDelete(pfx netip.Prefix) (val V, ok bool) { + return t.getAndDelete(pfx) +} + +// GetAndDeletePersist is similar to GetAndDelete but the receiver isn't modified. +// All nodes touched during delete are cloned and a new Table is returned. +// +// If the payload V is a pointer or contains a pointer, it should +// implement the cloner interface. +// +// This is orders of magnitude slower than GetAndDelete (μsec versus nsec). +func (t *Table[V]) GetAndDeletePersist(pfx netip.Prefix) (pt *Table[V], val V, ok bool) { + return t.getAndDeletePersist(pfx) +} + +func (t *Table[V]) getAndDelete(pfx netip.Prefix) (val V, ok bool) { + if !pfx.IsValid() { + return val, false + } + + // canonicalize prefix + pfx = pfx.Masked() + + // values derived from pfx + ip := pfx.Addr() + is4 := ip.Is4() + bits := pfx.Bits() + + n := t.rootNodeByVersion(is4) + + lastIdx, lastBits := lastOctetIdxAndBits(bits) + + octets := ip.AsSlice() + octets = octets[:lastIdx+1] + + // record path to deleted node + // needed to purge and/or path compress nodes after deletion + stack := [maxTreeDepth]*node[V]{} + + // find the trie node + for depth, octet := range octets { + // push current node on stack for path recording + stack[depth] = n + + // try to delete prefix in trie node + if depth == lastIdx { + val, ok = n.prefixes.DeleteAt(pfxToIdx(octet, lastBits)) + if !ok { + return val, false + } + + t.sizeUpdate(is4, -1) + n.purgeAndCompress(stack[:depth], octets, is4) + return val, ok + } + + addr := uint(octet) + if !n.children.Test(addr) { + return val, false + } + + // get the child: node or leaf + switch kid := n.children.MustGet(addr).(type) { + case *node[V]: + n = kid + continue // descend down to next trie level + + case *leaf[V]: + // reached a path compressed prefix, stop traversing + if kid.prefix != pfx { + return val, false + } + + // prefix is equal leaf, delete leaf + n.children.DeleteAt(addr) + + t.sizeUpdate(is4, -1) + n.purgeAndCompress(stack[:depth], octets, is4) + + return kid.value, true + + default: + panic("logic error, wrong node type") + } + } + + panic("unreachable") +} + +// getAndDeletePersist is similar to getAndDelete but the receiver isn't modified. +func (t *Table[V]) getAndDeletePersist(pfx netip.Prefix) (pt *Table[V], val V, ok bool) { + if !pfx.IsValid() { + return t, val, false + } + + // canonicalize prefix + pfx = pfx.Masked() + + // values derived from pfx + ip := pfx.Addr() + is4 := ip.Is4() + bits := pfx.Bits() + + pt = &Table[V]{ + root4: t.root4, + root6: t.root6, + size4: t.size4, + size6: t.size6, + } + + n := pt.rootNodeByVersion(is4) + + // clone the root of insertion path + *n = *n.cloneFlat() + + lastIdx, lastBits := lastOctetIdxAndBits(bits) + + octets := ip.AsSlice() + octets = octets[:lastIdx+1] + + // record path to deleted node + // needed to purge and/or path compress nodes after deletion + stack := [maxTreeDepth]*node[V]{} + + // find the trie node + for depth, octet := range octets { + // push cloned node on stack for path recording + stack[depth] = n + + // try to delete prefix in trie node + if depth == lastIdx { + val, ok = n.prefixes.DeleteAt(pfxToIdx(octet, lastBits)) + if !ok { + // nothing to delete + return pt, val, false + } + + pt.sizeUpdate(is4, -1) + n.purgeAndCompress(stack[:depth], octets, is4) + return pt, val, ok + } + + addr := uint(octet) + if !n.children.Test(addr) { + // nothing to delete + return pt, val, false + } + + // get the child: node or leaf + switch kid := n.children.MustGet(addr).(type) { + case *node[V]: + // proceed to next level + kid = kid.cloneFlat() + n.children.InsertAt(addr, kid) + n = kid + continue // descend down to next trie level + + case *leaf[V]: + kid = kid.cloneLeaf() + + // reached a path compressed prefix, stop traversing + if kid.prefix != pfx { + // nothing to delete + return pt, val, false + } + + // prefix is equal leaf, delete leaf + n.children.DeleteAt(addr) + + pt.sizeUpdate(is4, -1) + n.purgeAndCompress(stack[:depth], octets, is4) + + // kid.value is cloned + return pt, kid.value, true + + default: + panic("logic error, wrong node type") + } + } + + panic("unreachable") } // Get returns the associated payload for prefix and true, or false if // prefix is not set in the routing table. func (t *Table[V]) Get(pfx netip.Prefix) (val V, ok bool) { + var zero V + if !pfx.IsValid() { - return + return zero, false } + // canonicalize the prefix + pfx = pfx.Masked() + // values derived from pfx ip := pfx.Addr() is4 := ip.Is4() bits := pfx.Bits() n := t.rootNodeByVersion(is4) - if n == nil { - return - } - // do not allocate - a16 := ip.As16() - octets := a16[:] - if is4 { - octets = octets[12:] - } + lastIdx, lastBits := lastOctetIdxAndBits(bits) - // see comment in Insert() - lastOctetIdx := (bits - 1) / strideLen - lastOctet := octets[lastOctetIdx] - lastOctetBits := bits - (lastOctetIdx * strideLen) - - // mask the prefix - lastOctet = lastOctet & netMask(lastOctetBits) - - // find the proper trie node - for _, octet := range octets[:lastOctetIdx] { - c := n.getChild(octet) - if c == nil { - // not found - return - } - n = c - } - return n.getValue(prefixToBaseIndex(lastOctet, lastOctetBits)) -} - -// Delete removes pfx from the tree, pfx does not have to be present. -func (t *Table[V]) Delete(pfx netip.Prefix) { - if !pfx.IsValid() { - return - } - - // values derived from pfx - ip := pfx.Addr() - is4 := ip.Is4() - bits := pfx.Bits() - - n := t.rootNodeByVersion(is4) - if n == nil { - return - } - - // do not allocate - a16 := ip.As16() - octets := a16[:] - if is4 { - octets = octets[12:] - } - - // see comment in Insert() - lastOctetIdx := (bits - 1) / strideLen - lastOctet := octets[lastOctetIdx] - lastOctetBits := bits - (lastOctetIdx * strideLen) - - // mask the prefix - lastOctet = lastOctet & netMask(lastOctetBits) - octets[lastOctetIdx] = lastOctet - - // record path to deleted node - stack := [maxTreeDepth]*node[V]{} - - // run variable as stackPointer, see below - var i int + octets := ip.AsSlice() + octets = octets[:lastIdx+1] // find the trie node - for i = range octets { - // push current node on stack for path recording - stack[i] = n - - if i == lastOctetIdx { - break +LOOP: + for depth, octet := range octets { + if depth == lastIdx { + return n.prefixes.Get(pfxToIdx(octet, lastBits)) } - // descend down to next level - c := n.getChild(octets[i]) - if c == nil { - return - } - n = c - } - - // try to delete prefix in trie node - if !n.deletePrefix(lastOctet, lastOctetBits) { - // nothing deleted - return - } - t.sizeUpdate(is4, -1) - - // purge dangling nodes after successful deletion - for i > 0 { - if n.isEmpty() { - // purge empty node from parents children - parent := stack[i-1] - parent.deleteChild(octets[i-1]) + addr := uint(octet) + if !n.children.Test(addr) { + break LOOP } - // unwind the stack - i-- - n = stack[i] + // get the child: node or leaf + switch kid := n.children.MustGet(addr).(type) { + case *node[V]: + n = kid + continue // descend down to next trie level + + case *leaf[V]: + // reached a path compressed prefix, stop traversing + if kid.prefix == pfx { + return kid.value, true + } + break LOOP + + default: + panic("logic error, wrong node type") + } } + + return zero, false +} + +// Contains does a route lookup for IP and +// returns true if any route matched. +// +// Contains does not return the value nor the prefix of the matching item, +// but as a test against a black- or whitelist it's often sufficient +// and even few nanoseconds faster than [Table.Lookup]. +func (t *Table[V]) Contains(ip netip.Addr) bool { + if !ip.IsValid() { + return false + } + + is4 := ip.Is4() + n := t.rootNodeByVersion(is4) + + octets := ip.AsSlice() + + for _, octet := range octets { + addr := uint(octet) + + // contains: any lpm match good enough, no backtracking needed + if n.prefixes.Len() != 0 && n.lpmTest(hostIndex(addr)) { + return true + } + + if !n.children.Test(addr) { + return false + } + + // get node or leaf for octet + switch kid := n.children.MustGet(addr).(type) { + case *node[V]: + n = kid + continue // descend down to next trie level + + case *leaf[V]: + return kid.prefix.Contains(ip) + + default: + panic("logic error, wrong node type") + } + } + + panic("unreachable") } // Lookup does a route lookup (longest prefix match) for IP and // returns the associated value and true, or false if no route matched. func (t *Table[V]) Lookup(ip netip.Addr) (val V, ok bool) { if !ip.IsValid() { - return + return val, false } is4 := ip.Is4() - n := t.rootNodeByVersion(is4) - if n == nil { - return - } - // do not allocate - a16 := ip.As16() - octets := a16[:] - if is4 { - octets = octets[12:] - } + octets := ip.AsSlice() // stack of the traversed nodes for fast backtracking, if needed stack := [maxTreeDepth]*node[V]{} // run variable, used after for loop - var i int + var depth int var octet byte + var addr uint +LOOP: // find leaf node - for i, octet = range octets { + for depth, octet = range octets { + addr = uint(octet) + // push current node on stack for fast backtracking - stack[i] = n + stack[depth] = n - // go down in tight loop to leaf node - c := n.getChild(octet) - if c == nil { - break + // go down in tight loop to last octet + if !n.children.Test(addr) { + // no more nodes below octet + break LOOP } - n = c - } - // start backtracking, unwind the stack - for depth := i; depth >= 0; depth-- { - n = stack[depth] - octet = octets[depth] + // get the child: node or leaf + switch kid := n.children.MustGet(addr).(type) { + case *node[V]: + n = kid + continue // descend down to next trie level - // longest prefix match - // micro benchmarking: skip if node has no prefixes - if len(n.prefixes) != 0 { - if _, val, ok := n.lpm(octetToBaseIndex(octet)); ok { - return val, true + case *leaf[V]: + // reached a path compressed prefix, stop traversing + if kid.prefix.Contains(ip) { + return kid.value, true } + break LOOP + + default: + panic("logic error, wrong node type") } } - return + + // start backtracking, unwind the stack, bounds check eliminated + for ; depth >= 0 && depth < len(stack) && depth < len(octets); depth-- { + n = stack[depth] + + // longest prefix match, skip if node has no prefixes + if n.prefixes.Len() != 0 { + idx := hostIndex(uint(octets[depth])) + // lpmGet(idx), manually inlined + // -------------------------------------------------------------- + if topIdx, ok := n.prefixes.IntersectionTop(lpmLookupTbl[idx]); ok { + return n.prefixes.MustGet(topIdx), true + } + // -------------------------------------------------------------- + } + } + + return val, false } // LookupPrefix does a route lookup (longest prefix match) for pfx and // returns the associated value and true, or false if no route matched. func (t *Table[V]) LookupPrefix(pfx netip.Prefix) (val V, ok bool) { - _, _, val, ok = t.lpmPrefix(pfx) + _, val, ok = t.lookupPrefixLPM(pfx, false) return val, ok } @@ -383,353 +688,321 @@ func (t *Table[V]) LookupPrefix(pfx netip.Prefix) (val V, ok bool) { // This method is about 20-30% slower than LookupPrefix and should only // be used if the matching lpm entry is also required for other reasons. // -// If LookupPrefixLPM is to be used for IP addresses, +// If LookupPrefixLPM is to be used for IP address lookups, // they must be converted to /32 or /128 prefixes. func (t *Table[V]) LookupPrefixLPM(pfx netip.Prefix) (lpm netip.Prefix, val V, ok bool) { - depth, baseIdx, val, ok := t.lpmPrefix(pfx) - - if ok { - // calculate the mask from baseIdx and depth - mask := baseIndexToPrefixLen(baseIdx, depth) - - // calculate the lpm from ip and mask - lpm, _ = pfx.Addr().Prefix(mask) - } - - return lpm, val, ok + return t.lookupPrefixLPM(pfx, true) } -func (t *Table[V]) lpmPrefix(pfx netip.Prefix) (depth int, baseIdx uint, val V, ok bool) { +func (t *Table[V]) lookupPrefixLPM(pfx netip.Prefix, withLPM bool) (lpm netip.Prefix, val V, ok bool) { if !pfx.IsValid() { - return + return lpm, val, false } - // values derived from pfx ip := pfx.Addr() - is4 := ip.Is4() bits := pfx.Bits() + is4 := ip.Is4() n := t.rootNodeByVersion(is4) - if n == nil { - return - } - // do not allocate - a16 := ip.As16() - octets := a16[:] - if is4 { - octets = octets[12:] - } + lastIdx, lastBits := lastOctetIdxAndBits(bits) - // see comment in Insert() - lastOctetIdx := (bits - 1) / strideLen - lastOctet := octets[lastOctetIdx] - lastOctetBits := bits - (lastOctetIdx * strideLen) + octets := ip.AsSlice() + octets = octets[:lastIdx+1] - // mask the prefix - lastOctet = lastOctet & netMask(lastOctetBits) - octets[lastOctetIdx] = lastOctet - - var i int - var octet byte + // mask the last octet from IP + octets[lastIdx] &= netMask(lastBits) // record path to leaf node stack := [maxTreeDepth]*node[V]{} - // find the node - for i, octet = range octets[:lastOctetIdx+1] { - // push current node on stack - stack[i] = n - - // go down in tight loop - c := n.getChild(octet) - if c == nil { - break - } - n = c - } - - // start backtracking, unwind the stack - for depth = i; depth >= 0; depth-- { - n = stack[depth] - octet = octets[depth] - - // longest prefix match - // micro benchmarking: skip if node has no prefixes - if len(n.prefixes) != 0 { - - // only the lastOctet may have a different prefix len - // all others are just host routes - idx := uint(0) - if depth == lastOctetIdx { - idx = prefixToBaseIndex(octet, lastOctetBits) - } else { - idx = octetToBaseIndex(octet) - } - - baseIdx, val, ok = n.lpm(idx) - if ok { - return depth, baseIdx, val, ok - } - } - } - return -} - -// EachLookupPrefix calls yield() for each CIDR covering pfx -// in reverse CIDR sort order, from longest-prefix-match to -// shortest-prefix-match. -// -// If the yield function returns false, the iteration ends prematurely. -func (t *Table[V]) EachLookupPrefix(pfx netip.Prefix, yield func(pfx netip.Prefix, val V) bool) { - if !pfx.IsValid() { - return - } - - // values derived from pfx - ip := pfx.Addr() - is4 := ip.Is4() - bits := pfx.Bits() - - n := t.rootNodeByVersion(is4) - if n == nil { - return - } - - // do not allocate - path := ip.As16() - octets := path[:] - if is4 { - octets = octets[12:] - } - copy(path[:], octets[:]) - - // see comment in Insert() - lastOctetIdx := (bits - 1) / strideLen - lastOctet := octets[lastOctetIdx] - lastOctetBits := bits - (lastOctetIdx * strideLen) - - // mask the prefix - lastOctet = lastOctet & netMask(lastOctetBits) - octets[lastOctetIdx] = lastOctet - - // stack of the traversed nodes for reverse ordering of supernets - stack := [maxTreeDepth]*node[V]{} - - // run variable, used after for loop - var i int + var depth int var octet byte + var addr uint + +LOOP: + // find the last node on the octets path in the trie, + for depth, octet = range octets { + addr = uint(octet) - // find last node - for i, octet = range octets[:lastOctetIdx+1] { // push current node on stack - stack[i] = n + stack[depth] = n - // go down in tight loop - c := n.getChild(octet) - if c == nil { - break + // go down in tight loop to leaf node + if !n.children.Test(addr) { + break LOOP + } + + // get the child: node or leaf + switch kid := n.children.MustGet(addr).(type) { + case *node[V]: + n = kid + continue LOOP // descend down to next trie level + + case *leaf[V]: + // reached a path compressed prefix, stop traversing + // must not be masked for Contains(pfx.Addr) + if kid.prefix.Contains(ip) && kid.prefix.Bits() <= bits { + return kid.prefix, kid.value, true + } + + break LOOP + + default: + panic("logic error, wrong node type") } - n = c } - // start backtracking, unwind the stack - for depth := i; depth >= 0; depth-- { + // start backtracking, unwind the stack, bounds check eliminated + for ; depth >= 0 && depth < len(stack) && depth < len(octets); depth-- { n = stack[depth] - // microbenchmarking - if len(n.prefixes) == 0 { + // longest prefix match, skip if node has no prefixes + if n.prefixes.Len() == 0 { continue } // only the lastOctet may have a different prefix len - if depth == lastOctetIdx { - if !n.eachLookupPrefix(path, depth, is4, lastOctet, lastOctetBits, yield) { + // all others are just host routes + var idx uint + octet = octets[depth] + if depth == lastIdx { + idx = pfxToIdx(octet, lastBits) + } else { + idx = hostIndex(uint(octet)) + } + + // manually inlined lpmGet(idx) + if topIdx, ok := n.prefixes.IntersectionTop(lpmLookupTbl[idx]); ok { + val = n.prefixes.MustGet(topIdx) + + // called from LookupPrefix + if !withLPM { + return netip.Prefix{}, val, ok + } + + // called from LookupPrefixLPM + + // calculate the pfxLen from depth and top idx + pfxLen := depth*strideLen + int(baseIdxLookupTbl[topIdx].pfxLen) + + // calculate the lpm from incoming ip and new mask + lpm, _ = ip.Prefix(pfxLen) + return lpm, val, ok + } + } + + return lpm, val, false +} + +// Supernets returns an iterator over all CIDRs covering pfx. +// The iteration is in reverse CIDR sort order, from longest-prefix-match to shortest-prefix-match. +func (t *Table[V]) Supernets(pfx netip.Prefix) iter.Seq2[netip.Prefix, V] { + return func(yield func(netip.Prefix, V) bool) { + if !pfx.IsValid() { + return + } + + // canonicalize the prefix + pfx = pfx.Masked() + + // values derived from pfx + ip := pfx.Addr() + is4 := ip.Is4() + bits := pfx.Bits() + + n := t.rootNodeByVersion(is4) + + lastIdx, lastBits := lastOctetIdxAndBits(bits) + + octets := ip.AsSlice() + octets = octets[:lastIdx+1] + + // stack of the traversed nodes for reverse ordering of supernets + stack := [maxTreeDepth]*node[V]{} + + // run variable, used after for loop + var depth int + var octet byte + + // find last node along this octet path + LOOP: + for depth, octet = range octets { + addr := uint(octet) + + // push current node on stack + stack[depth] = n + + if !n.children.Test(addr) { + break LOOP + } + + switch kid := n.children.MustGet(addr).(type) { + case *node[V]: + n = kid + continue LOOP // descend down to next trie level + + case *leaf[V]: + if kid.prefix.Overlaps(pfx) && kid.prefix.Bits() <= pfx.Bits() { + if !yield(kid.prefix, kid.value) { + // early exit + return + } + } + // end of trie along this octets path + break LOOP + + default: + panic("logic error, wrong node type") + } + } + + // start backtracking, unwind the stack + for ; depth >= 0; depth-- { + n = stack[depth] + + // micro benchmarking + if n.prefixes.Len() == 0 { + continue + } + + // only the lastOctet may have a different prefix len + // all others are just host routes + pfxLen := strideLen + if depth == lastIdx { + pfxLen = lastBits + } + + if !n.eachLookupPrefix(octets, depth, is4, pfxLen, yield) { // early exit return } - continue - } - - // all others are just host routes - if !n.eachLookupPrefix(path, depth, is4, octets[depth], strideLen, yield) { - // early exit - return } } } -// EachSubnet calls yield() for each CIDR covered by pfx. -// If the yield function returns false, the iteration ends prematurely. -// -// The sort order is undefined and you must not rely on it! -func (t *Table[V]) EachSubnet(pfx netip.Prefix, yield func(pfx netip.Prefix, val V) bool) { - if !pfx.IsValid() { - return - } - - // values derived from pfx - ip := pfx.Addr() - is4 := ip.Is4() - bits := pfx.Bits() - - n := t.rootNodeByVersion(is4) - if n == nil { - return - } - - // do not allocate - path := ip.As16() - octets := path[:] - if is4 { - octets = octets[12:] - } - copy(path[:], octets[:]) - - // see comment in Insert() - lastOctetIdx := (bits - 1) / strideLen - lastOctet := octets[lastOctetIdx] - lastOctetBits := bits - (lastOctetIdx * strideLen) - - // mask the prefix - lastOctet = lastOctet & netMask(lastOctetBits) - octets[lastOctetIdx] = lastOctet - - // find the trie node - for i, octet := range octets { - if i == lastOctetIdx { - _ = n.eachSubnet(path, i, is4, lastOctet, lastOctetBits, yield) +// Subnets returns an iterator over all CIDRs covered by pfx. +// The iteration is in natural CIDR sort order. +func (t *Table[V]) Subnets(pfx netip.Prefix) iter.Seq2[netip.Prefix, V] { + return func(yield func(netip.Prefix, V) bool) { + if !pfx.IsValid() { return } - c := n.getChild(octet) - if c == nil { - break - } + // canonicalize the prefix + pfx = pfx.Masked() - n = c + // values derived from pfx + ip := pfx.Addr() + is4 := ip.Is4() + bits := pfx.Bits() + + n := t.rootNodeByVersion(is4) + + lastIdx, lastBits := lastOctetIdxAndBits(bits) + + octets := ip.AsSlice() + octets = octets[:lastIdx+1] + + // find the trie node + for depth, octet := range octets { + if depth == lastIdx { + _ = n.eachSubnet(octets, depth, is4, lastBits, yield) + return + } + + addr := uint(octet) + if !n.children.Test(addr) { + return + } + + // node or leaf? + switch kid := n.children.MustGet(addr).(type) { + case *node[V]: + n = kid + continue // descend down to next trie level + + case *leaf[V]: + if pfx.Overlaps(kid.prefix) && pfx.Bits() <= kid.prefix.Bits() { + _ = yield(kid.prefix, kid.value) + } + return + + default: + panic("logic error, wrong node type") + } + } } } -// OverlapsPrefix reports whether any IP in pfx matches a route in the table. +// OverlapsPrefix reports whether any IP in pfx is matched by a route in the table or vice versa. func (t *Table[V]) OverlapsPrefix(pfx netip.Prefix) bool { if !pfx.IsValid() { return false } - // values derived from pfx - ip := pfx.Addr() - is4 := ip.Is4() - bits := pfx.Bits() + // canonicalize the prefix + pfx = pfx.Masked() - // get the root node of the routing table + is4 := pfx.Addr().Is4() n := t.rootNodeByVersion(is4) - if n == nil { - return false - } - // do not allocate - a16 := ip.As16() - octets := a16[:] - if is4 { - octets = octets[12:] - } - - // see comment in Insert() - lastOctetIdx := (bits - 1) / strideLen - lastOctet := octets[lastOctetIdx] - lastOctetBits := bits - (lastOctetIdx * strideLen) - - // mask the prefix - lastOctet = lastOctet & netMask(lastOctetBits) - - for _, octet := range octets[:lastOctetIdx] { - // test if any route overlaps prefix´ so far - if n.lpmTest(octetToBaseIndex(octet)) { - return true - } - - // no overlap so far, go down to next c - c := n.getChild(octet) - if c == nil { - return false - } - n = c - } - - return n.overlapsPrefix(lastOctet, lastOctetBits) + return n.overlapsPrefixAtDepth(pfx, 0) } -// Overlaps reports whether any IP in the table matches a route in the -// other table. +// Overlaps reports whether any IP in the table is matched by a route in the +// other table or vice versa. func (t *Table[V]) Overlaps(o *Table[V]) bool { - t.init() - o.init() - - // t is empty - if t.Size() == 0 { - return false - } - - // o is empty - if o.Size() == 0 { - return false - } - - // at least one v4 is empty - if t.size4 == 0 || o.size4 == 0 { - return t.Overlaps6(o) - } - - // at least one v6 is empty - if t.size6 == 0 || o.size6 == 0 { - return t.Overlaps4(o) - } - return t.Overlaps4(o) || t.Overlaps6(o) } // Overlaps4 reports whether any IPv4 in the table matches a route in the -// other table. +// other table or vice versa. func (t *Table[V]) Overlaps4(o *Table[V]) bool { - t.init() - o.init() - - return t.rootV4.overlapsRec(o.rootV4) + if t.size4 == 0 || o.size4 == 0 { + return false + } + return t.root4.overlaps(&o.root4, 0) } // Overlaps6 reports whether any IPv6 in the table matches a route in the -// other table. +// other table or vice versa. func (t *Table[V]) Overlaps6(o *Table[V]) bool { - t.init() - o.init() - - return t.rootV6.overlapsRec(o.rootV6) + if t.size6 == 0 || o.size6 == 0 { + return false + } + return t.root6.overlaps(&o.root6, 0) } // Union combines two tables, changing the receiver table. -// If there are duplicate entries, the value is taken from the other table. +// If there are duplicate entries, the payload of type V is shallow copied from the other table. +// If type V implements the [Cloner] interface, the values are cloned, see also [Table.Clone]. func (t *Table[V]) Union(o *Table[V]) { - t.init() - o.init() - - dup4 := t.rootV4.unionRec(o.rootV4) - dup6 := t.rootV6.unionRec(o.rootV6) + dup4 := t.root4.unionRec(&o.root4, 0) + dup6 := t.root6.unionRec(&o.root6, 0) t.size4 += o.size4 - dup4 t.size6 += o.size6 - dup6 } +// Cloner, if implemented by payload of type V the values are deeply copied +// during [Table.UpdatePersist], [Table.DeletePersist], [Table.Clone] and [Table.Union]. +type Cloner[V any] interface { + Clone() V +} + // Clone returns a copy of the routing table. -// The payloads V are copied using assignment, so this is a shallow clone. +// The payload of type V is shallow copied, but if type V implements the [Cloner] interface, +// the values are cloned. func (t *Table[V]) Clone() *Table[V] { - t.init() + if t == nil { + return nil + } c := new(Table[V]) - c.init() - c.rootV4 = t.rootV4.cloneRec() - c.rootV6 = t.rootV6.cloneRec() + c.root4 = *t.root4.cloneRec() + c.root6 = *t.root6.cloneRec() c.size4 = t.size4 c.size6 = t.size6 @@ -737,66 +1010,12 @@ func (t *Table[V]) Clone() *Table[V] { return c } -// All may be used in a for/range loop to iterate -// through all the prefixes. -// The sort order is undefined and you must not rely on it! -// -// Prefixes must not be inserted or deleted during iteration, otherwise -// the behavior is undefined. However, value updates are permitted. -// -// If the yield function returns false, the iteration ends prematurely. -func (t *Table[V]) All(yield func(pfx netip.Prefix, val V) bool) { - t.init() - // respect early exit - _ = t.rootV4.allRec(zeroPath, 0, true, yield) && - t.rootV6.allRec(zeroPath, 0, false, yield) -} - -// All4, like [Table.All] but only for the v4 routing table. -func (t *Table[V]) All4(yield func(pfx netip.Prefix, val V) bool) { - t.init() - t.rootV4.allRec(zeroPath, 0, true, yield) -} - -// All6, like [Table.All] but only for the v6 routing table. -func (t *Table[V]) All6(yield func(pfx netip.Prefix, val V) bool) { - t.init() - t.rootV6.allRec(zeroPath, 0, false, yield) -} - -// AllSorted may be used in a for/range loop to iterate -// through all the prefixes in natural CIDR sort order. -// -// Prefixes must not be inserted or deleted during iteration, otherwise -// the behavior is undefined. However, value updates are permitted. -// -// If the yield function returns false, the iteration ends prematurely. -func (t *Table[V]) AllSorted(yield func(pfx netip.Prefix, val V) bool) { - t.init() - // respect early exit - _ = t.rootV4.allRecSorted(zeroPath, 0, true, yield) && - t.rootV6.allRecSorted(zeroPath, 0, false, yield) -} - -// All4Sorted, like [Table.AllSorted] but only for the v4 routing table. -func (t *Table[V]) All4Sorted(yield func(pfx netip.Prefix, val V) bool) { - t.init() - t.rootV4.allRecSorted(zeroPath, 0, true, yield) -} - -// All6Sorted, like [Table.AllSorted] but only for the v6 routing table. -func (t *Table[V]) All6Sorted(yield func(pfx netip.Prefix, val V) bool) { - t.init() - t.rootV6.allRecSorted(zeroPath, 0, false, yield) -} - func (t *Table[V]) sizeUpdate(is4 bool, n int) { - switch is4 { - case true: + if is4 { t.size4 += n - case false: - t.size6 += n + return } + t.size6 += n } // Size returns the prefix count. @@ -814,8 +1033,99 @@ func (t *Table[V]) Size6() int { return t.size6 } -// nodes, calculates the IPv4 and IPv6 nodes and returns the sum. -func (t *Table[V]) nodes() int { - t.init() - return t.rootV4.numNodesRec() + t.rootV6.numNodesRec() +// All returns an iterator over key-value pairs from Table. The iteration order +// is not specified and is not guaranteed to be the same from one call to the +// next. +func (t *Table[V]) All() iter.Seq2[netip.Prefix, V] { + return func(yield func(netip.Prefix, V) bool) { + _ = t.root4.allRec(stridePath{}, 0, true, yield) && t.root6.allRec(stridePath{}, 0, false, yield) + } } + +// All4, like [Table.All] but only for the v4 routing table. +func (t *Table[V]) All4() iter.Seq2[netip.Prefix, V] { + return func(yield func(netip.Prefix, V) bool) { + _ = t.root4.allRec(stridePath{}, 0, true, yield) + } +} + +// All6, like [Table.All] but only for the v6 routing table. +func (t *Table[V]) All6() iter.Seq2[netip.Prefix, V] { + return func(yield func(netip.Prefix, V) bool) { + _ = t.root6.allRec(stridePath{}, 0, false, yield) + } +} + +// AllSorted returns an iterator over key-value pairs from Table2 in natural CIDR sort order. +func (t *Table[V]) AllSorted() iter.Seq2[netip.Prefix, V] { + return func(yield func(netip.Prefix, V) bool) { + _ = t.root4.allRecSorted(stridePath{}, 0, true, yield) && + t.root6.allRecSorted(stridePath{}, 0, false, yield) + } +} + +// AllSorted4, like [Table.AllSorted] but only for the v4 routing table. +func (t *Table[V]) AllSorted4() iter.Seq2[netip.Prefix, V] { + return func(yield func(netip.Prefix, V) bool) { + _ = t.root4.allRecSorted(stridePath{}, 0, true, yield) + } +} + +// AllSorted6, like [Table.AllSorted] but only for the v6 routing table. +func (t *Table[V]) AllSorted6() iter.Seq2[netip.Prefix, V] { + return func(yield func(netip.Prefix, V) bool) { + _ = t.root6.allRecSorted(stridePath{}, 0, false, yield) + } +} + +// lastOctetIdxAndBits, get last significant octet Idx and significant bits +// +// lastIdx: +// +// 10.0.0.0/8 -> 0 +// 10.12.0.0/15 -> 1 +// 10.12.0.0/16 -> 1 +// 10.12.10.9/32 -> 3 +// +// lastBits: +// +// 10.0.0.0/8 -> 8 +// 10.12.0.0/15 -> 7 +// 10.12.0.0/16 -> 8 +// 10.12.10.9/32 -> 8 +// +// lastOctet := octets[lastIdx] +// +// 10.0.0.0/8 -> 10 +// 10.12.0.0/15 -> 12 +// 10.12.0.0/16 -> 12 +// 10.12.10.9/32 -> 9 +func lastOctetIdxAndBits(bits int) (lastIdx, lastBits int) { + if bits == 0 { + return + } + + lastIdx = (bits - 1) >> 3 + lastBits = bits - (lastIdx << 3) + + return +} + +// noCopy may be added to structs which must not be copied +// after the first use. +// +// type My struct { +// _ noCopy +// A state +// b foo +// } +// +// See https://golang.org/issues/8005#issuecomment-190753527 +// for details. +// +// Note that it must not be embedded, due to the Lock and Unlock methods. +type noCopy struct{} + +// Lock is a no-op used by -copylocks checker from `go vet`. +func (*noCopy) Lock() {} +func (*noCopy) Unlock() {} diff --git a/vendor/github.com/go-json-experiment/json/README.md b/vendor/github.com/go-json-experiment/json/README.md index 243e2af..25de18d 100644 --- a/vendor/github.com/go-json-experiment/json/README.md +++ b/vendor/github.com/go-json-experiment/json/README.md @@ -12,7 +12,7 @@ with the string "WARNING: " near the top of the commit message. It is your responsibility to inspect the list of commit changes when upgrading the module. Not all breaking changes will lead to build failures. -A [Discussion about including this package in Go as `encoding/json/v2`](https://github.com/golang/go/discussions/63397) has been started on the Go Github project on 2023-10-05. Please provide your feedback there. +A [proposal to include this module in Go as `encoding/json/v2` and `encoding/json/jsontext`](https://github.com/golang/go/issues/71497) has been started on the Go Github project on 2025-01-30. Please provide your feedback there. ## Goals and objectives @@ -24,7 +24,7 @@ in v2 to be named the same and have a mostly compatible signature. Behaviorally, we should aim for 95% to 99% backwards compatibility. We do not aim for 100% compatibility since we want the freedom to break certain behaviors that are now considered to have been a mistake. -We may provide options that can bring the v2 implementation to 100% compatibility, +Options exist that can bring the v2 implementation to 100% compatibility, but it will not be the default. * **More flexible:** There is a @@ -141,30 +141,28 @@ This table shows an overview of the changes: | v1 | v2 | Details | | -- | -- | ------- | -| JSON object members are unmarshaled into a Go struct using a **case-insensitive name match**. | JSON object members are unmarshaled into a Go struct using a **case-sensitive name match**. | [CaseSensitivity](/diff_test.go#:~:text=TestCaseSensitivity) | -| When marshaling a Go struct, a struct field marked as `omitempty` is omitted if **the field value is an empty Go value**, which is defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string. | When marshaling a Go struct, a struct field marked as `omitempty` is omitted if **the field value would encode as an empty JSON value**, which is defined as a JSON null, or an empty JSON string, object, or array. | [OmitEmptyOption](/diff_test.go#:~:text=TestOmitEmptyOption) | -| The `string` option **does affect** Go bools. | The `string` option **does not affect** Go bools. | [StringOption](/diff_test.go#:~:text=TestStringOption) | -| The `string` option **does not recursively affect** sub-values of the Go field value. | The `string` option **does recursively affect** sub-values of the Go field value. | [StringOption](/diff_test.go#:~:text=TestStringOption) | -| The `string` option **sometimes accepts** a JSON null escaped within a JSON string. | The `string` option **never accepts** a JSON null escaped within a JSON string. | [StringOption](/diff_test.go#:~:text=TestStringOption) | -| A nil Go slice is marshaled as a **JSON null**. | A nil Go slice is marshaled as an **empty JSON array**. | [NilSlicesAndMaps](/diff_test.go#:~:text=TestNilSlicesAndMaps) | -| A nil Go map is marshaled as a **JSON null**. | A nil Go map is marshaled as an **empty JSON object**. | [NilSlicesAndMaps](/diff_test.go#:~:text=TestNilSlicesAndMaps) | -| A Go array may be unmarshaled from a **JSON array of any length**. | A Go array must be unmarshaled from a **JSON array of the same length**. | [Arrays](/diff_test.go#:~:text=Arrays) | -| A Go byte array is represented as a **JSON array of JSON numbers**. | A Go byte array is represented as a **Base64-encoded JSON string**. | [ByteArrays](/diff_test.go#:~:text=TestByteArrays) | -| `MarshalJSON` and `UnmarshalJSON` methods declared on a pointer receiver are **inconsistently called**. | `MarshalJSON` and `UnmarshalJSON` methods declared on a pointer receiver are **consistently called**. | [PointerReceiver](/diff_test.go#:~:text=TestPointerReceiver) | -| A Go map is marshaled in a **deterministic order**. | A Go map is marshaled in a **non-deterministic order**. | [MapDeterminism](/diff_test.go#:~:text=TestMapDeterminism) | -| JSON strings are encoded **with HTML-specific characters being escaped**. | JSON strings are encoded **without any characters being escaped** (unless necessary). | [EscapeHTML](/diff_test.go#:~:text=TestEscapeHTML) | -| When marshaling, invalid UTF-8 within a Go string **are silently replaced**. | When marshaling, invalid UTF-8 within a Go string **results in an error**. | [InvalidUTF8](/diff_test.go#:~:text=TestInvalidUTF8) | -| When unmarshaling, invalid UTF-8 within a JSON string **are silently replaced**. | When unmarshaling, invalid UTF-8 within a JSON string **results in an error**. | [InvalidUTF8](/diff_test.go#:~:text=TestInvalidUTF8) | -| When marshaling, **an error does not occur** if the output JSON value contains objects with duplicate names. | When marshaling, **an error does occur** if the output JSON value contains objects with duplicate names. | [DuplicateNames](/diff_test.go#:~:text=TestDuplicateNames) | -| When unmarshaling, **an error does not occur** if the input JSON value contains objects with duplicate names. | When unmarshaling, **an error does occur** if the input JSON value contains objects with duplicate names. | [DuplicateNames](/diff_test.go#:~:text=TestDuplicateNames) | -| Unmarshaling a JSON null into a non-empty Go value **inconsistently clears the value or does nothing**. | Unmarshaling a JSON null into a non-empty Go value **always clears the value**. | [MergeNull](/diff_test.go#:~:text=TestMergeNull) | -| Unmarshaling a JSON value into a non-empty Go value **follows inconsistent and bizarre behavior**. | Unmarshaling a JSON value into a non-empty Go value **always merges if the input is an object, and otherwise replaces**. | [MergeComposite](/diff_test.go#:~:text=TestMergeComposite) | -| A `time.Duration` is represented as a **JSON number containing the decimal number of nanoseconds**. | A `time.Duration` is represented as a **JSON string containing the formatted duration (e.g., "1h2m3.456s")**. | [TimeDurations](/diff_test.go#:~:text=TestTimeDurations) | -| Unmarshaling a JSON number into a Go float beyond its representation **results in an error**. | Unmarshaling a JSON number into a Go float beyond its representation **uses the closest representable value (e.g., ±`math.MaxFloat`)**. | [MaxFloats](/diff_test.go#:~:text=TestMaxFloats) | -| A Go struct with only unexported fields **can be serialized**. | A Go struct with only unexported fields **cannot be serialized**. | [EmptyStructs](/diff_test.go#:~:text=TestEmptyStructs) | -| A Go struct that embeds an unexported struct type **can sometimes be serialized**. | A Go struct that embeds an unexported struct type **cannot be serialized**. | [EmbedUnexported](/diff_test.go#:~:text=TestEmbedUnexported) | +| JSON object members are unmarshaled into a Go struct using a **case-insensitive name match**. | JSON object members are unmarshaled into a Go struct using a **case-sensitive name match**. | [CaseSensitivity](/v1/diff_test.go#:~:text=TestCaseSensitivity) | +| When marshaling a Go struct, a struct field marked as `omitempty` is omitted if **the field value is an empty Go value**, which is defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string. | When marshaling a Go struct, a struct field marked as `omitempty` is omitted if **the field value would encode as an empty JSON value**, which is defined as a JSON null, or an empty JSON string, object, or array. | [OmitEmptyOption](/v1/diff_test.go#:~:text=TestOmitEmptyOption) | +| The `string` option **does affect** Go strings and bools. | The `string` option **does not affect** Go strings or bools. | [StringOption](/v1/diff_test.go#:~:text=TestStringOption) | +| The `string` option **does not recursively affect** sub-values of the Go field value. | The `string` option **does recursively affect** sub-values of the Go field value. | [StringOption](/v1/diff_test.go#:~:text=TestStringOption) | +| The `string` option **sometimes accepts** a JSON null escaped within a JSON string. | The `string` option **never accepts** a JSON null escaped within a JSON string. | [StringOption](/v1/diff_test.go#:~:text=TestStringOption) | +| A nil Go slice is marshaled as a **JSON null**. | A nil Go slice is marshaled as an **empty JSON array**. | [NilSlicesAndMaps](/v1/diff_test.go#:~:text=TestNilSlicesAndMaps) | +| A nil Go map is marshaled as a **JSON null**. | A nil Go map is marshaled as an **empty JSON object**. | [NilSlicesAndMaps](/v1/diff_test.go#:~:text=TestNilSlicesAndMaps) | +| A Go array may be unmarshaled from a **JSON array of any length**. | A Go array must be unmarshaled from a **JSON array of the same length**. | [Arrays](/v1/diff_test.go#:~:text=Arrays) | +| A Go byte array is represented as a **JSON array of JSON numbers**. | A Go byte array is represented as a **Base64-encoded JSON string**. | [ByteArrays](/v1/diff_test.go#:~:text=TestByteArrays) | +| `MarshalJSON` and `UnmarshalJSON` methods declared on a pointer receiver are **inconsistently called**. | `MarshalJSON` and `UnmarshalJSON` methods declared on a pointer receiver are **consistently called**. | [PointerReceiver](/v1/diff_test.go#:~:text=TestPointerReceiver) | +| A Go map is marshaled in a **deterministic order**. | A Go map is marshaled in a **non-deterministic order**. | [MapDeterminism](/v1/diff_test.go#:~:text=TestMapDeterminism) | +| JSON strings are encoded **with HTML-specific characters being escaped**. | JSON strings are encoded **without any characters being escaped** (unless necessary). | [EscapeHTML](/v1/diff_test.go#:~:text=TestEscapeHTML) | +| When marshaling, invalid UTF-8 within a Go string **are silently replaced**. | When marshaling, invalid UTF-8 within a Go string **results in an error**. | [InvalidUTF8](/v1/diff_test.go#:~:text=TestInvalidUTF8) | +| When unmarshaling, invalid UTF-8 within a JSON string **are silently replaced**. | When unmarshaling, invalid UTF-8 within a JSON string **results in an error**. | [InvalidUTF8](/v1/diff_test.go#:~:text=TestInvalidUTF8) | +| When marshaling, **an error does not occur** if the output JSON value contains objects with duplicate names. | When marshaling, **an error does occur** if the output JSON value contains objects with duplicate names. | [DuplicateNames](/v1/diff_test.go#:~:text=TestDuplicateNames) | +| When unmarshaling, **an error does not occur** if the input JSON value contains objects with duplicate names. | When unmarshaling, **an error does occur** if the input JSON value contains objects with duplicate names. | [DuplicateNames](/v1/diff_test.go#:~:text=TestDuplicateNames) | +| Unmarshaling a JSON null into a non-empty Go value **inconsistently clears the value or does nothing**. | Unmarshaling a JSON null into a non-empty Go value **always clears the value**. | [MergeNull](/v1/diff_test.go#:~:text=TestMergeNull) | +| Unmarshaling a JSON value into a non-empty Go value **follows inconsistent and bizarre behavior**. | Unmarshaling a JSON value into a non-empty Go value **always merges if the input is an object, and otherwise replaces**. | [MergeComposite](/v1/diff_test.go#:~:text=TestMergeComposite) | +| A `time.Duration` is represented as a **JSON number containing the decimal number of nanoseconds**. | A `time.Duration` is represented as a **JSON string containing the formatted duration (e.g., "1h2m3.456s")**. | [TimeDurations](/v1/diff_test.go#:~:text=TestTimeDurations) | +| A Go struct with only unexported fields **can be serialized**. | A Go struct with only unexported fields **cannot be serialized**. | [EmptyStructs](/v1/diff_test.go#:~:text=TestEmptyStructs) | -See [diff_test.go](/diff_test.go) for details about every change. +See [diff_test.go](/v1/diff_test.go) for details about every change. ## Performance diff --git a/vendor/github.com/go-json-experiment/json/arshal.go b/vendor/github.com/go-json-experiment/json/arshal.go index 1b1dc81..88b3f13 100644 --- a/vendor/github.com/go-json-experiment/json/arshal.go +++ b/vendor/github.com/go-json-experiment/json/arshal.go @@ -6,32 +6,33 @@ package json import ( "bytes" - "errors" + "encoding" "io" "reflect" "slices" + "strings" "sync" + "time" "github.com/go-json-experiment/json/internal" "github.com/go-json-experiment/json/internal/jsonflags" "github.com/go-json-experiment/json/internal/jsonopts" - "github.com/go-json-experiment/json/internal/jsonwire" "github.com/go-json-experiment/json/jsontext" ) +// Reference encoding and time packages to assist pkgsite +// in being able to hotlink references to those packages. +var ( + _ encoding.TextMarshaler + _ encoding.TextAppender + _ encoding.TextUnmarshaler + _ time.Time + _ time.Duration +) + // export exposes internal functionality of the "jsontext" package. var export = jsontext.Internal.Export(&internal.AllowInternalUse) -var structOptionsPool = &sync.Pool{New: func() any { return new(jsonopts.Struct) }} - -func getStructOptions() *jsonopts.Struct { - return structOptionsPool.Get().(*jsonopts.Struct) -} -func putStructOptions(o *jsonopts.Struct) { - *o = jsonopts.Struct{} - structOptionsPool.Put(o) -} - // Marshal serializes a Go value as a []byte according to the provided // marshal and encode options (while ignoring unmarshal or decode options). // It does not terminate the output with a newline. @@ -52,12 +53,16 @@ func putStructOptions(o *jsonopts.Struct) { // If all applicable functions return [SkipFunc], // then the value is encoded according to subsequent rules. // -// - If the value type implements [MarshalerV2], -// then the MarshalJSONV2 method is called to encode the value. +// - If the value type implements [MarshalerTo], +// then the MarshalJSONTo method is called to encode the value. // -// - If the value type implements [MarshalerV1], +// - If the value type implements [Marshaler], // then the MarshalJSON method is called to encode the value. // +// - If the value type implements [encoding.TextAppender], +// then the AppendText method is called to encode the value and +// subsequently encode its result as a JSON string. +// // - If the value type implements [encoding.TextMarshaler], // then the MarshalText method is called to encode the value and // subsequently encode its result as a JSON string. @@ -90,11 +95,12 @@ func putStructOptions(o *jsonopts.Struct) { // where each byte is recursively JSON-encoded as each JSON array element. // // - A Go integer is encoded as a JSON number without fractions or exponents. -// If [StringifyNumbers] is specified, then the JSON number is -// encoded within a JSON string. It does not support any custom format flags. +// If [StringifyNumbers] is specified or encoding a JSON object name, +// then the JSON number is encoded within a JSON string. +// It does not support any custom format flags. // // - A Go float is encoded as a JSON number. -// If [StringifyNumbers] is specified, +// If [StringifyNumbers] is specified or encoding a JSON object name, // then the JSON number is encoded within a JSON string. // If the format is "nonfinite", then NaN, +Inf, and -Inf are encoded as // the JSON strings "NaN", "Infinity", and "-Infinity", respectively. @@ -103,10 +109,8 @@ func putStructOptions(o *jsonopts.Struct) { // - A Go map is encoded as a JSON object, where each Go map key and value // is recursively encoded as a name and value pair in the JSON object. // The Go map key must encode as a JSON string, otherwise this results -// in a [SemanticError]. When encoding keys, [StringifyNumbers] -// is automatically applied so that numeric keys encode as JSON strings. -// The Go map is traversed in a non-deterministic order. -// For deterministic encoding, consider using [jsontext.Value.Canonicalize]. +// in a [SemanticError]. The Go map is traversed in a non-deterministic order. +// For deterministic encoding, consider using the [Deterministic] option. // If the format is "emitnull", then a nil map is encoded as a JSON null. // If the format is "emitempty", then a nil map is encoded as an empty JSON object, // regardless of whether [FormatNilMapAsNull] is specified. @@ -151,8 +155,6 @@ func putStructOptions(o *jsonopts.Struct) { // If the format is "sec", "milli", "micro", or "nano", // then the duration is encoded as a JSON number of the number of seconds // (or milliseconds, microseconds, or nanoseconds) in the duration. -// If the format is "base60", it is encoded as a JSON string -// using the "H:MM:SS.SSSSSSSSS" representation. // If the format is "units", it uses [time.Duration.String]. // // - All other Go types (e.g., complex numbers, channels, and functions) @@ -166,6 +168,9 @@ func Marshal(in any, opts ...Options) (out []byte, err error) { xe := export.Encoder(enc) xe.Flags.Set(jsonflags.OmitTopLevelNewline | 1) err = marshalEncode(enc, in, &xe.Struct) + if err != nil && xe.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return nil, internal.TransformMarshalError(in, err) + } return bytes.Clone(xe.Buf), err } @@ -178,21 +183,33 @@ func MarshalWrite(out io.Writer, in any, opts ...Options) (err error) { defer export.PutStreamingEncoder(enc) xe := export.Encoder(enc) xe.Flags.Set(jsonflags.OmitTopLevelNewline | 1) - return marshalEncode(enc, in, &xe.Struct) + err = marshalEncode(enc, in, &xe.Struct) + if err != nil && xe.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return internal.TransformMarshalError(in, err) + } + return err } // MarshalEncode serializes a Go value into an [jsontext.Encoder] according to // the provided marshal options (while ignoring unmarshal, encode, or decode options). +// Any marshal-relevant options already specified on the [jsontext.Encoder] +// take lower precedence than the set of options provided by the caller. // Unlike [Marshal] and [MarshalWrite], encode options are ignored because // they must have already been specified on the provided [jsontext.Encoder]. +// // See [Marshal] for details about the conversion of a Go value into JSON. func MarshalEncode(out *jsontext.Encoder, in any, opts ...Options) (err error) { - mo := getStructOptions() - defer putStructOptions(mo) - mo.Join(opts...) xe := export.Encoder(out) - mo.CopyCoderOptions(&xe.Struct) - return marshalEncode(out, in, mo) + if len(opts) > 0 { + optsOriginal := xe.Struct + defer func() { xe.Struct = optsOriginal }() + xe.Struct.JoinWithoutCoderOptions(opts...) + } + err = marshalEncode(out, in, &xe.Struct) + if err != nil && xe.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return internal.TransformMarshalError(in, err) + } + return err } func marshalEncode(out *jsontext.Encoder, in any, mo *jsonopts.Struct) (err error) { @@ -202,12 +219,13 @@ func marshalEncode(out *jsontext.Encoder, in any, mo *jsonopts.Struct) (err erro } // Shallow copy non-pointer values to obtain an addressable value. // It is beneficial to performance to always pass pointers to avoid this. - if v.Kind() != reflect.Pointer { + forceAddr := v.Kind() != reflect.Pointer + if forceAddr { v2 := reflect.New(v.Type()) v2.Elem().Set(v) v = v2 } - va := addressableValue{v.Elem()} // dereferenced pointer is always addressable + va := addressableValue{v.Elem(), forceAddr} // dereferenced pointer is always addressable t := va.Type() // Lookup and call the marshal function for this type. @@ -216,9 +234,8 @@ func marshalEncode(out *jsontext.Encoder, in any, mo *jsonopts.Struct) (err erro marshal, _ = mo.Marshalers.(*Marshalers).lookup(marshal, t) } if err := marshal(out, va, mo); err != nil { - xe := export.Encoder(out) - if !xe.Flags.Get(jsonflags.AllowDuplicateNames) { - xe.Tokens.InvalidateDisabledNamespaces() + if !mo.Flags.Get(jsonflags.AllowDuplicateNames) { + export.Encoder(out).Tokens.InvalidateDisabledNamespaces() } return err } @@ -245,10 +262,10 @@ func marshalEncode(out *jsontext.Encoder, in any, mo *jsonopts.Struct) (err erro // value. If all applicable functions return [SkipFunc], // then the input is decoded according to subsequent rules. // -// - If the value type implements [UnmarshalerV2], -// then the UnmarshalJSONV2 method is called to decode the JSON value. +// - If the value type implements [UnmarshalerFrom], +// then the UnmarshalJSONFrom method is called to decode the JSON value. // -// - If the value type implements [UnmarshalerV1], +// - If the value type implements [Unmarshaler], // then the UnmarshalJSON method is called to decode the JSON value. // // - If the value type implements [encoding.TextUnmarshaler], @@ -293,26 +310,24 @@ func marshalEncode(out *jsontext.Encoder, in any, mo *jsonopts.Struct) (err erro // otherwise it fails with a [SemanticError]. // // - A Go integer is decoded from a JSON number. -// It may also be decoded from a JSON string containing a JSON number -// if [StringifyNumbers] is specified. +// It must be decoded from a JSON string containing a JSON number +// if [StringifyNumbers] is specified or decoding a JSON object name. // It fails with a [SemanticError] if the JSON number // has a fractional or exponent component. // It also fails if it overflows the representation of the Go integer type. // It does not support any custom format flags. // // - A Go float is decoded from a JSON number. -// It may also be decoded from a JSON string containing a JSON number -// if [StringifyNumbers] is specified. -// The JSON number is parsed as the closest representable Go float value. +// It must be decoded from a JSON string containing a JSON number +// if [StringifyNumbers] is specified or decoding a JSON object name. +// It fails if it overflows the representation of the Go float type. // If the format is "nonfinite", then the JSON strings // "NaN", "Infinity", and "-Infinity" are decoded as NaN, +Inf, and -Inf. // Otherwise, the presence of such strings results in a [SemanticError]. // // - A Go map is decoded from a JSON object, // where each JSON object name and value pair is recursively decoded -// as the Go map key and value. When decoding keys, -// [StringifyNumbers] is automatically applied so that -// numeric keys can decode from JSON strings. Maps are not cleared. +// as the Go map key and value. Maps are not cleared. // If the Go map is nil, then a new map is allocated to decode into. // If the decoded key matches an existing Go map entry, the entry value // is reused by decoding the JSON object value into it. @@ -368,8 +383,6 @@ func marshalEncode(out *jsontext.Encoder, in any, mo *jsonopts.Struct) (err erro // If the format is "sec", "milli", "micro", or "nano", // then the duration is decoded from a JSON number of the number of seconds // (or milliseconds, microseconds, or nanoseconds) in the duration. -// If the format is "base60", it is decoded from a JSON string -// using the "H:MM:SS.SSSSSSSSS" representation. // If the format is "units", it uses [time.ParseDuration]. // // - All other Go types (e.g., complex numbers, channels, and functions) @@ -384,7 +397,11 @@ func Unmarshal(in []byte, out any, opts ...Options) (err error) { dec := export.GetBufferedDecoder(in, opts...) defer export.PutBufferedDecoder(dec) xd := export.Decoder(dec) - return unmarshalFull(dec, out, &xd.Struct) + err = unmarshalFull(dec, out, &xd.Struct) + if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return internal.TransformUnmarshalError(out, err) + } + return err } // UnmarshalRead deserializes a Go value from an [io.Reader] according to the @@ -397,7 +414,11 @@ func UnmarshalRead(in io.Reader, out any, opts ...Options) (err error) { dec := export.GetStreamingDecoder(in, opts...) defer export.PutStreamingDecoder(dec) xd := export.Decoder(dec) - return unmarshalFull(dec, out, &xd.Struct) + err = unmarshalFull(dec, out, &xd.Struct) + if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return internal.TransformUnmarshalError(out, err) + } + return err } func unmarshalFull(in *jsontext.Decoder, out any, uo *jsonopts.Struct) error { @@ -413,46 +434,53 @@ func unmarshalFull(in *jsontext.Decoder, out any, uo *jsonopts.Struct) error { // UnmarshalDecode deserializes a Go value from a [jsontext.Decoder] according to // the provided unmarshal options (while ignoring marshal, encode, or decode options). +// Any unmarshal options already specified on the [jsontext.Decoder] +// take lower precedence than the set of options provided by the caller. // Unlike [Unmarshal] and [UnmarshalRead], decode options are ignored because // they must have already been specified on the provided [jsontext.Decoder]. +// // The input may be a stream of one or more JSON values, // where this only unmarshals the next JSON value in the stream. // The output must be a non-nil pointer. // See [Unmarshal] for details about the conversion of JSON into a Go value. func UnmarshalDecode(in *jsontext.Decoder, out any, opts ...Options) (err error) { - uo := getStructOptions() - defer putStructOptions(uo) - uo.Join(opts...) xd := export.Decoder(in) - uo.CopyCoderOptions(&xd.Struct) - return unmarshalDecode(in, out, uo) + if len(opts) > 0 { + optsOriginal := xd.Struct + defer func() { xd.Struct = optsOriginal }() + xd.Struct.JoinWithoutCoderOptions(opts...) + } + err = unmarshalDecode(in, out, &xd.Struct) + if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return internal.TransformUnmarshalError(out, err) + } + return err } func unmarshalDecode(in *jsontext.Decoder, out any, uo *jsonopts.Struct) (err error) { v := reflect.ValueOf(out) - if !v.IsValid() || v.Kind() != reflect.Pointer || v.IsNil() { - var t reflect.Type - if v.IsValid() { - t = v.Type() - if t.Kind() == reflect.Pointer { - t = t.Elem() - } - } - err := errors.New("value must be passed as a non-nil pointer reference") - return &SemanticError{action: "unmarshal", GoType: t, Err: err} + if v.Kind() != reflect.Pointer || v.IsNil() { + return &SemanticError{action: "unmarshal", GoType: reflect.TypeOf(out), Err: internal.ErrNonNilReference} } - va := addressableValue{v.Elem()} // dereferenced pointer is always addressable + va := addressableValue{v.Elem(), false} // dereferenced pointer is always addressable t := va.Type() + // In legacy semantics, the entirety of the next JSON value + // was validated before attempting to unmarshal it. + if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + if err := export.Decoder(in).CheckNextValue(); err != nil { + return err + } + } + // Lookup and call the unmarshal function for this type. unmarshal := lookupArshaler(t).unmarshal if uo.Unmarshalers != nil { unmarshal, _ = uo.Unmarshalers.(*Unmarshalers).lookup(unmarshal, t) } if err := unmarshal(in, va, uo); err != nil { - xd := export.Decoder(in) - if !xd.Flags.Get(jsonflags.AllowDuplicateNames) { - xd.Tokens.InvalidateDisabledNamespaces() + if !uo.Flags.Get(jsonflags.AllowDuplicateNames) { + export.Decoder(in).Tokens.InvalidateDisabledNamespaces() } return err } @@ -465,13 +493,23 @@ func unmarshalDecode(in *jsontext.Decoder, out any, uo *jsonopts.Struct) (err er // There is no compile magic that enforces this property, // but rather the need to construct this type makes it easier to examine each // construction site to ensure that this property is upheld. -type addressableValue struct{ reflect.Value } +type addressableValue struct { + reflect.Value + + // forcedAddr reports whether this value is addressable + // only through the use of [newAddressableValue]. + // This is only used for [jsonflags.CallMethodsWithLegacySemantics]. + forcedAddr bool +} // newAddressableValue constructs a new addressable value of type t. func newAddressableValue(t reflect.Type) addressableValue { - return addressableValue{reflect.New(t).Elem()} + return addressableValue{reflect.New(t).Elem(), true} } +// TODO: Remove *jsonopts.Struct argument from [marshaler] and [unmarshaler]. +// This can be directly accessed on the encoder or decoder. + // All marshal and unmarshal behavior is implemented using these signatures. // The *jsonopts.Struct argument is guaranteed to identical to or at least // a strict super-set of the options in Encoder.Struct or Decoder.Struct. @@ -525,7 +563,6 @@ func putStrings(s *stringSlice) { stringsPools.Put(s) } -// Sort sorts the string slice according to RFC 8785, section 3.2.3. func (ss *stringSlice) Sort() { - slices.SortFunc(*ss, func(x, y string) int { return jsonwire.CompareUTF16(x, y) }) + slices.SortFunc(*ss, func(x, y string) int { return strings.Compare(x, y) }) } diff --git a/vendor/github.com/go-json-experiment/json/arshal_any.go b/vendor/github.com/go-json-experiment/json/arshal_any.go index 334ce94..c5a3573 100644 --- a/vendor/github.com/go-json-experiment/json/arshal_any.go +++ b/vendor/github.com/go-json-experiment/json/arshal_any.go @@ -5,9 +5,11 @@ package json import ( + "cmp" "reflect" "strconv" + "github.com/go-json-experiment/json/internal" "github.com/go-json-experiment/json/internal/jsonflags" "github.com/go-json-experiment/json/internal/jsonopts" "github.com/go-json-experiment/json/internal/jsonwire" @@ -19,6 +21,9 @@ import ( // no knowledge of the JSON schema. This is a common enough occurrence // to justify the complexity of adding logic for this. +// marshalValueAny marshals a Go any as a JSON value. +// This assumes that there are no special formatting directives +// for any possible nested value. func marshalValueAny(enc *jsontext.Encoder, val any, mo *jsonopts.Struct) error { switch val := val.(type) { case nil: @@ -44,6 +49,10 @@ func marshalValueAny(enc *jsontext.Encoder, val any, mo *jsonopts.Struct) error } } +// unmarshalValueAny unmarshals a JSON value as a Go any. +// This assumes that there are no special formatting directives +// for any possible nested value. +// Duplicate names must be rejected since this does not implement merging. func unmarshalValueAny(dec *jsontext.Decoder, uo *jsonopts.Struct) (any, error) { switch k := dec.PeekKind(); k { case '{': @@ -71,9 +80,12 @@ func unmarshalValueAny(dec *jsontext.Decoder, uo *jsonopts.Struct) (any, error) } return makeString(xd.StringCache, val), nil case '0': + if uo.Flags.Get(jsonflags.UnmarshalAnyWithRawNumber) { + return internal.RawNumberOf(val), nil + } fv, ok := jsonwire.ParseFloat(val, 64) - if !ok && uo.Flags.Get(jsonflags.RejectFloatOverflow) { - return nil, &SemanticError{action: "unmarshal", JSONKind: k, GoType: float64Type, Err: strconv.ErrRange} + if !ok { + return fv, newUnmarshalErrorAfterWithValue(dec, float64Type, strconv.ErrRange) } return fv, nil default: @@ -82,13 +94,15 @@ func unmarshalValueAny(dec *jsontext.Decoder, uo *jsonopts.Struct) (any, error) } } +// marshalObjectAny marshals a Go map[string]any as a JSON object +// (or as a JSON null if nil and [jsonflags.FormatNilMapAsNull]). func marshalObjectAny(enc *jsontext.Encoder, obj map[string]any, mo *jsonopts.Struct) error { // Check for cycles. xe := export.Encoder(enc) if xe.Tokens.Depth() > startDetectingCyclesAfter { v := reflect.ValueOf(obj) if err := visitPointer(&xe.SeenPointers, v); err != nil { - return err + return newMarshalErrorBefore(enc, anyType, err) } defer leavePointer(&xe.SeenPointers, v) } @@ -99,7 +113,7 @@ func marshalObjectAny(enc *jsontext.Encoder, obj map[string]any, mo *jsonopts.St return enc.WriteToken(jsontext.Null) } // Optimize for marshaling an empty map without any preceding whitespace. - if !xe.Flags.Get(jsonflags.Expand) && !xe.Tokens.Last.NeedObjectName() { + if !mo.Flags.Get(jsonflags.AnyWhitespace) && !xe.Tokens.Last.NeedObjectName() { xe.Buf = append(xe.Tokens.MayAppendDelim(xe.Buf, '{'), "{}"...) xe.Tokens.Last.Increment() if xe.NeedFlush() { @@ -109,12 +123,12 @@ func marshalObjectAny(enc *jsontext.Encoder, obj map[string]any, mo *jsonopts.St } } - if err := enc.WriteToken(jsontext.ObjectStart); err != nil { + if err := enc.WriteToken(jsontext.BeginObject); err != nil { return err } // A Go map guarantees that each entry has a unique key // The only possibility of duplicates is due to invalid UTF-8. - if !xe.Flags.Get(jsonflags.AllowInvalidUTF8) { + if !mo.Flags.Get(jsonflags.AllowInvalidUTF8) { xe.Tokens.Last.DisableNamespace() } if !mo.Flags.Get(jsonflags.Deterministic) || len(obj) <= 1 { @@ -144,64 +158,67 @@ func marshalObjectAny(enc *jsontext.Encoder, obj map[string]any, mo *jsonopts.St } putStrings(names) } - if err := enc.WriteToken(jsontext.ObjectEnd); err != nil { + if err := enc.WriteToken(jsontext.EndObject); err != nil { return err } return nil } +// unmarshalObjectAny unmarshals a JSON object as a Go map[string]any. +// It panics if not decoding a JSON object. func unmarshalObjectAny(dec *jsontext.Decoder, uo *jsonopts.Struct) (map[string]any, error) { - tok, err := dec.ReadToken() - if err != nil { + switch tok, err := dec.ReadToken(); { + case err != nil: return nil, err + case tok.Kind() != '{': + panic("BUG: invalid kind: " + tok.Kind().String()) } - k := tok.Kind() - switch k { - case 'n': - return nil, nil - case '{': - xd := export.Decoder(dec) - obj := make(map[string]any) - // A Go map guarantees that each entry has a unique key - // The only possibility of duplicates is due to invalid UTF-8. - if !xd.Flags.Get(jsonflags.AllowInvalidUTF8) { - xd.Tokens.Last.DisableNamespace() - } - for dec.PeekKind() != '}' { - tok, err := dec.ReadToken() - if err != nil { - return obj, err - } - name := tok.String() - - // Manually check for duplicate names. - if _, ok := obj[name]; ok { - name := xd.PreviousBuffer() - err := export.NewDuplicateNameError(name, dec.InputOffset()-len64(name)) - return obj, err - } - - val, err := unmarshalValueAny(dec, uo) - obj[name] = val - if err != nil { - return obj, err - } - } - if _, err := dec.ReadToken(); err != nil { + obj := make(map[string]any) + // A Go map guarantees that each entry has a unique key + // The only possibility of duplicates is due to invalid UTF-8. + if !uo.Flags.Get(jsonflags.AllowInvalidUTF8) { + export.Decoder(dec).Tokens.Last.DisableNamespace() + } + var errUnmarshal error + for dec.PeekKind() != '}' { + tok, err := dec.ReadToken() + if err != nil { return obj, err } - return obj, nil + name := tok.String() + + // Manually check for duplicate names. + if _, ok := obj[name]; ok { + // TODO: Unread the object name. + name := export.Decoder(dec).PreviousTokenOrValue() + err := newDuplicateNameError(dec.StackPointer(), nil, dec.InputOffset()-len64(name)) + return obj, err + } + + val, err := unmarshalValueAny(dec, uo) + obj[name] = val + if err != nil { + if isFatalError(err, uo.Flags) { + return obj, err + } + errUnmarshal = cmp.Or(err, errUnmarshal) + } } - return nil, &SemanticError{action: "unmarshal", JSONKind: k, GoType: mapStringAnyType} + if _, err := dec.ReadToken(); err != nil { + return obj, err + } + return obj, errUnmarshal } +// marshalArrayAny marshals a Go []any as a JSON array +// (or as a JSON null if nil and [jsonflags.FormatNilSliceAsNull]). func marshalArrayAny(enc *jsontext.Encoder, arr []any, mo *jsonopts.Struct) error { // Check for cycles. xe := export.Encoder(enc) if xe.Tokens.Depth() > startDetectingCyclesAfter { v := reflect.ValueOf(arr) if err := visitPointer(&xe.SeenPointers, v); err != nil { - return err + return newMarshalErrorBefore(enc, sliceAnyType, err) } defer leavePointer(&xe.SeenPointers, v) } @@ -212,7 +229,7 @@ func marshalArrayAny(enc *jsontext.Encoder, arr []any, mo *jsonopts.Struct) erro return enc.WriteToken(jsontext.Null) } // Optimize for marshaling an empty slice without any preceding whitespace. - if !xe.Flags.Get(jsonflags.Expand) && !xe.Tokens.Last.NeedObjectName() { + if !mo.Flags.Get(jsonflags.AnyWhitespace) && !xe.Tokens.Last.NeedObjectName() { xe.Buf = append(xe.Tokens.MayAppendDelim(xe.Buf, '['), "[]"...) xe.Tokens.Last.Increment() if xe.NeedFlush() { @@ -222,7 +239,7 @@ func marshalArrayAny(enc *jsontext.Encoder, arr []any, mo *jsonopts.Struct) erro } } - if err := enc.WriteToken(jsontext.ArrayStart); err != nil { + if err := enc.WriteToken(jsontext.BeginArray); err != nil { return err } for _, val := range arr { @@ -230,34 +247,35 @@ func marshalArrayAny(enc *jsontext.Encoder, arr []any, mo *jsonopts.Struct) erro return err } } - if err := enc.WriteToken(jsontext.ArrayEnd); err != nil { + if err := enc.WriteToken(jsontext.EndArray); err != nil { return err } return nil } +// unmarshalArrayAny unmarshals a JSON array as a Go []any. +// It panics if not decoding a JSON array. func unmarshalArrayAny(dec *jsontext.Decoder, uo *jsonopts.Struct) ([]any, error) { - tok, err := dec.ReadToken() - if err != nil { + switch tok, err := dec.ReadToken(); { + case err != nil: return nil, err + case tok.Kind() != '[': + panic("BUG: invalid kind: " + tok.Kind().String()) } - k := tok.Kind() - switch k { - case 'n': - return nil, nil - case '[': - arr := []any{} - for dec.PeekKind() != ']' { - val, err := unmarshalValueAny(dec, uo) - arr = append(arr, val) - if err != nil { + arr := []any{} + var errUnmarshal error + for dec.PeekKind() != ']' { + val, err := unmarshalValueAny(dec, uo) + arr = append(arr, val) + if err != nil { + if isFatalError(err, uo.Flags) { return arr, err } + errUnmarshal = cmp.Or(errUnmarshal, err) } - if _, err := dec.ReadToken(); err != nil { - return arr, err - } - return arr, nil } - return nil, &SemanticError{action: "unmarshal", JSONKind: k, GoType: sliceAnyType} + if _, err := dec.ReadToken(); err != nil { + return arr, err + } + return arr, errUnmarshal } diff --git a/vendor/github.com/go-json-experiment/json/arshal_default.go b/vendor/github.com/go-json-experiment/json/arshal_default.go index b353bc5..1972c7b 100644 --- a/vendor/github.com/go-json-experiment/json/arshal_default.go +++ b/vendor/github.com/go-json-experiment/json/arshal_default.go @@ -6,6 +6,8 @@ package json import ( "bytes" + "cmp" + "encoding" "encoding/base32" "encoding/base64" "encoding/hex" @@ -15,8 +17,10 @@ import ( "reflect" "slices" "strconv" + "strings" "sync" + "github.com/go-json-experiment/json/internal" "github.com/go-json-experiment/json/internal/jsonflags" "github.com/go-json-experiment/json/internal/jsonopts" "github.com/go-json-experiment/json/internal/jsonwire" @@ -30,15 +34,15 @@ const optimizeCommon = true var ( // Most natural Go type that correspond with each JSON type. - anyType = reflect.TypeOf((*any)(nil)).Elem() // JSON value - boolType = reflect.TypeOf((*bool)(nil)).Elem() // JSON bool - stringType = reflect.TypeOf((*string)(nil)).Elem() // JSON string - float64Type = reflect.TypeOf((*float64)(nil)).Elem() // JSON number - mapStringAnyType = reflect.TypeOf((*map[string]any)(nil)).Elem() // JSON object - sliceAnyType = reflect.TypeOf((*[]any)(nil)).Elem() // JSON array + anyType = reflect.TypeFor[any]() // JSON value + boolType = reflect.TypeFor[bool]() // JSON bool + stringType = reflect.TypeFor[string]() // JSON string + float64Type = reflect.TypeFor[float64]() // JSON number + mapStringAnyType = reflect.TypeFor[map[string]any]() // JSON object + sliceAnyType = reflect.TypeFor[[]any]() // JSON array - bytesType = reflect.TypeOf((*[]byte)(nil)).Elem() - emptyStructType = reflect.TypeOf((*struct{})(nil)).Elem() + bytesType = reflect.TypeFor[[]byte]() + emptyStructType = reflect.TypeFor[struct{}]() ) const startDetectingCyclesAfter = 1000 @@ -56,7 +60,7 @@ type typedPointer struct { func visitPointer(m *seenPointers, v reflect.Value) error { p := typedPointer{v.Type(), v.UnsafePointer(), sliceLen(v)} if _, ok := (*m)[p]; ok { - return &SemanticError{action: "marshal", GoType: p.typ, Err: errors.New("encountered a cycle")} + return internal.ErrCycle } if *m == nil { *m = make(seenPointers) @@ -98,13 +102,13 @@ func makeDefaultArshaler(t reflect.Type) *arshaler { return makeStructArshaler(t) case reflect.Slice: fncs := makeSliceArshaler(t) - if t.AssignableTo(bytesType) { + if t.Elem().Kind() == reflect.Uint8 { return makeBytesArshaler(t, fncs) } return fncs case reflect.Array: fncs := makeArrayArshaler(t) - if reflect.SliceOf(t.Elem()).AssignableTo(bytesType) { + if t.Elem().Kind() == reflect.Uint8 { return makeBytesArshaler(t, fncs) } return fncs @@ -122,11 +126,11 @@ func makeBoolArshaler(t reflect.Type) *arshaler { fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { xe := export.Encoder(enc) if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { - return newInvalidFormatError("marshal", t, mo.Format) + return newInvalidFormatError(enc, t, mo) } // Optimize for marshaling without preceding whitespace. - if optimizeCommon && !xe.Flags.Get(jsonflags.Expand) && !xe.Tokens.Last.NeedObjectName() { + if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace|jsonflags.StringifyBoolsAndStrings) && !xe.Tokens.Last.NeedObjectName() { xe.Buf = strconv.AppendBool(xe.Tokens.MayAppendDelim(xe.Buf, 't'), va.Bool()) xe.Tokens.Last.Increment() if xe.NeedFlush() { @@ -135,12 +139,19 @@ func makeBoolArshaler(t reflect.Type) *arshaler { return nil } + if mo.Flags.Get(jsonflags.StringifyBoolsAndStrings) { + if va.Bool() { + return enc.WriteToken(jsontext.String("true")) + } else { + return enc.WriteToken(jsontext.String("false")) + } + } return enc.WriteToken(jsontext.Bool(va.Bool())) } fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { xd := export.Decoder(dec) if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { - return newInvalidFormatError("unmarshal", t, uo.Format) + return newInvalidFormatError(dec, t, uo) } tok, err := dec.ReadToken() if err != nil { @@ -149,13 +160,35 @@ func makeBoolArshaler(t reflect.Type) *arshaler { k := tok.Kind() switch k { case 'n': - va.SetBool(false) + if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { + va.SetBool(false) + } return nil case 't', 'f': - va.SetBool(tok.Bool()) - return nil + if !uo.Flags.Get(jsonflags.StringifyBoolsAndStrings) { + va.SetBool(tok.Bool()) + return nil + } + case '"': + if uo.Flags.Get(jsonflags.StringifyBoolsAndStrings) { + switch tok.String() { + case "true": + va.SetBool(true) + case "false": + va.SetBool(false) + default: + if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) && tok.String() == "null" { + if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { + va.SetBool(false) + } + return nil + } + return newUnmarshalErrorAfterWithValue(dec, t, strconv.ErrSyntax) + } + return nil + } } - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t} + return newUnmarshalErrorAfterWithSkipping(dec, uo, t, nil) } return &fncs } @@ -165,31 +198,44 @@ func makeStringArshaler(t reflect.Type) *arshaler { fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { xe := export.Encoder(enc) if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { - return newInvalidFormatError("marshal", t, mo.Format) + return newInvalidFormatError(enc, t, mo) } - // Optimize for marshaling without preceding whitespace or string escaping. + // Optimize for marshaling without preceding whitespace. s := va.String() - if optimizeCommon && !xe.Flags.Get(jsonflags.Expand) && !xe.Tokens.Last.NeedObjectName() && !jsonwire.NeedEscape(s) { + if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace|jsonflags.StringifyBoolsAndStrings) && !xe.Tokens.Last.NeedObjectName() { b := xe.Buf b = xe.Tokens.MayAppendDelim(b, '"') - b = append(b, '"') - b = append(b, s...) - b = append(b, '"') - xe.Buf = b - xe.Tokens.Last.Increment() - if xe.NeedFlush() { - return xe.Flush() + b, err := jsonwire.AppendQuote(b, s, &mo.Flags) + if err == nil { + xe.Buf = b + xe.Tokens.Last.Increment() + if xe.NeedFlush() { + return xe.Flush() + } + return nil } - return nil + // Otherwise, the string contains invalid UTF-8, + // so let the logic below construct the proper error. } + if mo.Flags.Get(jsonflags.StringifyBoolsAndStrings) { + b, err := jsonwire.AppendQuote(nil, s, &mo.Flags) + if err != nil { + return newMarshalErrorBefore(enc, t, &jsontext.SyntacticError{Err: err}) + } + q, err := jsontext.AppendQuote(nil, b) + if err != nil { + panic("BUG: second AppendQuote should never fail: " + err.Error()) + } + return enc.WriteValue(q) + } return enc.WriteToken(jsontext.String(s)) } fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { xd := export.Decoder(dec) if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { - return newInvalidFormatError("unmarshal", t, uo.Format) + return newInvalidFormatError(dec, t, uo) } var flags jsonwire.ValueFlags val, err := xd.ReadValue(&flags) @@ -199,10 +245,24 @@ func makeStringArshaler(t reflect.Type) *arshaler { k := val.Kind() switch k { case 'n': - va.SetString("") + if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { + va.SetString("") + } return nil case '"': val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) + if uo.Flags.Get(jsonflags.StringifyBoolsAndStrings) { + val, err = jsontext.AppendUnquote(nil, val) + if err != nil { + return newUnmarshalErrorAfter(dec, t, err) + } + if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) && string(val) == "null" { + if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { + va.SetString("") + } + return nil + } + } if xd.StringCache == nil { xd.StringCache = new(stringCache) } @@ -210,101 +270,102 @@ func makeStringArshaler(t reflect.Type) *arshaler { va.SetString(str) return nil } - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t} + return newUnmarshalErrorAfter(dec, t, nil) } return &fncs } var ( - encodeBase16 = func(dst, src []byte) { hex.Encode(dst, src) } - encodeBase32 = base32.StdEncoding.Encode - encodeBase32Hex = base32.HexEncoding.Encode - encodeBase64 = base64.StdEncoding.Encode - encodeBase64URL = base64.URLEncoding.Encode - encodedLenBase16 = hex.EncodedLen - encodedLenBase32 = base32.StdEncoding.EncodedLen - encodedLenBase32Hex = base32.HexEncoding.EncodedLen - encodedLenBase64 = base64.StdEncoding.EncodedLen - encodedLenBase64URL = base64.URLEncoding.EncodedLen - decodeBase16 = hex.Decode - decodeBase32 = base32.StdEncoding.Decode - decodeBase32Hex = base32.HexEncoding.Decode - decodeBase64 = base64.StdEncoding.Decode - decodeBase64URL = base64.URLEncoding.Decode - decodedLenBase16 = hex.DecodedLen - decodedLenBase32 = base32.StdEncoding.WithPadding(base32.NoPadding).DecodedLen - decodedLenBase32Hex = base32.HexEncoding.WithPadding(base32.NoPadding).DecodedLen - decodedLenBase64 = base64.StdEncoding.WithPadding(base64.NoPadding).DecodedLen - decodedLenBase64URL = base64.URLEncoding.WithPadding(base64.NoPadding).DecodedLen + appendEncodeBase16 = hex.AppendEncode + appendEncodeBase32 = base32.StdEncoding.AppendEncode + appendEncodeBase32Hex = base32.HexEncoding.AppendEncode + appendEncodeBase64 = base64.StdEncoding.AppendEncode + appendEncodeBase64URL = base64.URLEncoding.AppendEncode + encodedLenBase16 = hex.EncodedLen + encodedLenBase32 = base32.StdEncoding.EncodedLen + encodedLenBase32Hex = base32.HexEncoding.EncodedLen + encodedLenBase64 = base64.StdEncoding.EncodedLen + encodedLenBase64URL = base64.URLEncoding.EncodedLen + appendDecodeBase16 = hex.AppendDecode + appendDecodeBase32 = base32.StdEncoding.AppendDecode + appendDecodeBase32Hex = base32.HexEncoding.AppendDecode + appendDecodeBase64 = base64.StdEncoding.AppendDecode + appendDecodeBase64URL = base64.URLEncoding.AppendDecode ) func makeBytesArshaler(t reflect.Type, fncs *arshaler) *arshaler { - // NOTE: This handles both []byte and [N]byte. + // NOTE: This handles both []~byte and [N]~byte. + // The v2 default is to treat a []namedByte as equivalent to []T + // since being able to convert []namedByte to []byte relies on + // dubious Go reflection behavior (see https://go.dev/issue/24746). + // For v1 emulation, we use jsonflags.FormatBytesWithLegacySemantics + // to forcibly treat []namedByte as a []byte. marshalArray := fncs.marshal + isNamedByte := t.Elem().PkgPath() != "" + hasMarshaler := implementsAny(t.Elem(), allMarshalerTypes...) fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { + if !mo.Flags.Get(jsonflags.FormatBytesWithLegacySemantics) && isNamedByte { + return marshalArray(enc, va, mo) // treat as []T or [N]T + } xe := export.Encoder(enc) - encode, encodedLen := encodeBase64, encodedLenBase64 + appendEncode := appendEncodeBase64 if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { switch mo.Format { case "base64": - encode, encodedLen = encodeBase64, encodedLenBase64 + appendEncode = appendEncodeBase64 case "base64url": - encode, encodedLen = encodeBase64URL, encodedLenBase64URL + appendEncode = appendEncodeBase64URL case "base32": - encode, encodedLen = encodeBase32, encodedLenBase32 + appendEncode = appendEncodeBase32 case "base32hex": - encode, encodedLen = encodeBase32Hex, encodedLenBase32Hex + appendEncode = appendEncodeBase32Hex case "base16", "hex": - encode, encodedLen = encodeBase16, encodedLenBase16 + appendEncode = appendEncodeBase16 case "array": mo.Format = "" return marshalArray(enc, va, mo) default: - return newInvalidFormatError("marshal", t, mo.Format) + return newInvalidFormatError(enc, t, mo) } - } else if mo.Flags.Get(jsonflags.FormatByteArrayAsArray) && va.Kind() == reflect.Array { + } else if mo.Flags.Get(jsonflags.FormatBytesWithLegacySemantics) && + (va.Kind() == reflect.Array || hasMarshaler) { return marshalArray(enc, va, mo) } if mo.Flags.Get(jsonflags.FormatNilSliceAsNull) && va.Kind() == reflect.Slice && va.IsNil() { // TODO: Provide a "emitempty" format override? return enc.WriteToken(jsontext.Null) } - val := enc.UnusedBuffer() - b := va.Bytes() - n := len(`"`) + encodedLen(len(b)) + len(`"`) - if cap(val) < n { - val = make([]byte, n) - } else { - val = val[:n] - } - val[0] = '"' - encode(val[len(`"`):len(val)-len(`"`)], b) - val[len(val)-1] = '"' - return enc.WriteValue(val) + return xe.AppendRaw('"', true, func(b []byte) ([]byte, error) { + return appendEncode(b, va.Bytes()), nil + }) } unmarshalArray := fncs.unmarshal fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { + if !uo.Flags.Get(jsonflags.FormatBytesWithLegacySemantics) && isNamedByte { + return unmarshalArray(dec, va, uo) // treat as []T or [N]T + } xd := export.Decoder(dec) - decode, decodedLen, encodedLen := decodeBase64, decodedLenBase64, encodedLenBase64 + appendDecode, encodedLen := appendDecodeBase64, encodedLenBase64 if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { switch uo.Format { case "base64": - decode, decodedLen, encodedLen = decodeBase64, decodedLenBase64, encodedLenBase64 + appendDecode, encodedLen = appendDecodeBase64, encodedLenBase64 case "base64url": - decode, decodedLen, encodedLen = decodeBase64URL, decodedLenBase64URL, encodedLenBase64URL + appendDecode, encodedLen = appendDecodeBase64URL, encodedLenBase64URL case "base32": - decode, decodedLen, encodedLen = decodeBase32, decodedLenBase32, encodedLenBase32 + appendDecode, encodedLen = appendDecodeBase32, encodedLenBase32 case "base32hex": - decode, decodedLen, encodedLen = decodeBase32Hex, decodedLenBase32Hex, encodedLenBase32Hex + appendDecode, encodedLen = appendDecodeBase32Hex, encodedLenBase32Hex case "base16", "hex": - decode, decodedLen, encodedLen = decodeBase16, decodedLenBase16, encodedLenBase16 + appendDecode, encodedLen = appendDecodeBase16, encodedLenBase16 case "array": uo.Format = "" return unmarshalArray(dec, va, uo) default: - return newInvalidFormatError("unmarshal", t, uo.Format) + return newInvalidFormatError(dec, t, uo) } - } else if uo.Flags.Get(jsonflags.FormatByteArrayAsArray) && va.Kind() == reflect.Array { + } else if uo.Flags.Get(jsonflags.FormatBytesWithLegacySemantics) && + (va.Kind() == reflect.Array || dec.PeekKind() == '[') { return unmarshalArray(dec, va, uo) } var flags jsonwire.ValueFlags @@ -315,50 +376,49 @@ func makeBytesArshaler(t reflect.Type, fncs *arshaler) *arshaler { k := val.Kind() switch k { case 'n': - va.SetZero() + if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) || va.Kind() != reflect.Array { + va.SetZero() + } return nil case '"': + // NOTE: The v2 default is to strictly comply with RFC 4648. + // Section 3.2 specifies that padding is required. + // Section 3.3 specifies that non-alphabet characters + // (e.g., '\r' or '\n') must be rejected. + // Section 3.5 specifies that unnecessary non-zero bits in + // the last quantum may be rejected. Since this is optional, + // we do not reject such inputs. val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) - - // For base64 and base32, decodedLen computes the maximum output size - // when given the original input size. To compute the exact size, - // adjust the input size by excluding trailing padding characters. - // This is unnecessary for base16, but also harmless. - n := len(val) - for n > 0 && val[n-1] == '=' { - n-- + b, err := appendDecode(va.Bytes()[:0], val) + if err != nil { + return newUnmarshalErrorAfter(dec, t, err) } - n = decodedLen(n) - b := va.Bytes() - if va.Kind() == reflect.Array { - if n != len(b) { - err := fmt.Errorf("decoded base64 length of %d mismatches array length of %d", n, len(b)) - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t, Err: err} - } - } else { - if b == nil || cap(b) < n { - b = make([]byte, n) - } else { - b = b[:n] - } - } - n2, err := decode(b, val) - if err == nil && len(val) != encodedLen(n2) { + if len(val) != encodedLen(len(b)) && !uo.Flags.Get(jsonflags.FormatBytesWithLegacySemantics) { // TODO(https://go.dev/issue/53845): RFC 4648, section 3.3, // specifies that non-alphabet characters must be rejected. // Unfortunately, the "base32" and "base64" packages allow // '\r' and '\n' characters by default. - err = errors.New("illegal data at input byte " + strconv.Itoa(bytes.IndexAny(val, "\r\n"))) + i := bytes.IndexAny(val, "\r\n") + err := fmt.Errorf("illegal character %s at offset %d", jsonwire.QuoteRune(val[i:]), i) + return newUnmarshalErrorAfter(dec, t, err) } - if err != nil { - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t, Err: err} - } - if va.Kind() == reflect.Slice { + + if va.Kind() == reflect.Array { + dst := va.Bytes() + clear(dst[copy(dst, b):]) // noop if len(b) <= len(dst) + if len(b) != len(dst) && !uo.Flags.Get(jsonflags.UnmarshalArrayFromAnyLength) { + err := fmt.Errorf("decoded length of %d mismatches array length of %d", len(b), len(dst)) + return newUnmarshalErrorAfter(dec, t, err) + } + } else { + if b == nil { + b = []byte{} + } va.SetBytes(b) } return nil } - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t} + return newUnmarshalErrorAfter(dec, t, nil) } return fncs } @@ -369,11 +429,11 @@ func makeIntArshaler(t reflect.Type) *arshaler { fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { xe := export.Encoder(enc) if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { - return newInvalidFormatError("marshal", t, mo.Format) + return newInvalidFormatError(enc, t, mo) } // Optimize for marshaling without preceding whitespace or string escaping. - if optimizeCommon && !xe.Flags.Get(jsonflags.Expand) && !mo.Flags.Get(jsonflags.StringifyNumbers) && !xe.Tokens.Last.NeedObjectName() { + if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace|jsonflags.StringifyNumbers) && !xe.Tokens.Last.NeedObjectName() { xe.Buf = strconv.AppendInt(xe.Tokens.MayAppendDelim(xe.Buf, '0'), va.Int(), 10) xe.Tokens.Last.Increment() if xe.NeedFlush() { @@ -382,7 +442,7 @@ func makeIntArshaler(t reflect.Type) *arshaler { return nil } - k := stringOrNumberKind(mo.Flags.Get(jsonflags.StringifyNumbers)) + k := stringOrNumberKind(xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers)) return xe.AppendRaw(k, true, func(b []byte) ([]byte, error) { return strconv.AppendInt(b, va.Int(), 10), nil }) @@ -390,8 +450,9 @@ func makeIntArshaler(t reflect.Type) *arshaler { fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { xd := export.Decoder(dec) if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { - return newInvalidFormatError("unmarshal", t, uo.Format) + return newInvalidFormatError(dec, t, uo) } + stringify := xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers) var flags jsonwire.ValueFlags val, err := xd.ReadValue(&flags) if err != nil { @@ -400,15 +461,26 @@ func makeIntArshaler(t reflect.Type) *arshaler { k := val.Kind() switch k { case 'n': - va.SetInt(0) + if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { + va.SetInt(0) + } return nil case '"': - if !uo.Flags.Get(jsonflags.StringifyNumbers) { + if !stringify { break } val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) + if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) && string(val) == "null" { + if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { + va.SetInt(0) + } + return nil + } fallthrough case '0': + if stringify && k == '0' { + break + } var negOffset int neg := len(val) > 0 && val[0] == '-' if neg { @@ -419,14 +491,12 @@ func makeIntArshaler(t reflect.Type) *arshaler { overflow := (neg && n > maxInt) || (!neg && n > maxInt-1) if !ok { if n != math.MaxUint64 { - err := fmt.Errorf("cannot parse %q as signed integer: %w", val, strconv.ErrSyntax) - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t, Err: err} + return newUnmarshalErrorAfterWithValue(dec, t, strconv.ErrSyntax) } overflow = true } if overflow { - err := fmt.Errorf("cannot parse %q as signed integer: %w", val, strconv.ErrRange) - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t, Err: err} + return newUnmarshalErrorAfterWithValue(dec, t, strconv.ErrRange) } if neg { va.SetInt(int64(-n)) @@ -435,7 +505,7 @@ func makeIntArshaler(t reflect.Type) *arshaler { } return nil } - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t} + return newUnmarshalErrorAfter(dec, t, nil) } return &fncs } @@ -446,11 +516,11 @@ func makeUintArshaler(t reflect.Type) *arshaler { fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { xe := export.Encoder(enc) if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { - return newInvalidFormatError("marshal", t, mo.Format) + return newInvalidFormatError(enc, t, mo) } // Optimize for marshaling without preceding whitespace or string escaping. - if optimizeCommon && !xe.Flags.Get(jsonflags.Expand) && !mo.Flags.Get(jsonflags.StringifyNumbers) && !xe.Tokens.Last.NeedObjectName() { + if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace|jsonflags.StringifyNumbers) && !xe.Tokens.Last.NeedObjectName() { xe.Buf = strconv.AppendUint(xe.Tokens.MayAppendDelim(xe.Buf, '0'), va.Uint(), 10) xe.Tokens.Last.Increment() if xe.NeedFlush() { @@ -459,7 +529,7 @@ func makeUintArshaler(t reflect.Type) *arshaler { return nil } - k := stringOrNumberKind(mo.Flags.Get(jsonflags.StringifyNumbers)) + k := stringOrNumberKind(xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers)) return xe.AppendRaw(k, true, func(b []byte) ([]byte, error) { return strconv.AppendUint(b, va.Uint(), 10), nil }) @@ -467,8 +537,9 @@ func makeUintArshaler(t reflect.Type) *arshaler { fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { xd := export.Decoder(dec) if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { - return newInvalidFormatError("unmarshal", t, uo.Format) + return newInvalidFormatError(dec, t, uo) } + stringify := xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers) var flags jsonwire.ValueFlags val, err := xd.ReadValue(&flags) if err != nil { @@ -477,33 +548,42 @@ func makeUintArshaler(t reflect.Type) *arshaler { k := val.Kind() switch k { case 'n': - va.SetUint(0) + if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { + va.SetUint(0) + } return nil case '"': - if !uo.Flags.Get(jsonflags.StringifyNumbers) { + if !stringify { break } val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) + if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) && string(val) == "null" { + if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { + va.SetUint(0) + } + return nil + } fallthrough case '0': + if stringify && k == '0' { + break + } n, ok := jsonwire.ParseUint(val) maxUint := uint64(1) << bits overflow := n > maxUint-1 if !ok { if n != math.MaxUint64 { - err := fmt.Errorf("cannot parse %q as unsigned integer: %w", val, strconv.ErrSyntax) - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t, Err: err} + return newUnmarshalErrorAfterWithValue(dec, t, strconv.ErrSyntax) } overflow = true } if overflow { - err := fmt.Errorf("cannot parse %q as unsigned integer: %w", val, strconv.ErrRange) - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t, Err: err} + return newUnmarshalErrorAfterWithValue(dec, t, strconv.ErrRange) } va.SetUint(n) return nil } - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t} + return newUnmarshalErrorAfter(dec, t, nil) } return &fncs } @@ -518,21 +598,21 @@ func makeFloatArshaler(t reflect.Type) *arshaler { if mo.Format == "nonfinite" { allowNonFinite = true } else { - return newInvalidFormatError("marshal", t, mo.Format) + return newInvalidFormatError(enc, t, mo) } } fv := va.Float() if math.IsNaN(fv) || math.IsInf(fv, 0) { if !allowNonFinite { - err := fmt.Errorf("invalid value: %v", fv) - return &SemanticError{action: "marshal", GoType: t, Err: err} + err := fmt.Errorf("unsupported value: %v", fv) + return newMarshalErrorBefore(enc, t, err) } return enc.WriteToken(jsontext.Float(fv)) } // Optimize for marshaling without preceding whitespace or string escaping. - if optimizeCommon && !xe.Flags.Get(jsonflags.Expand) && !mo.Flags.Get(jsonflags.StringifyNumbers) && !xe.Tokens.Last.NeedObjectName() { + if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace|jsonflags.StringifyNumbers) && !xe.Tokens.Last.NeedObjectName() { xe.Buf = jsonwire.AppendFloat(xe.Tokens.MayAppendDelim(xe.Buf, '0'), fv, bits) xe.Tokens.Last.Increment() if xe.NeedFlush() { @@ -541,7 +621,7 @@ func makeFloatArshaler(t reflect.Type) *arshaler { return nil } - k := stringOrNumberKind(mo.Flags.Get(jsonflags.StringifyNumbers)) + k := stringOrNumberKind(xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers)) return xe.AppendRaw(k, true, func(b []byte) ([]byte, error) { return jsonwire.AppendFloat(b, va.Float(), bits), nil }) @@ -553,9 +633,10 @@ func makeFloatArshaler(t reflect.Type) *arshaler { if uo.Format == "nonfinite" { allowNonFinite = true } else { - return newInvalidFormatError("unmarshal", t, uo.Format) + return newInvalidFormatError(dec, t, uo) } } + stringify := xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers) var flags jsonwire.ValueFlags val, err := xd.ReadValue(&flags) if err != nil { @@ -564,7 +645,9 @@ func makeFloatArshaler(t reflect.Type) *arshaler { k := val.Kind() switch k { case 'n': - va.SetFloat(0) + if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { + va.SetFloat(0) + } return nil case '"': val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) @@ -581,23 +664,31 @@ func makeFloatArshaler(t reflect.Type) *arshaler { return nil } } - if !uo.Flags.Get(jsonflags.StringifyNumbers) { + if !stringify { break } + if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) && string(val) == "null" { + if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { + va.SetFloat(0) + } + return nil + } if n, err := jsonwire.ConsumeNumber(val); n != len(val) || err != nil { - err := fmt.Errorf("cannot parse %q as JSON number: %w", val, strconv.ErrSyntax) - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t, Err: err} + return newUnmarshalErrorAfterWithValue(dec, t, strconv.ErrSyntax) } fallthrough case '0': - fv, ok := jsonwire.ParseFloat(val, bits) - if !ok && uo.Flags.Get(jsonflags.RejectFloatOverflow) { - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t, Err: strconv.ErrRange} + if stringify && k == '0' { + break } + fv, ok := jsonwire.ParseFloat(val, bits) va.SetFloat(fv) + if !ok { + return newUnmarshalErrorAfterWithValue(dec, t, strconv.ErrRange) + } return nil } - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t} + return newUnmarshalErrorAfter(dec, t, nil) } return &fncs } @@ -620,12 +711,14 @@ func makeMapArshaler(t reflect.Type) *arshaler { keyFncs = lookupArshaler(t.Key()) valFncs = lookupArshaler(t.Elem()) } + nillableLegacyKey := t.Key().Kind() == reflect.Pointer && + implementsAny(t.Key(), textMarshalerType, textAppenderType) fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { // Check for cycles. xe := export.Encoder(enc) if xe.Tokens.Depth() > startDetectingCyclesAfter { if err := visitPointer(&xe.SeenPointers, va.Value); err != nil { - return err + return newMarshalErrorBefore(enc, t, err) } defer leavePointer(&xe.SeenPointers, va.Value) } @@ -640,7 +733,7 @@ func makeMapArshaler(t reflect.Type) *arshaler { emitNull = false mo.Format = "" default: - return newInvalidFormatError("marshal", t, mo.Format) + return newInvalidFormatError(enc, t, mo) } } @@ -651,7 +744,7 @@ func makeMapArshaler(t reflect.Type) *arshaler { return enc.WriteToken(jsontext.Null) } // Optimize for marshaling an empty map without any preceding whitespace. - if optimizeCommon && !xe.Flags.Get(jsonflags.Expand) && !xe.Tokens.Last.NeedObjectName() { + if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace) && !xe.Tokens.Last.NeedObjectName() { xe.Buf = append(xe.Tokens.MayAppendDelim(xe.Buf, '{'), "{}"...) xe.Tokens.Last.Increment() if xe.NeedFlush() { @@ -662,7 +755,7 @@ func makeMapArshaler(t reflect.Type) *arshaler { } once.Do(init) - if err := enc.WriteToken(jsontext.ObjectStart); err != nil { + if err := enc.WriteToken(jsontext.BeginObject); err != nil { return err } if n > 0 { @@ -681,7 +774,7 @@ func makeMapArshaler(t reflect.Type) *arshaler { // A Go map guarantees that each entry has a unique key. // As such, disable the expensive duplicate name check if we know // that every Go key will serialize as a unique JSON string. - if !nonDefaultKey && mapKeyWithUniqueRepresentation(k.Kind(), xe.Flags.Get(jsonflags.AllowInvalidUTF8)) { + if !nonDefaultKey && mapKeyWithUniqueRepresentation(k.Kind(), mo.Flags.Get(jsonflags.AllowInvalidUTF8)) { xe.Tokens.Last.DisableNamespace() } @@ -689,15 +782,18 @@ func makeMapArshaler(t reflect.Type) *arshaler { case !mo.Flags.Get(jsonflags.Deterministic) || n <= 1: for iter := va.Value.MapRange(); iter.Next(); { k.SetIterKey(iter) - flagsOriginal := mo.Flags - mo.Flags.Set(jsonflags.StringifyNumbers | 1) // stringify for numeric keys err := marshalKey(enc, k, mo) - mo.Flags = flagsOriginal if err != nil { - // TODO: If err is errMissingName, then wrap it as a - // SemanticError since this key type cannot be serialized - // as a JSON string. - return err + if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && + errors.Is(err, jsontext.ErrNonStringName) && nillableLegacyKey && k.IsNil() { + err = enc.WriteToken(jsontext.String("")) + } + if err != nil { + if serr, ok := err.(*jsontext.SyntacticError); ok && serr.Err == jsontext.ErrNonStringName { + err = newMarshalErrorBefore(enc, k.Type(), err) + } + return err + } } v.SetIterValue(iter) if err := marshalVal(enc, v, mo); err != nil { @@ -734,19 +830,22 @@ func makeMapArshaler(t reflect.Type) *arshaler { vals := reflect.MakeSlice(reflect.SliceOf(t.Elem()), n, n) for i, iter := 0, va.Value.MapRange(); i < n && iter.Next(); i++ { // Marshal the member name. - k := addressableValue{keys.Index(i)} // indexed slice element is always addressable + k := addressableValue{keys.Index(i), true} // indexed slice element is always addressable k.SetIterKey(iter) - v := addressableValue{vals.Index(i)} // indexed slice element is always addressable + v := addressableValue{vals.Index(i), true} // indexed slice element is always addressable v.SetIterValue(iter) - flagsOriginal := mo.Flags - mo.Flags.Set(jsonflags.StringifyNumbers | 1) // stringify for numeric keys err := marshalKey(enc, k, mo) - mo.Flags = flagsOriginal if err != nil { - // TODO: If err is errMissingName, then wrap it as a - // SemanticError since this key type cannot be serialized - // as a JSON string. - return err + if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && + errors.Is(err, jsontext.ErrNonStringName) && nillableLegacyKey && k.IsNil() { + err = enc.WriteToken(jsontext.String("")) + } + if err != nil { + if serr, ok := err.(*jsontext.SyntacticError); ok && serr.Err == jsontext.ErrNonStringName { + err = newMarshalErrorBefore(enc, k.Type(), err) + } + return err + } } name := xe.UnwriteOnlyObjectMemberName() members[i] = member{name, k, v} @@ -755,7 +854,7 @@ func makeMapArshaler(t reflect.Type) *arshaler { // to reflect.Value as well if the names are equal. // See internal/fmtsort. slices.SortFunc(members, func(x, y member) int { - return jsonwire.CompareUTF16(x.name, y.name) + return strings.Compare(x.name, y.name) }) for _, member := range members { if err := enc.WriteToken(jsontext.String(member.name)); err != nil { @@ -767,7 +866,7 @@ func makeMapArshaler(t reflect.Type) *arshaler { } } } - if err := enc.WriteToken(jsontext.ObjectEnd); err != nil { + if err := enc.WriteToken(jsontext.EndObject); err != nil { return err } return nil @@ -779,7 +878,7 @@ func makeMapArshaler(t reflect.Type) *arshaler { case "emitnull", "emitempty": uo.Format = "" // only relevant for marshaling default: - return newInvalidFormatError("unmarshal", t, uo.Format) + return newInvalidFormatError(dec, t, uo) } } tok, err := dec.ReadToken() @@ -815,7 +914,7 @@ func makeMapArshaler(t reflect.Type) *arshaler { // will be rejected as duplicates since they semantically refer // to the same Go value. This is an unusual interaction // between syntax and semantics, but is more correct. - if !nonDefaultKey && mapKeyWithUniqueRepresentation(k.Kind(), xd.Flags.Get(jsonflags.AllowInvalidUTF8)) { + if !nonDefaultKey && mapKeyWithUniqueRepresentation(k.Kind(), uo.Flags.Get(jsonflags.AllowInvalidUTF8)) { xd.Tokens.Last.DisableNamespace() } @@ -824,50 +923,72 @@ func makeMapArshaler(t reflect.Type) *arshaler { // since existing presence alone is insufficient to indicate // whether the input had a duplicate name. var seen reflect.Value - if !xd.Flags.Get(jsonflags.AllowDuplicateNames) && va.Len() > 0 { + if !uo.Flags.Get(jsonflags.AllowDuplicateNames) && va.Len() > 0 { seen = reflect.MakeMap(reflect.MapOf(k.Type(), emptyStructType)) } + var errUnmarshal error for dec.PeekKind() != '}' { + // Unmarshal the map entry key. k.SetZero() - flagsOriginal := uo.Flags - uo.Flags.Set(jsonflags.StringifyNumbers | 1) // stringify for numeric keys err := unmarshalKey(dec, k, uo) - uo.Flags = flagsOriginal if err != nil { - return err - } - if k.Kind() == reflect.Interface && !k.IsNil() && !k.Elem().Type().Comparable() { - err := fmt.Errorf("invalid incomparable key type %v", k.Elem().Type()) - return &SemanticError{action: "unmarshal", GoType: t, Err: err} - } - - if v2 := va.MapIndex(k.Value); v2.IsValid() { - if !xd.Flags.Get(jsonflags.AllowDuplicateNames) && (!seen.IsValid() || seen.MapIndex(k.Value).IsValid()) { - // TODO: Unread the object name. - name := xd.PreviousBuffer() - err := export.NewDuplicateNameError(name, dec.InputOffset()-len64(name)) + if isFatalError(err, uo.Flags) { return err } - v.Set(v2) + if err := dec.SkipValue(); err != nil { + return err + } + errUnmarshal = cmp.Or(errUnmarshal, err) + continue + } + if k.Kind() == reflect.Interface && !k.IsNil() && !k.Elem().Type().Comparable() { + err := newUnmarshalErrorAfter(dec, t, fmt.Errorf("invalid incomparable key type %v", k.Elem().Type())) + if !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return err + } + if err2 := dec.SkipValue(); err2 != nil { + return err2 + } + errUnmarshal = cmp.Or(errUnmarshal, err) + continue + } + + // Check if a pre-existing map entry value exists for this key. + if v2 := va.MapIndex(k.Value); v2.IsValid() { + if !uo.Flags.Get(jsonflags.AllowDuplicateNames) && (!seen.IsValid() || seen.MapIndex(k.Value).IsValid()) { + // TODO: Unread the object name. + name := xd.PreviousTokenOrValue() + return newDuplicateNameError(dec.StackPointer(), nil, dec.InputOffset()-len64(name)) + } + if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { + v.Set(v2) + } else { + v.SetZero() + } } else { v.SetZero() } + + // Unmarshal the map entry value. err = unmarshalVal(dec, v, uo) va.SetMapIndex(k.Value, v.Value) if seen.IsValid() { seen.SetMapIndex(k.Value, reflect.Zero(emptyStructType)) } if err != nil { - return err + if isFatalError(err, uo.Flags) { + return err + } + errUnmarshal = cmp.Or(errUnmarshal, err) } } if _, err := dec.ReadToken(); err != nil { return err } - return nil + return errUnmarshal } - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t} + return newUnmarshalErrorAfterWithSkipping(dec, uo, t, nil) } return &fncs } @@ -893,6 +1014,8 @@ func mapKeyWithUniqueRepresentation(k reflect.Kind, allowInvalidUTF8 bool) bool } } +var errNilField = errors.New("cannot set embedded pointer to unexported struct type") + func makeStructArshaler(t reflect.Type) *arshaler { // NOTE: The logic below disables namespaces for tracking duplicate names // and does the tracking locally with an efficient bit-set based on which @@ -910,15 +1033,13 @@ func makeStructArshaler(t reflect.Type) *arshaler { fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { xe := export.Encoder(enc) if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { - return newInvalidFormatError("marshal", t, mo.Format) + return newInvalidFormatError(enc, t, mo) } once.Do(init) - if errInit != nil { - err := *errInit // shallow copy SemanticError - err.action = "marshal" - return &err + if errInit != nil && !mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return newMarshalErrorBefore(enc, errInit.GoType, errInit.Err) } - if err := enc.WriteToken(jsontext.ObjectStart); err != nil { + if err := enc.WriteToken(jsontext.BeginObject); err != nil { return err } var seenIdxs uintSet @@ -926,9 +1047,9 @@ func makeStructArshaler(t reflect.Type) *arshaler { xe.Tokens.Last.DisableNamespace() // we manually ensure unique names below for i := range fields.flattened { f := &fields.flattened[i] - v := addressableValue{va.Field(f.index[0])} // addressable if struct value is addressable - if len(f.index) > 1 { - v = v.fieldByIndex(f.index[1:], false) + v := addressableValue{va.Field(f.index0), va.forcedAddr} // addressable if struct value is addressable + if len(f.index) > 0 { + v = v.fieldByIndex(f.index, false) if !v.IsValid() { continue // implies a nil inlined field } @@ -936,7 +1057,8 @@ func makeStructArshaler(t reflect.Type) *arshaler { // OmitZero skips the field if the Go value is zero, // which we can determine up front without calling the marshaler. - if f.omitzero && ((f.isZero == nil && v.IsZero()) || (f.isZero != nil && f.isZero(v))) { + if (f.omitzero || mo.Flags.Get(jsonflags.OmitZeroStructFields)) && + ((f.isZero == nil && v.IsZero()) || (f.isZero != nil && f.isZero(v))) { continue } @@ -976,22 +1098,23 @@ func makeStructArshaler(t reflect.Type) *arshaler { b := xe.Buf if xe.Tokens.Last.Length() > 0 { b = append(b, ',') + if mo.Flags.Get(jsonflags.SpaceAfterComma) { + b = append(b, ' ') + } } - if xe.Flags.Get(jsonflags.Expand) { + if mo.Flags.Get(jsonflags.Multiline) { b = xe.AppendIndent(b, xe.Tokens.NeedIndent('"')) } // Append the token to the output and to the state machine. n0 := len(b) // offset before calling AppendQuote - if !xe.Flags.Get(jsonflags.EscapeForHTML | jsonflags.EscapeForJS) { + if !f.nameNeedEscape { b = append(b, f.quotedName...) } else { - b, _ = jsonwire.AppendQuote(b, f.name, &xe.Flags) + b, _ = jsonwire.AppendQuote(b, f.name, &mo.Flags) } xe.Buf = b - if !xe.Flags.Get(jsonflags.AllowDuplicateNames) { - xe.Names.ReplaceLastQuotedOffset(n0) - } + xe.Names.ReplaceLastQuotedOffset(n0) xe.Tokens.Last.Increment() } else { if err := enc.WriteToken(jsontext.String(f.name)); err != nil { @@ -1002,7 +1125,11 @@ func makeStructArshaler(t reflect.Type) *arshaler { // Write the object member value. flagsOriginal := mo.Flags if f.string { - mo.Flags.Set(jsonflags.StringifyNumbers | 1) + if !mo.Flags.Get(jsonflags.StringifyWithLegacySemantics) { + mo.Flags.Set(jsonflags.StringifyNumbers | 1) + } else if canLegacyStringify(f.typ) { + mo.Flags.Set(jsonflags.StringifyNumbers | jsonflags.StringifyBoolsAndStrings | 1) + } } if f.format != "" { mo.FormatDepth = xe.Tokens.Depth() @@ -1029,14 +1156,14 @@ func makeStructArshaler(t reflect.Type) *arshaler { // Remember the previous written object member. // The set of seen fields only needs to be updated to detect // duplicate names with those from the inlined fallback. - if !xe.Flags.Get(jsonflags.AllowDuplicateNames) && fields.inlinedFallback != nil { + if !mo.Flags.Get(jsonflags.AllowDuplicateNames) && fields.inlinedFallback != nil { seenIdxs.insert(uint(f.id)) } prevIdx = f.id } if fields.inlinedFallback != nil && !(mo.Flags.Get(jsonflags.DiscardUnknownMembers) && fields.inlinedFallback.unknown) { var insertUnquotedName func([]byte) bool - if !xe.Flags.Get(jsonflags.AllowDuplicateNames) { + if !mo.Flags.Get(jsonflags.AllowDuplicateNames) { insertUnquotedName = func(name []byte) bool { // Check that the name from inlined fallback does not match // one of the previously marshaled names from known fields. @@ -1060,7 +1187,7 @@ func makeStructArshaler(t reflect.Type) *arshaler { return err } } - if err := enc.WriteToken(jsontext.ObjectEnd); err != nil { + if err := enc.WriteToken(jsontext.EndObject); err != nil { return err } return nil @@ -1068,7 +1195,7 @@ func makeStructArshaler(t reflect.Type) *arshaler { fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { xd := export.Decoder(dec) if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { - return newInvalidFormatError("unmarshal", t, uo.Format) + return newInvalidFormatError(dec, t, uo) } tok, err := dec.ReadToken() if err != nil { @@ -1077,17 +1204,18 @@ func makeStructArshaler(t reflect.Type) *arshaler { k := tok.Kind() switch k { case 'n': - va.SetZero() + if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { + va.SetZero() + } return nil case '{': once.Do(init) - if errInit != nil { - err := *errInit // shallow copy SemanticError - err.action = "unmarshal" - return &err + if errInit != nil && !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return newUnmarshalErrorAfter(dec, errInit.GoType, errInit.Err) } var seenIdxs uintSet xd.Tokens.Last.DisableNamespace() + var errUnmarshal error for dec.PeekKind() != '}' { // Process the object member name. var flags jsonwire.ValueFlags @@ -1106,12 +1234,15 @@ func makeStructArshaler(t reflect.Type) *arshaler { } if f == nil { if uo.Flags.Get(jsonflags.RejectUnknownMembers) && (fields.inlinedFallback == nil || fields.inlinedFallback.unknown) { - return &SemanticError{action: "unmarshal", GoType: t, Err: fmt.Errorf("unknown name %s", val)} + err := newUnmarshalErrorAfter(dec, t, ErrUnknownName) + if !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return err + } + errUnmarshal = cmp.Or(errUnmarshal, err) } - if !xd.Flags.Get(jsonflags.AllowDuplicateNames) && !xd.Namespaces.Last().InsertUnquoted(name) { + if !uo.Flags.Get(jsonflags.AllowDuplicateNames) && !xd.Namespaces.Last().InsertUnquoted(name) { // TODO: Unread the object name. - err := export.NewDuplicateNameError(val, dec.InputOffset()-len64(val)) - return err + return newDuplicateNameError(dec.StackPointer(), nil, dec.InputOffset()-len64(val)) } if fields.inlinedFallback == nil { @@ -1122,16 +1253,18 @@ func makeStructArshaler(t reflect.Type) *arshaler { } else { // Marshal into value capable of storing arbitrary object members. if err := unmarshalInlinedFallbackNext(dec, va, uo, fields.inlinedFallback, val, name); err != nil { - return err + if isFatalError(err, uo.Flags) { + return err + } + errUnmarshal = cmp.Or(errUnmarshal, err) } } continue } } - if !xd.Flags.Get(jsonflags.AllowDuplicateNames) && !seenIdxs.insert(uint(f.id)) { + if !uo.Flags.Get(jsonflags.AllowDuplicateNames) && !seenIdxs.insert(uint(f.id)) { // TODO: Unread the object name. - err := export.NewDuplicateNameError(val, dec.InputOffset()-len64(val)) - return err + return newDuplicateNameError(dec.StackPointer(), nil, dec.InputOffset()-len64(val)) } // Process the object member value. @@ -1141,29 +1274,46 @@ func makeStructArshaler(t reflect.Type) *arshaler { } flagsOriginal := uo.Flags if f.string { - uo.Flags.Set(jsonflags.StringifyNumbers | 1) + if !uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) { + uo.Flags.Set(jsonflags.StringifyNumbers | 1) + } else if canLegacyStringify(f.typ) { + uo.Flags.Set(jsonflags.StringifyNumbers | jsonflags.StringifyBoolsAndStrings | 1) + } } if f.format != "" { uo.FormatDepth = xd.Tokens.Depth() uo.Format = f.format } - v := addressableValue{va.Field(f.index[0])} // addressable if struct value is addressable - if len(f.index) > 1 { - v = v.fieldByIndex(f.index[1:], true) + v := addressableValue{va.Field(f.index0), va.forcedAddr} // addressable if struct value is addressable + if len(f.index) > 0 { + v = v.fieldByIndex(f.index, true) + if !v.IsValid() { + err := newUnmarshalErrorBefore(dec, t, errNilField) + if !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return err + } + errUnmarshal = cmp.Or(errUnmarshal, err) + unmarshal = func(dec *jsontext.Decoder, _ addressableValue, _ *jsonopts.Struct) error { + return dec.SkipValue() + } + } } err = unmarshal(dec, v, uo) uo.Flags = flagsOriginal uo.Format = "" if err != nil { - return err + if isFatalError(err, uo.Flags) { + return err + } + errUnmarshal = cmp.Or(errUnmarshal, err) } } if _, err := dec.ReadToken(); err != nil { return err } - return nil + return errUnmarshal } - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t} + return newUnmarshalErrorAfterWithSkipping(dec, uo, t, nil) } return &fncs } @@ -1174,7 +1324,7 @@ func (va addressableValue) fieldByIndex(index []int, mayAlloc bool) addressableV if !va.IsValid() { return va } - va = addressableValue{va.Field(i)} // addressable if struct value is addressable + va = addressableValue{va.Field(i), va.forcedAddr} // addressable if struct value is addressable } return va } @@ -1182,12 +1332,12 @@ func (va addressableValue) fieldByIndex(index []int, mayAlloc bool) addressableV func (va addressableValue) indirect(mayAlloc bool) addressableValue { if va.Kind() == reflect.Pointer { if va.IsNil() { - if !mayAlloc { + if !mayAlloc || !va.CanSet() { return addressableValue{} } va.Set(reflect.New(va.Type().Elem())) } - va = addressableValue{va.Elem()} // dereferenced pointer is always addressable + va = addressableValue{va.Elem(), false} // dereferenced pointer is always addressable } return va } @@ -1212,6 +1362,25 @@ func isLegacyEmpty(v addressableValue) bool { return false } +// canLegacyStringify reports whether t can be stringified according to v1, +// where t is a bool, string, or number (or unnamed pointer to such). +// In v1, the `string` option does not apply recursively to nested types within +// a composite Go type (e.g., an array, slice, struct, map, or interface). +func canLegacyStringify(t reflect.Type) bool { + // Based on encoding/json.typeFields#L1126-L1143@v1.23.0 + if t.Name() == "" && t.Kind() == reflect.Ptr { + t = t.Elem() + } + switch t.Kind() { + case reflect.Bool, reflect.String, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, + reflect.Float32, reflect.Float64: + return true + } + return false +} + func makeSliceArshaler(t reflect.Type) *arshaler { var fncs arshaler var ( @@ -1226,7 +1395,7 @@ func makeSliceArshaler(t reflect.Type) *arshaler { xe := export.Encoder(enc) if xe.Tokens.Depth() > startDetectingCyclesAfter { if err := visitPointer(&xe.SeenPointers, va.Value); err != nil { - return err + return newMarshalErrorBefore(enc, t, err) } defer leavePointer(&xe.SeenPointers, va.Value) } @@ -1241,7 +1410,7 @@ func makeSliceArshaler(t reflect.Type) *arshaler { emitNull = false mo.Format = "" default: - return newInvalidFormatError("marshal", t, mo.Format) + return newInvalidFormatError(enc, t, mo) } } @@ -1252,7 +1421,7 @@ func makeSliceArshaler(t reflect.Type) *arshaler { return enc.WriteToken(jsontext.Null) } // Optimize for marshaling an empty slice without any preceding whitespace. - if optimizeCommon && !xe.Flags.Get(jsonflags.Expand) && !xe.Tokens.Last.NeedObjectName() { + if optimizeCommon && !mo.Flags.Get(jsonflags.AnyWhitespace) && !xe.Tokens.Last.NeedObjectName() { xe.Buf = append(xe.Tokens.MayAppendDelim(xe.Buf, '['), "[]"...) xe.Tokens.Last.Increment() if xe.NeedFlush() { @@ -1263,20 +1432,20 @@ func makeSliceArshaler(t reflect.Type) *arshaler { } once.Do(init) - if err := enc.WriteToken(jsontext.ArrayStart); err != nil { + if err := enc.WriteToken(jsontext.BeginArray); err != nil { return err } marshal := valFncs.marshal if mo.Marshalers != nil { marshal, _ = mo.Marshalers.(*Marshalers).lookup(marshal, t.Elem()) } - for i := 0; i < n; i++ { - v := addressableValue{va.Index(i)} // indexed slice element is always addressable + for i := range n { + v := addressableValue{va.Index(i), false} // indexed slice element is always addressable if err := marshal(enc, v, mo); err != nil { return err } } - if err := enc.WriteToken(jsontext.ArrayEnd); err != nil { + if err := enc.WriteToken(jsontext.EndArray); err != nil { return err } return nil @@ -1289,7 +1458,7 @@ func makeSliceArshaler(t reflect.Type) *arshaler { case "emitnull", "emitempty": uo.Format = "" // only relevant for marshaling default: - return newInvalidFormatError("unmarshal", t, uo.Format) + return newInvalidFormatError(dec, t, uo) } } @@ -1314,6 +1483,7 @@ func makeSliceArshaler(t reflect.Type) *arshaler { va.SetLen(cap) } var i int + var errUnmarshal error for dec.PeekKind() != ']' { if i == cap { va.Value.Grow(1) @@ -1321,14 +1491,17 @@ func makeSliceArshaler(t reflect.Type) *arshaler { va.SetLen(cap) mustZero = false // reflect.Value.Grow ensures new capacity is zero-initialized } - v := addressableValue{va.Index(i)} // indexed slice element is always addressable + v := addressableValue{va.Index(i), false} // indexed slice element is always addressable i++ - if mustZero { + if mustZero && !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { v.SetZero() } if err := unmarshal(dec, v, uo); err != nil { - va.SetLen(i) - return err + if isFatalError(err, uo.Flags) { + va.SetLen(i) + return err + } + errUnmarshal = cmp.Or(errUnmarshal, err) } } if i == 0 { @@ -1339,13 +1512,16 @@ func makeSliceArshaler(t reflect.Type) *arshaler { if _, err := dec.ReadToken(); err != nil { return err } - return nil + return errUnmarshal } - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t} + return newUnmarshalErrorAfterWithSkipping(dec, uo, t, nil) } return &fncs } +var errArrayUnderflow = errors.New("too few array elements") +var errArrayOverflow = errors.New("too many array elements") + func makeArrayArshaler(t reflect.Type) *arshaler { var fncs arshaler var ( @@ -1359,23 +1535,23 @@ func makeArrayArshaler(t reflect.Type) *arshaler { fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { xe := export.Encoder(enc) if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { - return newInvalidFormatError("marshal", t, mo.Format) + return newInvalidFormatError(enc, t, mo) } once.Do(init) - if err := enc.WriteToken(jsontext.ArrayStart); err != nil { + if err := enc.WriteToken(jsontext.BeginArray); err != nil { return err } marshal := valFncs.marshal if mo.Marshalers != nil { marshal, _ = mo.Marshalers.(*Marshalers).lookup(marshal, t.Elem()) } - for i := 0; i < n; i++ { - v := addressableValue{va.Index(i)} // indexed array element is addressable if array is addressable + for i := range n { + v := addressableValue{va.Index(i), va.forcedAddr} // indexed array element is addressable if array is addressable if err := marshal(enc, v, mo); err != nil { return err } } - if err := enc.WriteToken(jsontext.ArrayEnd); err != nil { + if err := enc.WriteToken(jsontext.EndArray); err != nil { return err } return nil @@ -1383,7 +1559,7 @@ func makeArrayArshaler(t reflect.Type) *arshaler { fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { xd := export.Decoder(dec) if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { - return newInvalidFormatError("unmarshal", t, uo.Format) + return newInvalidFormatError(dec, t, uo) } tok, err := dec.ReadToken() if err != nil { @@ -1392,7 +1568,9 @@ func makeArrayArshaler(t reflect.Type) *arshaler { k := tok.Kind() switch k { case 'n': - va.SetZero() + if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { + va.SetZero() + } return nil case '[': once.Do(init) @@ -1401,40 +1579,40 @@ func makeArrayArshaler(t reflect.Type) *arshaler { unmarshal, _ = uo.Unmarshalers.(*Unmarshalers).lookup(unmarshal, t.Elem()) } var i int + var errUnmarshal error for dec.PeekKind() != ']' { if i >= n { - if uo.Flags.Get(jsonflags.UnmarshalArrayFromAnyLength) { - if err := dec.SkipValue(); err != nil { - return err - } - continue + if err := dec.SkipValue(); err != nil { + return err } - err := errors.New("too many array elements") - return &SemanticError{action: "unmarshal", GoType: t, Err: err} + err = errArrayOverflow + continue + } + v := addressableValue{va.Index(i), va.forcedAddr} // indexed array element is addressable if array is addressable + if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { + v.SetZero() } - v := addressableValue{va.Index(i)} // indexed array element is addressable if array is addressable - v.SetZero() if err := unmarshal(dec, v, uo); err != nil { - return err + if isFatalError(err, uo.Flags) { + return err + } + errUnmarshal = cmp.Or(errUnmarshal, err) } i++ } + for ; i < n; i++ { + va.Index(i).SetZero() + err = errArrayUnderflow + } if _, err := dec.ReadToken(); err != nil { return err } - if i < n { - if uo.Flags.Get(jsonflags.UnmarshalArrayFromAnyLength) { - for ; i < n; i++ { - va.Index(i).SetZero() - } - return nil - } - err := errors.New("too few array elements") - return &SemanticError{action: "unmarshal", GoType: t, Err: err} + if err != nil && !uo.Flags.Get(jsonflags.UnmarshalArrayFromAnyLength) { + return newUnmarshalErrorAfter(dec, t, err) } - return nil + return errUnmarshal } - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t} + return newUnmarshalErrorAfterWithSkipping(dec, uo, t, nil) } return &fncs } @@ -1453,7 +1631,7 @@ func makePointerArshaler(t reflect.Type) *arshaler { xe := export.Encoder(enc) if xe.Tokens.Depth() > startDetectingCyclesAfter { if err := visitPointer(&xe.SeenPointers, va.Value); err != nil { - return err + return newMarshalErrorBefore(enc, t, err) } defer leavePointer(&xe.SeenPointers, va.Value) } @@ -1467,7 +1645,7 @@ func makePointerArshaler(t reflect.Type) *arshaler { if mo.Marshalers != nil { marshal, _ = mo.Marshalers.(*Marshalers).lookup(marshal, t.Elem()) } - v := addressableValue{va.Elem()} // dereferenced pointer is always addressable + v := addressableValue{va.Elem(), false} // dereferenced pointer is always addressable return marshal(enc, v, mo) } fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { @@ -1487,25 +1665,67 @@ func makePointerArshaler(t reflect.Type) *arshaler { if va.IsNil() { va.Set(reflect.New(t.Elem())) } - v := addressableValue{va.Elem()} // dereferenced pointer is always addressable - return unmarshal(dec, v, uo) + v := addressableValue{va.Elem(), false} // dereferenced pointer is always addressable + if err := unmarshal(dec, v, uo); err != nil { + return err + } + if uo.Flags.Get(jsonflags.StringifyWithLegacySemantics) && + uo.Flags.Get(jsonflags.StringifyNumbers|jsonflags.StringifyBoolsAndStrings) { + // A JSON null quoted within a JSON string should take effect + // within the pointer value, rather than the indirect value. + // + // TODO: This does not correctly handle escaped nulls + // (e.g., "\u006e\u0075\u006c\u006c"), but is good enough + // for such an esoteric use case of the `string` option. + if string(export.Decoder(dec).PreviousTokenOrValue()) == `"null"` { + va.SetZero() + } + } + return nil } return &fncs } +var errNilInterface = errors.New("cannot derive concrete type for nil interface with finite type set") + func makeInterfaceArshaler(t reflect.Type) *arshaler { // NOTE: Values retrieved from an interface are not addressable, // so we shallow copy the values to make them addressable and // store them back into the interface afterwards. var fncs arshaler + var whichMarshaler reflect.Type + for _, iface := range allMarshalerTypes { + if t.Implements(iface) { + whichMarshaler = t + break + } + } fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { xe := export.Encoder(enc) if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { - return newInvalidFormatError("marshal", t, mo.Format) + return newInvalidFormatError(enc, t, mo) } if va.IsNil() { return enc.WriteToken(jsontext.Null) + } else if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && whichMarshaler != nil { + // The marshaler for a pointer never calls the method on a nil receiver. + // Wrap the nil pointer within a struct type so that marshal + // instead appears on a value receiver and may be called. + if va.Elem().Kind() == reflect.Pointer && va.Elem().IsNil() { + v2 := newAddressableValue(whichMarshaler) + switch whichMarshaler { + case jsonMarshalerToType: + v2.Set(reflect.ValueOf(struct{ MarshalerTo }{va.Elem().Interface().(MarshalerTo)})) + case jsonMarshalerType: + v2.Set(reflect.ValueOf(struct{ Marshaler }{va.Elem().Interface().(Marshaler)})) + case textAppenderType: + v2.Set(reflect.ValueOf(struct{ encoding.TextAppender }{va.Elem().Interface().(encoding.TextAppender)})) + case textMarshalerType: + v2.Set(reflect.ValueOf(struct{ encoding.TextMarshaler }{va.Elem().Interface().(encoding.TextMarshaler)})) + } + va = v2 + } } v := newAddressableValue(va.Elem().Type()) v.Set(va.Elem()) @@ -1515,7 +1735,7 @@ func makeInterfaceArshaler(t reflect.Type) *arshaler { } // Optimize for the any type if there are no special options. if optimizeCommon && - t == anyType && !mo.Flags.Get(jsonflags.StringifyNumbers) && mo.Format == "" && + t == anyType && !mo.Flags.Get(jsonflags.StringifyNumbers|jsonflags.StringifyBoolsAndStrings) && mo.Format == "" && (mo.Marshalers == nil || !mo.Marshalers.(*Marshalers).fromAny) { return marshalValueAny(enc, va.Elem().Interface(), mo) } @@ -1524,7 +1744,26 @@ func makeInterfaceArshaler(t reflect.Type) *arshaler { fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { xd := export.Decoder(dec) if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { - return newInvalidFormatError("unmarshal", t, uo.Format) + return newInvalidFormatError(dec, t, uo) + } + if uo.Flags.Get(jsonflags.MergeWithLegacySemantics) && !va.IsNil() { + // Legacy merge behavior is difficult to explain. + // In general, it only merges for non-nil pointer kinds. + // As a special case, unmarshaling a JSON null into a pointer + // sets a concrete nil pointer of the underlying type + // (rather than setting the interface value itself to nil). + e := va.Elem() + if e.Kind() == reflect.Pointer && !e.IsNil() { + if dec.PeekKind() == 'n' && e.Elem().Kind() == reflect.Pointer { + if _, err := dec.ReadToken(); err != nil { + return err + } + va.Elem().Elem().SetZero() + return nil + } + } else { + va.SetZero() + } } if dec.PeekKind() == 'n' { if _, err := dec.ReadToken(); err != nil { @@ -1541,7 +1780,7 @@ func makeInterfaceArshaler(t reflect.Type) *arshaler { // Duplicate name check must be enforced since unmarshalValueAny // does not implement merge semantics. if optimizeCommon && - t == anyType && !xd.Flags.Get(jsonflags.AllowDuplicateNames) && uo.Format == "" && + t == anyType && !uo.Flags.Get(jsonflags.AllowDuplicateNames) && uo.Format == "" && (uo.Unmarshalers == nil || !uo.Unmarshalers.(*Unmarshalers).fromAny) { v, err := unmarshalValueAny(dec, uo) // We must check for nil interface values up front. @@ -1554,8 +1793,7 @@ func makeInterfaceArshaler(t reflect.Type) *arshaler { k := dec.PeekKind() if !isAnyType(t) { - err := errors.New("cannot derive concrete type for non-empty interface") - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t, Err: err} + return newUnmarshalErrorBeforeWithSkipping(dec, uo, t, errNilInterface) } switch k { case 'f', 't': @@ -1563,7 +1801,11 @@ func makeInterfaceArshaler(t reflect.Type) *arshaler { case '"': v = newAddressableValue(stringType) case '0': - v = newAddressableValue(float64Type) + if uo.Flags.Get(jsonflags.UnmarshalAnyWithRawNumber) { + v = addressableValue{reflect.ValueOf(internal.NewRawNumber()).Elem(), true} + } else { + v = newAddressableValue(float64Type) + } case '{': v = newAddressableValue(mapStringAnyType) case '[': @@ -1606,19 +1848,14 @@ func isAnyType(t reflect.Type) bool { func makeInvalidArshaler(t reflect.Type) *arshaler { var fncs arshaler fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { - return &SemanticError{action: "marshal", GoType: t} + return newMarshalErrorBefore(enc, t, nil) } fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { - return &SemanticError{action: "unmarshal", GoType: t} + return newUnmarshalErrorBefore(dec, t, nil) } return &fncs } -func newInvalidFormatError(action string, t reflect.Type, format string) error { - err := fmt.Errorf("invalid format flag: %q", format) - return &SemanticError{action: action, GoType: t, Err: err} -} - func stringOrNumberKind(isString bool) jsontext.Kind { if isString { return '"' diff --git a/vendor/github.com/go-json-experiment/json/arshal_funcs.go b/vendor/github.com/go-json-experiment/json/arshal_funcs.go index e608d75..0b7e82f 100644 --- a/vendor/github.com/go-json-experiment/json/arshal_funcs.go +++ b/vendor/github.com/go-json-experiment/json/arshal_funcs.go @@ -10,12 +10,13 @@ import ( "reflect" "sync" + "github.com/go-json-experiment/json/internal" "github.com/go-json-experiment/json/internal/jsonflags" "github.com/go-json-experiment/json/internal/jsonopts" "github.com/go-json-experiment/json/jsontext" ) -// SkipFunc may be returned by [MarshalFuncV2] and [UnmarshalFuncV2] functions. +// SkipFunc may be returned by [MarshalToFunc] and [UnmarshalFromFunc] functions. // // Any function that returns SkipFunc must not cause observable side effects // on the provided [jsontext.Encoder] or [jsontext.Decoder]. @@ -24,6 +25,9 @@ import ( // [jsontext.Encoder.WriteToken] since such methods mutate the state. var SkipFunc = errors.New("json: skip function") +var errSkipMutation = errors.New("must not read or write any tokens when skipping") +var errNonSingularValue = errors.New("must read or write exactly one value") + // Marshalers is a list of functions that may override the marshal behavior // of specific types. Populate [WithMarshalers] to use it with // [Marshal], [MarshalWrite], or [MarshalEncode]. @@ -31,7 +35,7 @@ var SkipFunc = errors.New("json: skip function") // There are no exported fields or methods on Marshalers. type Marshalers = typedMarshalers -// NewMarshalers constructs a flattened list of marshal functions. +// JoinMarshalers constructs a flattened list of marshal functions. // If multiple functions in the list are applicable for a value of a given type, // then those earlier in the list take precedence over those that come later. // If a function returns [SkipFunc], then the next applicable function is called, @@ -39,10 +43,10 @@ type Marshalers = typedMarshalers // // For example: // -// m1 := NewMarshalers(f1, f2) -// m2 := NewMarshalers(f0, m1, f3) // equivalent to m3 -// m3 := NewMarshalers(f0, f1, f2, f3) // equivalent to m2 -func NewMarshalers(ms ...*Marshalers) *Marshalers { +// m1 := JoinMarshalers(f1, f2) +// m2 := JoinMarshalers(f0, m1, f3) // equivalent to m3 +// m3 := JoinMarshalers(f0, f1, f2, f3) // equivalent to m2 +func JoinMarshalers(ms ...*Marshalers) *Marshalers { return newMarshalers(ms...) } @@ -53,7 +57,7 @@ func NewMarshalers(ms ...*Marshalers) *Marshalers { // There are no exported fields or methods on Unmarshalers. type Unmarshalers = typedUnmarshalers -// NewUnmarshalers constructs a flattened list of unmarshal functions. +// JoinUnmarshalers constructs a flattened list of unmarshal functions. // If multiple functions in the list are applicable for a value of a given type, // then those earlier in the list take precedence over those that come later. // If a function returns [SkipFunc], then the next applicable function is called, @@ -61,10 +65,10 @@ type Unmarshalers = typedUnmarshalers // // For example: // -// u1 := NewUnmarshalers(f1, f2) -// u2 := NewUnmarshalers(f0, u1, f3) // equivalent to u3 -// u3 := NewUnmarshalers(f0, f1, f2, f3) // equivalent to u2 -func NewUnmarshalers(us ...*Unmarshalers) *Unmarshalers { +// u1 := JoinUnmarshalers(f1, f2) +// u2 := JoinUnmarshalers(f0, u1, f3) // equivalent to u3 +// u3 := JoinUnmarshalers(f0, f1, f2, f3) // equivalent to u2 +func JoinUnmarshalers(us ...*Unmarshalers) *Unmarshalers { return newUnmarshalers(us...) } @@ -156,7 +160,7 @@ func (a *typedArshalers[Coder]) lookup(fnc func(*Coder, addressableValue, *jsono return v.(func(*Coder, addressableValue, *jsonopts.Struct) error), true } -// MarshalFuncV1 constructs a type-specific marshaler that +// MarshalFunc constructs a type-specific marshaler that // specifies how to marshal values of type T. // T can be any type except a named pointer. // The function is always provided with a non-nil pointer value @@ -165,8 +169,8 @@ func (a *typedArshalers[Coder]) lookup(fnc func(*Coder, addressableValue, *jsono // The function must marshal exactly one JSON value. // The value of T must not be retained outside the function call. // It may not return [SkipFunc]. -func MarshalFuncV1[T any](fn func(T) ([]byte, error)) *Marshalers { - t := reflect.TypeOf((*T)(nil)).Elem() +func MarshalFunc[T any](fn func(T) ([]byte, error)) *Marshalers { + t := reflect.TypeFor[T]() assertCastableTo(t, true) typFnc := typedMarshaler{ typ: t, @@ -174,12 +178,20 @@ func MarshalFuncV1[T any](fn func(T) ([]byte, error)) *Marshalers { val, err := fn(va.castTo(t).Interface().(T)) if err != nil { err = wrapSkipFunc(err, "marshal function of type func(T) ([]byte, error)") - // TODO: Avoid wrapping semantic errors. - return &SemanticError{action: "marshal", GoType: t, Err: err} + if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalFunc") // unlike unmarshal, always wrapped + } + err = newMarshalErrorBefore(enc, t, err) + return collapseSemanticErrors(err) } if err := enc.WriteValue(val); err != nil { - // TODO: Avoid wrapping semantic or I/O errors. - return &SemanticError{action: "marshal", JSONKind: jsontext.Value(val).Kind(), GoType: t, Err: err} + if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalFunc") // unlike unmarshal, always wrapped + } + if isSyntacticError(err) { + err = newMarshalErrorBefore(enc, t, err) + } + return err } return nil }, @@ -187,7 +199,7 @@ func MarshalFuncV1[T any](fn func(T) ([]byte, error)) *Marshalers { return &Marshalers{fncVals: []typedMarshaler{typFnc}, fromAny: castableToFromAny(t)} } -// MarshalFuncV2 constructs a type-specific marshaler that +// MarshalToFunc constructs a type-specific marshaler that // specifies how to marshal values of type T. // T can be any type except a named pointer. // The function is always provided with a non-nil pointer value @@ -197,10 +209,10 @@ func MarshalFuncV1[T any](fn func(T) ([]byte, error)) *Marshalers { // on the provided encoder. It may return [SkipFunc] such that marshaling can // move on to the next marshal function. However, no mutable method calls may // be called on the encoder if [SkipFunc] is returned. -// The pointer to [jsontext.Encoder], the value of T, and the [Options] value +// The pointer to [jsontext.Encoder] and the value of T // must not be retained outside the function call. -func MarshalFuncV2[T any](fn func(*jsontext.Encoder, T, Options) error) *Marshalers { - t := reflect.TypeOf((*T)(nil)).Elem() +func MarshalToFunc[T any](fn func(*jsontext.Encoder, T) error) *Marshalers { + t := reflect.TypeFor[T]() assertCastableTo(t, true) typFnc := typedMarshaler{ typ: t, @@ -208,21 +220,26 @@ func MarshalFuncV2[T any](fn func(*jsontext.Encoder, T, Options) error) *Marshal xe := export.Encoder(enc) prevDepth, prevLength := xe.Tokens.DepthLength() xe.Flags.Set(jsonflags.WithinArshalCall | 1) - err := fn(enc, va.castTo(t).Interface().(T), mo) + err := fn(enc, va.castTo(t).Interface().(T)) xe.Flags.Set(jsonflags.WithinArshalCall | 0) currDepth, currLength := xe.Tokens.DepthLength() if err == nil && (prevDepth != currDepth || prevLength+1 != currLength) { - err = errors.New("must write exactly one JSON value") + err = errNonSingularValue } if err != nil { if err == SkipFunc { if prevDepth == currDepth && prevLength == currLength { return SkipFunc } - err = errors.New("must not write any JSON tokens when skipping") + err = errSkipMutation } - // TODO: Avoid wrapping semantic or I/O errors. - return &SemanticError{action: "marshal", GoType: t, Err: err} + if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalToFunc") // unlike unmarshal, always wrapped + } + if !export.IsIOError(err) { + err = newSemanticErrorWithPosition(enc, t, prevDepth, prevLength, err) + } + return err } return nil }, @@ -231,7 +248,7 @@ func MarshalFuncV2[T any](fn func(*jsontext.Encoder, T, Options) error) *Marshal return &Marshalers{fncVals: []typedMarshaler{typFnc}, fromAny: castableToFromAny(t)} } -// UnmarshalFuncV1 constructs a type-specific unmarshaler that +// UnmarshalFunc constructs a type-specific unmarshaler that // specifies how to unmarshal values of type T. // T must be an unnamed pointer or an interface type. // The function is always provided with a non-nil pointer value. @@ -240,8 +257,8 @@ func MarshalFuncV2[T any](fn func(*jsontext.Encoder, T, Options) error) *Marshal // The input []byte must not be mutated. // The input []byte and value T must not be retained outside the function call. // It may not return [SkipFunc]. -func UnmarshalFuncV1[T any](fn func([]byte, T) error) *Unmarshalers { - t := reflect.TypeOf((*T)(nil)).Elem() +func UnmarshalFunc[T any](fn func([]byte, T) error) *Unmarshalers { + t := reflect.TypeFor[T]() assertCastableTo(t, false) typFnc := typedUnmarshaler{ typ: t, @@ -253,8 +270,11 @@ func UnmarshalFuncV1[T any](fn func([]byte, T) error) *Unmarshalers { err = fn(val, va.castTo(t).Interface().(T)) if err != nil { err = wrapSkipFunc(err, "unmarshal function of type func([]byte, T) error") - // TODO: Avoid wrapping semantic, syntactic, or I/O errors. - return &SemanticError{action: "unmarshal", JSONKind: val.Kind(), GoType: t, Err: err} + if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return err // unlike marshal, never wrapped + } + err = newUnmarshalErrorAfter(dec, t, err) + return collapseSemanticErrors(err) } return nil }, @@ -262,7 +282,7 @@ func UnmarshalFuncV1[T any](fn func([]byte, T) error) *Unmarshalers { return &Unmarshalers{fncVals: []typedUnmarshaler{typFnc}, fromAny: castableToFromAny(t)} } -// UnmarshalFuncV2 constructs a type-specific unmarshaler that +// UnmarshalFromFunc constructs a type-specific unmarshaler that // specifies how to unmarshal values of type T. // T must be an unnamed pointer or an interface type. // The function is always provided with a non-nil pointer value. @@ -271,10 +291,10 @@ func UnmarshalFuncV1[T any](fn func([]byte, T) error) *Unmarshalers { // on the provided decoder. It may return [SkipFunc] such that unmarshaling can // move on to the next unmarshal function. However, no mutable method calls may // be called on the decoder if [SkipFunc] is returned. -// The pointer to [jsontext.Decoder], the value of T, and [Options] value +// The pointer to [jsontext.Decoder] and the value of T // must not be retained outside the function call. -func UnmarshalFuncV2[T any](fn func(*jsontext.Decoder, T, Options) error) *Unmarshalers { - t := reflect.TypeOf((*T)(nil)).Elem() +func UnmarshalFromFunc[T any](fn func(*jsontext.Decoder, T) error) *Unmarshalers { + t := reflect.TypeFor[T]() assertCastableTo(t, false) typFnc := typedUnmarshaler{ typ: t, @@ -282,21 +302,29 @@ func UnmarshalFuncV2[T any](fn func(*jsontext.Decoder, T, Options) error) *Unmar xd := export.Decoder(dec) prevDepth, prevLength := xd.Tokens.DepthLength() xd.Flags.Set(jsonflags.WithinArshalCall | 1) - err := fn(dec, va.castTo(t).Interface().(T), uo) + err := fn(dec, va.castTo(t).Interface().(T)) xd.Flags.Set(jsonflags.WithinArshalCall | 0) currDepth, currLength := xd.Tokens.DepthLength() if err == nil && (prevDepth != currDepth || prevLength+1 != currLength) { - err = errors.New("must read exactly one JSON value") + err = errNonSingularValue } if err != nil { if err == SkipFunc { if prevDepth == currDepth && prevLength == currLength { return SkipFunc } - err = errors.New("must not read any JSON tokens when skipping") + err = errSkipMutation } - // TODO: Avoid wrapping semantic, syntactic, or I/O errors. - return &SemanticError{action: "unmarshal", GoType: t, Err: err} + if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + if err2 := xd.SkipUntil(prevDepth, prevLength+1); err2 != nil { + return err2 + } + return err // unlike marshal, never wrapped + } + if !isSyntacticError(err) && !export.IsIOError(err) { + err = newSemanticErrorWithPosition(dec, t, prevDepth, prevLength, err) + } + return err } return nil }, diff --git a/vendor/github.com/go-json-experiment/json/arshal_inlined.go b/vendor/github.com/go-json-experiment/json/arshal_inlined.go index 51e05f9..362087f 100644 --- a/vendor/github.com/go-json-experiment/json/arshal_inlined.go +++ b/vendor/github.com/go-json-experiment/json/arshal_inlined.go @@ -29,13 +29,15 @@ import ( // represent any arbitrary JSON object member. Explicitly named fields take // precedence over the inlined fallback. Only one inlined fallback is allowed. -var jsontextValueType = reflect.TypeOf((*jsontext.Value)(nil)).Elem() +var errRawInlinedNotObject = errors.New("inlined raw value must be a JSON object") + +var jsontextValueType = reflect.TypeFor[jsontext.Value]() // marshalInlinedFallbackAll marshals all the members in an inlined fallback. func marshalInlinedFallbackAll(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct, f *structField, insertUnquotedName func([]byte) bool) error { - v := addressableValue{va.Field(f.index[0])} // addressable if struct value is addressable - if len(f.index) > 1 { - v = v.fieldByIndex(f.index[1:], false) + v := addressableValue{va.Field(f.index0), va.forcedAddr} // addressable if struct value is addressable + if len(f.index) > 0 { + v = v.fieldByIndex(f.index, false) if !v.IsValid() { return nil // implies a nil inlined field } @@ -62,23 +64,22 @@ func marshalInlinedFallbackAll(enc *jsontext.Encoder, va addressableValue, mo *j if err == io.EOF { err = io.ErrUnexpectedEOF } - return &SemanticError{action: "marshal", GoType: jsontextValueType, Err: err} + return newMarshalErrorBefore(enc, v.Type(), err) } if tok.Kind() != '{' { - err := errors.New("inlined raw value must be a JSON object") - return &SemanticError{action: "marshal", JSONKind: tok.Kind(), GoType: jsontextValueType, Err: err} + return newMarshalErrorBefore(enc, v.Type(), errRawInlinedNotObject) } for dec.PeekKind() != '}' { // Parse the JSON object name. var flags jsonwire.ValueFlags val, err := xd.ReadValue(&flags) if err != nil { - return &SemanticError{action: "marshal", GoType: jsontextValueType, Err: err} + return newMarshalErrorBefore(enc, v.Type(), err) } if insertUnquotedName != nil { name := jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) if !insertUnquotedName(name) { - return export.NewDuplicateNameError(val, 0) + return newDuplicateNameError(enc.StackPointer().Parent(), val, enc.OutputOffset()) } } if err := enc.WriteValue(val); err != nil { @@ -88,38 +89,37 @@ func marshalInlinedFallbackAll(enc *jsontext.Encoder, va addressableValue, mo *j // Parse the JSON object value. val, err = xd.ReadValue(&flags) if err != nil { - return &SemanticError{action: "marshal", GoType: jsontextValueType, Err: err} + return newMarshalErrorBefore(enc, v.Type(), err) } if err := enc.WriteValue(val); err != nil { return err } } if _, err := dec.ReadToken(); err != nil { - return &SemanticError{action: "marshal", GoType: jsontextValueType, Err: err} + return newMarshalErrorBefore(enc, v.Type(), err) } if err := xd.CheckEOF(); err != nil { - return &SemanticError{action: "marshal", GoType: jsontextValueType, Err: err} + return newMarshalErrorBefore(enc, v.Type(), err) } return nil } else { - m := v // must be a map[string]V + m := v // must be a map[~string]V n := m.Len() if n == 0 { return nil } - mk := newAddressableValue(stringType) + mk := newAddressableValue(m.Type().Key()) mv := newAddressableValue(m.Type().Elem()) marshalKey := func(mk addressableValue) error { - xe := export.Encoder(enc) - b, err := jsonwire.AppendQuote(enc.UnusedBuffer(), mk.String(), &xe.Flags) + b, err := jsonwire.AppendQuote(enc.UnusedBuffer(), mk.String(), &mo.Flags) if err != nil { - return err + return newMarshalErrorBefore(enc, m.Type().Key(), err) } if insertUnquotedName != nil { isVerbatim := bytes.IndexByte(b, '\\') < 0 name := jsonwire.UnquoteMayCopy(b, isVerbatim) if !insertUnquotedName(name) { - return export.NewDuplicateNameError(b, 0) + return newDuplicateNameError(enc.StackPointer().Parent(), b, enc.OutputOffset()) } } return enc.WriteValue(b) @@ -165,9 +165,9 @@ func marshalInlinedFallbackAll(enc *jsontext.Encoder, va addressableValue, mo *j // unmarshalInlinedFallbackNext unmarshals only the next member in an inlined fallback. func unmarshalInlinedFallbackNext(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct, f *structField, quotedName, unquotedName []byte) error { - v := addressableValue{va.Field(f.index[0])} // addressable if struct value is addressable - if len(f.index) > 1 { - v = v.fieldByIndex(f.index[1:], true) + v := addressableValue{va.Field(f.index0), va.forcedAddr} // addressable if struct value is addressable + if len(f.index) > 0 { + v = v.fieldByIndex(f.index, true) } v = v.indirect(true) @@ -186,8 +186,7 @@ func unmarshalInlinedFallbackNext(dec *jsontext.Decoder, va addressableValue, uo *b = append(*b, ',') } } else { - err := errors.New("inlined raw value must be a JSON object") - return &SemanticError{action: "unmarshal", GoType: jsontextValueType, Err: err} + return newUnmarshalErrorAfterWithSkipping(dec, uo, v.Type(), errRawInlinedNotObject) } } *b = append(*b, quotedName...) @@ -202,12 +201,15 @@ func unmarshalInlinedFallbackNext(dec *jsontext.Decoder, va addressableValue, uo } else { name := string(unquotedName) // TODO: Intern this? - m := v // must be a map[string]V + m := v // must be a map[~string]V if m.IsNil() { m.Set(reflect.MakeMap(m.Type())) } mk := reflect.ValueOf(name) - mv := newAddressableValue(v.Type().Elem()) // TODO: Cache across calls? + if mkt := m.Type().Key(); mkt != stringType { + mk = mk.Convert(mkt) + } + mv := newAddressableValue(m.Type().Elem()) // TODO: Cache across calls? if v2 := m.MapIndex(mk); v2.IsValid() { mv.Set(v2) } diff --git a/vendor/github.com/go-json-experiment/json/arshal_methods.go b/vendor/github.com/go-json-experiment/json/arshal_methods.go index f7277c9..10efe14 100644 --- a/vendor/github.com/go-json-experiment/json/arshal_methods.go +++ b/vendor/github.com/go-json-experiment/json/arshal_methods.go @@ -9,62 +9,58 @@ import ( "errors" "reflect" + "github.com/go-json-experiment/json/internal" "github.com/go-json-experiment/json/internal/jsonflags" "github.com/go-json-experiment/json/internal/jsonopts" "github.com/go-json-experiment/json/internal/jsonwire" "github.com/go-json-experiment/json/jsontext" ) +var errNonStringValue = errors.New("JSON value must be string type") + // Interfaces for custom serialization. var ( - jsonMarshalerV1Type = reflect.TypeOf((*MarshalerV1)(nil)).Elem() - jsonMarshalerV2Type = reflect.TypeOf((*MarshalerV2)(nil)).Elem() - jsonUnmarshalerV1Type = reflect.TypeOf((*UnmarshalerV1)(nil)).Elem() - jsonUnmarshalerV2Type = reflect.TypeOf((*UnmarshalerV2)(nil)).Elem() - textAppenderType = reflect.TypeOf((*encodingTextAppender)(nil)).Elem() - textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() - textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() + jsonMarshalerType = reflect.TypeFor[Marshaler]() + jsonMarshalerToType = reflect.TypeFor[MarshalerTo]() + jsonUnmarshalerType = reflect.TypeFor[Unmarshaler]() + jsonUnmarshalerFromType = reflect.TypeFor[UnmarshalerFrom]() + textAppenderType = reflect.TypeFor[encoding.TextAppender]() + textMarshalerType = reflect.TypeFor[encoding.TextMarshaler]() + textUnmarshalerType = reflect.TypeFor[encoding.TextUnmarshaler]() - // TODO(https://go.dev/issue/62384): Use encoding.TextAppender instead of this hack. - // This exists for now to provide performance benefits to netip types. - // There is no semantic difference with this change. - appenderToType = reflect.TypeOf((*interface{ AppendTo([]byte) []byte })(nil)).Elem() + allMarshalerTypes = []reflect.Type{jsonMarshalerToType, jsonMarshalerType, textAppenderType, textMarshalerType} + allUnmarshalerTypes = []reflect.Type{jsonUnmarshalerFromType, jsonUnmarshalerType, textUnmarshalerType} + allMethodTypes = append(allMarshalerTypes, allUnmarshalerTypes...) ) -// TODO(https://go.dev/issue/62384): Use encoding.TextAppender instead -// and document public support for this method in json.Marshal. -type encodingTextAppender interface { - AppendText(b []byte) ([]byte, error) -} - -// MarshalerV1 is implemented by types that can marshal themselves. -// It is recommended that types implement [MarshalerV2] unless the implementation +// Marshaler is implemented by types that can marshal themselves. +// It is recommended that types implement [MarshalerTo] unless the implementation // is trying to avoid a hard dependency on the "jsontext" package. // // It is recommended that implementations return a buffer that is safe // for the caller to retain and potentially mutate. -type MarshalerV1 interface { +type Marshaler interface { MarshalJSON() ([]byte, error) } -// MarshalerV2 is implemented by types that can marshal themselves. -// It is recommended that types implement MarshalerV2 instead of [MarshalerV1] +// MarshalerTo is implemented by types that can marshal themselves. +// It is recommended that types implement MarshalerTo instead of [Marshaler] // since this is both more performant and flexible. -// If a type implements both MarshalerV1 and MarshalerV2, -// then MarshalerV2 takes precedence. In such a case, both implementations +// If a type implements both Marshaler and MarshalerTo, +// then MarshalerTo takes precedence. In such a case, both implementations // should aim to have equivalent behavior for the default marshal options. // // The implementation must write only one JSON value to the Encoder and -// must not retain the pointer to [jsontext.Encoder] or the [Options] value. -type MarshalerV2 interface { - MarshalJSONV2(*jsontext.Encoder, Options) error +// must not retain the pointer to [jsontext.Encoder]. +type MarshalerTo interface { + MarshalJSONTo(*jsontext.Encoder) error // TODO: Should users call the MarshalEncode function or // should/can they call this method directly? Does it matter? } -// UnmarshalerV1 is implemented by types that can unmarshal themselves. -// It is recommended that types implement [UnmarshalerV2] unless the implementation +// Unmarshaler is implemented by types that can unmarshal themselves. +// It is recommended that types implement [UnmarshalerFrom] unless the implementation // is trying to avoid a hard dependency on the "jsontext" package. // // The input can be assumed to be a valid encoding of a JSON value @@ -74,25 +70,24 @@ type MarshalerV2 interface { // unmarshaling into a pre-populated value. // // Implementations must not retain or mutate the input []byte. -type UnmarshalerV1 interface { +type Unmarshaler interface { UnmarshalJSON([]byte) error } -// UnmarshalerV2 is implemented by types that can unmarshal themselves. -// It is recommended that types implement UnmarshalerV2 instead of [UnmarshalerV1] +// UnmarshalerFrom is implemented by types that can unmarshal themselves. +// It is recommended that types implement UnmarshalerFrom instead of [Unmarshaler] // since this is both more performant and flexible. -// If a type implements both UnmarshalerV1 and UnmarshalerV2, -// then UnmarshalerV2 takes precedence. In such a case, both implementations +// If a type implements both Unmarshaler and UnmarshalerFrom, +// then UnmarshalerFrom takes precedence. In such a case, both implementations // should aim to have equivalent behavior for the default unmarshal options. // // The implementation must read only one JSON value from the Decoder. -// It is recommended that UnmarshalJSONV2 implement merge semantics when +// It is recommended that UnmarshalJSONFrom implement merge semantics when // unmarshaling into a pre-populated value. // -// Implementations must not retain the pointer to [jsontext.Decoder] or -// the [Options] value. -type UnmarshalerV2 interface { - UnmarshalJSONV2(*jsontext.Decoder, Options) error +// Implementations must not retain the pointer to [jsontext.Decoder]. +type UnmarshalerFrom interface { + UnmarshalJSONFrom(*jsontext.Decoder) error // TODO: Should users call the UnmarshalDecode function or // should/can they call this method directly? Does it matter? @@ -106,121 +101,118 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler { return fncs } - // Handle custom marshaler. - switch which := implementsWhich(t, jsonMarshalerV2Type, jsonMarshalerV1Type, textAppenderType, textMarshalerType); which { - case jsonMarshalerV2Type: + if needAddr, ok := implements(t, textMarshalerType); ok { fncs.nonDefault = true + prevMarshal := fncs.marshal fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { - xe := export.Encoder(enc) - prevDepth, prevLength := xe.Tokens.DepthLength() - xe.Flags.Set(jsonflags.WithinArshalCall | 1) - err := va.Addr().Interface().(MarshalerV2).MarshalJSONV2(enc, mo) - xe.Flags.Set(jsonflags.WithinArshalCall | 0) - currDepth, currLength := xe.Tokens.DepthLength() - if (prevDepth != currDepth || prevLength+1 != currLength) && err == nil { - err = errors.New("must write exactly one JSON value") + if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && + (needAddr && va.forcedAddr) { + return prevMarshal(enc, va, mo) } - if err != nil { - err = wrapSkipFunc(err, "marshal method") - // TODO: Avoid wrapping semantic or I/O errors. - return &SemanticError{action: "marshal", GoType: t, Err: err} - } - return nil - } - case jsonMarshalerV1Type: - fncs.nonDefault = true - fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { - marshaler := va.Addr().Interface().(MarshalerV1) - val, err := marshaler.MarshalJSON() - if err != nil { - err = wrapSkipFunc(err, "marshal method") - // TODO: Avoid wrapping semantic errors. - return &SemanticError{action: "marshal", GoType: t, Err: err} - } - if err := enc.WriteValue(val); err != nil { - // TODO: Avoid wrapping semantic or I/O errors. - return &SemanticError{action: "marshal", JSONKind: jsontext.Value(val).Kind(), GoType: t, Err: err} - } - return nil - } - case textAppenderType: - fncs.nonDefault = true - fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) (err error) { - appender := va.Addr().Interface().(encodingTextAppender) - if err := export.Encoder(enc).AppendRaw('"', false, appender.AppendText); err != nil { - // TODO: Avoid wrapping semantic, syntactic, or I/O errors. - err = wrapSkipFunc(err, "append method") - return &SemanticError{action: "marshal", JSONKind: '"', GoType: t, Err: err} - } - return nil - } - case textMarshalerType: - fncs.nonDefault = true - fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { marshaler := va.Addr().Interface().(encoding.TextMarshaler) if err := export.Encoder(enc).AppendRaw('"', false, func(b []byte) ([]byte, error) { b2, err := marshaler.MarshalText() return append(b, b2...), err }); err != nil { - // TODO: Avoid wrapping semantic, syntactic, or I/O errors. err = wrapSkipFunc(err, "marshal method") - return &SemanticError{action: "marshal", JSONKind: '"', GoType: t, Err: err} + if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalText") // unlike unmarshal, always wrapped + } + if !isSemanticError(err) && !export.IsIOError(err) { + err = newMarshalErrorBefore(enc, t, err) + } + return err } return nil } - // TODO(https://go.dev/issue/62384): Rely on encoding.TextAppender instead. - if implementsWhich(t, appenderToType) != nil && t.PkgPath() == "net/netip" { - fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { - appender := va.Addr().Interface().(interface{ AppendTo([]byte) []byte }) - if err := export.Encoder(enc).AppendRaw('"', false, func(b []byte) ([]byte, error) { - return appender.AppendTo(b), nil - }); err != nil { - // TODO: Avoid wrapping semantic, syntactic, or I/O errors. - err = wrapSkipFunc(err, "append method") - return &SemanticError{action: "marshal", JSONKind: '"', GoType: t, Err: err} - } - return nil - } - } } - // Handle custom unmarshaler. - switch which := implementsWhich(t, jsonUnmarshalerV2Type, jsonUnmarshalerV1Type, textUnmarshalerType); which { - case jsonUnmarshalerV2Type: + if needAddr, ok := implements(t, textAppenderType); ok { fncs.nonDefault = true - fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { - xd := export.Decoder(dec) - prevDepth, prevLength := xd.Tokens.DepthLength() - xd.Flags.Set(jsonflags.WithinArshalCall | 1) - err := va.Addr().Interface().(UnmarshalerV2).UnmarshalJSONV2(dec, uo) - xd.Flags.Set(jsonflags.WithinArshalCall | 0) - currDepth, currLength := xd.Tokens.DepthLength() + prevMarshal := fncs.marshal + fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) (err error) { + if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && + (needAddr && va.forcedAddr) { + return prevMarshal(enc, va, mo) + } + appender := va.Addr().Interface().(encoding.TextAppender) + if err := export.Encoder(enc).AppendRaw('"', false, appender.AppendText); err != nil { + err = wrapSkipFunc(err, "append method") + if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return internal.NewMarshalerError(va.Addr().Interface(), err, "AppendText") // unlike unmarshal, always wrapped + } + if !isSemanticError(err) && !export.IsIOError(err) { + err = newMarshalErrorBefore(enc, t, err) + } + return err + } + return nil + } + } + + if needAddr, ok := implements(t, jsonMarshalerType); ok { + fncs.nonDefault = true + prevMarshal := fncs.marshal + fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { + if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && + ((needAddr && va.forcedAddr) || export.Encoder(enc).Tokens.Last.NeedObjectName()) { + return prevMarshal(enc, va, mo) + } + marshaler := va.Addr().Interface().(Marshaler) + val, err := marshaler.MarshalJSON() + if err != nil { + err = wrapSkipFunc(err, "marshal method") + if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalJSON") // unlike unmarshal, always wrapped + } + err = newMarshalErrorBefore(enc, t, err) + return collapseSemanticErrors(err) + } + if err := enc.WriteValue(val); err != nil { + if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalJSON") // unlike unmarshal, always wrapped + } + if isSyntacticError(err) { + err = newMarshalErrorBefore(enc, t, err) + } + return err + } + return nil + } + } + + if needAddr, ok := implements(t, jsonMarshalerToType); ok { + fncs.nonDefault = true + prevMarshal := fncs.marshal + fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { + if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && + ((needAddr && va.forcedAddr) || export.Encoder(enc).Tokens.Last.NeedObjectName()) { + return prevMarshal(enc, va, mo) + } + xe := export.Encoder(enc) + prevDepth, prevLength := xe.Tokens.DepthLength() + xe.Flags.Set(jsonflags.WithinArshalCall | 1) + err := va.Addr().Interface().(MarshalerTo).MarshalJSONTo(enc) + xe.Flags.Set(jsonflags.WithinArshalCall | 0) + currDepth, currLength := xe.Tokens.DepthLength() if (prevDepth != currDepth || prevLength+1 != currLength) && err == nil { - err = errors.New("must read exactly one JSON value") + err = errNonSingularValue } if err != nil { - err = wrapSkipFunc(err, "unmarshal method") - // TODO: Avoid wrapping semantic, syntactic, or I/O errors. - return &SemanticError{action: "unmarshal", GoType: t, Err: err} + err = wrapSkipFunc(err, "marshal method") + if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalJSONTo") // unlike unmarshal, always wrapped + } + if !export.IsIOError(err) { + err = newSemanticErrorWithPosition(enc, t, prevDepth, prevLength, err) + } + return err } return nil } - case jsonUnmarshalerV1Type: - fncs.nonDefault = true - fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { - val, err := dec.ReadValue() - if err != nil { - return err // must be a syntactic or I/O error - } - unmarshaler := va.Addr().Interface().(UnmarshalerV1) - if err := unmarshaler.UnmarshalJSON(val); err != nil { - err = wrapSkipFunc(err, "unmarshal method") - // TODO: Avoid wrapping semantic, syntactic, or I/O errors. - return &SemanticError{action: "unmarshal", JSONKind: val.Kind(), GoType: t, Err: err} - } - return nil - } - case textUnmarshalerType: + } + + if _, ok := implements(t, textUnmarshalerType); ok { fncs.nonDefault = true fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { xd := export.Decoder(dec) @@ -229,16 +221,85 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler { if err != nil { return err // must be a syntactic or I/O error } + if val.Kind() == 'n' { + if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { + va.SetZero() + } + return nil + } if val.Kind() != '"' { - err = errors.New("JSON value must be string type") - return &SemanticError{action: "unmarshal", JSONKind: val.Kind(), GoType: t, Err: err} + return newUnmarshalErrorAfter(dec, t, errNonStringValue) } s := jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) unmarshaler := va.Addr().Interface().(encoding.TextUnmarshaler) if err := unmarshaler.UnmarshalText(s); err != nil { err = wrapSkipFunc(err, "unmarshal method") - // TODO: Avoid wrapping semantic, syntactic, or I/O errors. - return &SemanticError{action: "unmarshal", JSONKind: val.Kind(), GoType: t, Err: err} + if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return err // unlike marshal, never wrapped + } + if !isSemanticError(err) && !isSyntacticError(err) && !export.IsIOError(err) { + err = newUnmarshalErrorAfter(dec, t, err) + } + return err + } + return nil + } + } + + if _, ok := implements(t, jsonUnmarshalerType); ok { + fncs.nonDefault = true + prevUnmarshal := fncs.unmarshal + fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { + if uo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && + export.Decoder(dec).Tokens.Last.NeedObjectName() { + return prevUnmarshal(dec, va, uo) + } + val, err := dec.ReadValue() + if err != nil { + return err // must be a syntactic or I/O error + } + unmarshaler := va.Addr().Interface().(Unmarshaler) + if err := unmarshaler.UnmarshalJSON(val); err != nil { + err = wrapSkipFunc(err, "unmarshal method") + if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return err // unlike marshal, never wrapped + } + err = newUnmarshalErrorAfter(dec, t, err) + return collapseSemanticErrors(err) + } + return nil + } + } + + if _, ok := implements(t, jsonUnmarshalerFromType); ok { + fncs.nonDefault = true + prevUnmarshal := fncs.unmarshal + fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { + if uo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && + export.Decoder(dec).Tokens.Last.NeedObjectName() { + return prevUnmarshal(dec, va, uo) + } + xd := export.Decoder(dec) + prevDepth, prevLength := xd.Tokens.DepthLength() + xd.Flags.Set(jsonflags.WithinArshalCall | 1) + err := va.Addr().Interface().(UnmarshalerFrom).UnmarshalJSONFrom(dec) + xd.Flags.Set(jsonflags.WithinArshalCall | 0) + currDepth, currLength := xd.Tokens.DepthLength() + if (prevDepth != currDepth || prevLength+1 != currLength) && err == nil { + err = errNonSingularValue + } + if err != nil { + err = wrapSkipFunc(err, "unmarshal method") + if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + if err2 := xd.SkipUntil(prevDepth, prevLength+1); err2 != nil { + return err2 + } + return err // unlike marshal, never wrapped + } + if !isSyntacticError(err) && !export.IsIOError(err) { + err = newSemanticErrorWithPosition(dec, t, prevDepth, prevLength, err) + } + return err } return nil } @@ -247,13 +308,28 @@ func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler { return fncs } -// implementsWhich is like t.Implements(ifaceType) for a list of interfaces, +// implementsAny is like t.Implements(ifaceType) for a list of interfaces, // but checks whether either t or reflect.PointerTo(t) implements the interface. -func implementsWhich(t reflect.Type, ifaceTypes ...reflect.Type) (which reflect.Type) { +func implementsAny(t reflect.Type, ifaceTypes ...reflect.Type) bool { for _, ifaceType := range ifaceTypes { - if t.Implements(ifaceType) || reflect.PointerTo(t).Implements(ifaceType) { - return ifaceType + if _, ok := implements(t, ifaceType); ok { + return true } } - return nil + return false +} + +// implements is like t.Implements(ifaceType) but checks whether +// either t or reflect.PointerTo(t) implements the interface. +// It also reports whether the value needs to be addressed +// in order to satisfy the interface. +func implements(t, ifaceType reflect.Type) (needAddr, ok bool) { + switch { + case t.Implements(ifaceType): + return false, true + case reflect.PointerTo(t).Implements(ifaceType): + return true, true + default: + return false, false + } } diff --git a/vendor/github.com/go-json-experiment/json/arshal_time.go b/vendor/github.com/go-json-experiment/json/arshal_time.go index aad714c..f53ffe8 100644 --- a/vendor/github.com/go-json-experiment/json/arshal_time.go +++ b/vendor/github.com/go-json-experiment/json/arshal_time.go @@ -6,6 +6,7 @@ package json import ( "bytes" + "cmp" "errors" "fmt" "math" @@ -15,6 +16,7 @@ import ( "strings" "time" + "github.com/go-json-experiment/json/internal" "github.com/go-json-experiment/json/internal/jsonflags" "github.com/go-json-experiment/json/internal/jsonopts" "github.com/go-json-experiment/json/internal/jsonwire" @@ -22,12 +24,12 @@ import ( ) var ( - timeDurationType = reflect.TypeOf((*time.Duration)(nil)).Elem() - timeTimeType = reflect.TypeOf((*time.Time)(nil)).Elem() + timeDurationType = reflect.TypeFor[time.Duration]() + timeTimeType = reflect.TypeFor[time.Time]() ) func makeTimeArshaler(fncs *arshaler, t reflect.Type) *arshaler { - // Ideally, time types would implement MarshalerV2 and UnmarshalerV2, + // Ideally, time types would implement MarshalerTo and UnmarshalerFrom, // but that would incur a dependency on package json from package time. // Given how widely used time is, it is more acceptable that we incur a // dependency on time from json. @@ -44,17 +46,20 @@ func makeTimeArshaler(fncs *arshaler, t reflect.Type) *arshaler { var m durationArshaler if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { if !m.initFormat(mo.Format) { - return newInvalidFormatError("marshal", t, mo.Format) + return newInvalidFormatError(enc, t, mo) } - } else if mo.Flags.Get(jsonflags.FormatTimeDurationAsNanosecond) { + } else if mo.Flags.Get(jsonflags.FormatTimeWithLegacySemantics) { return marshalNano(enc, va, mo) } // TODO(https://go.dev/issue/62121): Use reflect.Value.AssertTo. m.td = *va.Addr().Interface().(*time.Duration) - k := stringOrNumberKind(!m.isNumeric() || mo.Flags.Get(jsonflags.StringifyNumbers)) + k := stringOrNumberKind(!m.isNumeric() || xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers)) if err := xe.AppendRaw(k, true, m.appendMarshal); err != nil { - return &SemanticError{action: "marshal", GoType: t, Err: err} + if !isSyntacticError(err) && !export.IsIOError(err) { + err = newMarshalErrorBefore(enc, t, err) + } + return err } return nil } @@ -64,12 +69,13 @@ func makeTimeArshaler(fncs *arshaler, t reflect.Type) *arshaler { var u durationArshaler if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { if !u.initFormat(uo.Format) { - return newInvalidFormatError("unmarshal", t, uo.Format) + return newInvalidFormatError(dec, t, uo) } - } else if uo.Flags.Get(jsonflags.FormatTimeDurationAsNanosecond) { + } else if uo.Flags.Get(jsonflags.FormatTimeWithLegacySemantics) { return unmarshalNano(dec, va, uo) } + stringify := !u.isNumeric() || xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers) var flags jsonwire.ValueFlags td := va.Addr().Interface().(*time.Duration) val, err := xd.ReadValue(&flags) @@ -78,30 +84,31 @@ func makeTimeArshaler(fncs *arshaler, t reflect.Type) *arshaler { } switch k := val.Kind(); k { case 'n': - *td = time.Duration(0) + if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { + *td = time.Duration(0) + } return nil case '"': - if u.isNumeric() && !uo.Flags.Get(jsonflags.StringifyNumbers) { - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t} + if !stringify { + break } val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) if err := u.unmarshal(val); err != nil { - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t, Err: err} + return newUnmarshalErrorAfter(dec, t, err) } *td = u.td return nil case '0': - if !u.isNumeric() { - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t} + if stringify { + break } if err := u.unmarshal(val); err != nil { - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t, Err: err} + return newUnmarshalErrorAfter(dec, t, err) } *td = u.td return nil - default: - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t} } + return newUnmarshalErrorAfter(dec, t, nil) } case timeTimeType: fncs.nonDefault = true @@ -110,15 +117,21 @@ func makeTimeArshaler(fncs *arshaler, t reflect.Type) *arshaler { var m timeArshaler if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() { if !m.initFormat(mo.Format) { - return newInvalidFormatError("marshal", t, mo.Format) + return newInvalidFormatError(enc, t, mo) } } // TODO(https://go.dev/issue/62121): Use reflect.Value.AssertTo. m.tt = *va.Addr().Interface().(*time.Time) - k := stringOrNumberKind(!m.isNumeric() || mo.Flags.Get(jsonflags.StringifyNumbers)) + k := stringOrNumberKind(!m.isNumeric() || xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers)) if err := xe.AppendRaw(k, !m.hasCustomFormat(), m.appendMarshal); err != nil { - return &SemanticError{action: "marshal", GoType: t, Err: err} + if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalJSON") // unlike unmarshal, always wrapped + } + if !isSyntacticError(err) && !export.IsIOError(err) { + err = newMarshalErrorBefore(enc, t, err) + } + return err } return nil } @@ -127,10 +140,13 @@ func makeTimeArshaler(fncs *arshaler, t reflect.Type) *arshaler { var u timeArshaler if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() { if !u.initFormat(uo.Format) { - return newInvalidFormatError("unmarshal", t, uo.Format) + return newInvalidFormatError(dec, t, uo) } + } else if uo.Flags.Get(jsonflags.FormatTimeWithLegacySemantics) { + u.looseRFC3339 = true } + stringify := !u.isNumeric() || xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers) var flags jsonwire.ValueFlags tt := va.Addr().Interface().(*time.Time) val, err := xd.ReadValue(&flags) @@ -139,30 +155,37 @@ func makeTimeArshaler(fncs *arshaler, t reflect.Type) *arshaler { } switch k := val.Kind(); k { case 'n': - *tt = time.Time{} + if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { + *tt = time.Time{} + } return nil case '"': - if u.isNumeric() && !uo.Flags.Get(jsonflags.StringifyNumbers) { - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t} + if !stringify { + break } val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) if err := u.unmarshal(val); err != nil { - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t, Err: err} + if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return err // unlike marshal, never wrapped + } + return newUnmarshalErrorAfter(dec, t, err) } *tt = u.tt return nil case '0': - if !u.isNumeric() { - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t} + if stringify { + break } if err := u.unmarshal(val); err != nil { - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t, Err: err} + if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { + return err // unlike marshal, never wrapped + } + return newUnmarshalErrorAfter(dec, t, err) } *tt = u.tt return nil - default: - return &SemanticError{action: "unmarshal", JSONKind: k, GoType: t} } + return newUnmarshalErrorAfter(dec, t, nil) } } return fncs @@ -175,8 +198,7 @@ type durationArshaler struct { // - 0 uses time.Duration.String // - 1e0, 1e3, 1e6, or 1e9 use a decimal encoding of the duration as // nanoseconds, microseconds, milliseconds, or seconds. - // - 60 uses a "H:MM:SS.SSSSSSSSS" encoding - base uint + base uint64 } func (a *durationArshaler) initFormat(format string) (ok bool) { @@ -191,8 +213,6 @@ func (a *durationArshaler) initFormat(format string) (ok bool) { a.base = 1e3 case "nano": a.base = 1e0 - case "base60": // see https://en.wikipedia.org/wiki/Sexagesimal#Modern_usage - a.base = 60 default: return false } @@ -207,8 +227,6 @@ func (a *durationArshaler) appendMarshal(b []byte) ([]byte, error) { switch a.base { case 0: return append(b, a.td.String()...), nil - case 60: - return appendDurationBase60(b, a.td), nil default: return appendDurationBase10(b, a.td, a.base), nil } @@ -218,8 +236,6 @@ func (a *durationArshaler) unmarshal(b []byte) (err error) { switch a.base { case 0: a.td, err = time.ParseDuration(string(b)) - case 60: - a.td, err = parseDurationBase60(b) default: a.td, err = parseDurationBase10(b, a.base) } @@ -234,8 +250,10 @@ type timeArshaler struct { // - 1e0, 1e3, 1e6, or 1e9 use a decimal encoding of the timestamp as // seconds, milliseconds, microseconds, or nanoseconds since Unix epoch. // - math.MaxUint uses time.Time.Format to encode the timestamp - base uint + base uint64 format string // time format passed to time.Parse + + looseRFC3339 bool } func (a *timeArshaler) initFormat(format string) bool { @@ -317,11 +335,7 @@ func (a *timeArshaler) hasCustomFormat() bool { func (a *timeArshaler) appendMarshal(b []byte) ([]byte, error) { switch a.base { case 0: - // TODO(https://go.dev/issue/60204): Use cmp.Or(a.format, time.RFC3339Nano). - format := a.format - if format == "" { - format = time.RFC3339Nano - } + format := cmp.Or(a.format, time.RFC3339Nano) n0 := len(b) b = a.tt.AppendFormat(b, format) // Not all Go timestamps can be represented as valid RFC 3339. @@ -360,6 +374,8 @@ func (a *timeArshaler) unmarshal(b []byte) (err error) { return &time.ParseError{Layout: layout, Value: value, LayoutElem: layoutElem, ValueElem: valueElem, Message: message} } switch { + case a.looseRFC3339: + return nil case b[len("2006-01-02T")+1] == ':': // hour must be two digits return newParseError(time.RFC3339, string(b), "15", string(b[len("2006-01-02T"):][:1]), "") case b[len("2006-01-02T15:04:05")] == ',': // sub-second separator must be a period @@ -384,16 +400,16 @@ func (a *timeArshaler) unmarshal(b []byte) (err error) { // appendDurationBase10 appends d formatted as a decimal fractional number, // where pow10 is a power-of-10 used to scale down the number. -func appendDurationBase10(b []byte, d time.Duration, pow10 uint) []byte { +func appendDurationBase10(b []byte, d time.Duration, pow10 uint64) []byte { b, n := mayAppendDurationSign(b, d) // append sign whole, frac := bits.Div64(0, n, uint64(pow10)) // compute whole and frac fields b = strconv.AppendUint(b, whole, 10) // append whole field - return appendFracBase10(b, uint(frac), pow10) // append frac field + return appendFracBase10(b, frac, pow10) // append frac field } // parseDurationBase10 parses d from a decimal fractional number, // where pow10 is a power-of-10 used to scale up the number. -func parseDurationBase10(b []byte, pow10 uint) (time.Duration, error) { +func parseDurationBase10(b []byte, pow10 uint64) (time.Duration, error) { suffix, neg := consumeSign(b) // consume sign wholeBytes, fracBytes := bytesCutByte(suffix, '.', true) // consume whole and frac fields whole, okWhole := jsonwire.ParseUint(wholeBytes) // parse whole field; may overflow @@ -410,45 +426,6 @@ func parseDurationBase10(b []byte, pow10 uint) (time.Duration, error) { } } -// appendDurationBase60 appends d formatted with H:MM:SS.SSS notation. -func appendDurationBase60(b []byte, d time.Duration) []byte { - b, n := mayAppendDurationSign(b, d) // append sign - n, nsec := bits.Div64(0, n, 1e9) // compute nsec field - n, sec := bits.Div64(0, n, 60) // compute sec field - hour, min := bits.Div64(0, n, 60) // compute hour and min fields - b = strconv.AppendUint(b, hour, 10) // append hour field - b = append(b, ':', '0'+byte(min/10), '0'+byte(min%10)) // append min field - b = append(b, ':', '0'+byte(sec/10), '0'+byte(sec%10)) // append sec field - return appendFracBase10(b, uint(nsec), 1e9) // append nsec field -} - -// parseDurationBase60 parses d formatted with H:MM:SS.SSS notation. -// The exact grammar is `-?(0|[1-9][0-9]*):[0-5][0-9]:[0-5][0-9]([.][0-9]+)?`. -func parseDurationBase60(b []byte) (time.Duration, error) { - checkBase60 := func(b []byte) bool { - return len(b) == 2 && ('0' <= b[0] && b[0] <= '5') && '0' <= b[1] && b[1] <= '9' - } - suffix, neg := consumeSign(b) // consume sign - hourBytes, suffix := bytesCutByte(suffix, ':', false) // consume hour field - minBytes, suffix := bytesCutByte(suffix, ':', false) // consume min field - secBytes, nsecBytes := bytesCutByte(suffix, '.', true) // consume sec and nsec fields - hour, okHour := jsonwire.ParseUint(hourBytes) // parse hour field; may overflow - min := parseDec2(minBytes) // parse min field - sec := parseDec2(secBytes) // parse sec field - nsec, okNsec := parseFracBase10(nsecBytes, 1e9) // parse nsec field - n := uint64(min)*60*1e9 + uint64(sec)*1e9 + uint64(nsec) // cannot overflow - hi, lo := bits.Mul64(hour, 60*60*1e9) // overflow if hi > 0 - sum, co := bits.Add64(lo, n, 0) // overflow if co > 0 - switch d := mayApplyDurationSign(sum, neg); { // overflow if neg != (d < 0) - case (!okHour && hour != math.MaxUint64) || !checkBase60(minBytes) || !checkBase60(secBytes) || !okNsec: - return 0, fmt.Errorf("invalid duration %q: %w", b, strconv.ErrSyntax) - case !okHour || hi > 0 || co > 0 || neg != (d < 0): - return 0, fmt.Errorf("invalid duration %q: %w", b, strconv.ErrRange) - default: - return d, nil - } -} - // mayAppendDurationSign appends a negative sign if n is negative. func mayAppendDurationSign(b []byte, d time.Duration) ([]byte, uint64) { if d < 0 { @@ -469,7 +446,7 @@ func mayApplyDurationSign(n uint64, neg bool) time.Duration { // appendTimeUnix appends t formatted as a decimal fractional number, // where pow10 is a power-of-10 used to scale up the number. -func appendTimeUnix(b []byte, t time.Time, pow10 uint) []byte { +func appendTimeUnix(b []byte, t time.Time, pow10 uint64) []byte { sec, nsec := t.Unix(), int64(t.Nanosecond()) if sec < 0 { b = append(b, '-') @@ -478,20 +455,20 @@ func appendTimeUnix(b []byte, t time.Time, pow10 uint) []byte { switch { case pow10 == 1e0: // fast case where units is in seconds b = strconv.AppendUint(b, uint64(sec), 10) - return appendFracBase10(b, uint(nsec), 1e9) + return appendFracBase10(b, uint64(nsec), 1e9) case uint64(sec) < 1e9: // intermediate case where units is not seconds, but no overflow - b = strconv.AppendUint(b, uint64(sec)*uint64(pow10)+uint64(uint(nsec)/(1e9/pow10)), 10) - return appendFracBase10(b, (uint(nsec)*pow10)%1e9, 1e9) + b = strconv.AppendUint(b, uint64(sec)*uint64(pow10)+uint64(uint64(nsec)/(1e9/pow10)), 10) + return appendFracBase10(b, (uint64(nsec)*pow10)%1e9, 1e9) default: // slow case where units is not seconds and overflow would occur b = strconv.AppendUint(b, uint64(sec), 10) - b = appendPaddedBase10(b, uint(uint(nsec)/(1e9/pow10)), pow10) - return appendFracBase10(b, (uint(nsec)*pow10)%1e9, 1e9) + b = appendPaddedBase10(b, uint64(nsec)/(1e9/pow10), pow10) + return appendFracBase10(b, (uint64(nsec)*pow10)%1e9, 1e9) } } // parseTimeUnix parses t formatted as a decimal fractional number, // where pow10 is a power-of-10 used to scale down the number. -func parseTimeUnix(b []byte, pow10 uint) (time.Time, error) { +func parseTimeUnix(b []byte, pow10 uint64) (time.Time, error) { suffix, neg := consumeSign(b) // consume sign wholeBytes, fracBytes := bytesCutByte(suffix, '.', true) // consume whole and frac fields whole, okWhole := jsonwire.ParseUint(wholeBytes) // parse whole field; may overflow @@ -502,14 +479,14 @@ func parseTimeUnix(b []byte, pow10 uint) (time.Time, error) { sec = int64(whole) // check overflow later after negation nsec = int64(frac) // cannot overflow case okWhole: // intermediate case where units is not seconds, but no overflow - sec = int64(whole / uint64(pow10)) // check overflow later after negation - nsec = int64((uint(whole)%pow10)*(1e9/pow10) + uint(frac)) // cannot overflow + sec = int64(whole / pow10) // check overflow later after negation + nsec = int64((whole%pow10)*(1e9/pow10) + frac) // cannot overflow case !okWhole && whole == math.MaxUint64: // slow case where units is not seconds and overflow occurred width := int(math.Log10(float64(pow10))) // compute len(strconv.Itoa(pow10-1)) whole, okWhole = jsonwire.ParseUint(wholeBytes[:len(wholeBytes)-width]) // parse the upper whole field mid, _ := parsePaddedBase10(wholeBytes[len(wholeBytes)-width:], pow10) // parse the lower whole field sec = int64(whole) // check overflow later after negation - nsec = int64(uint(mid)*(1e9/pow10) + frac) // cannot overflow + nsec = int64(mid*(1e9/pow10) + frac) // cannot overflow } if neg { sec, nsec = negateSecNano(sec, nsec) @@ -535,7 +512,7 @@ func negateSecNano(sec, nsec int64) (int64, int64) { // appendFracBase10 appends the fraction of n/max10, // where max10 is a power-of-10 that is larger than n. -func appendFracBase10(b []byte, n, max10 uint) []byte { +func appendFracBase10(b []byte, n, max10 uint64) []byte { if n == 0 { return b } @@ -544,7 +521,7 @@ func appendFracBase10(b []byte, n, max10 uint) []byte { // parseFracBase10 parses the fraction of n/max10, // where max10 is a power-of-10 that is larger than n. -func parseFracBase10(b []byte, max10 uint) (n uint, ok bool) { +func parseFracBase10(b []byte, max10 uint64) (n uint64, ok bool) { switch { case len(b) == 0: return 0, true @@ -556,31 +533,31 @@ func parseFracBase10(b []byte, max10 uint) (n uint, ok bool) { // appendPaddedBase10 appends a zero-padded encoding of n, // where max10 is a power-of-10 that is larger than n. -func appendPaddedBase10(b []byte, n, max10 uint) []byte { +func appendPaddedBase10(b []byte, n, max10 uint64) []byte { if n < max10/10 { // Formatting of n is shorter than log10(max10), // so add max10/10 to ensure the length is equal to log10(max10). i := len(b) - b = strconv.AppendUint(b, uint64(n+max10/10), 10) + b = strconv.AppendUint(b, n+max10/10, 10) b[i]-- // subtract the addition of max10/10 return b } - return strconv.AppendUint(b, uint64(n), 10) + return strconv.AppendUint(b, n, 10) } // parsePaddedBase10 parses b as the zero-padded encoding of n, // where max10 is a power-of-10 that is larger than n. // Truncated suffix is treated as implicit zeros. // Extended suffix is ignored, but verified to contain only digits. -func parsePaddedBase10(b []byte, max10 uint) (n uint, ok bool) { - pow10 := uint(1) +func parsePaddedBase10(b []byte, max10 uint64) (n uint64, ok bool) { + pow10 := uint64(1) for pow10 < max10 { n *= 10 if len(b) > 0 { if b[0] < '0' || '9' < b[0] { return n, false } - n += uint(b[0] - '0') + n += uint64(b[0] - '0') b = b[1:] } pow10 *= 10 diff --git a/vendor/github.com/go-json-experiment/json/benchmark-marshal-concrete.png b/vendor/github.com/go-json-experiment/json/benchmark-marshal-concrete.png deleted file mode 100644 index fe52d3df6d5b168e478824c9bb61a0d0abdced29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24890 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV6xy~V_;yI)YPlRz`(#+;1OBOz`!jG!i)^F z=14FwaQSCCI|l@0&Ql|}l*f)3`szJ?yrKpmbgt{d!66c_b1 zFYf3%_4{G<;_PdCzCSzrZ|ilt=W9OC-F%+?00+-B592`72A-8pa)J+TGPZl@74)V_>Yf%+0}Yz<2fm1DW>!{I8s5#xORtFditG zXyMJ#Aj05K)#tQ~!NHBOVeSmIV1@-O3<;-`lO8h!=rSaz*FU?=&@lJM%xXr4=qZY# zj0+|*C}b_wV5w$EIH9au!O$|3LB#D-xXnlHbpp?|7#J#MZnD{_V(Ho#&7oV!9v-eIr*Y0x zTwBB}ktuPOgWjRanUY40Cj1XRpJ8BFFi}+SLG$Oo73cWYojYgNw~a4e_tk#3|4Ky-n{wr$&(viN1UP)Pleb1OFtBUApCF6&pMkw-@iWC_eiDDD7Mj^<;R0VXTJC> zl{r6&vnA=yvwrtK+qwV$k-e;R#4~AUgqFzTK%v4umsvfZjg~5PI!)3%s(R^v%A@-_ zznSgsn=)+3vSX~CsJkLInfaTyx= zXh`#%RLH;(=c1w)a%!{vaSjFsmj#Vl8yuy-9F)*Gz$SB$_0B==KM7_nPAW$ZISDv% zr8LMCC1|c`a?)r!yFpefLH~+_tjU4EjJC-Ie0qmMcktO3@c&BWn0HWPPa`Lb;|UJo zM8#Vjj7eP)%6%N-Gh2Ts9`s-l>Q+%W*&!0B3~!Vz->4qo94F z^~u~Pho2Zfk$$51DVl3;l0)H=AHk0_f=*?5Nj?>LYVwpVb%v2+=;B#HcULS75j5?O za$37^ThRKz_7%b=rL!#0Hj8Sd`6@r>`8>tB@Y61+QA&TsmK@Jpv(y1$tI zg85514{w`j^YM;!4awOO>=Nmc>_$-sW+%0)L#K7F}^^E5;`Df;bMrdu*su7)d zifgLZRJEznTKXX?S1nt0Zxwgw=g`w3{VU^wYuCAj8V5gK$$4ek>d;kl16~J92dA&J zUeUfPeMNqV{gS%KznyH6hkXwFJ1+@burdDeo?{B!$&#BZbQH6BSGScmnjTTxc=l#Z znbz(Ze`R-f+pb!<(9+r1%Q$><(B~;>_Uw;m6#ke~;>Y=1WBK&YbzS#F-fKS6lwM}y zv(qp&CVSPi>C+-sd#nyz?f!bN*}AvO=Pujpx;yfBBcJ1OFZCF8_w@dAtaG0S-weLH zoNKw5udUVBb$Y9^mr5_(?NYu!Z~40!^Y+Cx%=5`#ey?)x^ItNx`hP?I=Kfm#)tx7T zZ8MJw+ijk65;jLo3-fJc^^f2F80Z{(*ui;e;?%_H4_hYgylAuds#~uce^2JIn8zxQ zbC2a7Tdc;Wrl{ua`^xv-tRUZ=%QTl+`&j!NKYQlvqO;d#n$EU0yl(V-_Vd}-XW!qR z5LFSSvu(w;9jTt1o9x1HR!a=YY)r#IMcuiKWptu`?|Nj!b~(RGL4P2M}Xc2{lhUt4zG_M3dGWus*4 zinkPrScO^Ln{{r^JNw$BU#7j(Pmee+aQ=qz<88vHHIHP@4W513JzYF~XL0lAj_ywH zrqg=U?eu0#AG>>E?-Q?*uZ6J>t1f+=JA3o&LvL5yUjNSQUFN&?JM+(&%-5V3X`jY`Ks@U@5SxD*%i%yZ1>p4 z{GQRh$oMnn2ezNse%k+V{=E3s`_A>s|5N@~{lCbtyg`*Qow>8ou`!zI_m8R?#r=Ku zR<~2XZMyl^v1h?fM^VTArnOB^53W_rIPqq}TE*|rXPldOE|ae{pzg)B3+#!{61xxA z@u;`9w}!Xb_Z4(RNL@6XZd!ivj&t#SmtQW^T<*d|8{wJbEn}&twazRrXW#ulZ$Gy`n)`_Rakcmi{S&bTl?%@u`qH{wY^9!% zj@2{=pAJ8ZDIXjKv{s1qsD2VISMB4fJS2N4T}l6<*~N|<&M{hYexE$Fe5)qCnYhQa zQst=eQk|zeThv!h*yF?Nb9c7YJh5423b{tMR(lPbCrzAC=(I}Fck;IMSLx5v%1*CI zZQb5r%eBpE*^7`Ujq6(Mo6=Lm)Apb3JY_j;^*rsfZ_jK# zb$f#OocHtpzZE(p^l;L)rET8fy0Q_^_O8jY++CTJho3?8Dv*~h0(~-~Za3+;=;aG1T{J+SSzGp1(JLw_n$}>gA7VzjI^P`sEhBJf0yI6x>eRw zz2+hNW%)AMbXol@r&*t7xy=rq^*cH#dYAthyNlOe-K+ZJep{Y@j)_fVrPt?>lbN?( zHeH^a{^@+r+^KVG>-2u!Nw~deTlMqgbN93O^WX0hD0z6v^?&zs>pj-zVm|FC`LyZw zQ{nI(;j`9T#pk{%d1do&@@40-a6iNzT1A)KKkFC8}IMb zXB{YC@cH5$_wQ`2&FBA3{Myg&%-TP*|8yH~+v|B2c9xcp?2G=s{IlHoe9C#XdE);T z{X4x*Tui_2$JN)@&t05xapCk&(u(=BbWCpF$qHk`xG!P9-yST# zQ!e{{@qK>(Cp8N78viqXZu}a2VfpXLl9MO@XJMZ4`A@R3?rjDJ28CpgAYTTCDpdxC zhGqtapZ^&c8eTFmlo~KFyh>nTu$sZZAf7)d{-_%RLs+V(i(^Q|tv7dTBSK35{r`Af zfk#VWd-I|jTF}*-o4aWsjIJ* zm+D@>vgPWp%HRjSS{YjRx;Z$S7Th`U=ih{xX$cLCi7g+0?pRl>S$uBJ%+Pcj&7x2UF&M=MIeYSU9c~X? z>h8c}_MeG?fuTVE*`o)EKd+ausO-0BiJ3S>JM&F1%Y>toYPt@$t2R_j6?EWX5ny0o zIFQTSv9pIEC_&g^oyVz(UrIumP6T=GGh;lm+l67H?f+&5ka2gc7>@`!(|uW9||oXPrMVglWCo>XwHwC%k#|^5iF`6G@)`CP|65^Si6hzb^c| z4rJi=ECEeRuB4w@VJ9bFELKVN+@&(R*eQqkM2#ooQN|}|T4JKm<2b1HyM zmUhqyZd}*j65-~k!}z4Akl|#=$EzE47*p0QIq>L1BB#Q%i~YZT{oKRve~6udfx&@8 zQ_zX)>*t>e)7B?Gy~Q%YdyF{V#q_ck)HGiYYwub1L{ikvWU!=)%JZ!VWU6BBxh$lou*| z-1da;ywJkKtLIz@ycoWoLy3Wbq2agD^pE@QA5PonUfA|QXQFP;v^#-CZYMtkUXzzj z`2w6pI1u`&79&f?{MbFG%%xf8QB>#CQmby>*oZ*QMI zd|3B$&zjr_N%^`T3*YVe?02{N{oX%ptPBjL>J2IB>90RLJZx3-W5cA$lfPaG_MaM+ z_V`$@Rmls1=#?_z>*KDzyuAGD%jNS|)&2dIb$eTGukAJK_j?w9et!P`h1ucZ*5&W! z?ECSEyI0=+-n(zv*Vkpfy|wk$#^m<9Z#g+Ry*xZFEc2Z$A}zf-{?8-vysi5~j+?!? zzkmO;b8}ZeJ3D)I=H+EFEes3`@>m4A8yXl?RaIZ!+M2y8eEqz;(nppoQ8CTB;t?4c znX@uU)m>6AcGnX9eLtM+|NU6JE$?pBV#X(bet!0|U4CoPiWMH(VQT`8_sOOj&3yB$ z_UqMfkRzl_G8Ww1Tm5?7?st>cuU~)Z^5w0mr^P^l*e#}e>Bq;%-gmd_X=h7^xn*Rm zuqt`6V5)X_)}J3A^DKi{7#On7`PM%d5ENYa=TFUCtI|{NzD-v5*Rr>d7ZeoCSz7et z_wVcv4-QURSD(sje|u~8^mFs=*UQ;fO{o&zmwVf+va&Ms%ZrP<-tYS@A|aunudi>K zdCBGfXZ!z)cfZ@^{qyI~TRRGsdrKC$_se+4qf`SY0?k<0Q zVxn@^%}qq3KqCiS>2UbJY@mF@ZQS67Fhew5z{=dV70&-QU;o zuN&FrE?iw5zBTQvl&Xr#iQBiMWvxmAe0+LrZ0qmIu8-ZlEPvlmw~rq`o;q_TWU*WC zm6gHjuI}!)b;GAETBKC_`K)=?wKX%P%=2>0^S{5lYc%`puJ8A%udazSZvX!N^78(5 zF*_GsxDc@WHa8d7mdej*Z*OjPkBp4`^!0MrKhF6+Wmgt<*nJ*O;S!w2>Sl>&F1qZ z-`+$@^00xD@1!sP|K0z8dH?^v`MaNj@@MdJzn7<`YA?03{r_aLf60#ziJn1qb^Ab; zR#sKLI>;`+=F{g@TAOdKS+hoGZS;1(Niy?J#7lCE>1?RGyLQ0>huhn7CvV@ree1SU zzrOGPpIhE{G(5g`>45_dZ*OdLR`;8;Vc*Yt+j3|3xGgUIJ^O50?U#%0WzYYoq@-k= zo~CP6`)i9^uas)@!GL$k@|Hy|GiT21>gp=8@SmiltbBS;eMZI#w|=?Y^4nXpuWzaN zn53$z8kxVl;^QK-{CjIAtNUkNSrNGOUPt(q%ZCm*ot>s{g2 z-;;3H|Mczl)r;dpBi(14<$gJ9e*eXbi;F>N@nn8514Dp0lSe_p1}W35C6|}`YwPR# z-@AA3)alcgUtV7R^zq~1SHciujx^l$|kK5bxuY){U`}><^&EolU z=dL|DSzTL2)r16TdKe3 z+5ULY3@VJZYPYUdcJF(!^ZC5VCsQsh^PRmV_qN&J`~UyWXJTUda;Nybrin?&>uYN- z_sLpsDSscA&2V#X^>#j4t0f;k6!1zKx%kd9x!B4rzNPAGmaJuwi~XMu&F^+TpI0Pr zZD_dhOu)36Gc{lSTK;3|$G_k2YinwH@=BXs`S9@Y)lI41s;a7)S678vRef2p@BhE* z(zmy+zMSWEsZZ8=%A7fC7A#P({rBTB7Z=y1Q&Y94&X}>{>}>Ptx8h~q9zOSN^`6{_ zsq@V9@5NmDD*PSPaySsV^-;C3prD|Zme!?>$;VY<_nTw|1_thYUjOH9e*Iu;E3Tu?C0zUE_R zXSeJBzu#}~tqDKcz{o5jC#RR6pa1pE&EQL40~b3svuWDc#JDXEto`*x^XlOrKPs{{ za_;Tfxo6LwD{CT+ZNJ?}zGi+})Uxu^5|x#nlhu|!i``olI_b&Vx3Md$bmCdx+}^(a z-Hyk6SJ%hKzrD3J*vH3b=K0l&=E>Pq1Wfue`~DxdhYufS-Po}3*Z24Op4TRB>-zTa z)r;`ZYl)l%)8d#J7%UENHnZV8T`A|@FBiJI?CqNPi5qRzm*{}1?VFp^LDhD4gW>G6 zeAD;7-FDmS?zN4{?x4c;*PqYlx7Po!v;A;@`P$@(vU9T&eqITmBxRD3z^iZmX^+<7 zPbW+B^49(P*kAwR(o*kTzu)bay%rX^Z87Vx$L^@Gqo*aca?Zfdh+;ja8}&mHr}ao=dRTbUuQ8VUhMSaX?rfsc$)4G@?+Gy z%ZpsOU+1b#UU?=^&HeUHt6!m0OCzd|hrVK9aG1-ZaOwR0v)ku1rZ`N)z!u; zy(<6yzNl?EGsD(IC{8~4+Aa4+ouV3Z3;2DFLXi0 z(&nYTfkD8{n>W2YJvED`fXXm-KAC`SFpS4>*J?>XS-$;WSDoy;_LhS@qvMXW%DnEeOvA9wm9(Z?d{h; zJUsmM&*$^rlY)YRv|`;$?bmljoU^y6`?I6&*Gu)?mD9ZUM!7Moy!`U=^47ZLTUh*W zYa4}z1q4h`IX?ef`I{Soa&mH@29sXQj)1H>P;K<@SGMP--`x+Vo&Gt^#{BRno71}z zoGNwdpIj(A^5)Ue?pZdKo6^qDd%LMFG*x!mJvMgs&$C4s7_Qu9`1H8nK8o3+a?hSU zDzX1}g(W5~?31@&_w@Ai=;ychz0^A&oxgYK$;s;3$NOYYojx60SGVtL%k4?(zpWPU znm2uO)Rv5e*6(&WPuh}sS#5XaH2;^|^Y5?Qv&TkNT|N8lt*xQ=BfH!K&&{)qUi{nX zc%Q7QC#dXgWM-c-fByO}UrInV=45sMYwhxN5f80&o_kqXl`EQUw;y4cqK+pEL% zLBgxU*I#>eb@kh4U*Fx`eW^6$`sYlCF06~)UGnEgVf(>^2L~EYoj7s9-~R6sP+5dqE?@6A&t|2n_p~Xu>b>Kdu1oI!b#=XnxcG8zalIF7x8K`z@7?3a zi(kBWk@Y@2^7aNTTl=~{J5)k{|Knj`;84)JxWrS~H0MUZ&Ye4rqd+yl*4EaQ z;p^jeeLiQc9qV3dyZ+R-b;Zxmb@lgOU*zJC4s{r{q>zrPDDE8E7z#B^n6ar)O+S66$fzmx8D`}>f;{=%-(*HdQ9 zSn=mi&DNZoLCkDC1+V5zIQ4Dy8c?MTYL+!NHfCL3#=GB>k)h!-Puk|nrAr(<87KWw z`RS3Ra56$Bz^3%?>L|HMJV%8CULQSr6x2-kby)u2gDa|YAMRPQMCI&!`}lslUn{K2 z-}yK*FznbmvwQiXM=Li}oSI(Z8q~KW$8+W+BbyiEcS1u#rpz+ST{YLb{8CTWw&Lf0 zrrFodyi=)VU|>iWaCoqdhpoAdUw&OPJAah_jAOmtetuz2PEAS4$*bQ^y2QZHz`(Sl zb;AY&UMUlg*VooAmb{vBcUP&DO~r=b`X53J3=34wF@n0<1*wYMzFY3CS{!(kTiWKzhx&OTdzU>lSvTXS*Q7J*amBmp+r;!wT~Ju$ zcQqm+Lc`zxeANDPpXThWiSrivw^S+gPxm2bw%#1`kcazx?^N9{{c5&CF!T75-gENx zRWDpMmx%7)acV-%(^dZ}AFVm#C!@|L`6Z$|jVn7~{xQZRmM7CTt3I4{?Y;JuHhJxN zAbMI$_SCwbw6n7!|JQ$d;@K-<=(PQQ-EL6#-FKc%q@|^0+3Ek^_x}%le{Zj-py0xN zwZF4|e|x+1+V+~CpNiy{>p)udtG4}nTDv(ge1FvH)zbUcRQ$?X`)S|Ji1gp$^78B3 z<*Gc^Mr{REizRPvY?S6#cpkpu#hoBgRsGc!R@+0Keb#>E@;~RlysT{O+vB;uYc|_R z`_(SrdVKqf(~s|mSgf_(=PK=2`}|7P+?#S+LnCi5F#Ef2b-*9{rE}%Ic25hldHd(X zuTOqa`|I}Bee8~35xF@H)R_hK+?OtonEvahuh%RymG}$Co?PKt&U;e)i?7!$Ut2$| z=;FDzwmUL7z6}cr*?fBXmovuaSGf1f-P)c%e_P&NEq{Oivoj12Tm8SV(0P_YV$;7r z&+W7S|NA@3By-ZSUg_mWj=1dpTJ!7W@?8ZFotDa3YifEPZs))L^Yio7>l?4HyZYwS z))n>jzb?-=$-JZ@Yf}-xZ~J9JT*brISD;o}{pa81PfkqCvd_y-n)_7l`?Ez-k^2_C z4V-PcnK$p*$5(gSc7-XQULU_duKv$sdDHrTHFIsN!`|=vz0R#)Zmq0!*_E63>(9OY zZo0X~S5`g!{JhfJxr|I43F?Z9j{E<<&42p%@!|;+1bpY)#m3isY%TqF|Np=8yzxvFz3JqTFSNcN&RMwV!dgA$dxykpt zer3k)tGStXb7%4MRsQqsCM~h8{+99JKx5Y3U0bb6UoAOr|NqWID`R8huSbOaSLEK_ zR`uzmI%tr<=z8S!ZSIwSK~=vnG`eC+lY zlq#3|&Hd6H|Hmo5_UqK({)=lOjdi28c--Apx_Ni}$=rbGZ`*Gry}7aR*YErP*MaKP zNo>4QOU&=r1Xq81vr#YjUY)nSc6hn#erB1shgHAde|)?jG>j1N``g>Cm7mkLv2rLB z=vsSC^78WXD;ILN=iL>NkXZ5c z_4VmhJuhBlye{~^E%)}93(owWlgx5&EpeBxo$@bqWBoQGBcm(3O0$1GUr^s?m$>DR zb^19O-#He6zrVe`+`!2E<=yW0w{+ztBvzca`|UHyB=HbSucWaXJD<#j`Tzf<|9zWZ zU%cZS$P=LWdGz@4*VXZVz1HvlS2gqXn(W()_tc%8XB%x>_2t6$`*o}LR)3!s^&Qk> zOg_#BlE~ltbz0f`du!kC`|bDn+1bl843p$&+tl1#`ti}xpx3jkN>|;hes7zao__o8z1`*c z?fDCQ)r9})VDD$eB=TOo~J)wtzKX9`|bAAw{J%?v-4f4|Myvb_s_q-z6LLL z>s5*U|L;qF-Dl~_>gv}I+vUrC$f#s~es&gA2ZNHoyIiGM7U3b!ET( zza4-6{4q&9)DrZ%?&Z?yPhP)XZCCs2#eqiVs#hzQgK|dQ-(M>?Y`E|;_tSFwzo1UC zPU-$#8}?rnJ3GsCv){RQ+rM1?xl8-iQsdtr&ds&{dP2GX#lPS0^+knlh$%EIILFPy zbLI8={p)z8%|NC~ndQtl)-Rtw_x=0#>$jNv7XGXkvtz-61q*^+gPKp9&)cn@X`DXo zmrLsTdA6s{p9i%Cca^+!`oC&peLJ6Qkegdu)%SP4|7E_cw-MKi*)VU$?LC#nbFItQ zUE$v1>gLu48sY@yyjK?&yU%>>c{jJ&IwST`} zFMEA^N8#dkd%wrE_g`HfZ=afylJWf9+-tW%-RhOW>U)2`+YRcFK7IJm@&Bro_0P}E zz059Ovp_t)X5zo87x#Z+VP$>!*)@0V?nSvl)4y+@ef09> z%kN^CU;gTRxox_xUiSW_^QYSTY5kIY(9_VskbVCqs2-RrA||%1-|m;kbp7~i$K~tS zSij$M*((1)10%TnxV+r|^`)iWzmD7g1C3rpKDYmVr?~3%+U=nJLuz_@_Tyu{Rp0NH ze|@w0{Is7H#_8vDN?j-1+gqLe?#@oW{dO+@S6$ox<448cpXckZ^++10m`J^hxBRR9 zGwsZ$&XkgpEubFM)924$PxiOFc%YH_^q%;nq(zGsF9r>i>PBr@ai;X!ySve^udNNv z%Ufsn|Ig>3`@7ej)w(73^sBa-n%n8=`r&0|+wN7r->b#G_Ee6r`|SnW-sW#TxTo^- zmp7ZwM>(GekFQPLt2OQIdkOd7x_{UFDGZX`&kTyGwXwUytjphpe1CWMCMXfVn`xRo z?b_Pt<=@`k&c3=Tv`qbo?`$*Q%*@QL&d$K+=jN8axS+WA^EvCX`K$gsmj8d@cK-gg zpt5>y`Mrz3-|t_4;=~Cfd3_U;kbc{55i89ve0_aA{QNxIm+_`w-}l%5S-dUh=AzsA z`}bb?zVqe%`XC0F{}{d6gQc1H7a9jL^bSNkpU>#M8Y zxwp6J7SFB!_j&%;qvG)^oZI<+y|4cd8s5J;vv%*Iw}El{)qG|w$i2O7W%c)WyZ(N= z{q*(g=%vpCX68Q1kiN3*?^?4L*VoVg_r3mqc=EBHz|CoAP14Rt?EQYP`r7KGsoU>g zI)6%D{pv^S2Oy_xN^U58H# z+&F%fN;-~SuOTmQXUDtyh0A3UO} zdmsH#R}sAYgWe>C5`{%`ph`;~NMNGHZe&~>sZuB-EY4f}*U834I zBBpNqmw#P7{cG*dUo7o*mUV9O^7e1PeA=ITGp2t#&+@{8@Mn)!uBgz`nfFOGcH$Ie z&FG+IOL+W$m1cij8^8JV?%Jg9UsqpzdUsyB!&$xltcTB^1}{Dxe)LGE@YcG&RZpKi zTNS+AuWbIlL!P`$S!F+?d-~J&O2x_*y#5~C({Lw>t9yy8J6Gw^PR9vsZY!g+{VPAY z+RkPZ)5?Fo-RSwVu$ltX9F6zuY*qY=_D$XC@a&5I(rmw&x{dSZ^DO%}sZr44`u}-5 zmgS#6s=53_mvH_nsTJ;*^*()ha5i*p`C13753N(4ANlzFt-34Ugja=srdH0GarV~K zX$$Wh>iVBl<9xnqm$^#7JhppI2W#UWhIR@HK$`H=Sq1EFgBD6YFe0&6ZS4*y7jdwbLO1+=k9yuNa4|c?y)k#ECP4D7*(vTZ|iQK zYJKf#pXprd^1i?QvsQFI?)uxm%VHVC-aIjgKafdW9TF_v5`_j(4+fbeVcrnp!-lA% zlf@1ks(%sob>7s+X`!Z*raW$oJ}vvY==iK#UeY)Iujrh$s`=#k1(}NFUhzlGXX3|s@Agb!E@e?x zU|?8qPRncWf;Z)Hiv__Uav)SurBw~mnG@eT)6jGoCq!KIp>jx_aNH6>2iZfOFE+fI z9eE_RVrBQNRf5wWE>+8Vw1ervgJ$L^P%s||m0&CsW@Tml^y$;Cg{5z5YUgvASMLms z_nE{cd?&wpcXI5zh+uZl*4a1zuXri8=A?DZ*LO42oeOyMFEDuR%v4q=EG+Em>kC`# z)@xGrC1b8l<)x?R4<;B`?0xg<>grSzsZ;}rko|SFxp#JKEZckW<%Pz*k_-XXPv&0S z>iqZxbHgoR2R=EQ6^zVm8FzLRg68s;cuxNEWU_zO$45uEZt?_;>OAhZUpG}d{8Wxv z_RC94K~15prLV6=eU=dx7QQ)~kzwoctCznpIK1UlSik2}SK65w3l}=KpE`creQosi zYlm97w}}BZcXyw@e!Y5`@9eCbn^Lb;vNb!t-}AXoNl7WiL<%&^w*1}n zY15Y7+gpA5{{8(SH#FbZf%-q6o}M;MIU(SAX>q^ZD%WnY%+7zz@k(FWl6g63 z>(s9j(?zLT|*|i@IvR|9;-Y2uNQ&?R~SJ&4#{oIu!ox*RY`FnX?`uF$u)}*6cM~@w| zD&4>T&r^LVtCAId^X+oQ%d~dIJ32P9@yq3G|MTJDVbjV_DX-68UgmrG%gf89|Nc}S zJ$5YXSdV1cXStdWj-aj?sGD$QWw7^GWlc>_P{SHD1X}#u@9&q({!6p8UmKoD+kAKb zBoP^zHM-H;GA=A|{PpRyzAAY5@BY5po39xeOix?Ke7&{LU!K7t#bEYXZBr_EWVgg+nj44F=f&u&>ZFK z^V{ ze|rNOGxJ(|Sjf&x>wVqIl`B7e{ybR)G<@{(_taM#&PvyIe|~=cc5Le@vlvx%_0#w7 z$4`3l{{8wXQ>Fy{ouJ}>{`Ks`mzpP?s^)RGowj6M>~7FVr@+- z9Plj;X7V^c&-Uy5|9{*UyY+6mw=MU!S+BIYA3ML?6ct`Mn}~}SFG`taO*wS<@YQ{_ z)yuEN-uo+Mp10=A86Q@5_UT-VPw$>TecC(w+M12OrN9HMha5aSI{M`8-+c($p*Gob z=gys!C#+FkAHP)s&-d*H>flB z-Ycq{(gPl-CZy5mftU}y8HBQJ}Aw7ILtqF>eQvzTO#4tAv%EUE9no z?7ZFYHEw+}nXzdfA03r4OlkowCyo%K`ma~Rzururzq0W0 zv0EDwo1dMT8N77g)bA3`?R=pwE-i;oqKDG z=VW#Nbsz4C?W<#DDD{5arueJqKu!B+3(mdo9;lSODr!z%^=*C&-}S057u~m(ybO|J zWXMz5lDJ`6iKMeK!xc-G3DFK!RlABWemyH3(>8tAij`7@l5tr~3{##tf|vH};8IrD z(Diy>bk(`NMk{yM&69NVEp?irQhQ|EqGeG5!45mVykJ@>E3V8~@Y#@wiJ@WlX&dFW zGT!pws9baFGI$}^oDaP2i#-;nalvO3zY5j+Y>Oe%dtPIVe6Dvi4rd*?ccNNaC2`%r)aU{WxLx+3>BGbH z3!iKEX0kkBv*45soBr==aA9F#UTAPp(WXO(4&BL%-U)6X)YR-*v}h5eUG;Uxqpwmc zUQ2+-tsfZmG#tpPZDO4X&o*5l7d%$hU0!cTAtcguc zOqG?DcefnB|MQofXx_J?)$?Ylh^p+bOA(IXLA*|l!HQkh>~Tm(%h-K}XpnDBS|8qZ0f#ZQ%=pWVD$es51Ds1#l* zxBgE2D%ESDVyBCl7#ObVyzf~jE9EZFz~pgN#-<{GnT_Ydj>5;FWeA>=)n1-dpMT}i z(Qa?uY_r*GCoi5~|L3Fo*_p=f)Ai%0sl@K9iQJri{#w8Nzlf#Bi&YE_C)x@zG|Ybc zDzl0~z+u(1so`-KdnAobN?ru~{PAN2sAaUHU}4#t8-Yu|f{I?yiWimK+uM9&cbBdG z^7!qot=@Ncmrq~6em!X7BK7n%&rR~3n)y2?>Ba2ax#L<|zO!EZ{eD0F2@3;5`jvb?evnUc?(PcRTlIC*?zN?_ul;(^%)e^OJ~`W}jMLL} zCoR#9-Ub?Yo?5qOqOyC|qa&SO-rkqb%rpiKgL!U}t^`@Q%y;%OcKMos^z-vV*T?NO zDSZ|4dXHxCvK8g;?}28R>wY|B|5nDpp!G<0T~+S=<@^r3Ml;Snn>vX}mDS_Z$(H>3@^#_k4<8CZ z3!~H~dmitX4+oXMU!zN2UTQu4AxPXbR9Ww^H>8hr{QdsuCo_!1{aud+Cw`ow|FUa| zjOWcsMyjbhzH)S&ObLpLnpInVCM|YP#YV5!+1J<2JvYx5yguegr*PK&eYH#F^=)lq zLCv`hiHEN&^PO!ZfBNRrNs}i(eg9tH6SOMJ%d4yOUMsgaXzt%L>)IO0LTLsD2J^Ym z@on4F&(HgHzW(3hz{PHn`M0;_&IXO>H?#AHRn@XJJKo(@dO3Uj-euMA_lC>K$xW@> zbFi6R+sZ0xv0HCYMMcF*f#ip8ijeE`Wlc>@Yd#-3bZE-NiHeg?E_w3gN!RPySDeb% z*UVVVw8GCle{PVoG~4T?ddXL9*9hO1We8B)F2^|2By-X-zqzaQ_x}kBUl$V?6Eo*n zkK|(UxQd0RUcb4xxZUpWm&-xV>n(m){Qmwv{QtkdSJy_HgGSKGzJLGpX;WXqlIPB)#>wV!<60o_AF$WG=2JV(4=l?)t;l>;@L+!1iN~ALQ+ze-2L0m zC%dYnql0Vu=C7|-uYa}qyj}3)W4&7w53`+}X?)x&|JIhwTRRFDM{Uho3YuB3tE+qS zks&L@D^JRofnmz&wf;`WOIcZ2XW7^9yS6TNweM`RsXJxj_cIkNmNMtLIGy>~^_|bp zdLAfcS6>(`Tzd6Xa@XVwg?BIe+pk@)K;h@FUs+dIg)aR!$(kW#`GvNFvo59b^n%Qt zEVg6)(Qa|;zu`AjPyTtv39gJndUx>XGcYU#7vc;DQY9E0Lu0<*y;S^es^{IW#d+MTIw$D@%GoJZWe|HE(0be26L^?JzI)&Y9W=7-lW1=atsWh3QU|c$B&h~()26TA+1`JV18mU)sg>cMGnv3P74QbvD*G~kYd=%{ zBez$4%#8vm3&;gkFfS+nKapColAD2Hfg8k=;ED)bUqkf3NpN)layw{gKe(7Dq22^n zdkiQfQC0T4gF|>+LFR)&>#6)hB9iZ4p5x|kh!z4hYjy+#zG6+?|5>URoFo|5aVct= zFoJ_}$BU!augp+`gmHLFf51=QiivIvJ5mdUtk(QW6DyRAd$nj;7HDjNlOaF~WEulQ zOq-y9x~PcAiPNV~ug$&#u4>EHOZkF_6QHdH=y1Zywu<)E_hdh(aP&QNm2#N-Xq&Ra z@jlsLAD^C@ni^22^5SCm*PouA4y{+dxUl)_f41g@x8|=un4n=A`lTXOH@L`l-@bjI z37OI#9}>S+FcgSarkA|EVDXEgfgvcmN5atQ;>C-g6;DY?i}vi{xZbIRV@A?wS-m@cljECenMF&c%m^+n>IDyY|bM63Dv1E_4{gnN4=juWy+GjzrSZ6?Go+k?VYOfI-}+7iX(lp)+Mj5XzqThl6h-OCa8Ek zH{X8!jT;f*nc(~u(j}APXFk4jEH0|8~(4@7fsOZYl z*VnAd-bAc?9u65C*zOm-EphptV!u;Wb=yFT)!XH&Jl^m9K5v$}{_o41^kR1vAQEWj zEQ@tF{{Q$}-YpZ1ZAf{$EF&i$-?b)IZqV}8rAwE-+`j+s+Iba^I6Z@|uZsmu4J=)@ zOiNGC&$jBzhI{9Q?6i_NlYW$5ZK(1g!U@UDph*6n+F@&f`u6_{##d^~8FVrKfh zi`wh=D0zOu=tf`twnI@-(W>sxj>F#H_|W_Bzop(bwzs#-RX!11x@_62mCNT{dUbX6 z>DYS)D_h^i{WNfAy%U#lIAQOV)HS=>OBYEpFzlFdyRX6K(+TBSw$EQv* zsoGY5+j36cBxAy}^Yin||G9&fq)nMLDd=I*-{0TEot&CJefqQ|;UH7#`+Ik-^8f$) z`|AGw{h(#7<@al^r|y+7&zrMp^JZ-xg#&9JIpyt2JF2@tkO9?Iz5?u!Hl?H|>ah`}Rd`$(Sgn8}+2% z-}n3V>p}B5;`@KJe%&_ddFYLQdy^i{Z0*5YlCVgXsr$E_CRZG76GJM+hOey)J`*G(=pEzWXo&WUire>0&dyDl zfdSM$$X*h6b~)JR3(7GPAfO-vEpURcan{J7Fo3jQU?c-Yb0Yzo^R_UE{d3;F>iZfQ^VO>+E|D?669u02 zxDs~j0BF`DMAoN{&G!EJ=&uz!*Hw_HlDi^*dj=5A8QIAHf<^K?n^~E-Cd-L*LFB@lj`EI?J`=(4+zEnL=Ae`Ut<1qKr5!JN`&JtIf`?rg)^W%${51Q6QZGZ6q@PoJ=>0QF zi1wvvpzv`~26lNqXrfKR9JZBL{0N;QysW!?!2*Z4xVWYN;)DAGWlx8OJxtT@<6vMY zc>Rele6RJhlL9i23(OXOO~u+TddtyqFhQeu)fp=ttCANFKK!3r_~wS;(IZDr96#=U z@Zdoy+o~;k@%v(4ehvHjk&%HRpl^@yuCff7+7*d;(hg_RHkTHC*}VDn1`i*fk{|z1 zNf;)zELyyH>ZD1FjvR3T?IOCg#B*v~eyBWXTcPNVs#$UZ4y)o{Ut2qM$`lpPTYIaw z^RP9Sy}P6N@|T9|>uYOO|JpDm{mwsmdlSaszFptJgbQb88eiR6obGvPU+r(uH0sY^ zzqCwDLh|?j-4?bs>gk7#Wp8gSeRp^F>Fd|SeP^3p-IRLzRE^)Zocg%ERa<-97K7?3 z&`|B|{Qar@>IzyL)hBD6 z7OSVK>bh{@!bwZMd@1prY2<4E=R@9i->>(ZYxVN$_4x4PeX>tqzkdB?my?rI z$)6t|jr6;-tNq-t*87h>)Pef#B_*KUMoT|@DA<~Rf8U|!lcr4z)A|D%b^+}zRG(k7 z=-=Pp+Lo3(&-|8F+j`-yw*0dd467~&Mg>fELiEeeGBj8{n)cVZrS|u?tE<=V%d)+{ zxcvRSS=Qz2l9FWNzu!E4+FMgobLqeP`|ImfRa7+e_5HcUbOOG=yL-CkjJsT=3uySM zQ&@e<#EA=UZcbmFetsUGd@^c{zx~ehO;umBo<4h)_3FyXveS1fpU;ijnl;tN)>c$T zCdc+Z3&WkGt#?Y!c11fVgPP~&Ode5Dvtk)eo;|Bu%Czg~g@w+df`Wms{%=k@d+D_P z{xuUO2EZKY!~8%R8CUCc>2{sV89JXv;;g<*yB5APQn9=#4{c(v#l zuk)9u4L{Ad@cA*Vv$o)zJ8Q-2FuCA4Eqn|+Ok2!&u1(QP&R}7#+DO0$>GvzoPm_HY9`T6t`<(>yh3f?J7yrAm zZR$Hdz6TAA3=E-%I5-%VFMawn``yE26DCk=jA4h{tE)A$AOp=YhePgr2!n^79nNxp zG|Q@)9R^YsBB{RcuvYCS`JFuarHl*=S2RGCAy_*DjKtYbhg8$xItbK~01cr-Ru&_Z z;MxjOH$l3gC?rv>f&;b{mzW}c@ZVi^Z*$R|HLKhv72PSwh73xLve0E^Aw4{`&KmD4`ZdH(DfQj!@=kec4{#|PsVKlj};VJcvr z)55pf`~RzzJ9b!XU!`ej8JU=vn74iHosD|sYc%cb;sOH$!L{_&s+f;eyjMyQqtFRk z?G8Avy!d^`UA}p*ma*q)nO?2hzVUycuxTi0#$Sr3W9prP6u})+!PWVzmPJ>%x&G{b zYQh8#za4GQm-4`x7>h61Pk;{Di|@%aY}HD>!6C(Xr4Zz}eKTE=CT#{d9l9G}@OAQ}9Na&Tbjhe0> zpSGTv;lSLd(5e0heT*qzUtO*G^YJ)n-RaD;X}YnyLip|fYyhol)}D92Lr@ts#6D$; zh^m^}sne&uC#(4;fsD8tYwOF;P|l-(doCV*?7Hpo>-P5;Bi)hDC3)CDOT3V}>z^-O zzI=6cICz8c`~Cm--Cc1Cd)17QK44}P>H*ekqRjE6i{yzJ{P;i_fC?H_L!Dja9T&k1R{kQ$I$-QL)T6t_${cTOv z*H=qd1~0dYxqf1zGH8r^>C&Z{&(6#Qbz>qboe8;P;we#&5QVsBS^lyE9!pk=EY})Smx;opp=iCh1UH(2S zAz=Y18u(J|{rd;~?__(N`VB*~A^X9G7 z3|{u4UB2$ZzS`ecmibES#_x-nYgM}HOY!EvJD+?uoay7`;W6Q4%BIzeUAx6V`#EiF zZ9_vsmRwsK{rbkn0HO z)I7X)T~q3Bw!3BSAHRQ}uJZHuZ*5i8qYrB@U%qUbf6oRq)?fYYji%}SPigy?aEt3{ z7<~8@pPGAZ&CI)d9z00Ujo9EY2~-*W{QUfNr~14LpsAUa&!2VV-Z*jQOh`aLz{=Ef z^X>KZ*Uw*{m1-i@d53|4VaLi>B@7=weY!NuH2clIwyjlPvv!-`g%7vue(v3cZ8mOUfFMfP{{Ozwmxx-7uc2z$;EF!S&R(Z zS6J2Zo#+zPHc2|d@!IntXs$m_^z@?m{dJ&~%Tp&$UYvS*nx@*ZkET08JLo|>kD|Bd zffk0&t>bHE=fAedwR_6csY@d_r`=?2#@=M`vo+V(*IygAH)`k3ouc!kFD-WGUmLSC z==QeU%Wt>e&)d7V{{KHO508MjxOrka5ewek-M#rZ^Ny8zPnKne-C>eqWMG-FEAz#L zg};70?iZDo)^0wy;Kq%J+D|9dudPnVY?ppSwDIHJbmtW?2U`Bcf!_0EPQylUE9VcM%KDa z=ey;eZ@02%ndi?-N>2WIuljvt{(Q^E98Sy;JE^-p7I;liU{c0?sCYwK0SU50|Tf=H`O6w$e}^S z&#Apv@3wU@e3T8%R`j`o23PFR zh6YL#gKBg54b>lp?)1D`)+*8CQ`V%h_sPHe3d(#-z07_I3u5|_JYy6&j9X1LQ z%Hg>Xy7bUBzrv?C6WV5S{lPKyev5b}OMrI)#*_hQM3%wgM?ixZs7Y8Lx?P@8Q$u6I z^y%W!w>Yii?=L@e_T5$O$x9Bge7_A@j(Wv0=wTXoNkdd^OeK8kpqJr+QfVE_lN%e8 zyE;23_V@QUH8-19eaVR3SM&3Ee2A>ol*;(#g9V5C1+sDPrdlj@+Jal!K=dVhW1K;k?G)`Yt{QO+m_UM2A&so0*?TB<+90)2_&w2a% zhp&&@du55I@ZSIbeovK4)yTiQ?X^|WlMW?iWzbwh>FaBe`Jh2?)P;oCDl;=PU)|lk z{m$?LL0?)Tv7w5)X?A2rN)^Zqu-~o^30~&@kzh`Eqs!#v_$j#{(wS$;EDv zP33?L8px~z9hva^`}^x%qS_+T(%E}!PfgJTS;8l8w+7VX_d36MP3i4lr{n)EQlDQF zBwzn$BWUBt-r8GRGOIouWH0^p2E2wnc)8!!-RCbXbT0k%CG+i#jfeAUF$XI^jiDQ# zAj1pn2U;;UX0CXxzOq`3U6kLm?a|6>9{&E#uTd=d-H)^{b!|zNoMv==@q7ZH!GMwJ{c-i)Yn_ z3@S`e0c{ug_va^QMB&ThetWB!eNSdrM^9@AxP&y7Kl84Qy!`y2@LO6sI#c@l`-5L^ zn>usm$^{D)+O2o*-@jkwoTi)8M7 z`{Lr_P_Idjj*g(CWC{ujR$iDgd$x9b{QV%srG<}=UHg55P1qB(MD63_<8$}%Y)nL1 z%*Sv%^sewNg9!an$<^-?=Vq|2ik)lE{$!%N+{HIHHAvaH z!&jO=n`&C|Apx|xEiy84mTC61*pAAlQ^P^0g1kI2Q5m$oJt=7sXmIN69Lvp@`Y&U& z7|Ky9mA(Gv+V$Al6$}kr@YMq>0`B*!Uh9JLzLu8P*;%HS z8=2X+q?{Cb{b!+byOxsDqc*u@)MWsNe@#{Qta{MM{$=<5zkap9z662}-`QVZZ~O6x zFlf`#Qu*gwug6{9Q~4RRrR@8?>ho2_t&$tOuhB@ z|Jmf^zf^0< zx%b@;N%e)*1r?!hUM`;xIRBkbLU7)e1xelF z`g&j8|J|AR6J^=oBDKEN(UsARsfpmhe8|f69q)E8eSSxK@~+pySwXCXSfoFE1|Ug-@P8e|~fxWEvss))r0B0Eh5#(cki=g+5agFvjdX z=N+Bw{xL;k9;mi;n1pS?GNb`jAPH&yAd}d9*EIXVgM-bWt+9Ld?iCdkT`FJqqj4F- z)tWyl>guNx3~u-`Xgz;)w3~~cf4QIoudMyLs z6>#>re@x6AHa;1R%{O!AGFZG{KEE!gq-4vvdA8oh4N_KhF<+xx85+yp-B}4baNys+ zf1vI93qX5yMHbBJpa0`Wg{!OUMS}%h?{>epv;F;MvkB9RgO87gt`B9~d~;7w(1Ill zo^_LIR7@wNOnDM%Qz_!#_J}j@$ocdBl9H02zI+LZi<{Tf)HG%CWas3DESowu9*G58 zwwS1@sc9J*1ad6}>D+dDghTU%RiZOxv}#xLjdnSo(z*Xp>{Ke)s|M?oBytM*a%pBLid((>>9 z|9}4F_bSzU8S_5;*eLtz-p=CXpcP(++xbB|jW2w9dRkOM!h^Z-)V{)p+7S+0u!iulr7rM%DP-snnFN;<3@efukGy$MX1o?Oaah1C^Ngoo zh$tgqREFqv zOqs6f#X4aT*C7r?(7qgp)I;to*F02wIcv$GNA>GN1zcPNK$bjEke?!Iv+iaZAOGwR zfe|MaoH#(jd2c^F%=xe(jnChcl~3)qLekG!(-ykCDEMLwGX6WC>?(zt8*KeSk%xnW z;yzA^Pg*v8N!8KdiM|IkejexMO|?-3se32wa?0xb;lLj!wm;$X_YCh=_ZBb|Yv(`z zXv4#dl*0+eGmpMtXJB9`&~D=|mRzWO->gK$KU_7|bjH~<&so}<0h8)KKG9yea0%O_ zSGQS&yfr>*2s(ibzGJ1hi-6}Wea!=E4L?NM zC;XbUr~7dGbYBKVaQLGxn8;}Q?i`oCJ?N5gmTn#iCO``=pe>(|dGUrbw{aPwcR z0RJ}7diV$1a`bmcub98TDfO>%^Q2?pTZGb?J5=_DDK$*lBQ;I6!GH^toOkeVZe~cb kW=i5z(6`#W>AyWg{eh%O=7;uxrY0FYUHx3vIVCg!0A~}=EdT%j diff --git a/vendor/github.com/go-json-experiment/json/benchmark-marshal-interface.png b/vendor/github.com/go-json-experiment/json/benchmark-marshal-interface.png deleted file mode 100644 index de6f3b6df807af7df6204bb142d8f29680f0506f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24868 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 A`~Uy| diff --git a/vendor/github.com/go-json-experiment/json/benchmark-unmarshal-concrete.png b/vendor/github.com/go-json-experiment/json/benchmark-unmarshal-concrete.png deleted file mode 100644 index b805fba23e55b580104b753fa1670f07618dd5d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25104 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV6xy~V_;yI)YPlRz`(#+;1OBOz`!jG!i)^F z=14FwaQSCCI|l@0&Ql|}l*f)3`szJ?yrKpmbgt{d!66c_b1 zFYf3%_4{G<;_PdCzCSzrZ|ilt=W9OC-F%+?00+-B592`72A-8pa)J+TGPZl@74)V_>Yf%+0}Yz<2fm1DW>!{I8s5#xORtFditG zXyMJ#Aj05K)#tQ~!NHBOVeSmIV1@-O3<;-`lO8h!=rSaz*FU?=&@lJM%xXr4=qZY# zj0+|*C}b_wV5w$EIH9au!O$|3LB#D-xXnlHbpp?|7#J#MZnD{_V(Ho#&7oV!9v-eIr*Y0x zTwBB}ktuPOgWjRanUY40Cj1XRpJ8BFFi}+SLG$Oo73cWYojYgNw~a4e_tk#3|4Ky-n{wr$&(viN1UP)Pleb1OFtBUApCF6&pMkw-@iWC_eiDDD7Mj^<;R0VXTJC> zl{r6&vnA=yvwrtK+qwV$k-e;R#4~AUgqFzTK%v4umsvfZjg~5PI!)3%s(R^v%A@-_ zznSgsn=)+3vSX~CsJkLInfaTyx= zXh`#%RLH;(=c1w)a%!{vaSjFsmj#Vl8yuy-9F)*Gz$SB$_0B==KM7_nPAW$ZISDv% zr8LMCC1|c`a?)r!yFpefLH~+_tjU4EjJC-Ie0qmMcktO3@c&BWn0HWPPa`Lb;|UJo zM8#Vjj7eP)%6%N-Gh2Ts9`s-l>Q+%W*&!0B3~!Vz->4qo94F z^~u~Pho2Zfk$$51DVl3;l0)H=AHk0_f=*?5Nj?>LYVwpVb%v2+=;B#HcULS75j5?O za$37^ThRKz_7%b=rL!#0Hj8Sd`6@r>`8>tB@Y61+QA&TsmK@Jpv(y1$tI zg85514{w`j^YM;!4awOO>=Nmc>_$-sW+%0)L#K7F}^^E5;`Df;bMrdu*su7)d zifgLZRJEznTKXX?S1nt0Zxwgw=g`w3{VU^wYuCAj8V5gK$$4ek>d;kl16~J92dA&J zUeUfPeMNqV{gS%KznyH6hkXwFJ1+@burdDeo?{B!$&#BZbQH6BSGScmnjTTxc=l#Z znbz(Ze`R-f+pb!<(9+r1%Q$><(B~;>_Uw;m6#ke~;>Y=1WBK&YbzS#F-fKS6lwM}y zv(qp&CVSPi>C+-sd#nyz?f!bN*}AvO=Pujpx;yfBBcJ1OFZCF8_w@dAtaG0S-weLH zoNKw5udUVBb$Y9^mr5_(?NYu!Z~40!^Y+Cx%=5`#ey?)x^ItNx`hP?I=Kfm#)tx7T zZ8MJw+ijk65;jLo3-fJc^^f2F80Z{(*ui;e;?%_H4_hYgylAuds#~uce^2JIn8zxQ zbC2a7Tdc;Wrl{ua`^xv-tRUZ=%QTl+`&j!NKYQlvqO;d#n$EU0yl(V-_Vd}-XW!qR z5LFSSvu(w;9jTt1o9x1HR!a=YY)r#IMcuiKWptu`?|Nj!b~(RGL4P2M}Xc2{lhUt4zG_M3dGWus*4 zinkPrScO^Ln{{r^JNw$BU#7j(Pmee+aQ=qz<88vHHIHP@4W513JzYF~XL0lAj_ywH zrqg=U?eu0#AG>>E?-Q?*uZ6J>t1f+=JA3o&LvL5yUjNSQUFN&?JM+(&%-5V3X`jY`Ks@U@5SxD*%i%yZ1>p4 z{GQRh$oMnn2ezNse%k+V{=E3s`_A>s|5N@~{lCbtyg`*Qow>8ou`!zI_m8R?#r=Ku zR<~2XZMyl^v1h?fM^VTArnOB^53W_rIPqq}TE*|rXPldOE|ae{pzg)B3+#!{61xxA z@u;`9w}!Xb_Z4(RNL@6XZd!ivj&t#SmtQW^T<*d|8{wJbEn}&twazRrXW#ulZ$Gy`n)`_Rakcmi{S&bTl?%@u`qH{wY^9!% zj@2{=pAJ8ZDIXjKv{s1qsD2VISMB4fJS2N4T}l6<*~N|<&M{hYexE$Fe5)qCnYhQa zQst=eQk|zeThv!h*yF?Nb9c7YJh5423b{tMR(lPbCrzAC=(I}Fck;IMSLx5v%1*CI zZQb5r%eBpE*^7`Ujq6(Mo6=Lm)Apb3JY_j;^*rsfZ_jK# zb$f#OocHtpzZE(p^l;L)rET8fy0Q_^_O8jY++CTJho3?8Dv*~h0(~-~Za3+;=;aG1T{J+SSzGp1(JLw_n$}>gA7VzjI^P`sEhBJf0yI6x>eRw zz2+hNW%)AMbXol@r&*t7xy=rq^*cH#dYAthyNlOe-K+ZJep{Y@j)_fVrPt?>lbN?( zHeH^a{^@+r+^KVG>-2u!Nw~deTlMqgbN93O^WX0hD0z6v^?&zs>pj-zVm|FC`LyZw zQ{nI(;j`9T#pk{%d1do&@@40-a6iNzT1A)KKkFC8}IMb zXB{YC@cH5$_wQ`2&FBA3{Myg&%-TP*|8yH~+v|B2c9xcp?2G=s{IlHoe9C#XdE);T z{X4x*Tui_2$JN)@&t05xapCk&(u(=BbWCpF$qHk`xG!P9-yST# zQ!e{{@qK>(Cp8N78viqXZu}a2VfpXLl9MO@XJMZ4`A@R3?rjDJ28CpgAYTTCDpdxC zhGqtapZ^&c8eTFmlo~KFyh>nTu$sZZAf7)d{-_%RL%6l4i(^Q|tv7coD?*GGK1aPwe-ceJZ!z?PsojARoTzT^Bn>-QXEvE&}D zm#&_@s+Ar^lb>jys~0_N7GMH7ZT*M9C=SinCTmVl+O$UT$-+}C6P8|k@Nn^bH+v~@PKBfI>s)_; z{2&#^p;>3H6V0%5(R??@O=~V6e#$!G=%gCeyD7Z#OJi&9dBpr?WME)0xuOtMBXXon zE9_(U#m%a*6H4M-*Kuk}IXv_Jw3$udy%OUQvtJLhcokgpcY8B{bV%hfZ1k<%WhIm( z&AO3wLiaU>Nt&j!S*KE;{bK{G!0i|A$$v}kwrf9R1|^sl5pKnwzg|`e+|G=c z-o-NE^CTk`-whJUaZ^MR=GK&cy~Q8Rkg20*!_L6K@FDnzhHi_LElW=-Rf!_%x|x?B0S7dg4R zE{_v*VPIfr_;q^9$9?ygo~RMeZY$88rh6xM=i(ndj~*^wqc5HE1?0Gl2%V#cI+otB znXbgRWQ)KfwUcL;dfX_`Rjv@Q0|nz0F}JSgEYppeI&6zYWR+Itd{C$XiEGT`*AjM- z65YRV@tOw*SAd+}@TsX|X_LYurISk+U2p_PLV>N~5yhU6Z+ziPb7er<4ldqPsp{qw zb1I@?0VpgVR5g2cGV)C~YGMP2)q!3PMZW%>0pcLV=bXUd?SMowfYS<;6aXhyWU_$) zltv&VgX+#}NBoxi%vAEM`uTMF`s|s%7Ff+o58aj-y=}*_UTJL$i-^0s%fs9GWLIrv zJ0|h=&dy+2>#{Y$wF$Sk<=)z!Ki{oaDm3ZdLg)4^rLV(e?dxKu>%|70o~Co| z?CXAddSCUwPcP+J{b+9ay^C|p@2%YZe&6iv&AhxUi&r82+?D#w&zjXQX*22ebpn&KW)4kNfDeSc-divB-p4Cb!DlTttZx64j z*`ww&BS7E1i-CdRdcy*qef#!F*;H&$dHLkzWRWEuxwp5yJTuey)xEvdo#qc`o99oP zJ$v@C9?8Y=|2|Fs^!@wv*|TTQGR+ue)<6W^MHLKBsAms=vSU^7Fg4 zE%&wt8w11FkhzkK8)NwmDnF&ve!1vwRr6!Rox68MMManHtNpzyaIqWT>9g}}qqDEA z2~0{_6cZCua^Cj)i+#V}U7o5PzNPAG7AW-O~xni>&F$(1*5MC{zXdwRxY)Pe2JSKsnzV`Rq z?OwjVQw`nD&N2 zAOHO6)0V`;Y;SLDbQaf(nXrESdaJTGE8_N6S#DXqX+87HSD7WRudTiO?(XiXbLX!8 z@S%WL#vI=jNit?)|s!FUY;OC-U99 zcf0=o`>pCZzy4okr~h(eW8<%1ug9-mu)x8&jYsq1GJg9%0n7d7PCA-&(bxR0is!HU z|Nkxj|L3_q-)T_ZI^HjT{psoH-ZfSK{{4Rc`amP|q$PLm#MFK~Dqd7ty48MtcINf1 zM#o+pYUPgFoYt#ixhHY$x#Y0O>s2|uhE?D1mT#^9U-x^Lq@?7n9fgbi=2$GexY+%4 z(#9#f-#4@KYZ)5{2L=W%JvVvDi4!M`uJdzpUYuc=EF-6_p>g5S(eBb89}<5jKR-A3 zavQI7$(tL7y>hm@j!1v(%9=HQ{`$(#&onJ9Z|*yHak2Z>f`?AFKc7tgRu>f~zfbV% zu4%bj^6o}~qO|VMNB6sRzu*3u%Er*Z5VYCG*48xZipI~MKQj-v@&5Ytdi~bg-`|At z)A;3VR;bUba5{MKVATG)y=M9M*8Kne|KI#SfBt+qBJ8iBqT-T$ZOz4Ly3t#TpZoou zeP#W=UtW_;QceiCy1K61up!`n&F5abzh8pi-rBnQiutd|$jDhnsa;J?O>g>h@9YSi z^yPK@|EP%*CmJ2oFfj$*8ckahYlY$O*tW8ntja&lsi_1t}glT zz_IrG-SStLmU{2}?dRpCWjrM{EzN7!FU`8pn%{4?gK{h=0FsVy+^u@O7Q_u(6R}Xf z{!ifjy5DPemA#Exdi~%u-RLQE=B#OGVEFrO`~FY|hlWRwA5Wb!WeKme*_0RhOTRum zb#3*Y6Mq4e|>rR_`hfOpZ)*${{NRxr}bAyZ_g_#FAslw ztoQ5b_0_WbyE^Snz}gI6tCJ>PHl&YdUk-i^JxtMu||{rzi}&#&8c z#Egw!Zq0=Y0Xui^el5QL$5GzQ>t8djte6;Go|p8d2-#=6XB(v>xln}t5Fi`l8<`RT)l6_-BW+*!PQul&~B z+hM)Z=GSD)?<~A=D*<4%b%nmB~qIMQ71(lq? z-|aqMXIPYZU24j;b$j;gd7Tv=dc$t#zLJ-d{(bDPfAQz%=UuPY?e?n83k|&q$(a80 z?Q}h>o=y$-x|^5!?n%kNKb4-7rcV#=teiJ*-lU}~Sy)UrAGE_>IdN^iS$)6bBZfq`Yh>t_!iF4PWRr=hOy-Yadc zXL#SND&Us-NmqI8_e`O;r7t{kT=wFh7q^ADUd)B+_j|*a`p4Va+IriVWn56Gtf+W# zJAePxMrQUm^R22YD_=frm)A2~74W6-+cb;bCFZf`WoX1O)?M{i>|2ytO&KALRa@ zzkgeQ`Tl6(Q867a?nRa#;j(Xcg-x6|v8$uw z!o$PuTdTfi{r%WquT#47&>^Sav*T~i&Pd;J?fJ`h@78IDuY0k+{_pCVnwoW)(s_A# zr%s;KES>WB+wJ`8A0Hpznty+v5%Y!+uu`4+o`u6)_M;`-K{!)0EHrT1>~GB8}3Bej$5NZG2Mw|Blj z+V}rowdXFy<^Myb<}OM4^W)>I`}_AVTC_;UZt2=rE1loHdzW>6-CVaGiG}~)|Ns48 z#ZyyL)AZiDt{dy@EsCCW)cttK-d?#adhabaW|fymI)%6H+kAW7ZH+4TWvjS2I3|Sr zTK-wqs$@cUcQ>fA+MIrV+Kl9c3I^mpjiZCr1BJ2Z0pouckr+j6x%LDj)wo7>C3fJ*qHq9Rb?*l+ji#VzZFr6NzS ztPH+dm1AA~P_I&mO zmn{2gc23iek4plVLC0mwLw3xaXIq{1^V8F)tyxpU) z{q@Pm`(8dc*!=DB#eKEapt^2;{lA@mh5uT=-}8BvTbatsWwY~w($bbaJ2zKbUS9t1 z*Y)*lrzPLsnjK#I|L=EDEi_Fx`kBFc&&g`9uCI?@`s>}c+}kBjPD~7HK6s#!dFsT8 z3+3y6IR5|legD_@_5XLfc>MhPzW#l|Ua#xxVz(AQ_mj0Q^YNahQy5{Vq_pUWZiV(^ z@%=wqg@lAkzP*Xu`|H)}Z^!rU*&`w>TzvR-=rzMV(`LzA7P(BytEgvVVBocA@VK-g z@$i*Rsott8Dlg8=G(L6i+_dS_r-NF>FJ8Qms{VX&e|^2En3$HPre|wwD;Fo{MceOp z7Wee<{QbWF|5fw*HNh*lmA<;-si&t0YEn#{HEY$MKQ*mwZL8AH&)fC+oOSk^*wBk> zB8@?cIy*Z-Ny@h2%e%YLtgNhF9v%U8b^G#mzcu5Px4TpK`uZvd8cRP&)+_rC#3N!G3;yb>BA6*EBNPbS3|L-jx*-|9xn;fARUe{q=Kmt*1_%s%md< z4|1Gs^|w9CxWC`Md-v;c`+tF;wtP^~q@v>D(${OZgX;3ByVRDf`l|I>BF_6PznqOm zeSQ7byt}jZUtnOk;w+Zzvqz=gvu;w2N~LF((#gA00WqatLv+PG#a^?RL~wF)Mr}-L z{rBUz{i|!y`AZedLB*eG{l6O99}k*eU0Es2%E+)F&*0k13sz5~m&bU5#wJcpnxd(B zxV4HgR9IAW>9e!5vtM6ZEAp7__O8;^hYlT*(YwUX!0?ruk!6Ka_t8ay%5E9&@9q7@ zy{z!>q{)-F=HItFdi3bs4bfiA3=B*h0s1X%ZCMug29tzuo|%SIp%A^N~rMJzq#K7+231+W%z{0GSIR6~J~NlMIY33=9ko zbDw!}N=>^g+4}3bd8L-gRFCCiFU>FJWxezF+p1|%8#Mjj&Jd$kQT?34iO=)p!WKV! zD01#pjGa#Lm!n?S&ljD(yvd|(*_poBhl`EKR& zxuC*t)8@^x)Bb-tt$%fOxW224%ZmK_`+hx}o$r7h1rupxsBIlj&t6$sSmvcqkecy_LUoTF$)t3Ev?UlRT z==kDoTCXLpEZbi$>h)*(manpzw=Z=qU;92LcHg9H>ta{W&fgcAn3%Zh>$PZ5k3Bmp zDR$L!am~zMIzQK3Q(YcrQ9G?BEPlz7t1n(JS#^G=-`89Lhk)IpVqxz;9ku;-Bl*?6 zy}Qfa-dgHA+wA1ktD(keXEvO_zrTLJn%|ri%jZ>j?Jj?R?a9f>rgeWRR8>_ibDq!t z|7ZERdA89@Yvt`~B9z^FF3dDe&x>K?=2}($Gb&`i{r{imXW3M4`u6Vb>fi78$NSs; zeA26tV5%Sg`KxushX=g%cf*dGovyt*`%qTozD17%XNNwMxbo!n)*|**3!|;J;}&pWVE_H? z?dA7%->oYvD>XGVJT5QyzkXc4K4<>_@B9D9p11qG=H34Pb(NKsFF{@VBb~xuzwiHl zH_91~VT%5P>XIkyAm&>Q#a*v3Z zA*LI(B=7Dn%QfMDB(6;R7Z%+kZSGh9|M&f?+w9<*UT?p$ zIqUrHMf(|-etr1p@AnfEm3O`0_xsAaSnJ#y8yb@tnK)ie2UVcY&dluU@4vp#x&6tz zckA|6f4}uS|Ng$%@AsMGH%+Dq$})*j0EU4CwkXY9syPf;#!-oq88kxV||NrlLV%`3_za^J_%{_Nj{rj@M?yGiX zMMcJs4-c1abDU(Bb7R57!|kU}pZ4ar`Ot7}ZFD#+Nr4(Rb-!=lKXv@LyRf>S&c?Ut z^J~NI-Mjbd^74LA@Vd)Yy2QoBy}G`B{-@8MwQGI;{dsPG`ts$?N2*E}?!PLQn3(u& z<)**Ws>1$NhKHO!_2uE(=+2tZ32y>smf4_cuT$Shi+HW&KrY0V4 z%RJP=`R(Vvefzw;i}x73e{*v)7YB#NMqPP%dE0+K9?!BYPV4j!DSLBc;hj4%s;a6h zi=Usn@}BKl{{Me}Pn|dsus&|@ig?Yh+UIX>PJb)@4AlKy?mu7eqx=?MH@7y>=%xLi zhy0*H!kM>yJUu7&_xJDhUAb~)YTo8`vi+Z4O`SGPEj~WpGbke?qcivRyzOuOLXY0( z3H>&Mg_ZT{&3|FhpaSGbMxZOQ=eWi7ru>w87}3DcWcBdf?)TSPxy4mHD=RBMefY59 z{O-qn)^EyBefawI>S2ESHOlUNH=dWjy%h=y<-^~ut&Lv3`~AM%S8Bh$zU~hiL)ulk z`mdq6xq0cE8-e+IKDNEv^;&P|jvWE}r9<|EhHc+&zkltrzrF9@Q!C;tnV6VBV@AKF zH!XJWw>q;uLg(9j`N}7Pq9P(MuJ8Z1b(&6O&@(e;X6DkLpHhF%=BTg#Z?rw~c1VfM zsny|^m-)VZzH9lCB~xycrOq#RJ-$Tm`}SFnUcGu%u(q+}>!B};w(IJxz8`dc)qX#% zU(x}Rb#-;$c3s}?$ly3vL`rHEXvk7rKkiEP`@PGp-|x9>mw%vv@z?MB|JMnt`+<7p zzmD7gTbOru*UjhlACCxEeZ3mKweD|KYHDic-Cdl!*|S%F zzu&)pppp4>jJ~F(r=g+Yt2;Y4i|Iy%JTt5Q`f90Z_O%z6mU>6+EK2SCye@llSD$<3 z*RI~)tL*YM3)ZaB+57X^?CUaHRu%bpS+i|jyZ+e1co?8Fsv3%9rt=F$CbY=$)$by7>Srje;jRC%RkpV6|zJ1%b%q-;Tj45S2S<&^Yd4GL5T{ z{CR86O{2BZ+x<>Y*MFW6di2)+-BzJt_n)ux)42NE-S5?2Wp%B+f8OWiF1&wF%I{%7 zyyWYUjJcoI2CrLkdeSDyIw+oV=y%ZB*>8641bT$&W9hQ?DFZUo|~HVNZ;7=<81od+Y3va(En`6t9tM zIb;3lsS+%ikMv5jpK68sUC|CYQ1dkBuh+9nOS|G@=FR)`;#O>t>hs$(ZDwBaU()1t zr*7lKew~AVRk@W5&i%IzT(I6xUBmi+k?Oq=)4=b~=01IOX!h!;^$PyCK5v{7+(5;8G`ux!+CuN2qV>spmS-#9m3^Wg&Yiz7p#Fb*xTu>0q+vft%;86l zG-z(_GIH}B!iF^5AtVE&;f_pVHs2wQcqj?6074@792^)N4{s@Wcqr=bzHV{-OZ%$s z?0fPg<(2#I7xgmnzvRCzuH{|uU(g{Soyj9COziFI<8Q5Nf0=w;T>HhoPycWKuZ#QG zF8qfWi%cS00iBS8bW0#4#77Vk;v-}d#dpa5g0P`J0(VgukS&$MNYr{KuUhSlQ132v zvb~ZWX6DMkz>uNPRI4LZ@tgDSGXK}F?@rn1*LqF!zSUE&T{@c4LDQD_cuMww`$N0| zS<^0_+Uq-aUp&~+7aZp9f8++9ZhRoKulF;==2h_<`dtsd_bL2U7prNTbMF7{b|E35 ztlZy|CQlZXlJfffD)YCHu&}78sO#Sh`M>>-z5g$++j4&8-}j3ye?Q3qngVB7p2)&d zmi;$oiqz$$VddAZMEy%zRD1nh`j!4~S0Da+E+nHgzw`Wwz1}AOXEHdr)*EXwGB8|U zZt!)@rnvfvP7L7iNN=4W(!~G{xjA3tvkHP?96>v$C&nK$xfmIy9&mlJ;q~mu6S)#a?x-L*4wZ*SAIvWmKQ z?_SouJv*oAMyJhB-x%@b*X#A#N=i=e-o1<3TUEOBnzy%i@cOvDPhP){R(dmK`@If9 zF!Gi==cJ|kc`|U2J&#ztf?Ck966?v&|51UO2{&Ih&ar&y@ z<$hV0m-X_=+v#}z`gmNv^tf#Kh1ZN%^n0TNm>CorrsQ8<<_oGd4kxdT+Is1B{{Gzm zwO3XIf*RbHE?qJye&*vl%j9I@&%^Ef+27yYjoMeU^U^?l-4^ z!&-Fh^y$-=A8cl~*0E1I!r?p9=;*)STQV=3)cz`&Ygz18SXcNrumM7^+>BD845#Ik)Ge z;jt%@$y_~#t+L`SNoA%b@bG zrG*8#JS^S(Uo>j7(>zn_l<3Vat4yO+A~zqiO7^Mgy~7GxHjtT_nRRbZ|e9s{H)*OG{OCsf(@3$*W&qJ=}10!H!Sg0;76WS7u*d z2bzNm3J#t+VZwrUcXv<>lo??XB8+I5T2( z*xDivW=BUytD+|!E4Lrw<>R}y)O-4qw{O>;Idevcaq*_|$6ERFM{jO>`RLIiyV_qF z$9g1R-P*d^#>VDUT>2;7UD|aP>$$GXkzXrsP{H=<=DEirvbQGAVqge3f8~U!!en)S za6js#`urE4o}Tvd@VIbeWAfK0ll^Z^zqz-1`>*fs*XP~c^|IIe-ij~VPDkfoSm0Ro zd~SKk!$Yile?01*8khg`(^Jrx&)=pGS67GMe&3aPd4GL9XrABF(lTm8LgS*vi{E|* zHI}Aohih3|N1vXi8=UiI>)rMH_SEj!xpOKh-o}TsV%S$dEo{*TBIdb)X3VWqYPwhMN=xDcT(Gw3>H#aRKqfM7?>*eo_ z+?G89SqzySi1nOPypl)%~sVooTf6P6cDF&psRIt68 zc`jL#g@NI#0OJxy4}bslF(tK6R|p9S{a|VQcD3WyKTZV(h8>168ldGo4C$bHj`QN} zrRrJvYP@ToeqCI9UEOQay}fOse-ABX7xySHn9Rz+@QTUJf#FK-O!cKd3a>DN21^+% zJdbf^F@S5jIY;)hnldne+6#UU#Pxb-_{%adtWe&;AzLX@oDy}&4u1?^HMHdjJm&1fxrCkPG9f4qA%Q+Gchn|v<;C0aT#Rl*BpVadXNB7@m zXJ81BHeg}`wcwB!8{ulF5opgqS{M%CCI^J1tSPlZ2tBC`+4j+@mEU%KP}$o2a@Kyky!(y-adgA3H?V-aBRt1@IaU&;ZF&I6JUm0j$F z=PwgrU|4YNu~Ny6uV;0hnCnbQ(97gfK8PybgHp?jR&2BqA)l7_@FD`B=}zjmgJlo<-}3{obGIJL$^4+Um2j z&Ce&^t^E9KW$o{8p||2IyYg4-Y%@F9S>(4W;eW*|a0=7BeQ$5IX~F@9UU~btlP6Dt z#$4sK-(&dz$dcKf}gCr_$O^Bj2@7#KJdQg3g`oLu$o&C3s<8sy8j+xhXA zzwIi2zphu>+-nl3t?=&d?(oX`#csWqmUvE{GHu$jna1f^mzH==dSdV?=w8uL-`Qrq zd#k@+TN%9k%I0)`-?>&-?cUE!pBK13Zg0th1B|ub@0Nf0_WB{HMS5=$A86s(%DDKJ zx_5Uhw`LSRw%hvd-rn6}IuQx{3h(!P_M7^Bd;Wd@@WB7?%J*Mh+;3MEdwOl;W;f%s zGZVIN-wqzX&A%V_|HpCrH=oPi+)#{ z`KIXL!GpU>UQXJxcQ0r?SwjQE?>!eT1f-^*Z5ZwWrRV3mS#cG&8%Vctj^^iw9^C#+t~@Qh!`ur0Xxu4m-pY_mu&( zjN{eCjmhr1vAaSpFZT~mNLcXb(Ie16RQ8n>f!9SHii(OrEBazC{}a=XTQgDFUCYQQ zXyU|)e6RUstwIC^1x5A3uW;+{SpZsA<~!T$DyY3}S^VtAb5Lx)zP2_Pv`}+fZuHL| zKTLk`%`ejI4YvjPc-8m&EppP*uMM;U=Db}OJhk@CyWQ{0X2jRr?D}S&bHjjF+U(4~ z-$y!y-`eZP@7oh}TJ&yuK){4+Ya)YR?PFqQ{`z!!yq3Pc|L5oD!>8-TO4YRIzmhz% zT8@EX0o%@ireCiwy32#sG40vAcWctoE}{ER?p*){`^%-%PTy#c-|^)E)62enC7{_n z^#m3c-soqZnsqXzpryqP41SXeo1_>(OHLWoKjuSoWrOgKR&V8J!JuWi>JODlZj}C8 zCXB_N1Jmz^%Ih0^z`?$|LfG~8+s zM4F9+RF;sc5ki7HxZuhk(gXmPEg%nLR*+b#NysPzG6`xsfa?K}84&A`Nr5s}!k57}XxJ=ru68`#0(p;TuoL>XhN8SWA4Hh(VeA}4u;H~-E!mj@rS z5{+73^LmQ*%S}siJR>I=sis1j111hDBi*#Wo0a~m12u^l9GFZ0bxDJVFdB+~n4MDw z4>_!;J7_1yyWjZe%ipC-zihDl|6b0^!(+wPx88n!VHp`3pkBB)YD=yE*G0SK-}ZO= z-B*X#S^_uLek~5n@|hlWH!?W;XLskfspnKJKo#D^>ggGA84L_21w9Q6E6Q3|rceF) zt6PK#oI)(LTb2YsBJ9Bud$WVSnoJA~3JnYeZa+9CoJZMR@!2fOEeljRCuyzO%eXU|htUIvCNm%Xx# zmL)GHfEM3AeY*6(0f$~mV>faAxZmcs+w$+<`?vXM($0r(w?^owF6;Uhe$D9U_Q!AE zuC0E*H=LbMX2Egu5=-^a4fQslWX>`{I`_$miCvwYfnHu+lO|1i^6c5NlatlsKYyDv zY0|2_XOBs=zjVue{o>-{SJ&3gcI%aL?Qbu6%3=yGXryzmuZxv3&zrMn?_NFL^fdVZ7MEEaTiR|PE}dVIX!T1VaU@-pAcUtV4=eRf9j z=+UE@$9g2cRbp1Nek)z`^45V0(RH!AFFlsF>MtC6nnWS`@Gvc28i-I=$yt-ZOgcDLcN z8KAD`vhw%$j!7i{`uaNk+WPqXGgnIzgMxzI+};s2?^3;8`Ma2vpFvZelc!Hl?=f7q zV8HMXJX1(snOF0RE4SZXMg|6lv#Yjmf5^+hapB|R<4@nd)vd3u2Tjyh{rmY` z6|`apG<7zoXV%*+|C#3;^NYJ`s^%IZ>0Y4 z-oM{&f2-^k*S~gRqOz!@f6oq(wCQ1t8AsFO!3YXVPt5CT5@k* z)6=(a*SdC#WnNt5y7b)tZ@2S7dok|Td_Mc_cvpOQ;Fs@DPfrie+S$;+(0==q7^q1G zug_24NsGL#|N7&mx^0~u9T)c1{(kW>qhMAQ8>oxTph3090yb&3kL@_(AydsX$c~l`FTtsj91Mo0v@bcJ=Z%RW&s&Ev+tbB?gACbGTJO zmCXa4byFD3kh{ReS-<~4`o3S5K4xNQuxb?)SfF>xM)PR@Vm@#sb->feFMt_bk3LZO zrweM+g9>G){RNpvYCt`PS2Caq^?AM(MuqBkn1kaDQ+!=;ty$j6yS+YEUcX-z{BE+j z^YyuzZfW=ed3_581}P0U2L=mYL`AO9z|c?(t;hu&7!JTHat;Ls;0R7 zfnk*>qy~c2$`BG#A45pWI zyGb!?CwG@_icr7eyf-Zs)KF<)Q@U|{QRDXc7xI5?*>}$u%LLRx@PPdVhNWqeYwz5? z^76MTxZdWy@>4qx(u6qo@U}%ixbMH<7whi`lRxJ~mcPF~_0r*IfA&{vC@LU1=DbRhsU* z_No4|wo7)?9|-*Psd0N3yQuOZ14F~Az5NSV7*?%9%m{#j8ag8Ynjx9<<+$<=O=w5> z9EZH(r%{e2wN5OrYK8Q5d^ZRM8x+PisYFIloAsD51+s9~?B z=BBBs>E-1$Y4+^dYX0+Lp1zHH{g0779GWKz+rrjHz5MX-@T4VgZ*M=Hv@zrLwY8Jh z^#yIoy6SbwUs=KRzwW;qt=!@!IX4VIn=MXEP&{?&)TZ~xlQw2NJ2MkB`KywNwGE(A z8h?9RZg5G-mOXp-Ufok!tQ);;%^5S%&@bOZSBHTX{`<}{3B0~8_UqN~_=}G}PCf?B zoEFaa_tk#=`Fy@NsE@1R@9&>`V}s))(8MHYpF!f!M~gLF31_9FMc~ex59y^wGYKmsmrj$-T84Cq|e*UG)mruXZuF@-I>NQ!-Hz+D< zR@%8aD?KNxP2Ck!30efbv-tU|M@PG>KAlwmdP2GX!sEiJ?mMKmR(4x4Ffc6NjGq2? zRZZNr+H}PZk4+KFcYRgS6>B$tlYM>NRqOYA7W3Qx3HbZ#Yw+@<1U)|Yh3~FMUs$pi3S8@N1G1p}-cI<1oQ~iD~XieXg$&(k)wJrw*pqG!&m7kxV ze?4n{e?|KFc~kFQn`xZ>T|?xTy`dZj=+)A&9&H#fhvXJ=!}I@rW|YhUf|OP4Nv z*?s@7AHVIFfR(p>QF`#dX3cvJTAHwBiwS5oh@zsRmyeH15i?d_{$cbAE7Q`Oa7>+<8~mdwfP zVsdUJdG z`nZaRtiQj??XCKH>CVn#QR(Pk-<6EQwGtFx{8qERZpyZn9F|9^k4u8lU|`|+6c(`~6&SA~KG8kVo$|Jw>}wAf$?X)4yGv0UPI*U<3`gJuvBMIH0Fkwfl?9+p|j+ZrxKSy6wDvOjSW+ ziF>@2Gy_A%1_?&SIjWzRh}idmGA9!UgZfDeaPORvrD5`q?F-l-H9zN{LrVoeuViLm z$hd$Q;C@{Qs%^8F-M~9sEqIj`HgMPc^!<8s$I>!$qn8?QH*cKFKuso;9cHC;^> z28I>EAX{Gs|2vXffodzs-Dyb0jZ$TUd%vLS3ErQFRMyBOs3L>75!^!pwV^PrUQo9I zy>uI@wY%D_^0#$ve^os74uUG_o;$l;KD%==1n3(wF)?iQNPHEUy7!+_E2!nkz;KRB zQB#DG0Tf;qFZqkXbN--ko`ab4U$Gq&gSE!oJ9+irt~R{WCdAOt)(G#kbG+HMZ;SU& z={s4uzndWQ{Jd{JbHMuQt;`GztCpPWZ&(wx)$856cbg(~vhM8I2wI5vvQ$^hd+WBh z7Zy5q_4ZDkK7Be9GqY*h8Hw0E6%*sycj-T0!u73xIUfVVf<)E{p{v7QZr}fR?W4z! zQ+qC6TIy|D^P>Q?=Q(UkKDNI5<<|lBF`x;328Y933d(Lh7eHmMqH~+aB)OUoj=E7> zJZ^8x-K<~y?v5p|gn=uHrBTKTgc|LvtO=7=UeuydUI>5_v2%|lecf*?&Re3iWL_ToSz^QR9V0;;O2rrr*lb>M&lXamfoFVpw` zaRn_%zE}O;)^~=%!NlL7Wz;i`(?!I^mrEL_U3grWT+y;RaQ5~U%nS@GtcaMMUnaKm zR?YGIxs%W8ZoiXsZmxBDkD;2a?cJ94_USwK`R3)VJ8a{rrmDL1%GX1O4xPEVIlb5L zn2cS`jl{U9s9BQ6X+1A*Y+PJeSZJ7gdz}eib z)4El%uSKNybe6A8PxPAf_@x)xB>I)o%c%45hW08dORju9H_ukPzP{cwC?X=FGq8)5 zTg+pUk&%%JXj90S3(laO^Q*6HyTroIe!KqMnKK~{4i25E=jK={n{S{0F6-&LcYcr9 z7#JLSS6ya2a`vq6>hSet7QES4SB3KB?`m#t26b2~tE;E~bc>zD#xJ*K#teyGIoqg* z4@-eDgF@z2pxo&v(Iw%33gSes>VWF2GP&h1F7$~oGccG~ zl>U;M0ID6IoS68n`%w7$xZM5P(|q^W{oPXZ)GIYTJ^SXS)UICLzt!BJktL*&e671} z2bwDa@U%Gp+htjYx~8rYgO6;!J~ z+^PsVL!qW-4`>17?Y!M*|5g0|_ZPGk=IN6s83&tKyZZW;9ly>59s3834s$4!p1rWp z`Rl#v_nLZoeq!COg@uJx|Nnk}TYhxX67jeSN6|9WY|FiU>iF^FcJHr-$A@}(buC)7NJLC*nQisAjFXd8r)J&$^z^i8 z(h&|&6U(`s@9DOON5$i>?5X?=${yzTYcBu$u_ki!mpjGhK|2t*#r3Y-&fo9bzg`tO z{eD5=>d$Nk(ER+JJ9mtpv$L{V-kG&cU29pHAyfoj!f} z&(F_Sdr#NzMkZF2f+{^ovn4aW7q+%x z_42pO3+H4k1BxCTOq<)ViQe3k5Rc016_|pfl2B2gK@OG}o|FZ_9baT!WP@ z14Dt8n?nQJGCYG5hxqfnAg#{^<3sKpHEMRgilCD80eoV93qJ$Hf+$cMh=Jii=BvLP z9&vH=?%cU!acSy?uS;W3-4CeF7S++LkJrtf;=V&_>s)p31RYrp28IPful{hHSm@j? zA}y`0udmO_#+G$vhT*P?kIVB*a_;Y|o%uRSXWHv~^^vz%yxErTBE71(dW8dQT_OX6 zlox}fWzmwPq@*d6CM{aBL}lmBotdAWoc#9F)6+9`U3SmPkKeAhnLV(I1-Di}>Thn% zo_?%XT0K8MzqO_1#n$U_m%Bu@RsNbt1;Cg2@%7)XtHa+Q39X#6a8IuI-D?M%*+HY9 z6DA0(jof_f-;bTe&rK2zF#P=WE9=35##1LwY&h=?U$40OXt%iao9~BOxj{qIfByUd zoePngntJi^YG=qa!-9n@6R=M+*!Sv*$fk1e@LW08EA4&v8iCeFx$j$@?Axw?pX%3N z1nrstt#A@n^Vwi;mwU_P>$|(rpp#V2&$BfxeHGGP3MwIm)%`L~Pt)bQjXCtO;Q0Lv z(0Ynzx}XuwfXHJrDw5AwC7;=TY=%nmnZjhBRff;@7^>Ztn4H{m()gH&L^7AJ?&N9H z(vI~=CR>%g$%u)G@wvS%_w2W~x8HtVZ+CQlou8-Y%1?VXY%nPP_9im9$FQAWUT*=)UGdqi)_ZS{qvV8gM4<8D^ljD;oP7KVtjX5n5eR{s)|a0{Vn(ZkAGbHze4`)>e+wSUzjEOY0XW=+p|=I*4|V)Im`5#Wb&ie ze_}T>SN+D&_Wz&Hse1Lg<(;78 z0^Ho%nwp!Z&YAPZV7+rYpHE z>`jIn&v)A`~4Vwjls9&@8?LEWK6hM`CJy%K-b^*W6|Mn z7}FUhwsH=W!o=Xfpm}=r`hBaWOc8N)b=B0-@u~jy=Het(?>C=8XF+vz zbiBTGd`sr#EqQmXw&vUn%Dug9>-t8{Tv+~qjnT5yjS--x5}o0YiW$vVh)CetYpJuN4!5xf1-ZUebV$L zYLo7ieihLT&kiV@n6lB27j%r#v-9)UgEqswzP^5a`T73K>lr+PAS(d>@!m~?v<0%? z7W?`5>{%9^K6mN1>;2y@{?CYSeqWDeF8j()L4ov&FBjcK1q2lG^Yhn6Y;^kk?CfF< zhF41wjgJuNaIb)kN4v$R|CqG@*NHtvA)K6?HBAn`vsmUcTzmhGks;wQwuVRO{I|ba zz4`SfynEq&oRNWH1(TaYL-xeVpe}iLS@0M^!{n4Xps^7K7J&nve?W_(LBkghSn3{L z>iBtuk%3`B7pUfktOEou)IlDR`S8^IYWm}8S$EwhwD10RXW7zsTwfMHU|?Y26;M_v zShZzN%vsxl4kyS!!*h?lle|Hd5{E)VF^hTGa!^Z&MPR`%*2*2(POqnd=FAr~K2j>V zvDE)(@Y;R6`V0&Vuk0XWGMGaY1R4O4W&jP^9?vC=(|p$E&F}B$2kqU+zPHB`w#Ks` zvUdabDhE(=NabY2a;Mi*^5+(*#!j1}tLYuIYzYsu+tz zROaXBcXf4rx%>UT#To@!_d!eYt;*hj#>YW3iR^qb8_s+C`As{TR5+vI)tmk=mKM9u zi@wiaw{G1RcZ;Jti=T_g$@wufe%|}(l(v*<)|7MeY**jgTb+Gwj-?2z-`i+VH+NqB zze>>L?1KZ1QnpoFYU7-on%MYcG?II2nO1GKzx4dU8@uo=>p^4DRj*bqf6>39%>K`Z zX3*w^S64KdIOgQPzP1*0!okzmuUFgu``CYLb2`6kWAN{5jm+$zde=1bl8dmK&xJl& z>o=dFJ39;?Zu#di-`V%?|EhO)Ecbr7esJ4E?>XL?VB${qu*RB z(D4SIL7UUgmV9{;*wrNUI{M|ymsz*Btvy`7FZ=qssq^R0f4B3woUDD_oI{JEek<4V znSM3@uylIdr5hWQukI*J{-wO??z-6BUrs3Z3pfNA>&5TOvA=)i?%mk%bukMyR&3k{ z>N;iq`tp+R|4+a9cCne6nX`=3{d#Mon%geRzbszSxxew|&6~fj@Bg>-{{Mg9zqnht zUS8&#opXQP6#0Mu{+&8~dh+bqvx|z0pT2zQ85p2koBjRWT`zzC>!97Kzmu2y&)@d{ z&Qfpj+*?~ZVNU#L{$aAeT_9wtl$q`A5Ibi$&un-dkaey=b6bPvCIv;%^0EV8TlybKI_pj1>h@6;TahveG@5;(pxG_* zbIxSj;vG{2?Rq2xL4pBW6@ucHX$U%SX>%yIfcrC{obsxh+Par8dH%ds&#lFwq|^cO zgodj86j2+lt~9>sN)MIycR99zPwF&z^C9r&gT(VP>n45jn%TuBcsny{TGGPBTkeC5 zzw-XVLasyZ7as&FW$*Ahwb5_q(X?HjSt)b5x>m?Mj-P<9Ot*lwHi)#Kl`C@_J7^*>RB{bRec;8-K9dixaw1R%$=~FdTAUShuV1j@hL`&!Do243ji7=ctJC zDoomPL&_mfOUPkX1arsRD>}DJ6~WQAAdy|*HtTcO^`Cdds5HcEV4L8cE3F~tppv;# zMgH}ZrSts`Z)z2|uEcm`X#|5JI558&S9mPF|50nd$Bzwj>!#{zp0=`$DRExPD&Sca z9`1km(?+%lj}|MqI(M`}LV3oAz+0`)UES^VqMMJqdh(0jkBDS+*<~e^v|H?mn1jt4 z#v{H<`qpJ8)JWeEXb7B(r@qxU(dObb%NSaCXdR+;H_e> z@);Tt&4OP+(T%jLdhEGq~d;98F7J-+q zzPFfM^A}%y+wY*(ue}O-GN3~|7u?gTx_!6iZwc45zus)BzAG}6r}8RH`jWJfA?QzD z#5RUQ8lY-7pngUWlgC9tfoO)xT}INs|FbhVeD^eFSgL#slnOju{an^LB{Ts5_f&fg diff --git a/vendor/github.com/go-json-experiment/json/benchmark-unmarshal-interface.png b/vendor/github.com/go-json-experiment/json/benchmark-unmarshal-interface.png deleted file mode 100644 index 0bafa928bf540bb831d9228156e09785c53f61fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24214 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV6xy~V_;yI)YPlRz`(#+;1OBOz`!jG!i)^F z=14FwaQSCCI|l@0&Ql|}l*f)3`szJ?yrKpmbgt{d!66c_b1 zFYf3%_4{G<;_PdCzCSzrZ|ilt=W9OC-F%+?00+-B592`72A-8pa)J+TGPZl@74)V_>Yf%+0}Yz<2fm1DW>!{I8s5#xORtFditG zXyMJ#Aj05K)#tQ~!NHBOVeSmIV1@-O3<;-`lO8h!=rSaz*FU?=&@lJM%xXr4=qZY# zj0+|*C}b_wV5w$EIH9au!O$|3LB#D-xXnlHbpp?|7#J#MZnD{_V(Ho#&7oV!9v-eIr*Y0x zTwBB}ktuPOgWjRanUY40Cj1XRpJ8BFFi}+SLG$Oo73cWYojYgNw~a4e_tk#3|4Ky-n{wr$&(viN1UP)Pleb1OFtBUApCF6&pMkw-@iWC_eiDDD7Mj^<;R0VXTJC> zl{r6&vnA=yvwrtK+qwV$k-e;R#4~AUgqFzTK%v4umsvfZjg~5PI!)3%s(R^v%A@-_ zznSgsn=)+3vSX~CsJkLInfaTyx= zXh`#%RLH;(=c1w)a%!{vaSjFsmj#Vl8yuy-9F)*Gz$SB$_0B==KM7_nPAW$ZISDv% zr8LMCC1|c`a?)r!yFpefLH~+_tjU4EjJC-Ie0qmMcktO3@c&BWn0HWPPa`Lb;|UJo zM8#Vjj7eP)%6%N-Gh2Ts9`s-l>Q+%W*&!0B3~!Vz->4qo94F z^~u~Pho2Zfk$$51DVl3;l0)H=AHk0_f=*?5Nj?>LYVwpVb%v2+=;B#HcULS75j5?O za$37^ThRKz_7%b=rL!#0Hj8Sd`6@r>`8>tB@Y61+QA&TsmK@Jpv(y1$tI zg85514{w`j^YM;!4awOO>=Nmc>_$-sW+%0)L#K7F}^^E5;`Df;bMrdu*su7)d zifgLZRJEznTKXX?S1nt0Zxwgw=g`w3{VU^wYuCAj8V5gK$$4ek>d;kl16~J92dA&J zUeUfPeMNqV{gS%KznyH6hkXwFJ1+@burdDeo?{B!$&#BZbQH6BSGScmnjTTxc=l#Z znbz(Ze`R-f+pb!<(9+r1%Q$><(B~;>_Uw;m6#ke~;>Y=1WBK&YbzS#F-fKS6lwM}y zv(qp&CVSPi>C+-sd#nyz?f!bN*}AvO=Pujpx;yfBBcJ1OFZCF8_w@dAtaG0S-weLH zoNKw5udUVBb$Y9^mr5_(?NYu!Z~40!^Y+Cx%=5`#ey?)x^ItNx`hP?I=Kfm#)tx7T zZ8MJw+ijk65;jLo3-fJc^^f2F80Z{(*ui;e;?%_H4_hYgylAuds#~uce^2JIn8zxQ zbC2a7Tdc;Wrl{ua`^xv-tRUZ=%QTl+`&j!NKYQlvqO;d#n$EU0yl(V-_Vd}-XW!qR z5LFSSvu(w;9jTt1o9x1HR!a=YY)r#IMcuiKWptu`?|Nj!b~(RGL4P2M}Xc2{lhUt4zG_M3dGWus*4 zinkPrScO^Ln{{r^JNw$BU#7j(Pmee+aQ=qz<88vHHIHP@4W513JzYF~XL0lAj_ywH zrqg=U?eu0#AG>>E?-Q?*uZ6J>t1f+=JA3o&LvL5yUjNSQUFN&?JM+(&%-5V3X`jY`Ks@U@5SxD*%i%yZ1>p4 z{GQRh$oMnn2ezNse%k+V{=E3s`_A>s|5N@~{lCbtyg`*Qow>8ou`!zI_m8R?#r=Ku zR<~2XZMyl^v1h?fM^VTArnOB^53W_rIPqq}TE*|rXPldOE|ae{pzg)B3+#!{61xxA z@u;`9w}!Xb_Z4(RNL@6XZd!ivj&t#SmtQW^T<*d|8{wJbEn}&twazRrXW#ulZ$Gy`n)`_Rakcmi{S&bTl?%@u`qH{wY^9!% zj@2{=pAJ8ZDIXjKv{s1qsD2VISMB4fJS2N4T}l6<*~N|<&M{hYexE$Fe5)qCnYhQa zQst=eQk|zeThv!h*yF?Nb9c7YJh5423b{tMR(lPbCrzAC=(I}Fck;IMSLx5v%1*CI zZQb5r%eBpE*^7`Ujq6(Mo6=Lm)Apb3JY_j;^*rsfZ_jK# zb$f#OocHtpzZE(p^l;L)rET8fy0Q_^_O8jY++CTJho3?8Dv*~h0(~-~Za3+;=;aG1T{J+SSzGp1(JLw_n$}>gA7VzjI^P`sEhBJf0yI6x>eRw zz2+hNW%)AMbXol@r&*t7xy=rq^*cH#dYAthyNlOe-K+ZJep{Y@j)_fVrPt?>lbN?( zHeH^a{^@+r+^KVG>-2u!Nw~deTlMqgbN93O^WX0hD0z6v^?&zs>pj-zVm|FC`LyZw zQ{nI(;j`9T#pk{%d1do&@@40-a6iNzT1A)KKkFC8}IMb zXB{YC@cH5$_wQ`2&FBA3{Myg&%-TP*|8yH~+v|B2c9xcp?2G=s{IlHoe9C#XdE);T z{X4x*Tui_2$JN)@&t05xapCk&(u(=BbWCpF$qHk`xG!P9-yST# zQ!e{{@qK>(Cp8N78viqXZu}a2VfpXLl9MO@XJMZ4`A@R3?rjDJ28CpgAYTTCDpdxC zhGqtapZ^&c8eTFmlo~KFyh>nTu$sZZAf7)d{-_%RL-0XQ7srr_TW{`GR)l=LdF*4g zlTo8i3V%yWRx?LNoC1sJrDYu~oKs|Zwcc`Tuy%!YafB`PU=UXMvqCJ3=9kmb6QmmM5acp^VFIWqM+%2Db&+HJUx9` z7TW~YqYoFSFl2_wIC-%PfRvtFp2DE1!>6dqd?M6y@@u6Aok>p=SGpGdFj)PDr(@-j z{UAkix&viwbpB79!+27kPcdBOsn@IuWyX}5D(4@4NaR$=6J-$)W@KStU?{l7kQ5@| zz~#jh>ifzzrhD}bB!aErr#c4H6vH9Q3z{J47U^15>iBnOP*(0u#p(ygwj9Dxb z%DWG@Z_i1$*ZTD%^yCLe4n~kKv}>k_J8AurxF+g(^QdApEaFB zVd?rh*B>C~%?jhttTol~X4tt(KHYIs_jJRltP@fv)u?RM;gf$lx8|PDoZlb=O|B{g zRf!$>6u9P+`r_vvyHs8-@|q(YWCZeaw2Z?ZFBXB*Z`!j988jEN(M9dq zD=$0@^L(-5)#7j#L6B*clA?Rwm1}Oix75OU$Fx&oY2NQN_AV;)pu^6vt6G`N^{&rJNmM0yZ4-pnyEZt-Q3j$(z;j$Sg}QzlkB{6#{l3@hRun zuW~A#^_qV_Fz`ddHISPeQXP+kxC#_bd=eD;LZJqvYR5!@Bw@Ez)vc>PmGLn!Ff=>} zyt&KBSW!?(U3wcgf%$N7HU@3l(G%Fz-}j|M>(9-#UhZ%A(}kIxFDIlnVr$k^J{gMz+TrUo^!5Gq^mzX( zCptc6nX=tpt_d8&E-H(Uto|p3LK1;W@x1ToXVSArmP_SWF$;(Ao zSBGbRdUBFau#17g;qOCp+fz>;KVH1hx!r5hxjB~3&R(EEI5*#Z{frqi+`_996Bnwy zoEDuIxH;|YlUJ`K-a8&Sazw+@GIDqM`?Ll|h6hii&hm6T-Td|PGT+O` zKY90VonGuN4L!Yc&suN%`}=!q@^QYow$)**tgN5DeG7AOX?gVMQHt5@(^tNnF+Ts| zZu$MttgKaed%uSD%GpLu+LC=;ulDcP>t5d8lM^Mf?(W)J_2tFFcXxMB|M~CJr%zkT z-bTq<6ga$l_wLoby}N&XeVzU}ub}kxs_bd^rv2OJeLi5yzP(ocktd4-w070M{D1#M za`oF=rnMiBihKF^goK4ni`tg6^27;`qsNYgy*^qI7&vj?k4N0CZEdSUSBI6Fm1)0r z_I{dM05i86Cbp?&>n%*<0%W*FAmmL_KWwd*tjkKzFv8G`Pa9%ucz&< z|Mz+Rt)0cozy6wBig zMO?d{92UE^Hi!4{h28J>Wf%K-r=>01mUnm6<>mg_cXkvS&GeZn_xr`g#ivf43JM9C za`#uj>|Lj&CyTB;c|%J_=gOg0?x}O;p-%d7g^8_my3?_OM7T=nPU zaZwSGC1+=wXaD~8_SgRZzwLki`t|DLary9qf(@WFIM=%T)$RQKTlabV{d8Ji)$?#0 zZ*WM+l&-F>Ey>6EYQNn~zqLI-ey9GI&6_uy*8VDCWn+uVzrCw;waUwb?D8QlE-gHV z1Co*!U0WBsdi}m%t9%$vo;h=6ie|8gfWU&>+uJffKRbJCd;a{dzgPLjng(9Hy1}b$ z!LN!lppr-`-g4Ep{pYQ@AkH}DlacAbOx1=b0QZ1o^yDDqO*vUl$O80|J~Z}cPFjeA02&bfn&3X zn3x(Ub-lXked+7WRz>GFP!dhs9QpUx*UkHWZ2xh2{=X&DXU{&9wz=xto0T9f{`P-MX4dk^T7@Vo zDjLl``|IZUx-j+9yB%p~XRUN@=bL3wxF~PeOSRoLX;(vUA2%~JyeP$Wdt0uyxw(03 zTidIH?DAXoWvuIZs`BpI+UVPB`M0jzy~i+e;;bIs)9yR#ex8ok($Vpelasrq-58nn zAuGDr!=uBupOK-VIBSBWz~qxEhYeCB+;+-WZj70^d{3$B{mO5jK20k5yZPDDsWlgK zZuv#L&XFccU*{&{re(vRsjmc)EQ@>4~|7XdW+}Pb^SFgv{ukE+{ z^muiF+Z zSYWi-Z0pLKmx50pzrw)4z_{exj@`RK)yk>Ur-MH~J9~P~_A_!jcJH2E9p8P*FJ$W; z23^?{FS+%58j4?DQr-LgUbShJ__f1_7oW*>ZsVD_d-v{r|9)l5S{5Do^=`xR<;#!t zNCu~cEqwAlG`#d`TYG!^ukY{IPt^|3y1FWqi;HX1KI7P#r#M6? z-=nWqc{@xFSv~n*_U-mtS7PtYSmWUfa&+k1{br`oRkJ2fKJ1?c%ATdCFJBG@m3pn* z;#ZdW&Ng~|`SRtpx37kUstbodng9RKa!|$e^Y?FUB_$_CMa8V!+txliKR>^AVQkg? zr?RKdp7m{J;|`9o|ve-tLEpXYipyIpPa0Iy*hTQsG#7&4<8C-?dxJd zwMTya@7qP&wY9W1?VGTz#jSe9+wYlXvrE6e3jO=BzkbU0?d5B~J$&|T*`7T%u{(>N zwjE2ay&gMR?rKU-WY*52r(I{?1jk;<`MD#!Htr%X1B1yPHcR#+p8{v*@Bh2)&R0-< zt8(?^@%pS&M!|-emsEIVECK=p1I^xFyY^+VbK2&}xz^>^PE1t(dPLaYV^UC1kkp=a ztBxE!>N&}8j>W?N|Gw`xd#yA5>DDuB9+zHTUM^d=A^P0y9TWGzdH4Rk{>gpsFI{)N zTWY#Zr@mt2lbn;S+~Ov+ze>)|HhO5|zmH-=<8Rx-|Rx zI!$eD@A#UJt)L3R^Xb36J-?nkd#2|3>)-G9p%D=)gw_3CH1peSSf~GU(QYG9Ikn7x z{<^u=m=)d3pKkx#jm( z7RgTwh>@?~x@VEy6|l#Yl$2CFrOk2zyu7-Kii*CRRG;rL$*Sy4g|lh2-rML;F>(wH z4{D^IC`Zh-D!mk2es}5J-R0SzpPfyOd*BtcK5p-oeYMrQub2IPyZ!a+_4}`_3SGS= z>*^|_*XQS0F20?&d+n*eU*6q~ULCgf(ygu8pi*>pY3;8snHzRxEvoQWOc_mj78*V_O4*#Gs@ zjc+e5I)h@rPu_mrRPFFvYqBpcYGvb*2w1yuclGzYxfX>^bFItQUH+x@$~pE*Yp%!+q+cZ0H&Zq$|wzUFtA1TJ=q zj5m0DW8>ne-!HGNoh?`OLhG2JK6o-LdI=ZU(MZPk`tB`+@}lwNgteQoX4 zwbACD+cqoI{{9xaK5p-mmoGKT%ggW9{eHXa{l4E>wR0XGZr9e(@HjimRQq%I_17gE zcJFvG(OoWZzFqB;_wVy%i$R6p63@x2N;B{F$y%Sfetr9yx9s+HcKrd)BF6nQ<}Bc{8#t6L@bBa=xaCnsmr=Ct0r-?#6-T5kVWlXoTa@qYR1 zi(I?E9AM^;aMovF$S~=7v~)#z8|^x77Wu;+3`95>@{}h=IYRZVof3*ZRP%fDhCsWH|1^ z0P4LsAdw8<-XfGl?!rLWkS+{_B+!vz0QaL&NDc*1KS#+Y4k@|IU0-P&n<>hEo?lNzh4k|%fD$Vn|u%RQ74WBB+~p`?2JnzH{s=JvY5 z-5=b(+KP#Zow|DU>cj7mGmWR8&;GfveuYQq{{;mTJ(KgL*BPw8=4V^>_OHa1?k~xg zmc6q7U-JHPP=a+`L8!vdQ=xzVK8cjPS}|`%%B5!WcC96@#Zv4Yk`vU@UoXtQwPAgL z^#0XVH#e*gh~|%7{n60L*?DdJ{||@xrA)J?}q!v6&2-d`~Q9a|Fw3t zzcg%YV*dXAejSv~-n?(-w_EYWLi8lK{xb*$r@2g^Wmr0pqOz4xfE_=-QAyW|`)k9}9Q;ZQuvpb4$L#*AGJNTg{ocFp zO)Oi#qUz??b6?-C&OF@4yX)n$*&tLFdvvi#Pz+~~DlIX-{?D5=IuPY&LyX}R`P zYI4!4eIB0q7oL0i?tkuPy3LWHFG@$s>gWzmvz z^X=oydH0m9t=nF{;NRbW-}hhNl6kr0!vn{=)$jLKeLAWBdQs!oJ++6wzkhLYG1R}m z_Lz6QO8vb`j^90O?(qeR^VeUkUa;=!>2K0zITzm7eYe()+TxLZe%@8-{5=alK0coP z{M_8$Z_neu9;^ME6CZzm^5*pOR&SFTnK%+2Us&k;>+AY@U4MUnRyMY*YilBZJ(=vk z=Jo$i)Azr)nLhvO-tYIcL9NZ=^R}~$QoH_rn!f+WoAhHnlCunx-F6=Tar1oLGWoh6 z2Y>0E)vx==?Rn|L!^5U!Zz6t$pZ-_-^Xc?gx3{mKWuCvT@bR&i2O62btmm3m{z>P5 zT6+3x^Zh@2t;*i4aF?renXVtd?Pl4*Ce~Ni*UwkUe1C7RlugBkTif&3pE%)B`{knh z(|5+&+TM%Z`@@d+$%2a3*gX{+57nA&JHB{RU20m|t9`%U1z%qm`}N)K_tR!Jf(o90 z&+GrW|Nm_Nf3fduvzPb(|J$yltXz88*Zk$?^LDGRffDl8l9xeW-`u?XtZu11v%6$| zU(%x^oxe`U|6BC$?{Du(pu!_OuF|#o`@5}q!8dm-op1Vk-|AnI0rw>IZ0r2zSS+l5 zx6>WeZkVPUU7_Q^&{+KP?(Xf+&dgkVb#?gb8yl02W}mgH_^_b#FQ}{V{cic~JImwu z*QGAYtN!*z)85`b_r`{WXAF~)lhuz--#&(F_azcP4v*8P38piFYF;xX^+w}1cq`SP$`-fPk_pP7p|h1FghXk@N> zwQ~8F<@SG9-l^U9>6G@bqxy9Vj~sFN`zGD~vbX-;kcW2Cw;u;a?tgZ6_VO7sBtWtC z>)Y-8({HMupPLKno`NL8<7-2!zrDE_9$&k(m0LXPPz&c(t2Wh^{F|GO!b5G*h7AFQ zg@tC@dF5;(Cad{w`nP{op|}0&|Fz*)Pk%aAkXiivTxd9_CPTkb!y^0i+kF7un~_5ak%_*A>!Z;bC2oz^WXFTeiaVDs1Y z^?y&N{cT`mzOpIR+w;1;{om8^|AOAVdk3m9Ppx&F1nPPIez)6y-n@Cc{{Q>EHS_W^ zuJ1Q*$n~H4_4ViT`LDzG|C+jI?_Sf?Q&Wt7*L}O0{`Be7rFDOQfzoo-kB99~U%p() z$jr84!-fsF`cJ;E|6g5MQ88s_e6mD-pOT5mm0cm_cP^cORewM9>n5w@itFoQLDrOh zzgs??lhZ~_p<%(r&!0boqGL&~wE3$8jm%PpNiAyr^KxR}KYqOUOUZ5F&q2Y#Pv5_f zPm8~I?_SlLjmJ&W&&@Gi#NuATXlA}xwf@+^lY=-OCZl3m#bcL=<(T^#>>x$I{y0daxp8n*p%NN6@P{A z{->&@_6k&&yt%nK)ok|5c-6n!f0NF9>PyMVS@ZAr{r_6__VMrc|KG>PFBkLh@1#kS zM5Luxzq`9T`{kvjqVG2Q&$o-(U$?iYxcKWucloJ5?`&0G{p#b2HSvXog})v&^G}&O zcP*&jaLsYGTEAyyf8*j_bN3Ae51nkk-AKMB@abmy{K)lPp`X%yDxpCjZqE#gT~K%8 z*4FIlixw}g)Nx>Nd~96)E@o}~{y0!+ILkCU$FF0yW%060moJNoi!aZ+y9+dkTJ`tq z_1t@*KS90g>v7e-p!VqN_50UtzgOigC@3f@r*B~q!Eg5?VW#+nv$M^^*T?OB5ik4o zefj?1b3r3f(Rn+Uo_W6W<^5*Sb@B!Y4PV7SU-q|O`}6a2P%jh|4A0KbkAL_#uJ&sv z$OEtL?%r-y_9o(?-TbOonzf%!s=vClwEN%R_x0J&&dlshTND1ZBIMe7&ERDjzrVfh z>g&6vyZw%mzW(~Cs{xabFWGbaz{O*;l_d-k8bBo%s3pwB%X_tjQ~1lX+4)iHyF$TL zLjAleN6$AbpI;ZH9lq|$kxt>Y@~w|HHrUSOIUJ#T(tpx=m3+^6lcGF~UjK^sD%a)H z(wpRSlv`@$)OfKMclAH7-uw53#O8nI$9j*6o{rraVyQhnth)OA|G&L9|Gt}>tc$qV zc~i^kU(MJ1ik$N`r_cX4@z~9qmzuM;JUK8cE8pHuDQ^Ex+k1LjMa9Ijo}QX|YfI+j zu(eS~n?r@A|CQ9PT=(yMY<$4F@BVWxR;&AkSO1Rxzh!OR*UJV{?CGf@`mRU46F*MU zf7!J}#`ET+O)9CoF0Eg7bamz5y!T%^@1EWrx4pb--M+88ZC|x)pPjxpFJ3x$x!=_` zUg;^bXRkhS!ee%Me4wvx&Fk{tYR4{bjoh2ZZ}IiDW}3sSX@`_DpI>x}U3pB!gM0Ip z&3jkJ{9F*%$tI?ie|@@9QSs`!qRNUBd)<4Uc%9pB#Fet7Rx5V(v8Up*D^H7<1Q;1I zr~jWXeErMQoh(m9;#MB(UM1F*c{z5S-ku#r71z0zFwgg>yjt;ZXSKIr^O7{1|5`Qk zB-+ZBr)zEB@M^!r`-iuD%2|J%yn4i2!{U8@#nlA17Vxygfjq{R@7q8P{TsZv+T@Uy zIdVq;!iIJPAe{n87XX=rbOazIT6e(2*L#{y;fr5-@%wyg{bJ&aij4j)wmT-@um8CJ zUtqkjL_Ldu$t;FRbLaZj`o-MeS^WHk{8z(&6*ZFeU;2N|I`BgoX;K6-HG-ut0dY5k zgt!<&qPQE=^$-^$lPIo-SO+09X2oPO>eRI52hZPW$rqF8?Rn+-p0A}-%r4o#+Pq#N zfATzu2kX-Qa4|6KPGn?1nNf#pyh=7{JEAQC_jMQ;h-a4eJ*E z{K@lPy!TUPIM8RoDH|sK|Drc1CnsNYd{NORCnu*B=RIG0`}l-}goylIypK(){tq7m zLp8_>28M>a2Fy&WdH3mgb??2rkUe`=v;E8!>%Y}Ka`{`#$u;f!l=PH+#w1v#Yl^^z<}c)4D$u ze?J`NFI#^w#VEA;_SWp{r*h0rrx>lQ{QL}*qm%bmyuQ?Wk%wXH#B#TVJ3qf*X0Rw` zu&ns7fQ?sbiRWZBO-sv2(8SFQ!{jYFH;vkJK!Ye>SI7VLS{=TATB1bM#-!GFyWiX8 z-rjaLG0VrxE6Ie}L3d{NjvONfi&BQle?Om_R)5RkmA8wTH*a3n{e63<=|nD?Yh50- z{pQ~4?TZ#K2DN<5a&KikJvH@OsoG@E_51(rI&}DOs@ZJNAZpfKeOueu+FxHL_V@eG z+z@>8uUntYN`AW^4u{)#C#%?gIKUjWt7K)_`+K=}pIut&4Ql4p)Yh8j+%QN@PmjJH zyQ9FdnT>Z+e}6w4zucNLXMASAPd(Zt3Yy{z2$*2^??-a(ogIO>x3*}0-WyuNbK1x6 zWc~9qGZ*LG-L*3Lc%N0>pB*YMK~oI5+wUG*!QK$`DHiIto7-|{SABn%TO9rS+uN_- zZs$k;w=a7W;XBtV^ySN!vy9XGmif)i+Whz98-!t_y5-gd*ZM`&cCTk8X6dK@9qk9ZsWPQ ze14sl=dBHi&A-0CKfi*#VbYz$CD$JFe_>>JbJU>cYFlEC5zpi7!v>Rh4qK#3xXntG z5a&I7!jMP#yg?7sVS{y&ZGkCQ7|qSimG$-4-@5($`E%*(-h2HfO`J3->GS_rcl1?M zj+{7i#)RjvL7%*R+}qz%@A*wC-MHiBve`XNO-zRkcpl%{n(bCmv7_|vS@ZijF*^zl z8t@!GapHu*p+kpG{f*<|;^Ogib8~asd3@a)3DK|5?f?Jmzqma={;&a0@_`1%W6#dc z)_zkQ5;EoCiF0$U-9e?DlM@qiY4=#B-t}nY!UY!APejr?w>-+37&6DyOtNj`F2{9E zpgEr}UrIpj@Dzcdw6tY^{{B_$h4O4;*lqYf-r9j`u@0R#r`O^YFO1xKpQ2X$c#wsy1DB zsxNR>>U=#tJy0Jw?fks8a<)|`?%v(|=(o@A$nrJ&`qNpZ&VAp)@KybWvcvhZ`72&b z@R-HOz`Mfn9OF#0+*xU7W-Ro#{~Hp%E+){)sY%Ue#sc;EHJ5gs1&u=#JaG8>=4NpI zo{w%@zsKJE3+mdI->Y<=t`~c$TYq1~+uxvczu2vJ(>#HFd3UW|hi=pX4O=?5^J(hq z`*(}$hn19UDZSgk$o%D^yS%2ly1RDxx{#Qdn6+Gh~(ZZsqg2SNGlj@bK{0d)4nX?d;;zCVPJT__6B$-|uU~ zk8XPNd*}0c!3hZqrs+f`6+8Xq*59)LG&Q<5YU`zAz0#)j|NcaMUArlnN8T>x;lqbd z@9C?lxv{dcvIsEv#(Cvg`7$)Hr5W)gZ&k7P+&5{DYNc0};>k6yLe?*s_x zIWfIg2#9ZfAnWjonZbltZwqLouwgH#o@;qwd+BlCY){$0dxKx?HVmBfB~SU?{QMbT z4kW!a)BDE2;E+0lk+EUdgi^OC+lhAIaZm>9lQzEm3=9elpylRUm$E}DJHDF3OD1-| zU}j(leV|ejQF{Mk@97Ug@y!p7_AoG*@SXuTIW|bAIV6aF_%!>~_R{6a;xkJo{gPR+ z&!K#C-TjSo-*J3+%E`jOu&Py3fMM&jdDGXky7yh=09%?MpBer+lL>6=hW-W5(q=J$ ztJPQW3wB3Nw%)Q>kbz;rEl_1IdAa_0YQ;)^28IQ3hTt(-qS_*m774ih0BJ>ljfYqQ zCm{_W2nlY2KpG-25?AvL;s9_v1>8npU|?7w7#_vIJ^$hDE9rTC%;7hJguYtl*UB#K z{nG#IjrNJ#OVrtRtd`u*#Bd;Q1|uVbNo3~Dwz%69+?5$XhBeG}I-%MOZSMT$$jV&A z2^yhhIKcPt@a-k)zjj~dVA!DS=hS}nX#JNUC#R;v*QU>zvu45sfmg+sehCQ+i;9Z6 z{$H`a@tFL6W`+ZCAS)Oc63ovu9LQ>3-+d|ReaVZ1v#w3ZwAF~X7d&s`&vO}U+zbp3 zx$(glnHE%aT?(4|_gA+G69dRKH?&)pTmY@>V&X_xuI>|{4T>5E2F5pnc1=%hpJqxi zGB6Y{gQDi|=B^z)`V0&VuSAW(!_{xvBn8-m0s<7w&9}2z|64cx+scCO*@wTWdjvgH zv~;h1mzZ@ebDtq4{jpEg$^}efo6Jq{LM1aIZ~sJ6GoHzN8nkV}WBc+sWg{ z-9alt($bcd#=5z+RegWA_S)L$*K4=mOL}(XqDj6tKWGm4$jqGE+kE#{f8VxqZSC)G zRlnbE&)&L!#taEi17OmY($`@}j~u!3qayiu-_%-=oPKq8dH&fMhKF~(o0&cjG|5x)q(ku4 zg@w+o$5*{8J9+Ztr;i^es{H)%Lqk>d=q^1|)6lxQx=BkeTnKQpW?*2DniG7!;mfP5 z-v57H-*1w4$KrJ^Xt;EV=j4(P4-QJbKc8Z>GX4C#s*gv-LF>3q9zDAB*l}sAk`+nG z$)ekC~}^YXIHV?C0;zFhV%eR@h%RYfJ^Pzxt$xITOD z`57}L{=Utx*Dn6&UfRFC{(l{4qS?0k8)zIWvAEvc-263I}GT+_VIj4nB#QW^o3wK(Mf-)|X$K9@;o-19V+9ui8bXZwf zH0IMydy?aZj6ukUaF|L6Ja(mkoCr)6GQ5!lty5#Zv|a`taKzx=unA3kVp z*M8Y59(SQ#zHUX>+NjLO$9iYk*Y7L6duFEb*38RlTeGkG&9y3>w0*m|vYf`WNwfWg z85lAc)D9bjd4HPxMEhj)q~%M*CY{;!Pf+*zqXmzYPKNARAgHOKaRD@=_wl$qXs%Z@ z@A&cc7p83a#BpVLvsh?#wO-SMJ6}~n6{S|!zd-rN{l}+&47Yas7!IyWp5_B%T3(BfB&96d$y#Von=&iQZ{2%lP%L1pYNO|ObiWd54^bN zT;G&>dez_X8>%NOo~lfLxO5-e;}`E4m>3#%9pnMe<$-#iVVoDMmmHThpKSGO{*Tq6 zwfhn;F?TP${mYnvk-=f|0UnME6E>amSgn4E9a3MZ&s_eJ5mH?V@89-?0bEJmXw08s zQY2UlTCT~azVPs>-+g&8ZPzlag1u)EL0+h3b}mkltBt z3=9m*55orp=I#J3rgc96PkBpbadB}ydG_qtmHUq&73AZ(e#c2%{GGpEEwcM=VETGX zz_JF5d3P8X4y>C~#`fgK#^kQoZRBRRNmn)|yUW_w#Z3D0_xt_V+ivGgE~$O?;Oq7H@QR8ZXVNx< zIyigxKG{F%%lG~NV;dVA&2D>MTIxOBB0yJe9ycXh z+q)9>b$bLQB{O&I*da03s?_M)o14iJZHa%L+y6KG_3dr8L|Y<{gu#Iudnz|4#`uf7 zd3kk}%3r@7{O`KBUW`WhU0?INDIy{w5^aeR*Vn}wA3A*a^jdv;`~7F^y!BM4#)aQ2 zoBDROYq!|335w1=!OQ(ZZ*5+&LZiLT=RAqs?OU1Y4opl;TPi*#y}h~F{pHJ-pqb#c z7Z1T(t*h$`8l>v%+;~sl!eU3%@9&>KYk&Xt`T2R!0xz}6o@Zy7UY=>3 zzUH-&k&#LIIhkGwLnm3Q5)FNxu!?`~FF!l4vT{FSzyq3z$-cHGaCh0;Ej2%jw&tF8 z&jT&Q-!SK!(Vl<*{#lj2nzColo+r>CIC|_@)}0-NT-@Bj&(F<$y_H>0PY*P|Hg(#xW$p5H z5!u(*tu3j(yk&Oj@mIeq!WKNN@#jA9WA)mEeg@mywTl)xD^=<+T9_=K%eeFZzu%_$ z_iX0cR0hqQIdhhI{=BNMuTo>}Q%(rzMr}Fq>`(ux9Xoews;VwM^%h&d7`2bxcDD+& z#4I&EJzUa(fuT1%E3fUDn$9vo1`Y+@r&q({L%qDZ7A;x?T7AIG&X@7?)6;8T4Gj&o zG&EL}F-Y3g>^OAz@aj8x@9ylZdbjhrh=jxnRqtsp-fq9YZC&)XoSAODQcF8JI9y#^ zZfuqJo~CmVG^2gzPK=u^gT=}zcS>e49C&E?)_nu08ZCJlq#L_y%blvzq%^)>aBD4@85s6X^$!>@|4|rHvFqUHAPeO-R4Dq!%M1N{6NhAESYfvID0)q_U%ElEeY+!z=RXtGqZyqNh;ID-Wwv+0koz@HNp zPnQS@3CV2R_vA@RYfDSO{K?m*&zP}d#R`pI?zKJp-EP=3tl$)n0(ET<#DVG$p+(<4 z`mOWSO22&nC$+`yzQN1JqnC33N}ga~IIz%=naQGgjq#;donIIk7(hj{=d(;mVZrd` z$a-B{NZDQXKw7Og#s!pZ4?l)?YOM-E6?k8RqyWgavco(aYnbBdg8y!NSMo+_vY%CI zZR5MNzx$G{?+QLR?ZCpo;MXfDaDZ{i^QYMdCnkd$Umy$JZ(Xec^^`ai7~Uwa*f|qY zEj0WB)%8#K-e#~cFcehHY2jPl^K$=Vqdk5xAXg|Suz{+0oYg3#)i0?uBn;JmkkQyAtQpjWnq`?3o1C-ZoVGy%BynW^QJ2LF+HY`5DLH%NEex^;p#n=iO#WcVg{ z<&ujqsBg*8AbY5NyQlw`^5udI3GSfa=>Gp=X-f-B`&xZV%Sc5<#VgO3AR2`6%)Rz? z>1PU3=9t})(2)V zKA3~ls|Cdmv{&oEz?iUHy#ms!1;rIouU3W&)P}1M6GU%Ly=jx2kfo)eF=6)X=$Y$Z zzm_Q780-7CDsw*9_8pdQk_A*&eweUgz1{0#{@~4i+^Jk0k3IPr7+$qrKG!hAXBpS@ zS#J(6@}92uv@TZoc%N)=Ow1e`TU${9fdwBQAAkMn>1oq@`MLf4A)4=d*2&HTB~J#% zCChjYZ_s=CcmJ;68$7(cw7$QdC4sH_hH5>1^)jSQ`YP!6x3{H#eiV9MnrB;`Vl)#p zr0jV;UGvuVeEpZlB_~Y!KW*Pz%n|nfWTTm&61w#DHQz~F^6%UE&anuLi;Lsp}yl1*WBG*u5D!%6&Dwmb$MBD*t(d=L|@gZfBxUvnw@Gk`|2WB?yoN{I>*=j zR8^J>&AvBH4%9aCh<$Z`|9;R^zUQTDYonh&e7I0IdYi{2vz!|X>i+(^nG;_nw)9CZ zsON|_R{ourgX6-rwb81cg@uKn5%p>M@#~b``%c`w8!IU(ncAo5iP;r?nioEEqOv<^ zAp>aQeO}EcPuo8q4);`qAZl%gy@rx)8>1%8SBdw$H_1kI>x7hRUngIQg|1G#v}2#= zf4A{Ue>rFU{>5Q_`zsBM%p#JKD`R(;WuBgk06& zp8k)=AD{lQxc3x+T{RRFYxGS_pOb|?N#63#lEebYhNFimzQTW(C>lG-}W&vgDY(={qE>b zb9n0O>*rdPdd0=Xefs?Q^5TBGRnO!2KC)wbU*uI(COH9 z`{ODevcCQ)SNrSB#U@s65%KVU_w5Uci-Wzqyk@Rv=aX51GQ?fddVCMowm|4R!*B2J zuWw{#Uj-Uyc-(8QwKnzbt*xidp1s;5X`Hid_up@~x2Bzy+PQ0&mV&~8s(qXc3qE?m zJMfH44A~}p`BE~QVbbi`(a%^)xkYBMv1GJ0cKqGV1zM9IN$0Jax|B#5&t3p?s6g}~1ZEXdGxY=#p=xsir^;X?t zx*+kjaeHS8@-z4;sG84JW60Pt>xk!z6>@fUtPH)*+Wii-Rv8lyUpee~z`Skpg_Y+y zkIAbqWM+7<2Hxj(Sp3wBJE3>o`Z-U)3ABQJ!Y_&X-tF}a0m4Wf;Hd(8-K*{t8n0Zu z|NHX|Uw^iF^6O0dv&-lNBZEV8G8;=lS!DW>tHLjtAzkdrXQ0Iy!;Q{(Xse&$%>i>C zshu65&P@9OPzP(@Vrg(mJ!Q@r1$G7o-aZ^PxY@5?On1-zsy$w|OZmWbM|K8=Su$x3 z4A$P~PhW3RJ`Spy6&e^e^lw@H6V|hH4=6VFg;bkg^)K9Ab5iyeXyp2WN}-U|8lz?Z z`%ZsAZ8jj+wUGK1LK3KDk*jtHn;I2-0pHN5yRU>-+iQj*)!#Ojj0^=zXBrp^JX|wZ zo~rxn3L0%@WMOzC>J*g01a8c1xXiy|K^Q2am^c`2DA%x@u0C}c)CyBa^txBBKWOnQ zwStks;Vz_w)c{@w0Gobas}CBG4xB&v+I82Uhhpk4=2y>{RT`xc>>y(w!oZ;6zIZ-k z^v_2bj7FrL$a zSKkH47&eu?jRNi4y7cPm>Qsrgur(12f4|%9e|uYQamO!E`~1d@h^0%GXlQDB=H=zh zGRu`(%vVqr?tht?fnkneLywGQkbKRD#x`DQHBWF`y5wch+k1O&?>Y(9^7o+mw>^9ITv_HTy*6g&rCsMzj9#L4!(*pUoVf7b-s;t*udh|T zUb{UfE%e*l+siwJ)lZ#1?S1gz!K$}guY-owvaW_zl`VVn-&buiXsv4A-CdrO`s8d^ zb#!pBva@IZ{q^9m$Pde`0y*qW{#K6b5P6-PLELa=8-D}dn z5AF6DXJ!~yz2E!Yr1DeB?7!z{nR-7zKR>*tW>4Drd1pJ=U(E(Zcult*14Dq|VS_N~ zwv8tZde-wE_AugkJS9;gvn?^kgh%m_PAR$UYc9#k%G#DFacpb$^_~wOK6w3> z6ctUi*i`)dT;P1+>(eJpaQMFhQSn+US}ka%{JXcW@6`G8=c{O%m~1(tbM(>C zZdK2jGiOF^$(ZQYFSqvnzTfNIwoX+CHwz%6;-_nnqoKY998)!yFT_ScKWRsViI&yI<%s;ZiK+p7(h-s!-6rgs)3Jl)k4z`6<+ z<0>5G>wYYZ+M2brSK2)5-=CjP-(}z2lnU~bl9G~$pkUxzskC!*R{G911GQ9NU0FGK z&)&UjUxSuBf{Gh0Ew6j7S{`@ zso8U{=CkkXx0tODGq98AfW{Fnw9LR<#pu2Tw#%m}h>MGBOU6Yd@N&>SmBowy$o=>s z%D|ApvDSv^>&peMTX*F{CdXyIRTqDOPGy!Z-n}t~V-@DcpSC}}l}{$RKY9ONUteDz zH2%mfuD3*!fq~(w$Q!{0>AUNzt>+Uc-Jx%xWrqt7O9#tF0S*~npVY%nHU>{qc z`}+eQegw%s?*AoG@4KcxqXucFR7H->W2UScepG|BbJ?^qc*FhZ~P&ID-fp@Z-9%z2eM8VIg zJ@mWm-5osoUri<4_w%SSFszV9Y8s(VpU+u>JbiwWoxwr)5D!NK+eF0lIfnuReEOV4 zfB`;z&d9=mJbi9r2WwBKTMA)A z+d0o4cyT8@G_INb>&)502VBu!i|n4SUB7tC#D9VFYgsF2e>uWXZu&T!fdRCVj-f$K zTle;bZ0S!KETB;yh7G|SJ5w&OFo4=x3G$A*z9x(epy7)fiZvCpzqr(wOEEH(9r1jz zVb_oTI4=*6f*ZdkO`a?&B;-`<7ZsnBv}n8uk^7-E zFzU@*KHG@PGManYSx;A=GB&y|dG-M#1H+1U*&0y{SNsB_R&9!}p9mWA7jR&xZk-?k z8UX^$m49L3%5oJ3k5)I>9&!hbPxyjnY_b|AUr4-azq;e}2PVXdh68zX>e!Y*Rtef% zy1L=@(ps%Mk9O?kniNv8Vp@3_d|088je#McVEM%Djwjnn&fmA+0Z-u?77=m?C54<8!MJ{z??Z!Y>w z_o|ON&Z)okcCKIS-mj&ki*mA*%d$Y`TF*Dc>4Kyq3`eQHBCOo zGy6Aa&CqiH`JjFJx!=r-pZT0cX=U6kao+`LWTe|LFgQ3H^CWLgl$gzP_{S}S9+kre zev)ky(&V1$h=(h zyCstY0|F8x+7e@Sm!0L{=U=~NdSGB+o3eHJJDIPRg|(cVoL@i%q|Lq_`(N(0y~Te- zMblfG9=(|mJV*6X*JjtC!fQ8DB#ymus~26<(7>P@w&+h=#@&#v}Ld$1nGrJ8Am#>3{zG`SN0M|Er(R z=dUmLeJe&)OGU+H=FFL(rJ+Sdo6hc97rXn_kxpUIrrWjKL1Q#sU0tiLexEdT>e7aW z2BU?Vkd=0+PF|qR9^W-3eN;3J3 zEPMaSO!)nNfBffXXD^?etUh(-Owgj-mEr5-u6@nR%S(-$as3K<>%kB-gCSS{r%=|m zDx|Wq(#y;1(qw;>C+S6$coXJWI>SJCr2F$e_?*;s)9v9uyQL zA}YG{!i50PNhznN>u+Bt51CQOe<1-Hgj?o2`^vgl>(Wu{T~i-|N3y4|LUqx?c6&% z0zW@LzkS_o>+*G=9U6SHRxi$3zu$86{+*r0U+)y32L&`}g5q}m{<9tIGA`gXcMK+; zz5kRW;^N{!Yl5fg#YVmR6}mbsa=+eRb91kM`!|&`GBW-G?Idk#V$zM;vf>Q)U(haV ze%mhrt)^k$cf7s5{rbPZzfa$>H!!#Wnz{gWmJYY^Ui;rKX?*P0*8ThUpH;1AwCD?y zYcyeGxS+E0LenbSPbZW=eg8gv`t<47)vbs&(LrTwCIh2fuRgEodBD=SbMelJZz!CX9i{l1`CEXhX;4y z3k?{UI1-=>4Hy_%Hb55|G%zqBEi@<)09EVntalZH)|oS0(MBvZ-@sMz)A#G`U6=Ka zbCsCC{w{m_WgkPl6h8yQg%$(mCge5*$R^klJdjneC3p@DjL2;W245cag@?70f4!Ia zWweKZfg$71U~5FYN&fTWBVX+N?c2>kg;(yaEeq?f9RKn7W9pxa_OG&;9-qh9hdwF$ z;<&n}*La4jJoPv=ZHlVqWavneGtzc%lx7QRi|GObpPbDK z&|c=dcVhzs13^923@)jXHLB|Br&Ek>>NwQyEO^*-=+L1I7MY|qA3yVd+f@AA&(+QC z)ZxRak+aTwZ*0$>FIV>? zQHrr$GW*XTXXg_qP6RCXn+x)vcKEszSFeUnN`V~QF{_D9HoLR4bCzlLv`d#So7VrU zxwp`5Z|2oiqP`8zy{2{l7Ao%fey4Dqyquhz2`jG^ zs0L2|`|F(b`zzaWZ)eCgs5Q>7-?07f@9&^h0sH?v)qh*&ljgAC+S+JsQ`68%Q)bON zbv5BZK=RrZD?Hx4duPJ$F!}I#`zzZ)Cm9`VVx47OzAm=ko1wAl>#L; z5>oZ$g=6rA1<7lj+xb9y+qk&7w^o18lrn|19|Mq2TZR|9|J_?f+XQ#k{-Ebn?lRy?36hi`{LKc!&jbLeuv< z#r<|a9x(s>`SYT~mHYaKg&y;7_#W~2xxAFq?y|Qfe|{9szMc2r`2sAn0iNJ=T%epK z;_!n*43zA5D>i^AP{SEK(T#ltCc!B6hKEXESOUh5cpw7m{IYLDID^x zraVe5po!WAneF|r*!Z)b6-*5YI2UBp5n;D1RZGZvjK`cK+*+ zHU!=~)3)+RQpZiu+RO!-ZTyRyE=-I!DiP5SSB*85Y*X~)R{81qNi%MbN~K4Z;>yZS zha^r_y`>P}EE9I}I$tL;jYA4vK1A#n^7mz0;EfMEfH?jzPf5h-;*{5_z@M(e##cdNl zrP=F*?>(h0=%Dkwu17Q9eJZQK%U_m?(-|GCriR=E)o$&0}$CQ%O?i;-R z#R`baflBZLnN##JQ~Ef_FFjrTT-G@yGywq2z&nQk diff --git a/vendor/github.com/go-json-experiment/json/benchmark-unmarshal-rawvalue.png b/vendor/github.com/go-json-experiment/json/benchmark-unmarshal-rawvalue.png deleted file mode 100644 index 0ca4fb02054163d4ba6e1dbed27e4b5888d415e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24810 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 0 && len(e.JSONValue) < 100 { + sb.WriteByte(' ') + sb.Write(e.JSONValue) } // Format Go type. if e.GoType != nil { - if !omitPreposition { - sb.WriteString(preposition) + typeString := e.GoType.String() + if len(typeString) > 100 { + // An excessively long type string most likely occurs for + // an anonymous struct declaration with many fields. + // Reduce the noise by just printing the kind, + // and optionally prepending it with the package name + // if the struct happens to include an unexported field. + typeString = e.GoType.Kind().String() + if e.GoType.Kind() == reflect.Struct && e.GoType.Name() == "" { + for i := range e.GoType.NumField() { + if pkgPath := e.GoType.Field(i).PkgPath; pkgPath != "" { + typeString = pkgPath[strings.LastIndexByte(pkgPath, '/')+len("/"):] + ".struct" + break + } + } + } } - sb.WriteString(" Go value of type ") - sb.WriteString(e.GoType.String()) + sb.WriteString(preposition) + sb.WriteString(" Go ") + sb.WriteString(typeString) + } + + // Special handling for unknown names. + if e.Err == ErrUnknownName { + sb.WriteString(": ") + sb.WriteString(ErrUnknownName.Error()) + sb.WriteString(" ") + sb.WriteString(strconv.Quote(e.JSONPointer.LastToken())) + if parent := e.JSONPointer.Parent(); parent != "" { + sb.WriteString(" within ") + sb.WriteString(strconv.Quote(jsonwire.TruncatePointer(string(parent), 100))) + } + return sb.String() } // Format where. - switch { + // Avoid printing if it overlaps with a wrapped SyntacticError. + switch serr, _ := e.Err.(*jsontext.SyntacticError); { case e.JSONPointer != "": - sb.WriteString(" within JSON value at ") - sb.WriteString(strconv.Quote(e.JSONPointer)) + if serr == nil || !e.JSONPointer.Contains(serr.JSONPointer) { + sb.WriteString(" within ") + sb.WriteString(strconv.Quote(jsonwire.TruncatePointer(string(e.JSONPointer), 100))) + } case e.ByteOffset > 0: - sb.WriteString(" after byte offset ") - sb.WriteString(strconv.FormatInt(e.ByteOffset, 10)) + if serr == nil || !(e.ByteOffset <= serr.ByteOffset) { + sb.WriteString(" after offset ") + sb.WriteString(strconv.FormatInt(e.ByteOffset, 10)) + } } // Format underlying error. if e.Err != nil { + errString := e.Err.Error() + if isSyntacticError(e.Err) { + errString = strings.TrimPrefix(errString, "jsontext: ") + } sb.WriteString(": ") - sb.WriteString(e.Err.Error()) + sb.WriteString(errString) } return sb.String() } + func (e *SemanticError) Unwrap() error { return e.Err } -func firstError(errs ...error) error { - for _, err := range errs { - if err != nil { - return err - } +func newDuplicateNameError(ptr jsontext.Pointer, quotedName []byte, offset int64) error { + if quotedName != nil { + name, _ := jsonwire.AppendUnquote(nil, quotedName) + ptr = ptr.AppendToken(string(name)) + } + return &jsontext.SyntacticError{ + ByteOffset: offset, + JSONPointer: ptr, + Err: jsontext.ErrDuplicateName, } - return nil } diff --git a/vendor/github.com/go-json-experiment/json/fields.go b/vendor/github.com/go-json-experiment/json/fields.go index 91e54c3..082f320 100644 --- a/vendor/github.com/go-json-experiment/json/fields.go +++ b/vendor/github.com/go-json-experiment/json/fields.go @@ -20,13 +20,11 @@ import ( "github.com/go-json-experiment/json/internal/jsonwire" ) -var errIgnoredField = errors.New("ignored field") - type isZeroer interface { IsZero() bool } -var isZeroerType = reflect.TypeOf((*isZeroer)(nil)).Elem() +var isZeroerType = reflect.TypeFor[isZeroer]() type structFields struct { flattened []structField // listed in depth-first ordering @@ -35,6 +33,27 @@ type structFields struct { inlinedFallback *structField } +// reindex recomputes index to avoid bounds check during runtime. +// +// During the construction of each [structField] in [makeStructFields], +// the index field is 0-indexed. However, before it returns, +// the 0th field is stored in index0 and index stores the remainder. +func (sf *structFields) reindex() { + reindex := func(f *structField) { + f.index0 = f.index[0] + f.index = f.index[1:] + if len(f.index) == 0 { + f.index = nil // avoid pinning the backing slice + } + } + for i := range sf.flattened { + reindex(&sf.flattened[i]) + } + if sf.inlinedFallback != nil { + reindex(sf.inlinedFallback) + } +} + // lookupByFoldedName looks up name by a case-insensitive match // that also ignores the presence of dashes and underscores. func (fs *structFields) lookupByFoldedName(name []byte) []*structField { @@ -43,7 +62,8 @@ func (fs *structFields) lookupByFoldedName(name []byte) []*structField { type structField struct { id int // unique numeric ID in breadth-first ordering - index []int // index into a struct according to reflect.Type.FieldByIndex + index0 int // 0th index into a struct according to [reflect.Type.FieldByIndex] + index []int // 1st index and remainder according to [reflect.Type.FieldByIndex] typ reflect.Type fncs *arshaler isZero func(addressableValue) bool @@ -51,7 +71,13 @@ type structField struct { fieldOptions } -func makeStructFields(root reflect.Type) (structFields, *SemanticError) { +var errNoExportedFields = errors.New("Go struct has no exported fields") + +func makeStructFields(root reflect.Type) (fs structFields, serr *SemanticError) { + orErrorf := func(serr *SemanticError, t reflect.Type, f string, a ...any) *SemanticError { + return cmp.Or(serr, &SemanticError{GoType: t, Err: fmt.Errorf(f, a...)}) + } + // Setup a queue for a breath-first search. var queueIndex int type queueEntry struct { @@ -74,14 +100,15 @@ func makeStructFields(root reflect.Type) (structFields, *SemanticError) { namesIndex := make(map[string]int) // index of each field with a given JSON object name in current struct var hasAnyJSONTag bool // whether any Go struct field has a `json` tag var hasAnyJSONField bool // whether any JSON serializable fields exist in current struct - for i := 0; i < t.NumField(); i++ { + for i := range t.NumField() { sf := t.Field(i) _, hasTag := sf.Tag.Lookup("json") hasAnyJSONTag = hasAnyJSONTag || hasTag options, ignored, err := parseFieldOptions(sf) if err != nil { - return structFields{}, &SemanticError{GoType: t, Err: err} - } else if ignored { + serr = cmp.Or(serr, &SemanticError{GoType: t, Err: err}) + } + if ignored { continue } hasAnyJSONField = true @@ -94,52 +121,55 @@ func makeStructFields(root reflect.Type) (structFields, *SemanticError) { fieldOptions: options, } if sf.Anonymous && !f.hasName { - f.inline = true // implied by use of Go embedding without an explicit name + if indirectType(f.typ).Kind() != reflect.Struct { + serr = orErrorf(serr, t, "embedded Go struct field %s of non-struct type must be explicitly given a JSON name", sf.Name) + } else { + f.inline = true // implied by use of Go embedding without an explicit name + } } if f.inline || f.unknown { // Handle an inlined field that serializes to/from // zero or more JSON object members. - if f.inline && f.unknown { - err := fmt.Errorf("Go struct field %s cannot have both `inline` and `unknown` specified", sf.Name) - return structFields{}, &SemanticError{GoType: t, Err: err} - } switch f.fieldOptions { case fieldOptions{name: f.name, quotedName: f.quotedName, inline: true}: case fieldOptions{name: f.name, quotedName: f.quotedName, unknown: true}: + case fieldOptions{name: f.name, quotedName: f.quotedName, inline: true, unknown: true}: + serr = orErrorf(serr, t, "Go struct field %s cannot have both `inline` and `unknown` specified", sf.Name) + f.inline = false // let `unknown` take precedence default: - err := fmt.Errorf("Go struct field %s cannot have any options other than `inline` or `unknown` specified", sf.Name) - return structFields{}, &SemanticError{GoType: t, Err: err} + serr = orErrorf(serr, t, "Go struct field %s cannot have any options other than `inline` or `unknown` specified", sf.Name) + if f.hasName { + continue // invalid inlined field; treat as ignored + } + f.fieldOptions = fieldOptions{name: f.name, quotedName: f.quotedName, inline: f.inline, unknown: f.unknown} + if f.inline && f.unknown { + f.inline = false // let `unknown` take precedence + } } - // Unwrap one level of pointer indirection similar to how Go - // only allows embedding either T or *T, but not **T. - tf := f.typ - if tf.Kind() == reflect.Pointer && tf.Name() == "" { - tf = tf.Elem() - } // Reject any types with custom serialization otherwise // it becomes impossible to know what sub-fields to inline. - if which := implementsWhich(tf, - jsonMarshalerV2Type, jsonMarshalerV1Type, textMarshalerType, - jsonUnmarshalerV2Type, jsonUnmarshalerV1Type, textUnmarshalerType, - ); which != nil && tf != jsontextValueType { - err := fmt.Errorf("inlined Go struct field %s of type %s must not implement JSON marshal or unmarshal methods", sf.Name, tf) - return structFields{}, &SemanticError{GoType: t, Err: err} + tf := indirectType(f.typ) + if implementsAny(tf, allMethodTypes...) && tf != jsontextValueType { + serr = orErrorf(serr, t, "inlined Go struct field %s of type %s must not implement marshal or unmarshal methods", sf.Name, tf) } // Handle an inlined field that serializes to/from // a finite number of JSON object members backed by a Go struct. if tf.Kind() == reflect.Struct { if f.unknown { - err := fmt.Errorf("inlined Go struct field %s of type %s with `unknown` tag must be a Go map of string key or a jsontext.Value", sf.Name, tf) - return structFields{}, &SemanticError{GoType: t, Err: err} + serr = orErrorf(serr, t, "inlined Go struct field %s of type %s with `unknown` tag must be a Go map of string key or a jsontext.Value", sf.Name, tf) + continue // invalid inlined field; treat as ignored } if qe.visitChildren { queue = append(queue, queueEntry{tf, f.index, !seen[tf]}) } seen[tf] = true continue + } else if !sf.IsExported() { + serr = orErrorf(serr, t, "inlined Go struct field %s is not exported", sf.Name) + continue // invalid inlined field; treat as ignored } // Handle an inlined field that serializes to/from any number of @@ -147,17 +177,22 @@ func makeStructFields(root reflect.Type) (structFields, *SemanticError) { switch { case tf == jsontextValueType: f.fncs = nil // specially handled in arshal_inlined.go - case tf.Kind() == reflect.Map && tf.Key() == stringType: + case tf.Kind() == reflect.Map && tf.Key().Kind() == reflect.String: + if implementsAny(tf.Key(), allMethodTypes...) { + serr = orErrorf(serr, t, "inlined map field %s of type %s must have a string key that does not implement marshal or unmarshal methods", sf.Name, tf) + continue // invalid inlined field; treat as ignored + } f.fncs = lookupArshaler(tf.Elem()) default: - err := fmt.Errorf("inlined Go struct field %s of type %s must be a Go struct, Go map of string key, or jsontext.Value", sf.Name, tf) - return structFields{}, &SemanticError{GoType: t, Err: err} + serr = orErrorf(serr, t, "inlined Go struct field %s of type %s must be a Go struct, Go map of string key, or jsontext.Value", sf.Name, tf) + continue // invalid inlined field; treat as ignored } // Reject multiple inlined fallback fields within the same struct. if inlinedFallbackIndex >= 0 { - err := fmt.Errorf("inlined Go struct fields %s and %s cannot both be a Go map or jsontext.Value", t.Field(inlinedFallbackIndex).Name, sf.Name) - return structFields{}, &SemanticError{GoType: t, Err: err} + serr = orErrorf(serr, t, "inlined Go struct fields %s and %s cannot both be a Go map or jsontext.Value", t.Field(inlinedFallbackIndex).Name, sf.Name) + // Still append f to inlinedFallbacks as there is still a + // check for a dominant inlined fallback before returning. } inlinedFallbackIndex = i @@ -166,6 +201,24 @@ func makeStructFields(root reflect.Type) (structFields, *SemanticError) { // Handle normal Go struct field that serializes to/from // a single JSON object member. + // Unexported fields cannot be serialized except for + // embedded fields of a struct type, + // which might promote exported fields of their own. + if !sf.IsExported() { + tf := indirectType(f.typ) + if !(sf.Anonymous && tf.Kind() == reflect.Struct) { + serr = orErrorf(serr, t, "Go struct field %s is not exported", sf.Name) + continue + } + // Unfortunately, methods on the unexported field + // still cannot be called. + if implementsAny(tf, allMethodTypes...) || + (f.omitzero && implementsAny(tf, isZeroerType)) { + serr = orErrorf(serr, t, "Go struct field %s is not exported for method calls", sf.Name) + continue + } + } + // Provide a function that uses a type's IsZero method. switch { case sf.Type.Kind() == reflect.Interface && sf.Type.Implements(isZeroerType): @@ -194,15 +247,11 @@ func makeStructFields(root reflect.Type) (structFields, *SemanticError) { f.isEmpty = func(va addressableValue) bool { return va.IsNil() } } - // Reject user-specified names with invalid UTF-8. - if !utf8.ValidString(f.name) { - err := fmt.Errorf("Go struct field %s has JSON object name %q with invalid UTF-8", sf.Name, f.name) - return structFields{}, &SemanticError{GoType: t, Err: err} - } // Reject multiple fields with same name within the same struct. if j, ok := namesIndex[f.name]; ok { - err := fmt.Errorf("Go struct fields %s and %s conflict over JSON object name %q", t.Field(j).Name, sf.Name, f.name) - return structFields{}, &SemanticError{GoType: t, Err: err} + serr = orErrorf(serr, t, "Go struct fields %s and %s conflict over JSON object name %q", t.Field(j).Name, sf.Name, f.name) + // Still append f to allFields as there is still a + // check for a dominant field before returning. } namesIndex[f.name] = i @@ -223,8 +272,7 @@ func makeStructFields(root reflect.Type) (structFields, *SemanticError) { // errors returned by errors.New would fail to serialize. isEmptyStruct := t.NumField() == 0 if !isEmptyStruct && !hasAnyJSONTag && !hasAnyJSONField { - err := errors.New("Go struct has no exported fields") - return structFields{}, &SemanticError{GoType: t, Err: err} + serr = cmp.Or(serr, &SemanticError{GoType: t, Err: errNoExportedFields}) } } @@ -236,19 +284,11 @@ func makeStructFields(root reflect.Type) (structFields, *SemanticError) { // or the one that is uniquely tagged with a JSON name. // Otherwise, no dominant field exists for the set. flattened := allFields[:0] - slices.SortFunc(allFields, func(x, y structField) int { - switch { - case x.name != y.name: - return strings.Compare(x.name, y.name) - case len(x.index) != len(y.index): - return cmp.Compare(len(x.index), len(y.index)) - case x.hasName && !y.hasName: - return -1 - case !x.hasName && y.hasName: - return +1 - default: - return 0 // TODO(https://go.dev/issue/61643): Compare bools better. - } + slices.SortStableFunc(allFields, func(x, y structField) int { + return cmp.Or( + strings.Compare(x.name, y.name), + cmp.Compare(len(x.index), len(y.index)), + boolsCompare(!x.hasName, !y.hasName)) }) for len(allFields) > 0 { n := 1 // number of fields with the same exact name @@ -279,7 +319,7 @@ func makeStructFields(root reflect.Type) (structFields, *SemanticError) { // Compute the mapping of fields in the byActualName map. // Pre-fold all names so that we can lookup folded names quickly. - fs := structFields{ + fs = structFields{ flattened: flattened, byActualName: make(map[string]*structField, len(flattened)), byFoldedName: make(map[string][]*structField, len(flattened)), @@ -291,7 +331,7 @@ func makeStructFields(root reflect.Type) (structFields, *SemanticError) { } for foldedName, fields := range fs.byFoldedName { if len(fields) > 1 { - // The precedence order for conflicting nocase names + // The precedence order for conflicting ignoreCase names // is by breadth-first order, rather than depth-first order. slices.SortFunc(fields, func(x, y *structField) int { return cmp.Compare(x.id, y.id) @@ -302,17 +342,27 @@ func makeStructFields(root reflect.Type) (structFields, *SemanticError) { if n := len(inlinedFallbacks); n == 1 || (n > 1 && len(inlinedFallbacks[0].index) != len(inlinedFallbacks[1].index)) { fs.inlinedFallback = &inlinedFallbacks[0] // dominant inlined fallback field } + fs.reindex() + return fs, serr +} - return fs, nil +// indirectType unwraps one level of pointer indirection +// similar to how Go only allows embedding either T or *T, +// but not **T or P (which is a named pointer). +func indirectType(t reflect.Type) reflect.Type { + if t.Kind() == reflect.Pointer && t.Name() == "" { + t = t.Elem() + } + return t } // matchFoldedName matches a case-insensitive name depending on the options. // It assumes that foldName(f.name) == foldName(name). // -// Case-insensitive matching is used if the `nocase` tag option is specified +// Case-insensitive matching is used if the `case:ignore` tag option is specified // or the MatchCaseInsensitiveNames call option is specified -// (and the `strictcase` tag option is not specified). -// Functionally, the `nocase` and `strictcase` tag options take precedence. +// (and the `case:strict` tag option is not specified). +// Functionally, the `case:ignore` and `case:strict` tag options take precedence. // // The v1 definition of case-insensitivity operated under strings.EqualFold // and would strictly compare dashes and underscores, @@ -320,7 +370,7 @@ func makeStructFields(root reflect.Type) (structFields, *SemanticError) { // Thus, if the MatchCaseSensitiveDelimiter call option is specified, // the match is further restricted to using strings.EqualFold. func (f *structField) matchFoldedName(name []byte, flags *jsonflags.Flags) bool { - if f.casing == nocase || (flags.Get(jsonflags.MatchCaseInsensitiveNames) && f.casing != strictcase) { + if f.casing == caseIgnore || (flags.Get(jsonflags.MatchCaseInsensitiveNames) && f.casing != caseStrict) { if !flags.Get(jsonflags.MatchCaseSensitiveDelimiter) || strings.EqualFold(string(name), f.name) { return true } @@ -329,21 +379,22 @@ func (f *structField) matchFoldedName(name []byte, flags *jsonflags.Flags) bool } const ( - nocase = 1 - strictcase = 2 + caseIgnore = 1 + caseStrict = 2 ) type fieldOptions struct { - name string - quotedName string // quoted name per RFC 8785, section 3.2.2.2. - hasName bool - casing int8 // either 0, nocase, or strictcase - inline bool - unknown bool - omitzero bool - omitempty bool - string bool - format string + name string + quotedName string // quoted name per RFC 8785, section 3.2.2.2. + hasName bool + nameNeedEscape bool + casing int8 // either 0, caseIgnore, or caseStrict + inline bool + unknown bool + omitzero bool + omitempty bool + string bool + format string } // parseFieldOptions parses the `json` tag in a Go struct field as @@ -357,19 +408,19 @@ func parseFieldOptions(sf reflect.StructField) (out fieldOptions, ignored bool, return fieldOptions{}, true, nil } - // Check whether this field is unexported. - if !sf.IsExported() { - // In contrast to v1, v2 no longer forwards exported fields from - // embedded fields of unexported types since Go reflection does not - // allow the same set of operations that are available in normal cases - // of purely exported fields. - // See https://go.dev/issue/21357 and https://go.dev/issue/24153. - if sf.Anonymous { - err = firstError(err, fmt.Errorf("embedded Go struct field %s of an unexported type must be explicitly ignored with a `json:\"-\"` tag", sf.Type.Name())) - } + // Check whether this field is unexported and not embedded, + // which Go reflection cannot mutate for the sake of serialization. + // + // An embedded field of an unexported type is still capable of + // forwarding exported fields, which may be JSON serialized. + // This technically operates on the edge of what is permissible by + // the Go language, but the most recent decision is to permit this. + // + // See https://go.dev/issue/24153 and https://go.dev/issue/32772. + if !sf.IsExported() && !sf.Anonymous { // Tag options specified on an unexported field suggests user error. if hasTag { - err = firstError(err, fmt.Errorf("unexported Go struct field %s cannot have non-ignored `json:%q` tag", sf.Name, tag)) + err = cmp.Or(err, fmt.Errorf("unexported Go struct field %s cannot have non-ignored `json:%q` tag", sf.Name, tag)) } return fieldOptions{}, true, err } @@ -384,21 +435,31 @@ func parseFieldOptions(sf reflect.StructField) (out fieldOptions, ignored bool, n := len(tag) - len(strings.TrimLeftFunc(tag, func(r rune) bool { return !strings.ContainsRune(",\\'\"`", r) // reserve comma, backslash, and quotes })) - opt := tag[:n] - if n == 0 { - // Allow a single quoted string for arbitrary names. - var err2 error - opt, n, err2 = consumeTagOption(tag) + name := tag[:n] + + // If the next character is not a comma, then the name is either + // malformed (if n > 0) or a single-quoted name. + // In either case, call consumeTagOption to handle it further. + var err2 error + if !strings.HasPrefix(tag[n:], ",") && len(name) != len(tag) { + name, n, err2 = consumeTagOption(tag) if err2 != nil { - err = firstError(err, fmt.Errorf("Go struct field %s has malformed `json` tag: %v", sf.Name, err2)) + err = cmp.Or(err, fmt.Errorf("Go struct field %s has malformed `json` tag: %v", sf.Name, err2)) } } - out.hasName = true - out.name = opt + if !utf8.ValidString(name) { + err = cmp.Or(err, fmt.Errorf("Go struct field %s has JSON object name %q with invalid UTF-8", sf.Name, name)) + name = string([]rune(name)) // replace invalid UTF-8 with utf8.RuneError + } + if err2 == nil { + out.hasName = true + out.name = name + } tag = tag[n:] } b, _ := jsonwire.AppendQuote(nil, out.name, &jsonflags.Flags{}) out.quotedName = string(b) + out.nameNeedEscape = jsonwire.NeedEscape(out.name) // Handle any additional tag options (if any). var wasFormat bool @@ -406,11 +467,11 @@ func parseFieldOptions(sf reflect.StructField) (out fieldOptions, ignored bool, for len(tag) > 0 { // Consume comma delimiter. if tag[0] != ',' { - err = firstError(err, fmt.Errorf("Go struct field %s has malformed `json` tag: invalid character %q before next option (expecting ',')", sf.Name, tag[0])) + err = cmp.Or(err, fmt.Errorf("Go struct field %s has malformed `json` tag: invalid character %q before next option (expecting ',')", sf.Name, tag[0])) } else { tag = tag[len(","):] if len(tag) == 0 { - err = firstError(err, fmt.Errorf("Go struct field %s has malformed `json` tag: invalid trailing ',' character", sf.Name)) + err = cmp.Or(err, fmt.Errorf("Go struct field %s has malformed `json` tag: invalid trailing ',' character", sf.Name)) break } } @@ -418,21 +479,41 @@ func parseFieldOptions(sf reflect.StructField) (out fieldOptions, ignored bool, // Consume and process the tag option. opt, n, err2 := consumeTagOption(tag) if err2 != nil { - err = firstError(err, fmt.Errorf("Go struct field %s has malformed `json` tag: %v", sf.Name, err2)) + err = cmp.Or(err, fmt.Errorf("Go struct field %s has malformed `json` tag: %v", sf.Name, err2)) } rawOpt := tag[:n] tag = tag[n:] switch { case wasFormat: - err = firstError(err, fmt.Errorf("Go struct field %s has `format` tag option that was not specified last", sf.Name)) + err = cmp.Or(err, fmt.Errorf("Go struct field %s has `format` tag option that was not specified last", sf.Name)) case strings.HasPrefix(rawOpt, "'") && strings.TrimFunc(opt, isLetterOrDigit) == "": - err = firstError(err, fmt.Errorf("Go struct field %s has unnecessarily quoted appearance of `%s` tag option; specify `%s` instead", sf.Name, rawOpt, opt)) + err = cmp.Or(err, fmt.Errorf("Go struct field %s has unnecessarily quoted appearance of `%s` tag option; specify `%s` instead", sf.Name, rawOpt, opt)) } switch opt { - case "nocase": - out.casing |= nocase - case "strictcase": - out.casing |= strictcase + case "case": + if !strings.HasPrefix(tag, ":") { + err = cmp.Or(err, fmt.Errorf("Go struct field %s is missing value for `case` tag option; specify `case:ignore` or `case:strict` instead", sf.Name)) + break + } + tag = tag[len(":"):] + opt, n, err2 := consumeTagOption(tag) + if err2 != nil { + err = cmp.Or(err, fmt.Errorf("Go struct field %s has malformed value for `case` tag option: %v", sf.Name, err2)) + break + } + rawOpt := tag[:n] + tag = tag[n:] + if strings.HasPrefix(rawOpt, "'") { + err = cmp.Or(err, fmt.Errorf("Go struct field %s has unnecessarily quoted appearance of `case:%s` tag option; specify `case:%s` instead", sf.Name, rawOpt, opt)) + } + switch opt { + case "ignore": + out.casing |= caseIgnore + case "strict": + out.casing |= caseStrict + default: + err = cmp.Or(err, fmt.Errorf("Go struct field %s has unknown `case:%s` tag value", sf.Name, rawOpt)) + } case "inline": out.inline = true case "unknown": @@ -445,13 +526,13 @@ func parseFieldOptions(sf reflect.StructField) (out fieldOptions, ignored bool, out.string = true case "format": if !strings.HasPrefix(tag, ":") { - err = firstError(err, fmt.Errorf("Go struct field %s is missing value for `format` tag option", sf.Name)) + err = cmp.Or(err, fmt.Errorf("Go struct field %s is missing value for `format` tag option", sf.Name)) break } tag = tag[len(":"):] opt, n, err2 := consumeTagOption(tag) if err2 != nil { - err = firstError(err, fmt.Errorf("Go struct field %s has malformed value for `format` tag option: %v", sf.Name, err2)) + err = cmp.Or(err, fmt.Errorf("Go struct field %s has malformed value for `format` tag option: %v", sf.Name, err2)) break } tag = tag[n:] @@ -462,8 +543,8 @@ func parseFieldOptions(sf reflect.StructField) (out fieldOptions, ignored bool, // This catches invalid mutants such as "omitEmpty" or "omit_empty". normOpt := strings.ReplaceAll(strings.ToLower(opt), "_", "") switch normOpt { - case "nocase", "strictcase", "inline", "unknown", "omitzero", "omitempty", "string", "format": - err = firstError(err, fmt.Errorf("Go struct field %s has invalid appearance of `%s` tag option; specify `%s` instead", sf.Name, opt, normOpt)) + case "case", "inline", "unknown", "omitzero", "omitempty", "string", "format": + err = cmp.Or(err, fmt.Errorf("Go struct field %s has invalid appearance of `%s` tag option; specify `%s` instead", sf.Name, opt, normOpt)) } // NOTE: Everything else is ignored. This does not mean it is @@ -473,16 +554,20 @@ func parseFieldOptions(sf reflect.StructField) (out fieldOptions, ignored bool, // Reject duplicates. switch { - case out.casing == nocase|strictcase: - err = firstError(err, fmt.Errorf("Go struct field %s cannot have both `nocase` and `structcase` tag options", sf.Name)) + case out.casing == caseIgnore|caseStrict: + err = cmp.Or(err, fmt.Errorf("Go struct field %s cannot have both `case:ignore` and `case:strict` tag options", sf.Name)) case seenOpts[opt]: - err = firstError(err, fmt.Errorf("Go struct field %s has duplicate appearance of `%s` tag option", sf.Name, rawOpt)) + err = cmp.Or(err, fmt.Errorf("Go struct field %s has duplicate appearance of `%s` tag option", sf.Name, rawOpt)) } seenOpts[opt] = true } return out, false, err } +// consumeTagOption consumes the next option, +// which is either a Go identifier or a single-quoted string. +// If the next option is invalid, it returns all of in until the next comma, +// and reports an error. func consumeTagOption(in string) (string, int, error) { // For legacy compatibility with v1, assume options are comma-separated. i := strings.IndexByte(in, ',') @@ -545,3 +630,15 @@ func consumeTagOption(in string) (string, int, error) { func isLetterOrDigit(r rune) bool { return r == '_' || unicode.IsLetter(r) || unicode.IsNumber(r) } + +// boolsCompare compares x and y, ordering false before true. +func boolsCompare(x, y bool) int { + switch { + case !x && y: + return -1 + default: + return 0 + case x && !y: + return +1 + } +} diff --git a/vendor/github.com/go-json-experiment/json/internal/internal.go b/vendor/github.com/go-json-experiment/json/internal/internal.go index cf020cd..bb36b03 100644 --- a/vendor/github.com/go-json-experiment/json/internal/internal.go +++ b/vendor/github.com/go-json-experiment/json/internal/internal.go @@ -4,6 +4,8 @@ package internal +import "errors" + // NotForPublicUse is a marker type that an API is for internal use only. // It does not perfectly prevent usage of that API, but helps to restrict usage. // Anything with this marker is not covered by the Go compatibility agreement. @@ -12,3 +14,26 @@ type NotForPublicUse struct{} // AllowInternalUse is passed from "json" to "jsontext" to authenticate // that the caller can have access to internal functionality. var AllowInternalUse NotForPublicUse + +// Sentinel error values internally shared between jsonv1 and jsonv2. +var ( + ErrCycle = errors.New("encountered a cycle") + ErrNonNilReference = errors.New("value must be passed as a non-nil pointer reference") +) + +var ( + // TransformMarshalError converts a v2 error into a v1 error. + // It is called only at the top-level of a Marshal function. + TransformMarshalError func(any, error) error + // NewMarshalerError constructs a jsonv1.MarshalerError. + // It is called after a user-defined Marshal method/function fails. + NewMarshalerError func(any, error, string) error + // TransformUnmarshalError converts a v2 error into a v1 error. + // It is called only at the top-level of a Unmarshal function. + TransformUnmarshalError func(any, error) error + + // NewRawNumber returns new(jsonv1.Number). + NewRawNumber func() any + // RawNumberOf returns jsonv1.Number(b). + RawNumberOf func(b []byte) any +) diff --git a/vendor/github.com/go-json-experiment/json/internal/jsonflags/flags.go b/vendor/github.com/go-json-experiment/json/internal/jsonflags/flags.go index c2473cd..d9cad6e 100644 --- a/vendor/github.com/go-json-experiment/json/internal/jsonflags/flags.go +++ b/vendor/github.com/go-json-experiment/json/internal/jsonflags/flags.go @@ -14,7 +14,7 @@ import "github.com/go-json-experiment/json/internal" // // In common usage, this is OR'd with 0 or 1. For example: // - (AllowInvalidUTF8 | 0) means "AllowInvalidUTF8 is false" -// - (Expand | Indent | 1) means "Expand and Indent are true" +// - (Multiline | Indent | 1) means "Multiline and Indent are true" type Bools uint64 func (Bools) JSONOptions(internal.NotForPublicUse) {} @@ -50,40 +50,59 @@ const ( AllowInvalidUTF8 | EscapeForHTML | EscapeForJS | + EscapeInvalidUTF8 | + PreserveRawStrings | Deterministic | FormatNilMapAsNull | FormatNilSliceAsNull | MatchCaseInsensitiveNames | - FormatByteArrayAsArray | - FormatTimeDurationAsNanosecond | - IgnoreStructErrors | + CallMethodsWithLegacySemantics | + FormatBytesWithLegacySemantics | + FormatTimeWithLegacySemantics | MatchCaseSensitiveDelimiter | MergeWithLegacySemantics | OmitEmptyWithLegacyDefinition | - RejectFloatOverflow | - ReportLegacyErrorValues | - SkipUnaddressableMethods | + ReportErrorsWithLegacySemantics | StringifyWithLegacySemantics | UnmarshalArrayFromAnyLength + + // AnyWhitespace reports whether the encoded output might have any whitespace. + AnyWhitespace = Multiline | SpaceAfterColon | SpaceAfterComma + + // WhitespaceFlags is the set of flags related to whitespace formatting. + // In contrast to AnyWhitespace, this includes Indent and IndentPrefix + // as those settings take no effect if Multiline is false. + WhitespaceFlags = AnyWhitespace | Indent | IndentPrefix + + // AnyEscape is the set of flags related to escaping in a JSON string. + AnyEscape = EscapeForHTML | EscapeForJS | EscapeInvalidUTF8 + + // CanonicalizeNumbers is the set of flags related to raw number canonicalization. + CanonicalizeNumbers = CanonicalizeRawInts | CanonicalizeRawFloats ) // Encoder and decoder flags. const ( initFlag Bools = 1 << iota // reserved for the boolean value itself - AllowDuplicateNames // encode or decode - AllowInvalidUTF8 // encode or decode - WithinArshalCall // encode or decode; for internal use by json.Marshal and json.Unmarshal - OmitTopLevelNewline // encode only; for internal use by json.Marshal and json.MarshalWrite - PreserveRawStrings // encode only; for internal use by jsontext.Value.Canonicalize - CanonicalizeNumbers // encode only; for internal use by jsontext.Value.Canonicalize - EscapeForHTML // encode only - EscapeForJS // encode only - Expand // encode only - Indent // encode only; non-boolean flag - IndentPrefix // encode only; non-boolean flag - ByteLimit // encode or decode; non-boolean flag - DepthLimit // encode or decode; non-boolean flag + AllowDuplicateNames // encode or decode + AllowInvalidUTF8 // encode or decode + WithinArshalCall // encode or decode; for internal use by json.Marshal and json.Unmarshal + OmitTopLevelNewline // encode only; for internal use by json.Marshal and json.MarshalWrite + PreserveRawStrings // encode only + CanonicalizeRawInts // encode only + CanonicalizeRawFloats // encode only + ReorderRawObjects // encode only + EscapeForHTML // encode only + EscapeForJS // encode only + EscapeInvalidUTF8 // encode only; only exposed in v1 + Multiline // encode only + SpaceAfterColon // encode only + SpaceAfterComma // encode only + Indent // encode only; non-boolean flag + IndentPrefix // encode only; non-boolean flag + ByteLimit // encode or decode; non-boolean flag + DepthLimit // encode or decode; non-boolean flag maxCoderFlag ) @@ -96,6 +115,7 @@ const ( Deterministic // marshal only FormatNilMapAsNull // marshal only FormatNilSliceAsNull // marshal only + OmitZeroStructFields // marshal only MatchCaseInsensitiveNames // marshal or unmarshal DiscardUnknownMembers // marshal only RejectUnknownMembers // unmarshal only @@ -109,18 +129,17 @@ const ( const ( _ Bools = (maxArshalV2Flag >> 1) << iota - FormatByteArrayAsArray // marshal or unmarshal - FormatTimeDurationAsNanosecond // marshal or unmarshal - IgnoreStructErrors // marshal or unmarshal - MatchCaseSensitiveDelimiter // marshal or unmarshal - MergeWithLegacySemantics // unmarshal - OmitEmptyWithLegacyDefinition // marshal - RejectFloatOverflow // unmarshal - ReportLegacyErrorValues // marshal or unmarshal - SkipUnaddressableMethods // marshal or unmarshal - StringifyWithLegacySemantics // marshal or unmarshal - UnmarshalAnyWithRawNumber // unmarshal; for internal use by jsonv1.Decoder.UseNumber - UnmarshalArrayFromAnyLength // unmarshal + CallMethodsWithLegacySemantics // marshal or unmarshal + FormatBytesWithLegacySemantics // marshal or unmarshal + FormatTimeWithLegacySemantics // marshal or unmarshal + MatchCaseSensitiveDelimiter // marshal or unmarshal + MergeWithLegacySemantics // unmarshal + OmitEmptyWithLegacyDefinition // marshal + ReportErrorsWithLegacySemantics // marshal or unmarshal + StringifyWithLegacySemantics // marshal or unmarshal + StringifyBoolsAndStrings // marshal or unmarshal; for internal use by jsonv2.makeStructArshaler + UnmarshalAnyWithRawNumber // unmarshal; for internal use by jsonv1.Decoder.UseNumber + UnmarshalArrayFromAnyLength // unmarshal maxArshalV1Flag ) diff --git a/vendor/github.com/go-json-experiment/json/internal/jsonopts/options.go b/vendor/github.com/go-json-experiment/json/internal/jsonopts/options.go index 6b63d5c..cd24e84 100644 --- a/vendor/github.com/go-json-experiment/json/internal/jsonopts/options.go +++ b/vendor/github.com/go-json-experiment/json/internal/jsonopts/options.go @@ -46,30 +46,17 @@ type ArshalValues struct { // DefaultOptionsV2 is the set of all options that define default v2 behavior. var DefaultOptionsV2 = Struct{ Flags: jsonflags.Flags{ - Presence: uint64(jsonflags.AllFlags), + Presence: uint64(jsonflags.AllFlags & ^jsonflags.WhitespaceFlags), Values: uint64(0), }, - CoderValues: CoderValues{Indent: "\t"}, // Indent is set, but Expand is set to false } // DefaultOptionsV1 is the set of all options that define default v1 behavior. var DefaultOptionsV1 = Struct{ Flags: jsonflags.Flags{ - Presence: uint64(jsonflags.AllFlags), + Presence: uint64(jsonflags.AllFlags & ^jsonflags.WhitespaceFlags), Values: uint64(jsonflags.DefaultV1Flags), }, - CoderValues: CoderValues{Indent: "\t"}, // Indent is set, but Expand is set to false -} - -// CopyCoderOptions copies coder-specific options from src to dst. -// This is used by json.MarshalEncode and json.UnmarshalDecode since those -// functions ignore any coder-specific options and uses the options from the -// Encoder or Decoder that is passed in. -func (dst *Struct) CopyCoderOptions(src *Struct) { - srcFlags := src.Flags - srcFlags.Clear(^jsonflags.AllCoderFlags) - dst.Flags.Join(srcFlags) - dst.CoderValues = src.CoderValues } func (*Struct) JSONOptions(internal.NotForPublicUse) {} @@ -125,50 +112,73 @@ func GetOption[T any](opts Options, setter func(T) Options) (T, bool) { var JoinUnknownOption = func(*Struct, Options) { panic("unknown option") } func (dst *Struct) Join(srcs ...Options) { + dst.join(false, srcs...) +} + +func (dst *Struct) JoinWithoutCoderOptions(srcs ...Options) { + dst.join(true, srcs...) +} + +func (dst *Struct) join(excludeCoderOptions bool, srcs ...Options) { for _, src := range srcs { switch src := src.(type) { case nil: continue case jsonflags.Bools: + if excludeCoderOptions { + src &= ^jsonflags.AllCoderFlags + } dst.Flags.Set(src) case Indent: - dst.Flags.Set(jsonflags.Expand | jsonflags.Indent | 1) + if excludeCoderOptions { + continue + } + dst.Flags.Set(jsonflags.Multiline | jsonflags.Indent | 1) dst.Indent = string(src) case IndentPrefix: - dst.Flags.Set(jsonflags.Expand | jsonflags.IndentPrefix | 1) + if excludeCoderOptions { + continue + } + dst.Flags.Set(jsonflags.Multiline | jsonflags.IndentPrefix | 1) dst.IndentPrefix = string(src) case ByteLimit: + if excludeCoderOptions { + continue + } dst.Flags.Set(jsonflags.ByteLimit | 1) dst.ByteLimit = int64(src) case DepthLimit: + if excludeCoderOptions { + continue + } dst.Flags.Set(jsonflags.DepthLimit | 1) dst.DepthLimit = int(src) case *Struct: - dst.Flags.Join(src.Flags) - if src.Flags.Has(jsonflags.NonBooleanFlags) { - if src.Flags.Has(jsonflags.Indent) { + srcFlags := src.Flags // shallow copy the flags + if excludeCoderOptions { + srcFlags.Clear(jsonflags.AllCoderFlags) + } + dst.Flags.Join(srcFlags) + if srcFlags.Has(jsonflags.NonBooleanFlags) { + if srcFlags.Has(jsonflags.Indent) { dst.Indent = src.Indent } - if src.Flags.Has(jsonflags.IndentPrefix) { + if srcFlags.Has(jsonflags.IndentPrefix) { dst.IndentPrefix = src.IndentPrefix } - if src.Flags.Has(jsonflags.ByteLimit) { + if srcFlags.Has(jsonflags.ByteLimit) { dst.ByteLimit = src.ByteLimit } - if src.Flags.Has(jsonflags.DepthLimit) { + if srcFlags.Has(jsonflags.DepthLimit) { dst.DepthLimit = src.DepthLimit } - if src.Flags.Has(jsonflags.Marshalers) { + if srcFlags.Has(jsonflags.Marshalers) { dst.Marshalers = src.Marshalers } - if src.Flags.Has(jsonflags.Unmarshalers) { + if srcFlags.Has(jsonflags.Unmarshalers) { dst.Unmarshalers = src.Unmarshalers } } - if src.Format != "" { - dst.Format = src.Format - dst.FormatDepth = src.FormatDepth - } default: JoinUnknownOption(dst, src) } diff --git a/vendor/github.com/go-json-experiment/json/internal/jsonwire/decode.go b/vendor/github.com/go-json-experiment/json/internal/jsonwire/decode.go index 76ee382..0278771 100644 --- a/vendor/github.com/go-json-experiment/json/internal/jsonwire/decode.go +++ b/vendor/github.com/go-json-experiment/json/internal/jsonwire/decode.go @@ -74,7 +74,7 @@ func ConsumeTrue(b []byte) int { func ConsumeLiteral(b []byte, lit string) (n int, err error) { for i := 0; i < len(b) && i < len(lit); i++ { if b[i] != lit[i] { - return i, NewInvalidCharacterError(b[i:], "within literal "+lit+" (expecting "+strconv.QuoteRune(rune(lit[i]))+")") + return i, NewInvalidCharacterError(b[i:], "in literal "+lit+" (expecting "+strconv.QuoteRune(rune(lit[i]))+")") } } if len(b) < len(lit) { @@ -240,7 +240,7 @@ func ConsumeStringResumable(flags *ValueFlags, b []byte, resumeOffset int, valid // Handle invalid control characters. case r < ' ': flags.Join(stringNonVerbatim | stringNonCanonical) - return n, NewInvalidCharacterError(b[n:], "within string (expecting non-control character)") + return n, NewInvalidCharacterError(b[n:], "in string (expecting non-control character)") default: panic("BUG: unhandled character " + QuoteRune(b[n:])) } @@ -374,7 +374,7 @@ func AppendUnquote[Bytes ~[]byte | ~string](dst []byte, src Bytes) (v []byte, er // Handle invalid control characters. case r < ' ': dst = append(dst, src[i:n]...) - return dst, NewInvalidCharacterError(src[n:], "within string (expecting non-control character)") + return dst, NewInvalidCharacterError(src[n:], "in string (expecting non-control character)") default: panic("BUG: unhandled character " + QuoteRune(src[n:])) } @@ -386,7 +386,7 @@ func AppendUnquote[Bytes ~[]byte | ~string](dst []byte, src Bytes) (v []byte, er // hasEscapedUTF16Prefix reports whether b is possibly // the truncated prefix of a \uFFFF escape sequence. func hasEscapedUTF16Prefix[Bytes ~[]byte | ~string](b Bytes, lowerSurrogateHalf bool) bool { - for i := 0; i < len(b); i++ { + for i := range len(b) { switch c := b[i]; { case i == 0 && c != '\\': return false @@ -513,7 +513,7 @@ beforeInteger: } state = withinIntegerDigits default: - return n, state, NewInvalidCharacterError(b[n:], "within number (expecting digit)") + return n, state, NewInvalidCharacterError(b[n:], "in number (expecting digit)") } // Consume optional fractional component. @@ -527,7 +527,7 @@ beforeFractional: case '0' <= b[n] && b[n] <= '9': n++ default: - return n, state, NewInvalidCharacterError(b[n:], "within number (expecting digit)") + return n, state, NewInvalidCharacterError(b[n:], "in number (expecting digit)") } for uint(len(b)) > uint(n) && ('0' <= b[n] && b[n] <= '9') { n++ @@ -549,7 +549,7 @@ beforeExponent: case '0' <= b[n] && b[n] <= '9': n++ default: - return n, state, NewInvalidCharacterError(b[n:], "within number (expecting digit)") + return n, state, NewInvalidCharacterError(b[n:], "in number (expecting digit)") } for uint(len(b)) > uint(n) && ('0' <= b[n] && b[n] <= '9') { n++ @@ -567,7 +567,7 @@ func parseHexUint16[Bytes ~[]byte | ~string](b Bytes) (v uint16, ok bool) { if len(b) != 4 { return 0, false } - for i := 0; i < 4; i++ { + for i := range 4 { c := b[i] switch { case '0' <= c && c <= '9': @@ -610,19 +610,6 @@ func ParseUint(b []byte) (v uint64, ok bool) { // then we return MaxFloat since any finite value will always be infinitely // more accurate at representing another finite value than an infinite value. func ParseFloat(b []byte, bits int) (v float64, ok bool) { - // Fast path for exact integer numbers which fit in the - // 24-bit or 53-bit significand of a float32 or float64. - var negLen int // either 0 or 1 - if len(b) > 0 && b[0] == '-' { - negLen = 1 - } - u, ok := ParseUint(b[negLen:]) - if ok && ((bits == 32 && u <= 1<<24) || (bits == 64 && u <= 1<<53)) { - return math.Copysign(float64(u), float64(-1*negLen)), true - } - - // Note that the []byte->string conversion unfortunately allocates. - // See https://go.dev/issue/42429 for more information. fv, err := strconv.ParseFloat(string(b), bits) if math.IsInf(fv, 0) { switch { diff --git a/vendor/github.com/go-json-experiment/json/internal/jsonwire/encode.go b/vendor/github.com/go-json-experiment/json/internal/jsonwire/encode.go index c9ea707..fb4c50d 100644 --- a/vendor/github.com/go-json-experiment/json/internal/jsonwire/encode.go +++ b/vendor/github.com/go-json-experiment/json/internal/jsonwire/encode.go @@ -66,35 +66,41 @@ func AppendQuote[Bytes ~[]byte | ~string](dst []byte, src Bytes, flags *jsonflag dst = slices.Grow(dst, len(`"`)+len(src)+len(`"`)) dst = append(dst, '"') for uint(len(src)) > uint(n) { - // Handle single-byte ASCII. if c := src[n]; c < utf8.RuneSelf { + // Handle single-byte ASCII. n++ - if escapeASCII[c] > 0 { - if (c == '<' || c == '>' || c == '&') && !flags.Get(jsonflags.EscapeForHTML) { - continue - } + if escapeASCII[c] == 0 { + continue // no escaping possibly needed + } + // Handle escaping of single-byte ASCII. + if !(c == '<' || c == '>' || c == '&') || flags.Get(jsonflags.EscapeForHTML) { dst = append(dst, src[i:n-1]...) dst = appendEscapedASCII(dst, c) i = n } - continue - } - - // Handle multi-byte Unicode. - switch r, rn := utf8.DecodeRuneInString(string(truncateMaxUTF8(src[n:]))); { - case r == utf8.RuneError && rn == 1: - hasInvalidUTF8 = true - dst = append(dst, src[i:n]...) - dst = append(dst, "\ufffd"...) - n += rn - i = n - case (r == '\u2028' || r == '\u2029') && flags.Get(jsonflags.EscapeForJS): - dst = append(dst, src[i:n]...) - dst = appendEscapedUnicode(dst, r) - n += rn - i = n - default: + } else { + // Handle multi-byte Unicode. + r, rn := utf8.DecodeRuneInString(string(truncateMaxUTF8(src[n:]))) n += rn + if r != utf8.RuneError && r != '\u2028' && r != '\u2029' { + continue // no escaping possibly needed + } + // Handle escaping of multi-byte Unicode. + switch { + case isInvalidUTF8(r, rn): + hasInvalidUTF8 = true + dst = append(dst, src[i:n-rn]...) + if flags.Get(jsonflags.EscapeInvalidUTF8) { + dst = append(dst, `\ufffd`...) + } else { + dst = append(dst, "\ufffd"...) + } + i = n + case (r == '\u2028' || r == '\u2029') && flags.Get(jsonflags.EscapeForJS): + dst = append(dst, src[i:n-rn]...) + dst = appendEscapedUnicode(dst, r) + i = n + } } } dst = append(dst, src[i:n]...) @@ -141,7 +147,7 @@ func appendEscapedUTF16(dst []byte, x uint16) []byte { } // ReformatString consumes a JSON string from src and appends it to dst, -// reformatting it if necessary for the given escapeRune parameter. +// reformatting it if necessary according to the specified flags. // It returns the appended output and the number of consumed input bytes. func ReformatString(dst, src []byte, flags *jsonflags.Flags) ([]byte, int, error) { // TODO: Should this update ValueFlags as input? @@ -150,18 +156,48 @@ func ReformatString(dst, src []byte, flags *jsonflags.Flags) ([]byte, int, error if err != nil { return dst, n, err } - isCanonical := !flags.Get(jsonflags.EscapeForHTML | jsonflags.EscapeForJS) - if flags.Get(jsonflags.PreserveRawStrings) || (isCanonical && valFlags.IsCanonical()) { + + // If the output requires no special escapes, and the input + // is already in canonical form or should be preserved verbatim, + // then directly copy the input to the output. + if !flags.Get(jsonflags.AnyEscape) && + (valFlags.IsCanonical() || flags.Get(jsonflags.PreserveRawStrings)) { dst = append(dst, src[:n]...) // copy the string verbatim return dst, n, nil } - // TODO: Implement a direct, raw-to-raw reformat for strings. - // If the escapeRune option would have resulted in no changes to the output, - // it would be faster to simply append src to dst without going through - // an intermediary representation in a separate buffer. + // Under [jsonflags.PreserveRawStrings], any pre-escaped sequences + // remain escaped, however we still need to respect the + // [jsonflags.EscapeForHTML] and [jsonflags.EscapeForJS] options. + if flags.Get(jsonflags.PreserveRawStrings) { + var i, lastAppendIndex int + for i < n { + if c := src[i]; c < utf8.RuneSelf { + if (c == '<' || c == '>' || c == '&') && flags.Get(jsonflags.EscapeForHTML) { + dst = append(dst, src[lastAppendIndex:i]...) + dst = appendEscapedASCII(dst, c) + lastAppendIndex = i + 1 + } + i++ + } else { + r, rn := utf8.DecodeRune(truncateMaxUTF8(src[i:])) + if (r == '\u2028' || r == '\u2029') && flags.Get(jsonflags.EscapeForJS) { + dst = append(dst, src[lastAppendIndex:i]...) + dst = appendEscapedUnicode(dst, r) + lastAppendIndex = i + rn + } + i += rn + } + } + return append(dst, src[lastAppendIndex:n]...), n, nil + } + + // The input contains characters that might need escaping, + // unnecessary escape sequences, or invalid UTF-8. + // Perform a round-trip unquote and quote to properly reformat + // these sequences according the current flags. b, _ := AppendUnquote(nil, src[:n]) - dst, _ = AppendQuote(dst, string(b), flags) + dst, _ = AppendQuote(dst, b, flags) return dst, n, nil } @@ -204,23 +240,45 @@ func AppendFloat(dst []byte, src float64, bits int) []byte { // ReformatNumber consumes a JSON string from src and appends it to dst, // canonicalizing it if specified. // It returns the appended output and the number of consumed input bytes. -func ReformatNumber(dst, src []byte, canonicalize bool) ([]byte, int, error) { +func ReformatNumber(dst, src []byte, flags *jsonflags.Flags) ([]byte, int, error) { n, err := ConsumeNumber(src) if err != nil { return dst, n, err } - if !canonicalize { + if !flags.Get(jsonflags.CanonicalizeNumbers) { dst = append(dst, src[:n]...) // copy the number verbatim return dst, n, nil } - // Canonicalize the number per RFC 8785, section 3.2.2.3. - // As an optimization, we can copy integer numbers below 2⁵³ verbatim. - const maxExactIntegerDigits = 16 // len(strconv.AppendUint(nil, 1<<53, 10)) - if n < maxExactIntegerDigits && ConsumeSimpleNumber(src[:n]) == n { - dst = append(dst, src[:n]...) // copy the number verbatim - return dst, n, nil + // Identify the kind of number. + var isFloat bool + for _, c := range src[:n] { + if c == '.' || c == 'e' || c == 'E' { + isFloat = true // has fraction or exponent + break + } } + + // Check if need to canonicalize this kind of number. + switch { + case string(src[:n]) == "-0": + break // canonicalize -0 as 0 regardless of kind + case isFloat: + if !flags.Get(jsonflags.CanonicalizeRawFloats) { + dst = append(dst, src[:n]...) // copy the number verbatim + return dst, n, nil + } + default: + // As an optimization, we can copy integer numbers below 2⁵³ verbatim + // since the canonical form is always identical. + const maxExactIntegerDigits = 16 // len(strconv.AppendUint(nil, 1<<53, 10)) + if !flags.Get(jsonflags.CanonicalizeRawInts) || n < maxExactIntegerDigits { + dst = append(dst, src[:n]...) // copy the number verbatim + return dst, n, nil + } + } + + // Parse and reformat the number (which uses a canonical format). fv, _ := strconv.ParseFloat(string(src[:n]), 64) switch { case fv == 0: diff --git a/vendor/github.com/go-json-experiment/json/internal/jsonwire/wire.go b/vendor/github.com/go-json-experiment/json/internal/jsonwire/wire.go index 6adfa3e..1831a66 100644 --- a/vendor/github.com/go-json-experiment/json/internal/jsonwire/wire.go +++ b/vendor/github.com/go-json-experiment/json/internal/jsonwire/wire.go @@ -76,13 +76,8 @@ func CompareUTF16[Bytes ~[]byte | ~string](x, y Bytes) int { return ('\u0000' <= r && r <= '\uD7FF') || ('\uE000' <= r && r <= '\uFFFF') } - var invalidUTF8 bool - x0, y0 := x, y for { if len(x) == 0 || len(y) == 0 { - if len(x) == len(y) && invalidUTF8 { - return strings.Compare(string(x0), string(y0)) - } return cmp.Compare(len(x), len(y)) } @@ -114,7 +109,14 @@ func CompareUTF16[Bytes ~[]byte | ~string](x, y Bytes) int { if rx != ry { return cmp.Compare(rx, ry) } - invalidUTF8 = invalidUTF8 || (rx == utf8.RuneError && nx == 1) || (ry == utf8.RuneError && ny == 1) + + // Check for invalid UTF-8, in which case, + // we just perform a byte-for-byte comparison. + if isInvalidUTF8(rx, nx) || isInvalidUTF8(ry, ny) { + if x[0] != y[0] { + return cmp.Compare(x[0], y[0]) + } + } x, y = x[nx:], y[ny:] } } @@ -141,16 +143,12 @@ func truncateMaxUTF8[Bytes ~[]byte | ~string](b Bytes) Bytes { return b } -// NewError and ErrInvalidUTF8 are injected by the "jsontext" package, -// so that these error types use the jsontext.SyntacticError type. -var ( - NewError = errors.New - ErrInvalidUTF8 = errors.New("invalid UTF-8 within string") -) +// TODO(https://go.dev/issue/70547): Use utf8.ErrInvalid instead. +var ErrInvalidUTF8 = errors.New("invalid UTF-8") func NewInvalidCharacterError[Bytes ~[]byte | ~string](prefix Bytes, where string) error { what := QuoteRune(prefix) - return NewError("invalid character " + what + " " + where) + return errors.New("invalid character " + what + " " + where) } func NewInvalidEscapeSequenceError[Bytes ~[]byte | ~string](what Bytes) error { @@ -162,8 +160,56 @@ func NewInvalidEscapeSequenceError[Bytes ~[]byte | ~string](what Bytes) error { return r == '`' || r == utf8.RuneError || unicode.IsSpace(r) || !unicode.IsPrint(r) }) >= 0 if needEscape { - return NewError("invalid " + label + " " + strconv.Quote(string(what)) + " within string") + return errors.New("invalid " + label + " " + strconv.Quote(string(what)) + " in string") } else { - return NewError("invalid " + label + " `" + string(what) + "` within string") + return errors.New("invalid " + label + " `" + string(what) + "` in string") } } + +// TruncatePointer optionally truncates the JSON pointer, +// enforcing that the length roughly does not exceed n. +func TruncatePointer(s string, n int) string { + if len(s) <= n { + return s + } + i := n / 2 + j := len(s) - n/2 + + // Avoid truncating a name if there are multiple names present. + if k := strings.LastIndexByte(s[:i], '/'); k > 0 { + i = k + } + if k := strings.IndexByte(s[j:], '/'); k >= 0 { + j += k + len("/") + } + + // Avoid truncation in the middle of a UTF-8 rune. + for i > 0 && isInvalidUTF8(utf8.DecodeLastRuneInString(s[:i])) { + i-- + } + for j < len(s) && isInvalidUTF8(utf8.DecodeRuneInString(s[j:])) { + j++ + } + + // Determine the right middle fragment to use. + var middle string + switch strings.Count(s[i:j], "/") { + case 0: + middle = "…" + case 1: + middle = "…/…" + default: + middle = "…/…/…" + } + if strings.HasPrefix(s[i:j], "/") && middle != "…" { + middle = strings.TrimPrefix(middle, "…") + } + if strings.HasSuffix(s[i:j], "/") && middle != "…" { + middle = strings.TrimSuffix(middle, "…") + } + return s[:i] + middle + s[j:] +} + +func isInvalidUTF8(r rune, rn int) bool { + return r == utf8.RuneError && rn == 1 +} diff --git a/vendor/github.com/go-json-experiment/json/jsontext/decode.go b/vendor/github.com/go-json-experiment/json/jsontext/decode.go index db39b8a..e8441dc 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/decode.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/decode.go @@ -125,16 +125,16 @@ func NewDecoder(r io.Reader, opts ...Options) *Decoder { // Reset resets a decoder such that it is reading afresh from r and // configured with the provided options. Reset must not be called on an -// a Decoder passed to the [encoding/json/v2.UnmarshalerV2.UnmarshalJSONV2] method -// or the [encoding/json/v2.UnmarshalFuncV2] function. +// a Decoder passed to the [encoding/json/v2.UnmarshalerFrom.UnmarshalJSONFrom] method +// or the [encoding/json/v2.UnmarshalFromFunc] function. func (d *Decoder) Reset(r io.Reader, opts ...Options) { switch { case d == nil: panic("jsontext: invalid nil Decoder") case r == nil: - panic("jsontext: invalid nil io.Writer") + panic("jsontext: invalid nil io.Reader") case d.s.Flags.Get(jsonflags.WithinArshalCall): - panic("jsontext: cannot reset Decoder passed to json.UnmarshalerV2") + panic("jsontext: cannot reset Decoder passed to json.UnmarshalerFrom") } d.s.reset(nil, r, opts...) } @@ -142,8 +142,21 @@ func (d *Decoder) Reset(r io.Reader, opts ...Options) { func (d *decoderState) reset(b []byte, r io.Reader, opts ...Options) { d.state.reset() d.decodeBuffer = decodeBuffer{buf: b, rd: r} - d.Struct = jsonopts.Struct{} - d.Struct.Join(opts...) + opts2 := jsonopts.Struct{} // avoid mutating d.Struct in case it is part of opts + opts2.Join(opts...) + d.Struct = opts2 +} + +// Options returns the options used to construct the encoder and +// may additionally contain semantic options passed to a +// [encoding/json/v2.UnmarshalDecode] call. +// +// If operating within +// a [encoding/json/v2.UnmarshalerFrom.UnmarshalJSONFrom] method call or +// a [encoding/json/v2.UnmarshalFromFunc] function call, +// then the returned options are only valid within the call. +func (d *Decoder) Options() Options { + return &d.s.Struct } var errBufferWriteAfterNext = errors.New("invalid bytes.Buffer.Write call after calling bytes.Buffer.Next") @@ -255,23 +268,40 @@ func (d *decodeBuffer) needMore(pos int) bool { return pos == len(d.buf) } -// injectSyntacticErrorWithPosition wraps a SyntacticError with the position, -// otherwise it returns the error as is. -// It takes a position relative to the start of the start of d.buf. -func (d *decodeBuffer) injectSyntacticErrorWithPosition(err error, pos int) error { - if serr, ok := err.(*SyntacticError); ok { - return serr.withOffset(d.baseOffset + int64(pos)) - } - return err -} - +func (d *decodeBuffer) offsetAt(pos int) int64 { return d.baseOffset + int64(pos) } func (d *decodeBuffer) previousOffsetStart() int64 { return d.baseOffset + int64(d.prevStart) } func (d *decodeBuffer) previousOffsetEnd() int64 { return d.baseOffset + int64(d.prevEnd) } -func (d *decodeBuffer) PreviousBuffer() []byte { return d.buf[d.prevStart:d.prevEnd] } +func (d *decodeBuffer) previousBuffer() []byte { return d.buf[d.prevStart:d.prevEnd] } func (d *decodeBuffer) unreadBuffer() []byte { return d.buf[d.prevEnd:len(d.buf)] } +// PreviousTokenOrValue returns the previously read token or value +// unless it has been invalidated by a call to PeekKind. +// If a token is just a delimiter, then this returns a 1-byte buffer. +// This method is used for error reporting at the semantic layer. +func (d *decodeBuffer) PreviousTokenOrValue() []byte { + b := d.previousBuffer() + // If peek was called, then the previous token or buffer is invalidated. + if d.peekPos > 0 || len(b) > 0 && b[0] == invalidateBufferByte { + return nil + } + // ReadToken does not preserve the buffer for null, bools, or delimiters. + // Manually re-construct that buffer. + if len(b) == 0 { + b = d.buf[:d.prevEnd] // entirety of the previous buffer + for _, tok := range []string{"null", "false", "true", "{", "}", "[", "]"} { + if len(b) >= len(tok) && string(b[len(b)-len(tok):]) == tok { + return b[len(b)-len(tok):] + } + } + } + return b +} + // PeekKind retrieves the next token kind, but does not advance the read offset. -// It returns 0 if there are no more tokens. +// +// It returns 0 if an error occurs. Any such error is cached until +// the next read call and it is the caller's responsibility to eventually +// follow up a PeekKind call with a read call. func (d *Decoder) PeekKind() Kind { return d.s.PeekKind() } @@ -292,7 +322,7 @@ func (d *decoderState) PeekKind() Kind { if err == io.ErrUnexpectedEOF && d.Tokens.Depth() == 1 { err = io.EOF // EOF possibly if no Tokens present after top-level value } - d.peekPos, d.peekErr = -1, err + d.peekPos, d.peekErr = -1, wrapSyntacticError(d, err, pos, 0) return invalidKind } } @@ -305,6 +335,7 @@ func (d *decoderState) PeekKind() Kind { pos += jsonwire.ConsumeWhitespace(d.buf[pos:]) if d.needMore(pos) { if pos, err = d.consumeWhitespace(pos); err != nil { + err = wrapSyntacticError(d, err, pos, 0) d.peekPos, d.peekErr = -1, d.checkDelimBeforeIOError(delim, err) return invalidKind } @@ -339,12 +370,33 @@ func (d *decoderState) checkDelimBeforeIOError(delim byte, err error) error { return err } +// CountNextDelimWhitespace counts the number of upcoming bytes of +// delimiter or whitespace characters. +// This method is used for error reporting at the semantic layer. +func (d *decoderState) CountNextDelimWhitespace() int { + d.PeekKind() // populate unreadBuffer + return len(d.unreadBuffer()) - len(bytes.TrimLeft(d.unreadBuffer(), ",: \n\r\t")) +} + // checkDelim checks whether delim is valid for the given next kind. func (d *decoderState) checkDelim(delim byte, next Kind) error { + where := "at start of value" + switch d.Tokens.needDelim(next) { + case delim: + return nil + case ':': + where = "after object name (expecting ':')" + case ',': + if d.Tokens.Last.isObject() { + where = "after object value (expecting ',' or '}')" + } else { + where = "after array element (expecting ',' or ']')" + } + } pos := d.prevEnd // restore position to right after leading whitespace pos += jsonwire.ConsumeWhitespace(d.buf[pos:]) - err := d.Tokens.checkDelim(delim, next) - return d.injectSyntacticErrorWithPosition(err, pos) + err := jsonwire.NewInvalidCharacterError(d.buf[pos:], where) + return wrapSyntacticError(d, err, pos, 0) } // SkipValue is semantically equivalent to calling [Decoder.ReadValue] and discarding @@ -377,6 +429,30 @@ func (d *decoderState) SkipValue() error { } } +// SkipValueRemainder skips the remainder of a value +// after reading a '{' or '[' token. +func (d *decoderState) SkipValueRemainder() error { + if d.Tokens.Depth()-1 > 0 && d.Tokens.Last.Length() == 0 { + for n := d.Tokens.Depth(); d.Tokens.Depth() >= n; { + if _, err := d.ReadToken(); err != nil { + return err + } + } + } + return nil +} + +// SkipUntil skips all tokens until the state machine +// is at or past the specified depth and length. +func (d *decoderState) SkipUntil(depth int, length int64) error { + for d.Tokens.Depth() > depth || (d.Tokens.Depth() == depth && d.Tokens.Last.Length() < length) { + if _, err := d.ReadToken(); err != nil { + return err + } + } + return nil +} + // ReadToken reads the next [Token], advancing the read offset. // The returned token is only valid until the next Peek, Read, or Skip call. // It returns [io.EOF] if there are no more tokens. @@ -408,7 +484,7 @@ func (d *decoderState) ReadToken() (Token, error) { if err == io.ErrUnexpectedEOF && d.Tokens.Depth() == 1 { err = io.EOF // EOF possibly if no Tokens present after top-level value } - return Token{}, err + return Token{}, wrapSyntacticError(d, err, pos, 0) } } @@ -420,6 +496,7 @@ func (d *decoderState) ReadToken() (Token, error) { pos += jsonwire.ConsumeWhitespace(d.buf[pos:]) if d.needMore(pos) { if pos, err = d.consumeWhitespace(pos); err != nil { + err = wrapSyntacticError(d, err, pos, 0) return Token{}, d.checkDelimBeforeIOError(delim, err) } } @@ -437,13 +514,13 @@ func (d *decoderState) ReadToken() (Token, error) { if jsonwire.ConsumeNull(d.buf[pos:]) == 0 { pos, err = d.consumeLiteral(pos, "null") if err != nil { - return Token{}, d.injectSyntacticErrorWithPosition(err, pos) + return Token{}, wrapSyntacticError(d, err, pos, +1) } } else { pos += len("null") } if err = d.Tokens.appendLiteral(); err != nil { - return Token{}, d.injectSyntacticErrorWithPosition(err, pos-len("null")) // report position at start of literal + return Token{}, wrapSyntacticError(d, err, pos-len("null"), +1) // report position at start of literal } d.prevStart, d.prevEnd = pos, pos return Null, nil @@ -452,13 +529,13 @@ func (d *decoderState) ReadToken() (Token, error) { if jsonwire.ConsumeFalse(d.buf[pos:]) == 0 { pos, err = d.consumeLiteral(pos, "false") if err != nil { - return Token{}, d.injectSyntacticErrorWithPosition(err, pos) + return Token{}, wrapSyntacticError(d, err, pos, +1) } } else { pos += len("false") } if err = d.Tokens.appendLiteral(); err != nil { - return Token{}, d.injectSyntacticErrorWithPosition(err, pos-len("false")) // report position at start of literal + return Token{}, wrapSyntacticError(d, err, pos-len("false"), +1) // report position at start of literal } d.prevStart, d.prevEnd = pos, pos return False, nil @@ -467,13 +544,13 @@ func (d *decoderState) ReadToken() (Token, error) { if jsonwire.ConsumeTrue(d.buf[pos:]) == 0 { pos, err = d.consumeLiteral(pos, "true") if err != nil { - return Token{}, d.injectSyntacticErrorWithPosition(err, pos) + return Token{}, wrapSyntacticError(d, err, pos, +1) } } else { pos += len("true") } if err = d.Tokens.appendLiteral(); err != nil { - return Token{}, d.injectSyntacticErrorWithPosition(err, pos-len("true")) // report position at start of literal + return Token{}, wrapSyntacticError(d, err, pos-len("true"), +1) // report position at start of literal } d.prevStart, d.prevEnd = pos, pos return True, nil @@ -486,23 +563,25 @@ func (d *decoderState) ReadToken() (Token, error) { newAbsPos := d.baseOffset + int64(pos) n = int(newAbsPos - oldAbsPos) if err != nil { - return Token{}, d.injectSyntacticErrorWithPosition(err, pos) + return Token{}, wrapSyntacticError(d, err, pos, +1) } } else { pos += n } - if !d.Flags.Get(jsonflags.AllowDuplicateNames) && d.Tokens.Last.NeedObjectName() { - if !d.Tokens.Last.isValidNamespace() { - return Token{}, errInvalidNamespace - } - if d.Tokens.Last.isActiveNamespace() && !d.Namespaces.Last().insertQuoted(d.buf[pos-n:pos], flags.IsVerbatim()) { - err = newDuplicateNameError(d.buf[pos-n : pos]) - return Token{}, d.injectSyntacticErrorWithPosition(err, pos-n) // report position at start of string + if d.Tokens.Last.NeedObjectName() { + if !d.Flags.Get(jsonflags.AllowDuplicateNames) { + if !d.Tokens.Last.isValidNamespace() { + return Token{}, wrapSyntacticError(d, errInvalidNamespace, pos-n, +1) + } + if d.Tokens.Last.isActiveNamespace() && !d.Namespaces.Last().insertQuoted(d.buf[pos-n:pos], flags.IsVerbatim()) { + err = wrapWithObjectName(ErrDuplicateName, d.buf[pos-n:pos]) + return Token{}, wrapSyntacticError(d, err, pos-n, +1) // report position at start of string + } } d.Names.ReplaceLastQuotedOffset(pos - n) // only replace if insertQuoted succeeds } if err = d.Tokens.appendString(); err != nil { - return Token{}, d.injectSyntacticErrorWithPosition(err, pos-n) // report position at start of string + return Token{}, wrapSyntacticError(d, err, pos-n, +1) // report position at start of string } d.prevStart, d.prevEnd = pos-n, pos return Token{raw: &d.decodeBuffer, num: uint64(d.previousOffsetStart())}, nil @@ -516,60 +595,60 @@ func (d *decoderState) ReadToken() (Token, error) { newAbsPos := d.baseOffset + int64(pos) n = int(newAbsPos - oldAbsPos) if err != nil { - return Token{}, d.injectSyntacticErrorWithPosition(err, pos) + return Token{}, wrapSyntacticError(d, err, pos, +1) } } else { pos += n } if err = d.Tokens.appendNumber(); err != nil { - return Token{}, d.injectSyntacticErrorWithPosition(err, pos-n) // report position at start of number + return Token{}, wrapSyntacticError(d, err, pos-n, +1) // report position at start of number } d.prevStart, d.prevEnd = pos-n, pos return Token{raw: &d.decodeBuffer, num: uint64(d.previousOffsetStart())}, nil case '{': if err = d.Tokens.pushObject(); err != nil { - return Token{}, d.injectSyntacticErrorWithPosition(err, pos) + return Token{}, wrapSyntacticError(d, err, pos, +1) } + d.Names.push() if !d.Flags.Get(jsonflags.AllowDuplicateNames) { - d.Names.push() d.Namespaces.push() } pos += 1 d.prevStart, d.prevEnd = pos, pos - return ObjectStart, nil + return BeginObject, nil case '}': if err = d.Tokens.popObject(); err != nil { - return Token{}, d.injectSyntacticErrorWithPosition(err, pos) + return Token{}, wrapSyntacticError(d, err, pos, +1) } + d.Names.pop() if !d.Flags.Get(jsonflags.AllowDuplicateNames) { - d.Names.pop() d.Namespaces.pop() } pos += 1 d.prevStart, d.prevEnd = pos, pos - return ObjectEnd, nil + return EndObject, nil case '[': if err = d.Tokens.pushArray(); err != nil { - return Token{}, d.injectSyntacticErrorWithPosition(err, pos) + return Token{}, wrapSyntacticError(d, err, pos, +1) } pos += 1 d.prevStart, d.prevEnd = pos, pos - return ArrayStart, nil + return BeginArray, nil case ']': if err = d.Tokens.popArray(); err != nil { - return Token{}, d.injectSyntacticErrorWithPosition(err, pos) + return Token{}, wrapSyntacticError(d, err, pos, +1) } pos += 1 d.prevStart, d.prevEnd = pos, pos - return ArrayEnd, nil + return EndArray, nil default: - err = newInvalidCharacterError(d.buf[pos:], "at start of token") - return Token{}, d.injectSyntacticErrorWithPosition(err, pos) + err = jsonwire.NewInvalidCharacterError(d.buf[pos:], "at start of value") + return Token{}, wrapSyntacticError(d, err, pos, +1) } } @@ -612,7 +691,7 @@ func (d *decoderState) ReadValue(flags *jsonwire.ValueFlags) (Value, error) { if err == io.ErrUnexpectedEOF && d.Tokens.Depth() == 1 { err = io.EOF // EOF possibly if no Tokens present after top-level value } - return nil, err + return nil, wrapSyntacticError(d, err, pos, 0) } } @@ -624,6 +703,7 @@ func (d *decoderState) ReadValue(flags *jsonwire.ValueFlags) (Value, error) { pos += jsonwire.ConsumeWhitespace(d.buf[pos:]) if d.needMore(pos) { if pos, err = d.consumeWhitespace(pos); err != nil { + err = wrapSyntacticError(d, err, pos, 0) return nil, d.checkDelimBeforeIOError(delim, err) } } @@ -640,20 +720,22 @@ func (d *decoderState) ReadValue(flags *jsonwire.ValueFlags) (Value, error) { newAbsPos := d.baseOffset + int64(pos) n := int(newAbsPos - oldAbsPos) if err != nil { - return nil, d.injectSyntacticErrorWithPosition(err, pos) + return nil, wrapSyntacticError(d, err, pos, +1) } switch next { case 'n', 't', 'f': err = d.Tokens.appendLiteral() case '"': - if !d.Flags.Get(jsonflags.AllowDuplicateNames) && d.Tokens.Last.NeedObjectName() { - if !d.Tokens.Last.isValidNamespace() { - err = errInvalidNamespace - break - } - if d.Tokens.Last.isActiveNamespace() && !d.Namespaces.Last().insertQuoted(d.buf[pos-n:pos], flags.IsVerbatim()) { - err = newDuplicateNameError(d.buf[pos-n : pos]) - break + if d.Tokens.Last.NeedObjectName() { + if !d.Flags.Get(jsonflags.AllowDuplicateNames) { + if !d.Tokens.Last.isValidNamespace() { + err = errInvalidNamespace + break + } + if d.Tokens.Last.isActiveNamespace() && !d.Namespaces.Last().insertQuoted(d.buf[pos-n:pos], flags.IsVerbatim()) { + err = wrapWithObjectName(ErrDuplicateName, d.buf[pos-n:pos]) + break + } } d.Names.ReplaceLastQuotedOffset(pos - n) // only replace if insertQuoted succeeds } @@ -676,19 +758,36 @@ func (d *decoderState) ReadValue(flags *jsonwire.ValueFlags) (Value, error) { } } if err != nil { - return nil, d.injectSyntacticErrorWithPosition(err, pos-n) // report position at start of value + return nil, wrapSyntacticError(d, err, pos-n, +1) // report position at start of value } d.prevEnd = pos d.prevStart = pos - n return d.buf[pos-n : pos : pos], nil } +// CheckNextValue checks whether the next value is syntactically valid, +// but does not advance the read offset. +func (d *decoderState) CheckNextValue() error { + d.PeekKind() // populates d.peekPos and d.peekErr + pos, err := d.peekPos, d.peekErr + d.peekPos, d.peekErr = 0, nil + if err != nil { + return err + } + + var flags jsonwire.ValueFlags + if pos, err := d.consumeValue(&flags, pos, d.Tokens.Depth()); err != nil { + return wrapSyntacticError(d, err, pos, +1) + } + return nil +} + // CheckEOF verifies that the input has no more data. func (d *decoderState) CheckEOF() error { switch pos, err := d.consumeWhitespace(d.prevEnd); err { case nil: - err := newInvalidCharacterError(d.buf[pos:], "after top-level value") - return d.injectSyntacticErrorWithPosition(err, pos) + err := jsonwire.NewInvalidCharacterError(d.buf[pos:], "after top-level value") + return wrapSyntacticError(d, err, pos, 0) case io.ErrUnexpectedEOF: return nil default: @@ -763,14 +862,17 @@ func (d *decoderState) consumeValue(flags *jsonwire.ValueFlags, pos, depth int) case '[': return d.consumeArray(flags, pos, depth) default: - return pos, newInvalidCharacterError(d.buf[pos:], "at start of value") + if (d.Tokens.Last.isObject() && next == ']') || (d.Tokens.Last.isArray() && next == '}') { + return pos, errMismatchDelim + } + return pos, jsonwire.NewInvalidCharacterError(d.buf[pos:], "at start of value") } if err == io.ErrUnexpectedEOF { absPos := d.baseOffset + int64(pos) err = d.fetch() // will mutate d.buf and invalidate pos pos = int(absPos - d.baseOffset) if err != nil { - return pos, err + return pos + n, err } continue } @@ -788,7 +890,7 @@ func (d *decoderState) consumeLiteral(pos int, lit string) (newPos int, err erro err = d.fetch() // will mutate d.buf and invalidate pos pos = int(absPos - d.baseOffset) if err != nil { - return pos, err + return pos + n, err } continue } @@ -807,7 +909,7 @@ func (d *decoderState) consumeString(flags *jsonwire.ValueFlags, pos int) (newPo err = d.fetch() // will mutate d.buf and invalidate pos pos = int(absPos - d.baseOffset) if err != nil { - return pos, err + return pos + n, err } continue } @@ -894,19 +996,21 @@ func (d *decoderState) consumeObject(flags *jsonwire.ValueFlags, pos, depth int) } else { pos += n } - if !d.Flags.Get(jsonflags.AllowDuplicateNames) && !names.insertQuoted(d.buf[pos-n:pos], flags2.IsVerbatim()) { - return pos - n, newDuplicateNameError(d.buf[pos-n : pos]) + quotedName := d.buf[pos-n : pos] + if !d.Flags.Get(jsonflags.AllowDuplicateNames) && !names.insertQuoted(quotedName, flags2.IsVerbatim()) { + return pos - n, wrapWithObjectName(ErrDuplicateName, quotedName) } // Handle after name. pos += jsonwire.ConsumeWhitespace(d.buf[pos:]) if d.needMore(pos) { if pos, err = d.consumeWhitespace(pos); err != nil { - return pos, err + return pos, wrapWithObjectName(err, quotedName) } } if d.buf[pos] != ':' { - return pos, newInvalidCharacterError(d.buf[pos:], "after object name (expecting ':')") + err := jsonwire.NewInvalidCharacterError(d.buf[pos:], "after object name (expecting ':')") + return pos, wrapWithObjectName(err, quotedName) } pos++ @@ -914,12 +1018,12 @@ func (d *decoderState) consumeObject(flags *jsonwire.ValueFlags, pos, depth int) pos += jsonwire.ConsumeWhitespace(d.buf[pos:]) if d.needMore(pos) { if pos, err = d.consumeWhitespace(pos); err != nil { - return pos, err + return pos, wrapWithObjectName(err, quotedName) } } pos, err = d.consumeValue(flags, pos, depth) if err != nil { - return pos, err + return pos, wrapWithObjectName(err, quotedName) } // Handle after value. @@ -937,7 +1041,7 @@ func (d *decoderState) consumeObject(flags *jsonwire.ValueFlags, pos, depth int) pos++ return pos, nil default: - return pos, newInvalidCharacterError(d.buf[pos:], "after object value (expecting ',' or '}')") + return pos, jsonwire.NewInvalidCharacterError(d.buf[pos:], "after object value (expecting ',' or '}')") } } } @@ -965,6 +1069,7 @@ func (d *decoderState) consumeArray(flags *jsonwire.ValueFlags, pos, depth int) return pos, nil } + var idx int64 depth++ for { // Handle before value. @@ -976,7 +1081,7 @@ func (d *decoderState) consumeArray(flags *jsonwire.ValueFlags, pos, depth int) } pos, err = d.consumeValue(flags, pos, depth) if err != nil { - return pos, err + return pos, wrapWithArrayIndex(err, idx) } // Handle after value. @@ -989,12 +1094,13 @@ func (d *decoderState) consumeArray(flags *jsonwire.ValueFlags, pos, depth int) switch d.buf[pos] { case ',': pos++ + idx++ continue case ']': pos++ return pos, nil default: - return pos, newInvalidCharacterError(d.buf[pos:], "after array value (expecting ',' or ']')") + return pos, jsonwire.NewInvalidCharacterError(d.buf[pos:], "after array element (expecting ',' or ']')") } } } @@ -1017,8 +1123,8 @@ func (d *Decoder) UnreadBuffer() []byte { // StackDepth returns the depth of the state machine for read JSON data. // Each level on the stack represents a nested JSON object or array. -// It is incremented whenever an [ObjectStart] or [ArrayStart] token is encountered -// and decremented whenever an [ObjectEnd] or [ArrayEnd] token is encountered. +// It is incremented whenever an [BeginObject] or [BeginArray] token is encountered +// and decremented whenever an [EndObject] or [EndArray] token is encountered. // The depth is zero-indexed, where zero represents the top-level JSON value. func (d *Decoder) StackDepth() int { // NOTE: Keep in sync with Encoder.StackDepth. @@ -1037,7 +1143,7 @@ func (d *Decoder) StackDepth() int { // Each name and value in a JSON object is counted separately, // so the effective number of members would be half the length. // A complete JSON object must have an even length. -func (d *Decoder) StackIndex(i int) (Kind, int) { +func (d *Decoder) StackIndex(i int) (Kind, int64) { // NOTE: Keep in sync with Encoder.StackIndex. switch s := d.s.Tokens.index(i); { case i > 0 && s.isObject(): @@ -1050,9 +1156,11 @@ func (d *Decoder) StackIndex(i int) (Kind, int) { } // StackPointer returns a JSON Pointer (RFC 6901) to the most recently read value. -// Object names are only present if [AllowDuplicateNames] is false, otherwise -// object members are represented using their index within the object. -func (d *Decoder) StackPointer() string { - d.s.Names.copyQuotedBuffer(d.s.buf) - return string(d.s.appendStackPointer(nil)) +func (d *Decoder) StackPointer() Pointer { + return Pointer(d.s.AppendStackPointer(nil, -1)) +} + +func (d *decoderState) AppendStackPointer(b []byte, where int) []byte { + d.Names.copyQuotedBuffer(d.buf) + return d.state.appendStackPointer(b, where) } diff --git a/vendor/github.com/go-json-experiment/json/jsontext/encode.go b/vendor/github.com/go-json-experiment/json/jsontext/encode.go index c45b325..997820f 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/encode.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/encode.go @@ -25,19 +25,19 @@ import ( // // can be composed with the following calls (ignoring errors for brevity): // -// e.WriteToken(ObjectStart) // { +// e.WriteToken(BeginObject) // { // e.WriteToken(String("name")) // "name" // e.WriteToken(String("value")) // "value" // e.WriteValue(Value(`"array"`)) // "array" -// e.WriteToken(ArrayStart) // [ +// e.WriteToken(BeginArray) // [ // e.WriteToken(Null) // null // e.WriteToken(False) // false // e.WriteValue(Value("true")) // true // e.WriteToken(Float(3.14159)) // 3.14159 -// e.WriteToken(ArrayEnd) // ] +// e.WriteToken(EndArray) // ] // e.WriteValue(Value(`"object"`)) // "object" // e.WriteValue(Value(`{"k":"v"}`)) // {"k":"v"} -// e.WriteToken(ObjectEnd) // } +// e.WriteToken(EndObject) // } // // The above is one of many possible sequence of calls and // may not represent the most sensible method to call for any given token/value. @@ -94,8 +94,8 @@ func NewEncoder(w io.Writer, opts ...Options) *Encoder { // Reset resets an encoder such that it is writing afresh to w and // configured with the provided options. Reset must not be called on -// a Encoder passed to the [encoding/json/v2.MarshalerV2.MarshalJSONV2] method -// or the [encoding/json/v2.MarshalFuncV2] function. +// a Encoder passed to the [encoding/json/v2.MarshalerTo.MarshalJSONTo] method +// or the [encoding/json/v2.MarshalToFunc] function. func (e *Encoder) Reset(w io.Writer, opts ...Options) { switch { case e == nil: @@ -103,7 +103,7 @@ func (e *Encoder) Reset(w io.Writer, opts ...Options) { case w == nil: panic("jsontext: invalid nil io.Writer") case e.s.Flags.Get(jsonflags.WithinArshalCall): - panic("jsontext: cannot reset Encoder passed to json.MarshalerV2") + panic("jsontext: cannot reset Encoder passed to json.MarshalerTo") } e.s.reset(nil, w, opts...) } @@ -114,13 +114,35 @@ func (e *encoderState) reset(b []byte, w io.Writer, opts ...Options) { if bb, ok := w.(*bytes.Buffer); ok && bb != nil { e.Buf = bb.Bytes()[bb.Len():] // alias the unused buffer of bb } - e.Struct = jsonopts.Struct{} - e.Struct.Join(opts...) - if e.Flags.Get(jsonflags.Expand) && !e.Flags.Has(jsonflags.Indent) { - e.Indent = "\t" + opts2 := jsonopts.Struct{} // avoid mutating e.Struct in case it is part of opts + opts2.Join(opts...) + e.Struct = opts2 + if e.Flags.Get(jsonflags.Multiline) { + if !e.Flags.Has(jsonflags.SpaceAfterColon) { + e.Flags.Set(jsonflags.SpaceAfterColon | 1) + } + if !e.Flags.Has(jsonflags.SpaceAfterComma) { + e.Flags.Set(jsonflags.SpaceAfterComma | 0) + } + if !e.Flags.Has(jsonflags.Indent) { + e.Flags.Set(jsonflags.Indent | 1) + e.Indent = "\t" + } } } +// Options returns the options used to construct the decoder and +// may additionally contain semantic options passed to a +// [encoding/json/v2.MarshalEncode] call. +// +// If operating within +// a [encoding/json/v2.MarshalerTo.MarshalJSONTo] method call or +// a [encoding/json/v2.MarshalToFunc] function call, +// then the returned options are only valid within the call. +func (e *Encoder) Options() Options { + return &e.s.Struct +} + // NeedFlush determines whether to flush at this point. func (e *encoderState) NeedFlush() bool { // NOTE: This function is carefully written to be inlinable. @@ -200,17 +222,7 @@ func (e *encoderState) Flush() error { return nil } - -// injectSyntacticErrorWithPosition wraps a SyntacticError with the position, -// otherwise it returns the error as is. -// It takes a position relative to the start of the start of e.buf. -func (e *encodeBuffer) injectSyntacticErrorWithPosition(err error, pos int) error { - if serr, ok := err.(*SyntacticError); ok { - return serr.withOffset(e.baseOffset + int64(pos)) - } - return err -} - +func (d *encodeBuffer) offsetAt(pos int) int64 { return d.baseOffset + int64(pos) } func (e *encodeBuffer) previousOffsetEnd() int64 { return e.baseOffset + int64(len(e.Buf)) } func (e *encodeBuffer) unflushedBuffer() []byte { return e.Buf } @@ -219,7 +231,7 @@ func (e *encodeBuffer) unflushedBuffer() []byte { return e.Buf } func (e *encoderState) avoidFlush() bool { switch { case e.Tokens.Last.Length() == 0: - // Never flush after ObjectStart or ArrayStart since we don't know yet + // Never flush after BeginObject or BeginArray since we don't know yet // if the object or array will end up being empty. return true case e.Tokens.Last.needObjectValue(): @@ -286,11 +298,11 @@ func (e *encoderState) UnwriteEmptyObjectMember(prevName *string) bool { if e.Tokens.Last.isActiveNamespace() { e.Namespaces.Last().removeLast() } - e.Names.clearLast() - if prevName != nil { - e.Names.copyQuotedBuffer(e.Buf) // required by objectNameStack.replaceLastUnquotedName - e.Names.replaceLastUnquotedName(*prevName) - } + } + e.Names.clearLast() + if prevName != nil { + e.Names.copyQuotedBuffer(e.Buf) // required by objectNameStack.replaceLastUnquotedName + e.Names.replaceLastUnquotedName(*prevName) } return true } @@ -314,8 +326,8 @@ func (e *encoderState) UnwriteOnlyObjectMemberName() string { if e.Tokens.Last.isActiveNamespace() { e.Namespaces.Last().removeLast() } - e.Names.clearLast() } + e.Names.clearLast() return name } @@ -337,7 +349,7 @@ func (e *encoderState) WriteToken(t Token) error { // Append any delimiters or optional whitespace. b = e.Tokens.MayAppendDelim(b, k) - if e.Flags.Get(jsonflags.Expand) { + if e.Flags.Get(jsonflags.AnyWhitespace) { b = e.appendWhitespace(b, k) } pos := len(b) // offset before the token @@ -358,20 +370,22 @@ func (e *encoderState) WriteToken(t Token) error { if b, err = t.appendString(b, &e.Flags); err != nil { break } - if !e.Flags.Get(jsonflags.AllowDuplicateNames) && e.Tokens.Last.NeedObjectName() { - if !e.Tokens.Last.isValidNamespace() { - err = errInvalidNamespace - break - } - if e.Tokens.Last.isActiveNamespace() && !e.Namespaces.Last().insertQuoted(b[pos:], false) { - err = newDuplicateNameError(b[pos:]) - break + if e.Tokens.Last.NeedObjectName() { + if !e.Flags.Get(jsonflags.AllowDuplicateNames) { + if !e.Tokens.Last.isValidNamespace() { + err = errInvalidNamespace + break + } + if e.Tokens.Last.isActiveNamespace() && !e.Namespaces.Last().insertQuoted(b[pos:], false) { + err = wrapWithObjectName(ErrDuplicateName, b[pos:]) + break + } } e.Names.ReplaceLastQuotedOffset(pos) // only replace if insertQuoted succeeds } err = e.Tokens.appendString() case '0': - if b, err = t.appendNumber(b, e.Flags.Get(jsonflags.CanonicalizeNumbers)); err != nil { + if b, err = t.appendNumber(b, &e.Flags); err != nil { break } err = e.Tokens.appendNumber() @@ -380,8 +394,8 @@ func (e *encoderState) WriteToken(t Token) error { if err = e.Tokens.pushObject(); err != nil { break } + e.Names.push() if !e.Flags.Get(jsonflags.AllowDuplicateNames) { - e.Names.push() e.Namespaces.push() } case '}': @@ -389,8 +403,8 @@ func (e *encoderState) WriteToken(t Token) error { if err = e.Tokens.popObject(); err != nil { break } + e.Names.pop() if !e.Flags.Get(jsonflags.AllowDuplicateNames) { - e.Names.pop() e.Namespaces.pop() } case '[': @@ -400,10 +414,10 @@ func (e *encoderState) WriteToken(t Token) error { b = append(b, ']') err = e.Tokens.popArray() default: - err = &SyntacticError{str: "invalid json.Token"} + err = errInvalidToken } if err != nil { - return e.injectSyntacticErrorWithPosition(err, pos) + return wrapSyntacticError(e, err, pos, +1) } // Finish off the buffer and store it back into e. @@ -428,7 +442,7 @@ func (e *encoderState) AppendRaw(k Kind, safeASCII bool, appendFn func([]byte) ( // Append any delimiters or optional whitespace. b = e.Tokens.MayAppendDelim(b, k) - if e.Flags.Get(jsonflags.Expand) { + if e.Flags.Get(jsonflags.AnyWhitespace) { b = e.appendWhitespace(b, k) } pos := len(b) // offset before the token @@ -453,30 +467,32 @@ func (e *encoderState) AppendRaw(k Kind, safeASCII bool, appendFn func([]byte) ( b, err = jsonwire.AppendQuote(b[:pos], string(b2), &e.Flags) e.unusedCache = b2[:0] if err != nil { - return e.injectSyntacticErrorWithPosition(err, pos) + return wrapSyntacticError(e, err, pos, +1) } } // Update the state machine. - if !e.Flags.Get(jsonflags.AllowDuplicateNames) && e.Tokens.Last.NeedObjectName() { - if !e.Tokens.Last.isValidNamespace() { - return errInvalidNamespace - } - if e.Tokens.Last.isActiveNamespace() && !e.Namespaces.Last().insertQuoted(b[pos:], isVerbatim) { - err := newDuplicateNameError(b[pos:]) - return e.injectSyntacticErrorWithPosition(err, pos) + if e.Tokens.Last.NeedObjectName() { + if !e.Flags.Get(jsonflags.AllowDuplicateNames) { + if !e.Tokens.Last.isValidNamespace() { + return wrapSyntacticError(e, err, pos, +1) + } + if e.Tokens.Last.isActiveNamespace() && !e.Namespaces.Last().insertQuoted(b[pos:], isVerbatim) { + err = wrapWithObjectName(ErrDuplicateName, b[pos:]) + return wrapSyntacticError(e, err, pos, +1) + } } e.Names.ReplaceLastQuotedOffset(pos) // only replace if insertQuoted succeeds } if err := e.Tokens.appendString(); err != nil { - return e.injectSyntacticErrorWithPosition(err, pos) + return wrapSyntacticError(e, err, pos, +1) } case '0': if b, err = appendFn(b); err != nil { return err } if err := e.Tokens.appendNumber(); err != nil { - return e.injectSyntacticErrorWithPosition(err, pos) + return wrapSyntacticError(e, err, pos, +1) } default: panic("BUG: invalid kind") @@ -513,7 +529,7 @@ func (e *encoderState) WriteValue(v Value) error { // Append any delimiters or optional whitespace. b = e.Tokens.MayAppendDelim(b, k) - if e.Flags.Get(jsonflags.Expand) { + if e.Flags.Get(jsonflags.AnyWhitespace) { b = e.appendWhitespace(b, k) } pos := len(b) // offset before the value @@ -523,13 +539,13 @@ func (e *encoderState) WriteValue(v Value) error { n += jsonwire.ConsumeWhitespace(v[n:]) b, m, err := e.reformatValue(b, v[n:], e.Tokens.Depth()) if err != nil { - return e.injectSyntacticErrorWithPosition(err, pos+n+m) + return wrapSyntacticError(e, err, pos+n+m, +1) } n += m n += jsonwire.ConsumeWhitespace(v[n:]) if len(v) > n { - err = newInvalidCharacterError(v[n:], "after top-level value") - return e.injectSyntacticErrorWithPosition(err, pos+n) + err = jsonwire.NewInvalidCharacterError(v[n:], "after top-level value") + return wrapSyntacticError(e, err, pos+n, 0) } // Append the kind to the state machine. @@ -537,14 +553,16 @@ func (e *encoderState) WriteValue(v Value) error { case 'n', 'f', 't': err = e.Tokens.appendLiteral() case '"': - if !e.Flags.Get(jsonflags.AllowDuplicateNames) && e.Tokens.Last.NeedObjectName() { - if !e.Tokens.Last.isValidNamespace() { - err = errInvalidNamespace - break - } - if e.Tokens.Last.isActiveNamespace() && !e.Namespaces.Last().insertQuoted(b[pos:], false) { - err = newDuplicateNameError(b[pos:]) - break + if e.Tokens.Last.NeedObjectName() { + if !e.Flags.Get(jsonflags.AllowDuplicateNames) { + if !e.Tokens.Last.isValidNamespace() { + err = errInvalidNamespace + break + } + if e.Tokens.Last.isActiveNamespace() && !e.Namespaces.Last().insertQuoted(b[pos:], false) { + err = wrapWithObjectName(ErrDuplicateName, b[pos:]) + break + } } e.Names.ReplaceLastQuotedOffset(pos) // only replace if insertQuoted succeeds } @@ -558,6 +576,9 @@ func (e *encoderState) WriteValue(v Value) error { if err = e.Tokens.popObject(); err != nil { panic("BUG: popObject should never fail immediately after pushObject: " + err.Error()) } + if e.Flags.Get(jsonflags.ReorderRawObjects) { + mustReorderObjects(b[pos:]) + } case '[': if err = e.Tokens.pushArray(); err != nil { break @@ -565,9 +586,12 @@ func (e *encoderState) WriteValue(v Value) error { if err = e.Tokens.popArray(); err != nil { panic("BUG: popArray should never fail immediately after pushArray: " + err.Error()) } + if e.Flags.Get(jsonflags.ReorderRawObjects) { + mustReorderObjects(b[pos:]) + } } if err != nil { - return e.injectSyntacticErrorWithPosition(err, pos) + return wrapSyntacticError(e, err, pos, +1) } // Finish off the buffer and store it back into e. @@ -578,13 +602,47 @@ func (e *encoderState) WriteValue(v Value) error { return nil } +// CountNextDelimWhitespace counts the number of bytes of delimiter and +// whitespace bytes assuming the upcoming token is a JSON value. +// This method is used for error reporting at the semantic layer. +func (e *encoderState) CountNextDelimWhitespace() (n int) { + const next = Kind('"') // arbitrary kind as next JSON value + delim := e.Tokens.needDelim(next) + if delim > 0 { + n += len(",") | len(":") + } + if delim == ':' { + if e.Flags.Get(jsonflags.SpaceAfterColon) { + n += len(" ") + } + } else { + if delim == ',' && e.Flags.Get(jsonflags.SpaceAfterComma) { + n += len(" ") + } + if e.Flags.Get(jsonflags.Multiline) { + if m := e.Tokens.NeedIndent(next); m > 0 { + n += len("\n") + len(e.IndentPrefix) + (m-1)*len(e.Indent) + } + } + } + return n +} + // appendWhitespace appends whitespace that immediately precedes the next token. func (e *encoderState) appendWhitespace(b []byte, next Kind) []byte { - if e.Tokens.needDelim(next) == ':' { - return append(b, ' ') + if delim := e.Tokens.needDelim(next); delim == ':' { + if e.Flags.Get(jsonflags.SpaceAfterColon) { + b = append(b, ' ') + } } else { - return e.AppendIndent(b, e.Tokens.NeedIndent(next)) + if delim == ',' && e.Flags.Get(jsonflags.SpaceAfterComma) { + b = append(b, ' ') + } + if e.Flags.Get(jsonflags.Multiline) { + b = e.AppendIndent(b, e.Tokens.NeedIndent(next)) + } } + return b } // AppendIndent appends the appropriate number of indentation characters @@ -630,22 +688,22 @@ func (e *encoderState) reformatValue(dst []byte, src Value, depth int) ([]byte, return append(dst, "true"...), len("true"), nil case '"': if n := jsonwire.ConsumeSimpleString(src); n > 0 { - dst, src = append(dst, src[:n]...), src[n:] // copy simple strings verbatim + dst = append(dst, src[:n]...) // copy simple strings verbatim return dst, n, nil } return jsonwire.ReformatString(dst, src, &e.Flags) case '0': if n := jsonwire.ConsumeSimpleNumber(src); n > 0 && !e.Flags.Get(jsonflags.CanonicalizeNumbers) { - dst, src = append(dst, src[:n]...), src[n:] // copy simple numbers verbatim + dst = append(dst, src[:n]...) // copy simple numbers verbatim return dst, n, nil } - return jsonwire.ReformatNumber(dst, src, e.Flags.Get(jsonflags.CanonicalizeNumbers)) + return jsonwire.ReformatNumber(dst, src, &e.Flags) case '{': return e.reformatObject(dst, src, depth) case '[': return e.reformatArray(dst, src, depth) default: - return dst, 0, newInvalidCharacterError(src, "at start of value") + return dst, 0, jsonwire.NewInvalidCharacterError(src, "at start of value") } } @@ -683,7 +741,7 @@ func (e *encoderState) reformatObject(dst []byte, src Value, depth int) ([]byte, depth++ for { // Append optional newline and indentation. - if e.Flags.Get(jsonflags.Expand) { + if e.Flags.Get(jsonflags.Multiline) { dst = e.AppendIndent(dst, depth) } @@ -693,7 +751,8 @@ func (e *encoderState) reformatObject(dst []byte, src Value, depth int) ([]byte, return dst, n, io.ErrUnexpectedEOF } m := jsonwire.ConsumeSimpleString(src[n:]) - if m > 0 { + isVerbatim := m > 0 + if isVerbatim { dst = append(dst, src[n:n+m]...) } else { dst, m, err = jsonwire.ReformatString(dst, src[n:], &e.Flags) @@ -701,34 +760,35 @@ func (e *encoderState) reformatObject(dst []byte, src Value, depth int) ([]byte, return dst, n + m, err } } - // TODO: Specify whether the name is verbatim or not. - if !e.Flags.Get(jsonflags.AllowDuplicateNames) && !names.insertQuoted(src[n:n+m], false) { - return dst, n, newDuplicateNameError(src[n : n+m]) + quotedName := src[n : n+m] + if !e.Flags.Get(jsonflags.AllowDuplicateNames) && !names.insertQuoted(quotedName, isVerbatim) { + return dst, n, wrapWithObjectName(ErrDuplicateName, quotedName) } n += m // Append colon. n += jsonwire.ConsumeWhitespace(src[n:]) if uint(len(src)) <= uint(n) { - return dst, n, io.ErrUnexpectedEOF + return dst, n, wrapWithObjectName(io.ErrUnexpectedEOF, quotedName) } if src[n] != ':' { - return dst, n, newInvalidCharacterError(src[n:], "after object name (expecting ':')") + err = jsonwire.NewInvalidCharacterError(src[n:], "after object name (expecting ':')") + return dst, n, wrapWithObjectName(err, quotedName) } dst = append(dst, ':') n += len(":") - if e.Flags.Get(jsonflags.Expand) { + if e.Flags.Get(jsonflags.SpaceAfterColon) { dst = append(dst, ' ') } // Append object value. n += jsonwire.ConsumeWhitespace(src[n:]) if uint(len(src)) <= uint(n) { - return dst, n, io.ErrUnexpectedEOF + return dst, n, wrapWithObjectName(io.ErrUnexpectedEOF, quotedName) } dst, m, err = e.reformatValue(dst, src[n:], depth) if err != nil { - return dst, n + m, err + return dst, n + m, wrapWithObjectName(err, quotedName) } n += m @@ -740,17 +800,20 @@ func (e *encoderState) reformatObject(dst []byte, src Value, depth int) ([]byte, switch src[n] { case ',': dst = append(dst, ',') + if e.Flags.Get(jsonflags.SpaceAfterComma) { + dst = append(dst, ' ') + } n += len(",") continue case '}': - if e.Flags.Get(jsonflags.Expand) { + if e.Flags.Get(jsonflags.Multiline) { dst = e.AppendIndent(dst, depth-1) } dst = append(dst, '}') n += len("}") return dst, n, nil default: - return dst, n, newInvalidCharacterError(src[n:], "after object value (expecting ',' or '}')") + return dst, n, jsonwire.NewInvalidCharacterError(src[n:], "after object value (expecting ',' or '}')") } } } @@ -779,11 +842,12 @@ func (e *encoderState) reformatArray(dst []byte, src Value, depth int) ([]byte, return dst, n, nil } + var idx int64 var err error depth++ for { // Append optional newline and indentation. - if e.Flags.Get(jsonflags.Expand) { + if e.Flags.Get(jsonflags.Multiline) { dst = e.AppendIndent(dst, depth) } @@ -795,7 +859,7 @@ func (e *encoderState) reformatArray(dst []byte, src Value, depth int) ([]byte, var m int dst, m, err = e.reformatValue(dst, src[n:], depth) if err != nil { - return dst, n + m, err + return dst, n + m, wrapWithArrayIndex(err, idx) } n += m @@ -807,17 +871,21 @@ func (e *encoderState) reformatArray(dst []byte, src Value, depth int) ([]byte, switch src[n] { case ',': dst = append(dst, ',') + if e.Flags.Get(jsonflags.SpaceAfterComma) { + dst = append(dst, ' ') + } n += len(",") + idx++ continue case ']': - if e.Flags.Get(jsonflags.Expand) { + if e.Flags.Get(jsonflags.Multiline) { dst = e.AppendIndent(dst, depth-1) } dst = append(dst, ']') n += len("]") return dst, n, nil default: - return dst, n, newInvalidCharacterError(src[n:], "after array value (expecting ',' or ']')") + return dst, n, jsonwire.NewInvalidCharacterError(src[n:], "after array value (expecting ',' or ']')") } } } @@ -859,8 +927,8 @@ func (e *Encoder) UnusedBuffer() []byte { // StackDepth returns the depth of the state machine for written JSON data. // Each level on the stack represents a nested JSON object or array. -// It is incremented whenever an [ObjectStart] or [ArrayStart] token is encountered -// and decremented whenever an [ObjectEnd] or [ArrayEnd] token is encountered. +// It is incremented whenever an [BeginObject] or [BeginArray] token is encountered +// and decremented whenever an [EndObject] or [EndArray] token is encountered. // The depth is zero-indexed, where zero represents the top-level JSON value. func (e *Encoder) StackDepth() int { // NOTE: Keep in sync with Decoder.StackDepth. @@ -879,7 +947,7 @@ func (e *Encoder) StackDepth() int { // Each name and value in a JSON object is counted separately, // so the effective number of members would be half the length. // A complete JSON object must have an even length. -func (e *Encoder) StackIndex(i int) (Kind, int) { +func (e *Encoder) StackIndex(i int) (Kind, int64) { // NOTE: Keep in sync with Decoder.StackIndex. switch s := e.s.Tokens.index(i); { case i > 0 && s.isObject(): @@ -892,9 +960,11 @@ func (e *Encoder) StackIndex(i int) (Kind, int) { } // StackPointer returns a JSON Pointer (RFC 6901) to the most recently written value. -// Object names are only present if [AllowDuplicateNames] is false, otherwise -// object members are represented using their index within the object. -func (e *Encoder) StackPointer() string { - e.s.Names.copyQuotedBuffer(e.s.Buf) - return string(e.s.appendStackPointer(nil)) +func (e *Encoder) StackPointer() Pointer { + return Pointer(e.s.AppendStackPointer(nil, -1)) +} + +func (e *encoderState) AppendStackPointer(b []byte, where int) []byte { + e.Names.copyQuotedBuffer(e.Buf) + return e.state.appendStackPointer(b, where) } diff --git a/vendor/github.com/go-json-experiment/json/jsontext/errors.go b/vendor/github.com/go-json-experiment/json/jsontext/errors.go index 2a5d078..eb5f0e2 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/errors.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/errors.go @@ -5,6 +5,10 @@ package jsontext import ( + "bytes" + "io" + "strconv" + "github.com/go-json-experiment/json/internal/jsonwire" ) @@ -32,29 +36,145 @@ type SyntacticError struct { // ByteOffset indicates that an error occurred after this byte offset. ByteOffset int64 - str string + // JSONPointer indicates that an error occurred within this JSON value + // as indicated using the JSON Pointer notation (see RFC 6901). + JSONPointer Pointer + + // Err is the underlying error. + Err error +} + +// wrapSyntacticError wraps an error and annotates it with a precise location +// using the provided [encoderState] or [decoderState]. +// If err is an [ioError] or [io.EOF], then it is not wrapped. +// +// It takes a relative offset pos that can be resolved into +// an absolute offset using state.offsetAt. +// +// It takes a where that specify how the JSON pointer is derived. +// If the underlying error is a [pointerSuffixError], +// then the suffix is appended to the derived pointer. +func wrapSyntacticError(state interface { + offsetAt(pos int) int64 + AppendStackPointer(b []byte, where int) []byte +}, err error, pos, where int) error { + if _, ok := err.(*ioError); err == io.EOF || ok { + return err + } + offset := state.offsetAt(pos) + ptr := state.AppendStackPointer(nil, where) + if serr, ok := err.(*pointerSuffixError); ok { + ptr = serr.appendPointer(ptr) + err = serr.error + } + if d, ok := state.(*decoderState); ok && err == errMismatchDelim { + where := "at start of value" + if len(d.Tokens.Stack) > 0 && d.Tokens.Last.Length() > 0 { + switch { + case d.Tokens.Last.isArray(): + where = "after array element (expecting ',' or ']')" + ptr = []byte(Pointer(ptr).Parent()) // problem is with parent array + case d.Tokens.Last.isObject(): + where = "after object value (expecting ',' or '}')" + ptr = []byte(Pointer(ptr).Parent()) // problem is with parent object + } + } + err = jsonwire.NewInvalidCharacterError(d.buf[pos:], where) + } + return &SyntacticError{ByteOffset: offset, JSONPointer: Pointer(ptr), Err: err} } func (e *SyntacticError) Error() string { - return errorPrefix + e.str -} -func (e *SyntacticError) withOffset(pos int64) error { - return &SyntacticError{ByteOffset: pos, str: e.str} + pointer := e.JSONPointer + offset := e.ByteOffset + b := []byte(errorPrefix) + if e.Err != nil { + b = append(b, e.Err.Error()...) + if e.Err == ErrDuplicateName { + b = strconv.AppendQuote(append(b, ' '), pointer.LastToken()) + pointer = pointer.Parent() + offset = 0 // not useful to print offset for duplicate names + } + } else { + b = append(b, "syntactic error"...) + } + if pointer != "" { + b = strconv.AppendQuote(append(b, " within "...), jsonwire.TruncatePointer(string(pointer), 100)) + } + if offset > 0 { + b = strconv.AppendInt(append(b, " after offset "...), offset, 10) + } + return string(b) } -func newDuplicateNameError[Bytes ~[]byte | ~string](quoted Bytes) *SyntacticError { - return &SyntacticError{str: "duplicate name " + string(quoted) + " in object"} +func (e *SyntacticError) Unwrap() error { + return e.Err } -func newInvalidCharacterError[Bytes ~[]byte | ~string](prefix Bytes, where string) *SyntacticError { - what := jsonwire.QuoteRune(prefix) - return &SyntacticError{str: "invalid character " + what + " " + where} +// pointerSuffixError represents a JSON pointer suffix to be appended +// to [SyntacticError.JSONPointer]. It is an internal error type +// used within this package and does not appear in the public API. +// +// This type is primarily used to annotate errors in Encoder.WriteValue +// and Decoder.ReadValue with precise positions. +// At the time WriteValue or ReadValue is called, a JSON pointer to the +// upcoming value can be constructed using the Encoder/Decoder state. +// However, tracking pointers within values during normal operation +// would incur a performance penalty in the error-free case. +// +// To provide precise error locations without this overhead, +// the error is wrapped with object names or array indices +// as the call stack is popped when an error occurs. +// Since this happens in reverse order, pointerSuffixError holds +// the pointer in reverse and is only later reversed when appending to +// the pointer prefix. +// +// For example, if the encoder is at "/alpha/bravo/charlie" +// and an error occurs in WriteValue at "/xray/yankee/zulu", then +// the final pointer should be "/alpha/bravo/charlie/xray/yankee/zulu". +// +// As pointerSuffixError is populated during the error return path, +// it first contains "/zulu", then "/zulu/yankee", +// and finally "/zulu/yankee/xray". +// These tokens are reversed and concatenated to "/alpha/bravo/charlie" +// to form the full pointer. +type pointerSuffixError struct { + error + + // reversePointer is a JSON pointer, but with each token in reverse order. + reversePointer []byte } -// TODO: Error types between "json", "jsontext", and "jsonwire" is a mess. -// Clean this up. -func init() { - // Inject behavior in "jsonwire" so that it can produce SyntacticError types. - jsonwire.NewError = func(s string) error { return &SyntacticError{str: s} } - jsonwire.ErrInvalidUTF8 = &SyntacticError{str: jsonwire.ErrInvalidUTF8.Error()} +// wrapWithObjectName wraps err with a JSON object name access, +// which must be a valid quoted JSON string. +func wrapWithObjectName(err error, quotedName []byte) error { + serr, _ := err.(*pointerSuffixError) + if serr == nil { + serr = &pointerSuffixError{error: err} + } + name := jsonwire.UnquoteMayCopy(quotedName, false) + serr.reversePointer = appendEscapePointerName(append(serr.reversePointer, '/'), name) + return serr +} + +// wrapWithArrayIndex wraps err with a JSON array index access. +func wrapWithArrayIndex(err error, index int64) error { + serr, _ := err.(*pointerSuffixError) + if serr == nil { + serr = &pointerSuffixError{error: err} + } + serr.reversePointer = strconv.AppendUint(append(serr.reversePointer, '/'), uint64(index), 10) + return serr +} + +// appendPointer appends the path encoded in e to the end of pointer. +func (e *pointerSuffixError) appendPointer(pointer []byte) []byte { + // Copy each token in reversePointer to the end of pointer in reverse order. + // Double reversal means that the appended suffix is now in forward order. + bi, bo := e.reversePointer, pointer + for len(bi) > 0 { + i := bytes.LastIndexByte(bi, '/') + bi, bo = bi[:i], append(bo, bi[i:]...) + } + return bo } diff --git a/vendor/github.com/go-json-experiment/json/jsontext/export.go b/vendor/github.com/go-json-experiment/json/jsontext/export.go index 06b3335..ab600b5 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/export.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/export.go @@ -69,15 +69,7 @@ func (export) PutStreamingDecoder(d *Decoder) { putStreamingDecoder(d) } -func (export) NewDuplicateNameError(quoted []byte, pos int64) error { - return newDuplicateNameError(quoted).withOffset(pos) -} -func (export) NewInvalidCharacterError(prefix, where string, pos int64) error { - return newInvalidCharacterError(prefix, where).withOffset(pos) -} -func (export) NewMissingNameError(pos int64) error { - return errMissingName.withOffset(pos) -} -func (export) NewInvalidUTF8Error(pos int64) error { - return errInvalidUTF8.withOffset(pos) +func (export) IsIOError(err error) bool { + _, ok := err.(*ioError) + return ok } diff --git a/vendor/github.com/go-json-experiment/json/jsontext/options.go b/vendor/github.com/go-json-experiment/json/jsontext/options.go index 242c50a..8696e02 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/options.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/options.go @@ -17,6 +17,25 @@ import ( // Each function takes in a variadic list of options, where properties // set in latter options override the value of previously set properties. // +// There is a single Options type, which is used with both encoding and decoding. +// Some options affect both operations, while others only affect one operation: +// +// - [AllowDuplicateNames] affects encoding and decoding +// - [AllowInvalidUTF8] affects encoding and decoding +// - [EscapeForHTML] affects encoding only +// - [EscapeForJS] affects encoding only +// - [PreserveRawStrings] affects encoding only +// - [CanonicalizeRawInts] affects encoding only +// - [CanonicalizeRawFloats] affects encoding only +// - [ReorderRawObjects] affects encoding only +// - [SpaceAfterColon] affects encoding only +// - [SpaceAfterComma] affects encoding only +// - [Multiline] affects encoding only +// - [WithIndent] affects encoding only +// - [WithIndentPrefix] affects encoding only +// +// Options that do not affect a particular operation are ignored. +// // The Options type is identical to [encoding/json.Options] and // [encoding/json/v2.Options]. Options from the other packages may // be passed to functionality in this package, but are ignored. @@ -78,20 +97,122 @@ func EscapeForJS(v bool) Options { } } -// Expand specifies that the JSON output should be expanded, -// where every JSON object member or JSON array element -// appears on a new, indented line according to the nesting depth. -// If an indent is not already specified, then it defaults to using "\t". -// -// If set to false, then the output is compact, -// where no whitespace is emitted between JSON values. +// PreserveRawStrings specifies that when encoding a raw JSON string in a +// [Token] or [Value], pre-escaped sequences +// in a JSON string are preserved to the output. +// However, raw strings still respect [EscapeForHTML] and [EscapeForJS] +// such that the relevant characters are escaped. +// If [AllowInvalidUTF8] is enabled, bytes of invalid UTF-8 +// are preserved to the output. // // This only affects encoding and is ignored when decoding. -func Expand(v bool) Options { +func PreserveRawStrings(v bool) Options { if v { - return jsonflags.Expand | 1 + return jsonflags.PreserveRawStrings | 1 } else { - return jsonflags.Expand | 0 + return jsonflags.PreserveRawStrings | 0 + } +} + +// CanonicalizeRawInts specifies that when encoding a raw JSON +// integer number (i.e., a number without a fraction and exponent) in a +// [Token] or [Value], the number is canonicalized +// according to RFC 8785, section 3.2.2.3. As a special case, +// the number -0 is canonicalized as 0. +// +// JSON numbers are treated as IEEE 754 double precision numbers. +// Any numbers with precision beyond what is representable by that form +// will lose their precision when canonicalized. For example, +// integer values beyond ±2⁵³ will lose their precision. +// For example, 1234567890123456789 is formatted as 1234567890123456800. +// +// This only affects encoding and is ignored when decoding. +func CanonicalizeRawInts(v bool) Options { + if v { + return jsonflags.CanonicalizeRawInts | 1 + } else { + return jsonflags.CanonicalizeRawInts | 0 + } +} + +// CanonicalizeRawFloats specifies that when encoding a raw JSON +// floating-point number (i.e., a number with a fraction or exponent) in a +// [Token] or [Value], the number is canonicalized +// according to RFC 8785, section 3.2.2.3. As a special case, +// the number -0 is canonicalized as 0. +// +// JSON numbers are treated as IEEE 754 double precision numbers. +// It is safe to canonicalize a serialized single precision number and +// parse it back as a single precision number and expect the same value. +// If a number exceeds ±1.7976931348623157e+308, which is the maximum +// finite number, then it saturated at that value and formatted as such. +// +// This only affects encoding and is ignored when decoding. +func CanonicalizeRawFloats(v bool) Options { + if v { + return jsonflags.CanonicalizeRawFloats | 1 + } else { + return jsonflags.CanonicalizeRawFloats | 0 + } +} + +// ReorderRawObjects specifies that when encoding a raw JSON object in a +// [Value], the object members are reordered according to +// RFC 8785, section 3.2.3. +// +// This only affects encoding and is ignored when decoding. +func ReorderRawObjects(v bool) Options { + if v { + return jsonflags.ReorderRawObjects | 1 + } else { + return jsonflags.ReorderRawObjects | 0 + } +} + +// SpaceAfterColon specifies that the JSON output should emit a space character +// after each colon separator following a JSON object name. +// If false, then no space character appears after the colon separator. +// +// This only affects encoding and is ignored when decoding. +func SpaceAfterColon(v bool) Options { + if v { + return jsonflags.SpaceAfterColon | 1 + } else { + return jsonflags.SpaceAfterColon | 0 + } +} + +// SpaceAfterComma specifies that the JSON output should emit a space character +// after each comma separator following a JSON object value or array element. +// If false, then no space character appears after the comma separator. +// +// This only affects encoding and is ignored when decoding. +func SpaceAfterComma(v bool) Options { + if v { + return jsonflags.SpaceAfterComma | 1 + } else { + return jsonflags.SpaceAfterComma | 0 + } +} + +// Multiline specifies that the JSON output should expand to multiple lines, +// where every JSON object member or JSON array element appears on +// a new, indented line according to the nesting depth. +// +// If [SpaceAfterColon] is not specified, then the default is true. +// If [SpaceAfterComma] is not specified, then the default is false. +// If [WithIndent] is not specified, then the default is "\t". +// +// If set to false, then the output is a single-line, +// where the only whitespace emitted is determined by the current +// values of [SpaceAfterColon] and [SpaceAfterComma]. +// +// This only affects encoding and is ignored when decoding. +func Multiline(v bool) Options { + if v { + return jsonflags.Multiline | 1 + } else { + return jsonflags.Multiline | 0 } } @@ -102,10 +223,10 @@ func Expand(v bool) Options { // The indent must only be composed of space or tab characters. // // If the intent to emit indented output without a preference for -// the particular indent string, then use [Expand] instead. +// the particular indent string, then use [Multiline] instead. // // This only affects encoding and is ignored when decoding. -// Use of this option implies [Expand] being set to true. +// Use of this option implies [Multiline] being set to true. func WithIndent(indent string) Options { // Fast-path: Return a constant for common indents, which avoids allocating. // These are derived from analyzing the Go module proxy on 2023-07-01. @@ -138,7 +259,7 @@ func WithIndent(indent string) Options { // The prefix must only be composed of space or tab characters. // // This only affects encoding and is ignored when decoding. -// Use of this option implies [Expand] being set to true. +// Use of this option implies [Multiline] being set to true. func WithIndentPrefix(prefix string) Options { if s := strings.Trim(prefix, " \t"); len(s) > 0 { panic("json: invalid character " + jsonwire.QuoteRune(s) + " in indent prefix") @@ -160,6 +281,7 @@ func WithIndentPrefix(prefix string) Options { // // A non-positive limit is equivalent to no limit at all. // If unspecified, the default limit is no limit at all. +// This affects either encoding or decoding. func WithByteLimit(n int64) Options { return jsonopts.ByteLimit(max(n, 0)) } @@ -172,6 +294,7 @@ func WithByteLimit(n int64) Options { // // A non-positive limit is equivalent to no limit at all. // If unspecified, the default limit is 10000. +// This affects either encoding or decoding. func WithDepthLimit(n int) Options { return jsonopts.DepthLimit(max(n, 0)) } diff --git a/vendor/github.com/go-json-experiment/json/jsontext/quote.go b/vendor/github.com/go-json-experiment/json/jsontext/quote.go index 27f846d..8faa435 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/quote.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/quote.go @@ -9,15 +9,18 @@ import ( "github.com/go-json-experiment/json/internal/jsonwire" ) -var errInvalidUTF8 = &SyntacticError{str: "invalid UTF-8 within string"} - // AppendQuote appends a double-quoted JSON string literal representing src // to dst and returns the extended buffer. // It uses the minimal string representation per RFC 8785, section 3.2.2.2. // Invalid UTF-8 bytes are replaced with the Unicode replacement character // and an error is returned at the end indicating the presence of invalid UTF-8. +// The dst must not overlap with the src. func AppendQuote[Bytes ~[]byte | ~string](dst []byte, src Bytes) ([]byte, error) { - return jsonwire.AppendQuote(dst, src, &jsonflags.Flags{}) + dst, err := jsonwire.AppendQuote(dst, src, &jsonflags.Flags{}) + if err != nil { + err = &SyntacticError{Err: err} + } + return dst, err } // AppendUnquote appends the decoded interpretation of src as a @@ -26,6 +29,11 @@ func AppendQuote[Bytes ~[]byte | ~string](dst []byte, src Bytes) ([]byte, error) // Invalid UTF-8 bytes are replaced with the Unicode replacement character // and an error is returned at the end indicating the presence of invalid UTF-8. // Any trailing bytes after the JSON string literal results in an error. +// The dst must not overlap with the src. func AppendUnquote[Bytes ~[]byte | ~string](dst []byte, src Bytes) ([]byte, error) { - return jsonwire.AppendUnquote(dst, src) + dst, err := jsonwire.AppendUnquote(dst, src) + if err != nil { + err = &SyntacticError{Err: err} + } + return dst, err } diff --git a/vendor/github.com/go-json-experiment/json/jsontext/state.go b/vendor/github.com/go-json-experiment/json/jsontext/state.go index 1a8174c..d6b2f02 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/state.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/state.go @@ -5,21 +5,45 @@ package jsontext import ( + "errors" + "iter" "math" "strconv" + "strings" + "unicode/utf8" "github.com/go-json-experiment/json/internal/jsonwire" ) -var ( - errMissingName = &SyntacticError{str: "missing string for object name"} - errMissingColon = &SyntacticError{str: "missing character ':' after object name"} - errMissingValue = &SyntacticError{str: "missing value after object name"} - errMissingComma = &SyntacticError{str: "missing character ',' after object or array value"} - errMismatchDelim = &SyntacticError{str: "mismatching structural token for object or array"} - errMaxDepth = &SyntacticError{str: "exceeded max depth"} +// ErrDuplicateName indicates that a JSON token could not be +// encoded or decoded because it results in a duplicate JSON object name. +// This error is directly wrapped within a [SyntacticError] when produced. +// +// The name of a duplicate JSON object member can be extracted as: +// +// err := ... +// var serr jsontext.SyntacticError +// if errors.As(err, &serr) && serr.Err == jsontext.ErrDuplicateName { +// ptr := serr.JSONPointer // JSON pointer to duplicate name +// name := ptr.LastToken() // duplicate name itself +// ... +// } +// +// This error is only returned if [AllowDuplicateNames] is false. +var ErrDuplicateName = errors.New("duplicate object member name") - errInvalidNamespace = &SyntacticError{str: "object namespace is in an invalid state"} +// ErrNonStringName indicates that a JSON token could not be +// encoded or decoded because it is not a string, +// as required for JSON object names according to RFC 8259, section 4. +// This error is directly wrapped within a [SyntacticError] when produced. +var ErrNonStringName = errors.New("object member name must be a string") + +var ( + errMissingValue = errors.New("missing value after object name") + errMismatchDelim = errors.New("mismatching structural token for object or array") + errMaxDepth = errors.New("exceeded max depth") + + errInvalidNamespace = errors.New("object namespace is in an invalid state") ) // Per RFC 8259, section 9, implementations may enforce a maximum depth. @@ -31,7 +55,6 @@ type state struct { Tokens stateMachine // Names is a stack of object names. - // Not used if AllowDuplicateNames is true. Names objectNameStack // Namespaces is a stack of object namespaces. @@ -42,48 +65,151 @@ type state struct { Namespaces objectNamespaceStack } +// needObjectValue reports whether the next token should be an object value. +// This method is used by [wrapSyntacticError]. +func (s *state) needObjectValue() bool { + return s.Tokens.Last.needObjectValue() +} + func (s *state) reset() { s.Tokens.reset() s.Names.reset() s.Namespaces.reset() } +// Pointer is a JSON Pointer (RFC 6901) that references a particular JSON value +// relative to the root of the top-level JSON value. +// +// A Pointer is a slash-separated list of tokens, where each token is +// either a JSON object name or an index to a JSON array element +// encoded as a base-10 integer value. +// It is impossible to distinguish between an array index and an object name +// (that happens to be an base-10 encoded integer) without also knowing +// the structure of the top-level JSON value that the pointer refers to. +// +// There is exactly one representation of a pointer to a particular value, +// so comparability of Pointer values is equivalent to checking whether +// they both point to the exact same value. +type Pointer string + +// IsValid reports whether p is a valid JSON Pointer according to RFC 6901. +// Note that the concatenation of two valid pointers produces a valid pointer. +func (p Pointer) IsValid() bool { + for i, r := range p { + switch { + case r == '~' && (i+1 == len(p) || (p[i+1] != '0' && p[i+1] != '1')): + return false // invalid escape + case r == '\ufffd' && !strings.HasPrefix(string(p[i:]), "\ufffd"): + return false // invalid UTF-8 + } + } + return len(p) == 0 || p[0] == '/' +} + +// Contains reports whether the JSON value that p points to +// is equal to or contains the JSON value that pc points to. +func (p Pointer) Contains(pc Pointer) bool { + // Invariant: len(p) <= len(pc) if p.Contains(pc) + suffix, ok := strings.CutPrefix(string(pc), string(p)) + return ok && (suffix == "" || suffix[0] == '/') +} + +// Parent strips off the last token and returns the remaining pointer. +// The parent of an empty p is an empty string. +func (p Pointer) Parent() Pointer { + return p[:max(strings.LastIndexByte(string(p), '/'), 0)] +} + +// LastToken returns the last token in the pointer. +// The last token of an empty p is an empty string. +func (p Pointer) LastToken() string { + last := p[max(strings.LastIndexByte(string(p), '/'), 0):] + return unescapePointerToken(strings.TrimPrefix(string(last), "/")) +} + +// AppendToken appends a token to the end of p and returns the full pointer. +func (p Pointer) AppendToken(tok string) Pointer { + return Pointer(appendEscapePointerName([]byte(p+"/"), tok)) +} + +// TODO: Add Pointer.AppendTokens, +// but should this take in a ...string or an iter.Seq[string]? + +// Tokens returns an iterator over the reference tokens in the JSON pointer, +// starting from the first token until the last token (unless stopped early). +func (p Pointer) Tokens() iter.Seq[string] { + return func(yield func(string) bool) { + for len(p) > 0 { + p = Pointer(strings.TrimPrefix(string(p), "/")) + i := min(uint(strings.IndexByte(string(p), '/')), uint(len(p))) + if !yield(unescapePointerToken(string(p)[:i])) { + return + } + p = p[i:] + } + } +} + +func unescapePointerToken(token string) string { + if strings.Contains(token, "~") { + // Per RFC 6901, section 3, unescape '~' and '/' characters. + token = strings.ReplaceAll(token, "~1", "/") + token = strings.ReplaceAll(token, "~0", "~") + } + return token +} + // appendStackPointer appends a JSON Pointer (RFC 6901) to the current value. -// The returned pointer is only accurate if s.names is populated, -// otherwise it uses the numeric index as the object member name. +// +// - If where is -1, then it points to the previously processed token. +// +// - If where is 0, then it points to the parent JSON object or array, +// or an object member if in-between an object member key and value. +// This is useful when the position is ambiguous whether +// we are interested in the previous or next token, or +// when we are uncertain whether the next token +// continues or terminates the current object or array. +// +// - If where is +1, then it points to the next expected value, +// assuming that it continues the current JSON object or array. +// As a special case, if the next token is a JSON object name, +// then it points to the parent JSON object. // // Invariant: Must call s.names.copyQuotedBuffer beforehand. -func (s state) appendStackPointer(b []byte) []byte { +func (s state) appendStackPointer(b []byte, where int) []byte { var objectDepth int for i := 1; i < s.Tokens.Depth(); i++ { e := s.Tokens.index(i) - if e.Length() == 0 { - break // empty object or array + arrayDelta := -1 // by default point to previous array element + if isLast := i == s.Tokens.Depth()-1; isLast { + switch { + case where < 0 && e.Length() == 0 || where == 0 && !e.needObjectValue() || where > 0 && e.NeedObjectName(): + return b + case where > 0 && e.isArray(): + arrayDelta = 0 // point to next array element + } } - b = append(b, '/') switch { case e.isObject(): - if objectDepth < s.Names.length() { - for _, c := range s.Names.getUnquoted(objectDepth) { - // Per RFC 6901, section 3, escape '~' and '/' characters. - switch c { - case '~': - b = append(b, "~0"...) - case '/': - b = append(b, "~1"...) - default: - b = append(b, c) - } - } - } else { - // Since the names stack is unpopulated, the name is unknown. - // As a best-effort replacement, use the numeric member index. - // While inaccurate, it produces a syntactically valid pointer. - b = strconv.AppendUint(b, uint64((e.Length()-1)/2), 10) - } + b = appendEscapePointerName(append(b, '/'), s.Names.getUnquoted(objectDepth)) objectDepth++ case e.isArray(): - b = strconv.AppendUint(b, uint64(e.Length()-1), 10) + b = strconv.AppendUint(append(b, '/'), uint64(e.Length()+int64(arrayDelta)), 10) + } + } + return b +} + +func appendEscapePointerName[Bytes ~[]byte | ~string](b []byte, name Bytes) []byte { + for _, r := range string(name) { + // Per RFC 6901, section 3, escape '~' and '/' characters. + switch r { + case '~': + b = append(b, "~0"...) + case '/': + b = append(b, "~1"...) + default: + b = utf8.AppendRune(b, r) } } return b @@ -133,7 +259,7 @@ func (m *stateMachine) index(i int) *stateEntry { // DepthLength reports the current nested depth and // the length of the last JSON object or array. -func (m stateMachine) DepthLength() (int, int) { +func (m stateMachine) DepthLength() (int, int64) { return m.Depth(), m.Last.Length() } @@ -142,7 +268,7 @@ func (m stateMachine) DepthLength() (int, int) { func (m *stateMachine) appendLiteral() error { switch { case m.Last.NeedObjectName(): - return errMissingName + return ErrNonStringName case !m.Last.isValidNamespace(): return errInvalidNamespace default: @@ -174,7 +300,7 @@ func (m *stateMachine) appendNumber() error { func (m *stateMachine) pushObject() error { switch { case m.Last.NeedObjectName(): - return errMissingName + return ErrNonStringName case !m.Last.isValidNamespace(): return errInvalidNamespace case len(m.Stack) == maxNestingDepth: @@ -209,7 +335,7 @@ func (m *stateMachine) popObject() error { func (m *stateMachine) pushArray() error { switch { case m.Last.NeedObjectName(): - return errMissingName + return ErrNonStringName case !m.Last.isValidNamespace(): return errInvalidNamespace case len(m.Stack) == maxNestingDepth: @@ -283,21 +409,6 @@ func (m stateMachine) needDelim(next Kind) (delim byte) { } } -// checkDelim reports whether the specified delimiter should be there given -// the kind of the next token that appears immediately afterwards. -func (m stateMachine) checkDelim(delim byte, next Kind) error { - switch needDelim := m.needDelim(next); { - case needDelim == delim: - return nil - case needDelim == ':': - return errMissingColon - case needDelim == ',': - return errMissingComma - default: - return newInvalidCharacterError([]byte{delim}, "before next token") - } -} - // InvalidateDisabledNamespaces marks all disabled namespaces as invalid. // // For efficiency, Marshal and Unmarshal may disable namespaces since there are @@ -306,7 +417,7 @@ func (m stateMachine) checkDelim(delim byte, next Kind) error { // Mark the namespaces as invalid so that future method calls on // Encoder or Decoder will return an error. func (m *stateMachine) InvalidateDisabledNamespaces() { - for i := 0; i < m.Depth(); i++ { + for i := range m.Depth() { e := m.index(i) if !e.isActiveNamespace() { e.invalidateNamespace() @@ -342,8 +453,8 @@ const ( // Length reports the number of elements in the JSON object or array. // Each name and value in an object entry is treated as a separate element. -func (e stateEntry) Length() int { - return int(e & stateCountMask) +func (e stateEntry) Length() int64 { + return int64(e & stateCountMask) } // isObject reports whether this is a JSON object. @@ -453,7 +564,7 @@ func (ns *objectNameStack) length() int { return len(ns.offsets) } -// getUnquoted retrieves the ith unquoted name in the namespace. +// getUnquoted retrieves the ith unquoted name in the stack. // It returns an empty string if the last object is empty. // // Invariant: Must call copyQuotedBuffer beforehand. diff --git a/vendor/github.com/go-json-experiment/json/jsontext/token.go b/vendor/github.com/go-json-experiment/json/jsontext/token.go index 157a5bd..2d2a7f0 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/token.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/token.go @@ -5,6 +5,8 @@ package jsontext import ( + "bytes" + "errors" "math" "strconv" @@ -20,9 +22,11 @@ const ( maxUint64 = math.MaxUint64 minUint64 = 0 // for consistency and readability purposes - invalidTokenPanic = "invalid json.Token; it has been voided by a subsequent json.Decoder call" + invalidTokenPanic = "invalid jsontext.Token; it has been voided by a subsequent json.Decoder call" ) +var errInvalidToken = errors.New("invalid jsontext.Token") + // Token represents a lexical JSON token, which may be one of the following: // - a JSON literal (i.e., null, true, or false) // - a JSON string (e.g., "hello, world!") @@ -90,10 +94,10 @@ var ( False Token = rawToken("false") True Token = rawToken("true") - ObjectStart Token = rawToken("{") - ObjectEnd Token = rawToken("}") - ArrayStart Token = rawToken("[") - ArrayEnd Token = rawToken("]") + BeginObject Token = rawToken("{") + EndObject Token = rawToken("}") + BeginArray Token = rawToken("[") + EndArray Token = rawToken("]") zeroString Token = rawToken(`""`) zeroNumber Token = rawToken(`0`) @@ -172,22 +176,21 @@ func (t Token) Clone() Token { return False case True.raw: return True - case ObjectStart.raw: - return ObjectStart - case ObjectEnd.raw: - return ObjectEnd - case ArrayStart.raw: - return ArrayStart - case ArrayEnd.raw: - return ArrayEnd + case BeginObject.raw: + return BeginObject + case EndObject.raw: + return EndObject + case BeginArray.raw: + return BeginArray + case EndArray.raw: + return EndArray } } if uint64(raw.previousOffsetStart()) != t.num { panic(invalidTokenPanic) } - // TODO(https://go.dev/issue/45038): Use bytes.Clone. - buf := append([]byte(nil), raw.PreviousBuffer()...) + buf := bytes.Clone(raw.previousBuffer()) return Token{raw: &decodeBuffer{buf: buf, prevStart: 0, prevEnd: len(buf)}} } return t @@ -211,7 +214,7 @@ func (t Token) Bool() bool { func (t Token) appendString(dst []byte, flags *jsonflags.Flags) ([]byte, error) { if raw := t.raw; raw != nil { // Handle raw string value. - buf := raw.PreviousBuffer() + buf := raw.previousBuffer() if Kind(buf[0]) == '"' { if jsonwire.ConsumeSimpleString(buf) == len(buf) { return append(dst, buf...), nil @@ -245,7 +248,7 @@ func (t Token) string() (string, []byte) { if uint64(raw.previousOffsetStart()) != t.num { panic(invalidTokenPanic) } - buf := raw.PreviousBuffer() + buf := raw.previousBuffer() if buf[0] == '"' { // TODO: Preserve ValueFlags in Token? isVerbatim := jsonwire.ConsumeSimpleString(buf) == len(buf) @@ -268,20 +271,17 @@ func (t Token) string() (string, []byte) { return strconv.FormatUint(uint64(t.num), 10), nil } } - return "", nil + return "", nil } // appendNumber appends a JSON number to dst and returns it. // It panics if t is not a JSON number. -func (t Token) appendNumber(dst []byte, canonicalize bool) ([]byte, error) { +func (t Token) appendNumber(dst []byte, flags *jsonflags.Flags) ([]byte, error) { if raw := t.raw; raw != nil { // Handle raw number value. - buf := raw.PreviousBuffer() + buf := raw.previousBuffer() if Kind(buf[0]).normalize() == '0' { - if !canonicalize { - return append(dst, buf...), nil - } - dst, _, err := jsonwire.ReformatNumber(dst, buf, canonicalize) + dst, _, err := jsonwire.ReformatNumber(dst, buf, flags) return dst, err } } else if t.num != 0 { @@ -309,7 +309,7 @@ func (t Token) Float() float64 { if uint64(raw.previousOffsetStart()) != t.num { panic(invalidTokenPanic) } - buf := raw.PreviousBuffer() + buf := raw.previousBuffer() if Kind(buf[0]).normalize() == '0' { fv, _ := jsonwire.ParseFloat(buf, 64) return fv @@ -353,7 +353,7 @@ func (t Token) Int() int64 { panic(invalidTokenPanic) } neg := false - buf := raw.PreviousBuffer() + buf := raw.previousBuffer() if len(buf) > 0 && buf[0] == '-' { neg, buf = true, buf[1:] } @@ -414,7 +414,7 @@ func (t Token) Uint() uint64 { panic(invalidTokenPanic) } neg := false - buf := raw.PreviousBuffer() + buf := raw.previousBuffer() if len(buf) > 0 && buf[0] == '-' { neg, buf = true, buf[1:] } @@ -512,7 +512,7 @@ func (k Kind) String() string { case ']': return "]" default: - return "" + return "" } } diff --git a/vendor/github.com/go-json-experiment/json/jsontext/value.go b/vendor/github.com/go-json-experiment/json/jsontext/value.go index 361c1fc..f2fd14b 100644 --- a/vendor/github.com/go-json-experiment/json/jsontext/value.go +++ b/vendor/github.com/go-json-experiment/json/jsontext/value.go @@ -9,7 +9,6 @@ import ( "errors" "io" "slices" - "strings" "sync" "github.com/go-json-experiment/json/internal/jsonflags" @@ -18,6 +17,22 @@ import ( // NOTE: Value is analogous to v1 json.RawMessage. +// AppendFormat formats the JSON value in src and appends it to dst +// according to the specified options. +// See [Value.Format] for more details about the formatting behavior. +// +// The dst and src may overlap. +// If an error is reported, then the entirety of src is appended to dst. +func AppendFormat(dst, src []byte, opts ...Options) ([]byte, error) { + e := getBufferedEncoder(opts...) + defer putBufferedEncoder(e) + e.s.Flags.Set(jsonflags.OmitTopLevelNewline | 1) + if err := e.s.WriteValue(src); err != nil { + return append(dst, src...), err + } + return append(dst, e.s.Buf...), nil +} + // Value represents a single raw JSON value, which may be one of the following: // - a JSON literal (i.e., null, true, or false) // - a JSON string (e.g., "hello, world!") @@ -43,70 +58,159 @@ func (v Value) String() string { } // IsValid reports whether the raw JSON value is syntactically valid -// according to RFC 7493. +// according to the specified options. // +// By default (if no options are specified), it validates according to RFC 7493. // It verifies whether the input is properly encoded as UTF-8, // that escape sequences within strings decode to valid Unicode codepoints, and // that all names in each object are unique. // It does not verify whether numbers are representable within the limits // of any common numeric type (e.g., float64, int64, or uint64). -func (v Value) IsValid() bool { - d := getBufferedDecoder(v) +// +// Relevant options include: +// - [AllowDuplicateNames] +// - [AllowInvalidUTF8] +// +// All other options are ignored. +func (v Value) IsValid(opts ...Options) bool { + // TODO: Document support for [WithByteLimit] and [WithDepthLimit]. + d := getBufferedDecoder(v, opts...) defer putBufferedDecoder(d) _, errVal := d.ReadValue() _, errEOF := d.ReadToken() return errVal == nil && errEOF == io.EOF } +// Format formats the raw JSON value in place. +// +// By default (if no options are specified), it validates according to RFC 7493 +// and produces the minimal JSON representation, where +// all whitespace is elided and JSON strings use the shortest encoding. +// +// Relevant options include: +// - [AllowDuplicateNames] +// - [AllowInvalidUTF8] +// - [EscapeForHTML] +// - [EscapeForJS] +// - [PreserveRawStrings] +// - [CanonicalizeRawInts] +// - [CanonicalizeRawFloats] +// - [ReorderRawObjects] +// - [SpaceAfterColon] +// - [SpaceAfterComma] +// - [Multiline] +// - [WithIndent] +// - [WithIndentPrefix] +// +// All other options are ignored. +// +// It is guaranteed to succeed if the value is valid according to the same options. +// If the value is already formatted, then the buffer is not mutated. +func (v *Value) Format(opts ...Options) error { + // TODO: Document support for [WithByteLimit] and [WithDepthLimit]. + return v.format(opts, nil) +} + +// format accepts two []Options to avoid the allocation appending them together. +// It is equivalent to v.Format(append(opts1, opts2...)...). +func (v *Value) format(opts1, opts2 []Options) error { + e := getBufferedEncoder(opts1...) + defer putBufferedEncoder(e) + e.s.Join(opts2...) + e.s.Flags.Set(jsonflags.OmitTopLevelNewline | 1) + if err := e.s.WriteValue(*v); err != nil { + return err + } + if !bytes.Equal(*v, e.s.Buf) { + *v = append((*v)[:0], e.s.Buf...) + } + return nil +} + // Compact removes all whitespace from the raw JSON value. // -// It does not reformat JSON strings to use any other representation. -// It is guaranteed to succeed if the input is valid. -// If the value is already compacted, then the buffer is not mutated. -func (v *Value) Compact() error { - return v.reformat(false, false, "", "") +// It does not reformat JSON strings or numbers to use any other representation. +// To maximize the set of JSON values that can be formatted, +// this permits values with duplicate names and invalid UTF-8. +// +// Compact is equivalent to calling [Value.Format] with the following options: +// - [AllowDuplicateNames](true) +// - [AllowInvalidUTF8](true) +// - [PreserveRawStrings](true) +// +// Any options specified by the caller are applied after the initial set +// and may deliberately override prior options. +func (v *Value) Compact(opts ...Options) error { + return v.format([]Options{ + AllowDuplicateNames(true), + AllowInvalidUTF8(true), + PreserveRawStrings(true), + }, opts) } // Indent reformats the whitespace in the raw JSON value so that each element -// in a JSON object or array begins on a new, indented line beginning with -// prefix followed by one or more copies of indent according to the nesting. -// The value does not begin with the prefix nor any indention, -// to make it easier to embed inside other formatted JSON data. +// in a JSON object or array begins on a indented line according to the nesting. // -// It does not reformat JSON strings to use any other representation. -// It is guaranteed to succeed if the input is valid. -// If the value is already indented properly, then the buffer is not mutated. +// It does not reformat JSON strings or numbers to use any other representation. +// To maximize the set of JSON values that can be formatted, +// this permits values with duplicate names and invalid UTF-8. // -// The prefix and indent strings must be composed of only spaces and/or tabs. -func (v *Value) Indent(prefix, indent string) error { - return v.reformat(false, true, prefix, indent) +// Indent is equivalent to calling [Value.Format] with the following options: +// - [AllowDuplicateNames](true) +// - [AllowInvalidUTF8](true) +// - [PreserveRawStrings](true) +// - [Multiline](true) +// +// Any options specified by the caller are applied after the initial set +// and may deliberately override prior options. +func (v *Value) Indent(opts ...Options) error { + return v.format([]Options{ + AllowDuplicateNames(true), + AllowInvalidUTF8(true), + PreserveRawStrings(true), + Multiline(true), + }, opts) } // Canonicalize canonicalizes the raw JSON value according to the // JSON Canonicalization Scheme (JCS) as defined by RFC 8785 // where it produces a stable representation of a JSON value. // +// JSON strings are formatted to use their minimal representation, +// JSON numbers are formatted as double precision numbers according +// to some stable serialization algorithm. +// JSON object members are sorted in ascending order by name. +// All whitespace is removed. +// // The output stability is dependent on the stability of the application data // (see RFC 8785, Appendix E). It cannot produce stable output from // fundamentally unstable input. For example, if the JSON value // contains ephemeral data (e.g., a frequently changing timestamp), // then the value is still unstable regardless of whether this is called. // +// Canonicalize is equivalent to calling [Value.Format] with the following options: +// - [CanonicalizeRawInts](true) +// - [CanonicalizeRawFloats](true) +// - [ReorderRawObjects](true) +// +// Any options specified by the caller are applied after the initial set +// and may deliberately override prior options. +// // Note that JCS treats all JSON numbers as IEEE 754 double precision numbers. // Any numbers with precision beyond what is representable by that form // will lose their precision when canonicalized. For example, integer values -// beyond ±2⁵³ will lose their precision. It is recommended that -// int64 and uint64 data types be represented as a JSON string. +// beyond ±2⁵³ will lose their precision. To preserve the original representation +// of JSON integers, additionally set [CanonicalizeRawInts] to false: // -// It is guaranteed to succeed if the input is valid. -// If the value is already canonicalized, then the buffer is not mutated. -func (v *Value) Canonicalize() error { - return v.reformat(true, false, "", "") +// v.Canonicalize(jsontext.CanonicalizeRawInts(false)) +func (v *Value) Canonicalize(opts ...Options) error { + return v.format([]Options{ + CanonicalizeRawInts(true), + CanonicalizeRawFloats(true), + ReorderRawObjects(true), + }, opts) } -// TODO: Instead of implementing the v1 Marshaler/Unmarshaler, -// consider implementing the v2 versions instead. - // MarshalJSON returns v as the JSON encoding of v. // It returns the stored value as the raw JSON output without any validation. // If v is nil, then this returns a JSON null. @@ -123,7 +227,7 @@ func (v Value) MarshalJSON() ([]byte, error) { func (v *Value) UnmarshalJSON(b []byte) error { // NOTE: This matches the behavior of v1 json.RawMessage.UnmarshalJSON. if v == nil { - return errors.New("json.Value: UnmarshalJSON on nil pointer") + return errors.New("jsontext.Value: UnmarshalJSON on nil pointer") } *v = append((*v)[:0], b...) return nil @@ -138,93 +242,62 @@ func (v Value) Kind() Kind { return invalidKind } -func (v *Value) reformat(canonical, multiline bool, prefix, indent string) error { - // Write the entire value to reformat all tokens and whitespace. - e := getBufferedEncoder() - defer putBufferedEncoder(e) - eo := &e.s.Struct - if canonical { - eo.Flags.Set(jsonflags.AllowInvalidUTF8 | 0) // per RFC 8785, section 3.2.4 - eo.Flags.Set(jsonflags.AllowDuplicateNames | 0) // per RFC 8785, section 3.1 - eo.Flags.Set(jsonflags.CanonicalizeNumbers | 1) // per RFC 8785, section 3.2.2.3 - eo.Flags.Set(jsonflags.PreserveRawStrings | 0) // per RFC 8785, section 3.2.2.2 - eo.Flags.Set(jsonflags.EscapeForHTML | 0) // per RFC 8785, section 3.2.2.2 - eo.Flags.Set(jsonflags.EscapeForJS | 0) // per RFC 8785, section 3.2.2.2 - eo.Flags.Set(jsonflags.Expand | 0) // per RFC 8785, section 3.2.1 - } else { - if s := strings.TrimLeft(prefix, " \t"); len(s) > 0 { - panic("json: invalid character " + jsonwire.QuoteRune(s) + " in indent prefix") - } - if s := strings.TrimLeft(indent, " \t"); len(s) > 0 { - panic("json: invalid character " + jsonwire.QuoteRune(s) + " in indent") - } - eo.Flags.Set(jsonflags.AllowInvalidUTF8 | 1) - eo.Flags.Set(jsonflags.AllowDuplicateNames | 1) - eo.Flags.Set(jsonflags.PreserveRawStrings | 1) - if multiline { - eo.Flags.Set(jsonflags.Expand | 1) - eo.Flags.Set(jsonflags.Indent | 1) - eo.Flags.Set(jsonflags.IndentPrefix | 1) - eo.IndentPrefix = prefix - eo.Indent = indent - } else { - eo.Flags.Set(jsonflags.Expand | 0) - } - } - eo.Flags.Set(jsonflags.OmitTopLevelNewline | 1) - if err := e.s.WriteValue(*v); err != nil { - return err - } +const commaAndWhitespace = ", \n\r\t" - // For canonical output, we may need to reorder object members. - if canonical { - // Obtain a buffered encoder just to use its internal buffer as - // a scratch buffer in reorderObjects for reordering object members. - e2 := getBufferedEncoder() - defer putBufferedEncoder(e2) - - // Disable redundant checks performed earlier during encoding. - d := getBufferedDecoder(e.s.Buf) - defer putBufferedDecoder(d) - d.s.Flags.Set(jsonflags.AllowDuplicateNames | jsonflags.AllowInvalidUTF8 | 1) - reorderObjects(d, &e2.s.Buf) // per RFC 8785, section 3.2.3 - } - - // Store the result back into the value if different. - if !bytes.Equal(*v, e.s.Buf) { - *v = append((*v)[:0], e.s.Buf...) - } - return nil +type objectMember struct { + // name is the unquoted name. + name []byte // e.g., "name" + // buffer is the entirety of the raw JSON object member + // starting from right after the previous member (or opening '{') + // until right after the member value. + buffer []byte // e.g., `, \n\r\t"name": "value"` } -type memberName struct { - // name is the unescaped name. - name []byte - // before and after are byte offsets into Decoder.buf that represents - // the entire name/value pair. It may contain leading commas. - before, after int64 +func (x objectMember) Compare(y objectMember) int { + if c := jsonwire.CompareUTF16(x.name, y.name); c != 0 { + return c + } + // With [AllowDuplicateNames] or [AllowInvalidUTF8], + // names could be identical, so also sort using the member value. + return jsonwire.CompareUTF16( + bytes.TrimLeft(x.buffer, commaAndWhitespace), + bytes.TrimLeft(y.buffer, commaAndWhitespace)) } -var memberNamePool = sync.Pool{New: func() any { return new([]memberName) }} +var objectMemberPool = sync.Pool{New: func() any { return new([]objectMember) }} -func getMemberNames() *[]memberName { - ns := memberNamePool.Get().(*[]memberName) +func getObjectMembers() *[]objectMember { + ns := objectMemberPool.Get().(*[]objectMember) *ns = (*ns)[:0] return ns } -func putMemberNames(ns *[]memberName) { +func putObjectMembers(ns *[]objectMember) { if cap(*ns) < 1<<10 { - clear(*ns) // avoid pinning name - memberNamePool.Put(ns) + clear(*ns) // avoid pinning name and buffer + objectMemberPool.Put(ns) } } -// reorderObjects recursively reorders all object members in place +// mustReorderObjects reorders in-place all object members in a JSON value, +// which must be valid otherwise it panics. +func mustReorderObjects(b []byte) { + // Obtain a buffered encoder just to use its internal buffer as + // a scratch buffer for reordering object members. + e2 := getBufferedEncoder() + defer putBufferedEncoder(e2) + + // Disable unnecessary checks to syntactically parse the JSON value. + d := getBufferedDecoder(b) + defer putBufferedDecoder(d) + d.s.Flags.Set(jsonflags.AllowDuplicateNames | jsonflags.AllowInvalidUTF8 | 1) + mustReorderObjectsFromDecoder(d, &e2.s.Buf) // per RFC 8785, section 3.2.3 +} + +// mustReorderObjectsFromDecoder recursively reorders all object members in place // according to the ordering specified in RFC 8785, section 3.2.3. // // Pre-conditions: // - The value is valid (i.e., no decoder errors should ever occur). -// - The value is compact (i.e., no whitespace is present). // - Initial call is provided a Decoder reading from the start of v. // // Post-conditions: @@ -234,13 +307,13 @@ func putMemberNames(ns *[]memberName) { // // The runtime is approximately O(n·log(n)) + O(m·log(m)), // where n is len(v) and m is the total number of object members. -func reorderObjects(d *Decoder, scratch *[]byte) { - switch tok, _ := d.ReadToken(); tok.Kind() { +func mustReorderObjectsFromDecoder(d *Decoder, scratch *[]byte) { + switch tok, err := d.ReadToken(); tok.Kind() { case '{': // Iterate and collect the name and offsets for every object member. - members := getMemberNames() - defer putMemberNames(members) - var prevName []byte + members := getObjectMembers() + defer putObjectMembers(members) + var prevMember objectMember isSorted := true beforeBody := d.InputOffset() // offset after '{' @@ -249,14 +322,15 @@ func reorderObjects(d *Decoder, scratch *[]byte) { var flags jsonwire.ValueFlags name, _ := d.s.ReadValue(&flags) name = jsonwire.UnquoteMayCopy(name, flags.IsVerbatim()) - reorderObjects(d, scratch) + mustReorderObjectsFromDecoder(d, scratch) afterValue := d.InputOffset() + currMember := objectMember{name, d.s.buf[beforeName:afterValue]} if isSorted && len(*members) > 0 { - isSorted = jsonwire.CompareUTF16(prevName, []byte(name)) < 0 + isSorted = objectMember.Compare(prevMember, currMember) < 0 } - *members = append(*members, memberName{name, beforeName, afterValue}) - prevName = name + *members = append(*members, currMember) + prevMember = currMember } afterBody := d.InputOffset() // offset before '}' d.ReadToken() @@ -265,9 +339,9 @@ func reorderObjects(d *Decoder, scratch *[]byte) { if isSorted { return } - slices.SortFunc(*members, func(x, y memberName) int { - return jsonwire.CompareUTF16(x.name, y.name) - }) + firstBufferBeforeSorting := (*members)[0].buffer + slices.SortFunc(*members, objectMember.Compare) + firstBufferAfterSorting := (*members)[0].buffer // Append the reordered members to a new buffer, // then copy the reordered members back over the original members. @@ -277,14 +351,24 @@ func reorderObjects(d *Decoder, scratch *[]byte) { // // The following invariant must hold: // sum([m.after-m.before for m in members]) == afterBody-beforeBody + commaAndWhitespacePrefix := func(b []byte) []byte { + return b[:len(b)-len(bytes.TrimLeft(b, commaAndWhitespace))] + } sorted := (*scratch)[:0] for i, member := range *members { - if d.s.buf[member.before] == ',' { - member.before++ // trim leading comma - } - sorted = append(sorted, d.s.buf[member.before:member.after]...) - if i < len(*members)-1 { - sorted = append(sorted, ',') // append trailing comma + switch { + case i == 0 && &member.buffer[0] != &firstBufferBeforeSorting[0]: + // First member after sorting is not the first member before sorting, + // so use the prefix of the first member before sorting. + sorted = append(sorted, commaAndWhitespacePrefix(firstBufferBeforeSorting)...) + sorted = append(sorted, bytes.TrimLeft(member.buffer, commaAndWhitespace)...) + case i != 0 && &member.buffer[0] == &firstBufferBeforeSorting[0]: + // Later member after sorting is the first member before sorting, + // so use the prefix of the first member after sorting. + sorted = append(sorted, commaAndWhitespacePrefix(firstBufferAfterSorting)...) + sorted = append(sorted, bytes.TrimLeft(member.buffer, commaAndWhitespace)...) + default: + sorted = append(sorted, member.buffer...) } } if int(afterBody-beforeBody) != len(sorted) { @@ -298,8 +382,12 @@ func reorderObjects(d *Decoder, scratch *[]byte) { } case '[': for d.PeekKind() != ']' { - reorderObjects(d, scratch) + mustReorderObjectsFromDecoder(d, scratch) } d.ReadToken() + default: + if err != nil { + panic("BUG: " + err.Error()) + } } } diff --git a/vendor/github.com/go-json-experiment/json/migrate.sh b/vendor/github.com/go-json-experiment/json/migrate.sh new file mode 100644 index 0000000..70b9e63 --- /dev/null +++ b/vendor/github.com/go-json-experiment/json/migrate.sh @@ -0,0 +1,243 @@ +#!/usr/bin/env bash + +GOROOT=${1:-../go} +JSONROOT="." + +# Check if the Go toolchain has a clean checkout. +if [ -n "$(cd $GOROOT; git status --porcelain)" ]; then + (cd $GOROOT; git status --porcelain) + echo "Working directory is not clean." + echo "" + echo "To cleanup, run:" + echo " (cd $GOROOT && git checkout . && git clean -fd)" + exit 1 +fi + +/bin/rm -rf $GOROOT/src/encoding/json/* +cp $JSONROOT/v1/* $GOROOT/src/encoding/json/ +cp -r $JSONROOT/internal/ $GOROOT/src/encoding/json/internal/ +mkdir $GOROOT/src/encoding/json/v2/ +cp -r $JSONROOT/*.go $GOROOT/src/encoding/json/v2/ +mkdir $GOROOT/src/encoding/json/jsontext/ +cp -r $JSONROOT/jsontext/*.go $GOROOT/src/encoding/json/jsontext/ +find $GOROOT/src/encoding/json -type f -exec sed -i 's|github[.]com/go-json-experiment/json/v1|encoding/json|g' {} + +find $GOROOT/src/encoding/json -type f -exec sed -i 's|github[.]com/go-json-experiment/json/|encoding/json/|g' {} + +find $GOROOT/src/encoding/json -type f -exec sed -i 's|github[.]com/go-json-experiment/json|encoding/json/v2|g' {} + + +# Adjust for changed package path. +sed -i 's/json\.struct/v2.struct/g' $GOROOT/src/encoding/json/v2/errors_test.go + +# Adjust tests that hardcode formatted error strings. +sed -i 's/}`, "Time.UnmarshalJSON: input is not a JSON string/}`, "json: cannot unmarshal JSON object into Go type time.Time/g' $GOROOT/src/time/time_test.go +sed -i 's/]`, "Time.UnmarshalJSON: input is not a JSON string/]`, "json: cannot unmarshal JSON array into Go type time.Time/g' $GOROOT/src/time/time_test.go + +# Adjust for changed dependency tree. +sed -i 's|encoding/json|encoding/json/v2|g' $GOROOT/src/cmd/go/internal/imports/scan_test.go +sed -i 's|encoding/binary|internal/reflectlite|g' $GOROOT/src/cmd/go/internal/imports/scan_test.go +LINE=$(sed -n '/encoding\/json, encoding\/pem, encoding\/xml, mime;/=' $GOROOT/src/go/build/deps_test.go) +sed -i 's|encoding/json, encoding/pem, encoding/xml, mime|encoding/pem, encoding/xml, mime|g' $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+ 1)) i\\\\" $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+ 2)) i\\\tSTR, errors" $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+ 3)) i\\\t< encoding/json/internal" $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+ 4)) i\\\t< encoding/json/internal/jsonflags" $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+ 5)) i\\\t< encoding/json/internal/jsonopts" $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+ 6)) i\\\t< encoding/json/internal/jsonwire" $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+ 7)) i\\\t< encoding/json/jsontext;" $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+ 8)) i\\\\" $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+ 9)) i\\\tFMT," $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+10)) i\\\tencoding/hex," $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+11)) i\\\tencoding/base32," $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+12)) i\\\tencoding/base64," $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+13)) i\\\tencoding/binary," $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+14)) i\\\tencoding/json/jsontext," $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+15)) i\\\tencoding/json/internal," $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+16)) i\\\tencoding/json/internal/jsonflags," $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+17)) i\\\tencoding/json/internal/jsonopts," $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+18)) i\\\tencoding/json/internal/jsonwire" $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+19)) i\\\t< encoding/json/v2" $GOROOT/src/go/build/deps_test.go +sed -i "$((LINE+20)) i\\\t< encoding/json;" $GOROOT/src/go/build/deps_test.go +LINE=$(sed -n '/Test-only packages can have anything they want/=' $GOROOT/src/go/build/deps_test.go) +sed -i "$((LINE+1)) i\\\tFMT, compress/gzip, embed, encoding/binary < encoding/json/internal/jsontest;" $GOROOT/src/go/build/deps_test.go + +# Adjust for newly added API. +ISSUE=71497 +FILE="next/$ISSUE.txt" +NEXT="$GOROOT/doc/next/6-stdlib/99-minor" +mkdir -p $NEXT/encoding/json +echo "A new [Options] type with associated constructors provide individual options" >> $NEXT/encoding/json/$ISSUE.md +echo "to configure \"encoding/json/v2\" to operate with certain historical v1 behavior." >> $NEXT/encoding/json/$ISSUE.md +echo "The [DefaultOptionsV2] option represents the set of all options needed" >> $NEXT/encoding/json/$ISSUE.md +echo "to configure \"encoding/json/v2\" to entirely operate with historical v1 behavior." >> $NEXT/encoding/json/$ISSUE.md +mkdir -p $NEXT/encoding/json/v2 +echo "A new major version of \"encoding/json\" for processing JSON at a semantic level which is" >> $NEXT/encoding/json/v2/$ISSUE.md +echo "functionality that determines the meaning of JSON values as Go values and vice-versa." >> $NEXT/encoding/json/v2/$ISSUE.md +mkdir -p $NEXT/encoding/json/jsontext +echo "A new package to process JSON at a syntactic level that" >> $NEXT/encoding/json/jsontext/$ISSUE.md +echo "is concerned with processing JSON based on its grammar alone." >> $NEXT/encoding/json/jsontext/$ISSUE.md +NEXT="$GOROOT/api/next/$ISSUE.txt" +echo "pkg encoding/json, func CallMethodsWithLegacySemantics(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json, func DefaultOptionsV1() jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json, func EscapeInvalidUTF8(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json, func FormatBytesWithLegacySemantics(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json, func FormatTimeWithLegacySemantics(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json, func MatchCaseSensitiveDelimiter(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json, func MergeWithLegacySemantics(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json, func OmitEmptyWithLegacyDefinition(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json, func ReportErrorsWithLegacySemantics(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json, func StringifyWithLegacySemantics(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json, func UnmarshalArrayFromAnyLength(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json, method (*Number) UnmarshalJSONFrom(*jsontext.Decoder, jsonopts.Options) error #$ISSUE" >> $NEXT +echo "pkg encoding/json, method (*UnmarshalTypeError) Unwrap() error #$ISSUE" >> $NEXT +echo "pkg encoding/json, method (Number) MarshalJSONTo(*jsontext.Encoder, jsonopts.Options) error #$ISSUE" >> $NEXT +echo "pkg encoding/json, type Marshaler = json.Marshaler #$ISSUE" >> $NEXT +echo "pkg encoding/json, type Options = jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json, type RawMessage = jsontext.Value #$ISSUE" >> $NEXT +echo "pkg encoding/json, type UnmarshalTypeError struct, Err error #$ISSUE" >> $NEXT +echo "pkg encoding/json, type Unmarshaler = json.Unmarshaler #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func AllowDuplicateNames(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func AllowInvalidUTF8(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func AppendFormat([]uint8, []uint8, ...jsonopts.Options) ([]uint8, error) #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func AppendQuote[\$0 interface{ ~[]uint8 | ~string }]([]uint8, \$0) ([]uint8, error) #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func AppendUnquote[\$0 interface{ ~[]uint8 | ~string }]([]uint8, \$0) ([]uint8, error) #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func Bool(bool) Token #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func CanonicalizeRawFloats(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func CanonicalizeRawInts(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func EscapeForHTML(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func EscapeForJS(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func Float(float64) Token #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func Int(int64) Token #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func Multiline(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func NewDecoder(io.Reader, ...jsonopts.Options) *Decoder #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func NewEncoder(io.Writer, ...jsonopts.Options) *Encoder #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func PreserveRawStrings(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func ReorderRawObjects(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func SpaceAfterColon(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func SpaceAfterComma(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func String(string) Token #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func Uint(uint64) Token #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func WithIndent(string) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, func WithIndentPrefix(string) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Decoder) InputOffset() int64 #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Decoder) PeekKind() Kind #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Decoder) ReadToken() (Token, error) #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Decoder) ReadValue() (Value, error) #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Decoder) Reset(io.Reader, ...jsonopts.Options) #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Decoder) SkipValue() error #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Decoder) StackDepth() int #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Decoder) StackIndex(int) (Kind, int64) #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Decoder) StackPointer() Pointer #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Decoder) UnreadBuffer() []uint8 #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Encoder) OutputOffset() int64 #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Encoder) Reset(io.Writer, ...jsonopts.Options) #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Encoder) StackDepth() int #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Encoder) StackIndex(int) (Kind, int64) #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Encoder) StackPointer() Pointer #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Encoder) UnusedBuffer() []uint8 #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Encoder) WriteToken(Token) error #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Encoder) WriteValue(Value) error #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*SyntacticError) Error() string #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*SyntacticError) Unwrap() error #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Value) Canonicalize(...jsonopts.Options) error #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Value) Compact(...jsonopts.Options) error #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Value) Format(...jsonopts.Options) error #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Value) Indent(...jsonopts.Options) error #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (*Value) UnmarshalJSON([]uint8) error #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Kind) String() string #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Pointer) AppendToken(string) Pointer #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Pointer) Contains(Pointer) bool #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Pointer) IsValid() bool #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Pointer) LastToken() string #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Pointer) Parent() Pointer #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Pointer) Tokens() iter.Seq[string] #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Token) Bool() bool #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Token) Clone() Token #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Token) Float() float64 #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Token) Int() int64 #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Token) Kind() Kind #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Token) String() string #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Token) Uint() uint64 #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Value) Clone() Value #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Value) IsValid(...jsonopts.Options) bool #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Value) Kind() Kind #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Value) MarshalJSON() ([]uint8, error) #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, method (Value) String() string #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, type Decoder struct #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, type Encoder struct #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, type Kind uint8 #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, type Options = jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, type Pointer string #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, type SyntacticError struct #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, type SyntacticError struct, ByteOffset int64 #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, type SyntacticError struct, Err error #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, type SyntacticError struct, JSONPointer Pointer #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, type Token struct #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, type Value []uint8 #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, var BeginArray Token #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, var BeginObject Token #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, var EndArray Token #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, var EndObject Token #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, var ErrDuplicateName error #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, var ErrNonStringName error #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, var False Token #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, var Internal exporter #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, var Null Token #$ISSUE" >> $NEXT +echo "pkg encoding/json/jsontext, var True Token #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func DefaultOptionsV2() jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func Deterministic(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func DiscardUnknownMembers(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func FormatNilMapAsNull(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func FormatNilSliceAsNull(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func GetOption[\$0 interface{}](jsonopts.Options, func(\$0) jsonopts.Options) (\$0, bool) #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func JoinMarshalers(...*typedArshalers[jsontext.Encoder]) *typedArshalers[jsontext.Encoder] #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func JoinOptions(...jsonopts.Options) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func JoinUnmarshalers(...*typedArshalers[jsontext.Decoder]) *typedArshalers[jsontext.Decoder] #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func Marshal(interface{}, ...jsonopts.Options) ([]uint8, error) #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func MarshalEncode(*jsontext.Encoder, interface{}, ...jsonopts.Options) error #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func MarshalFunc[\$0 interface{}](func(\$0) ([]uint8, error)) *typedArshalers[jsontext.Encoder] #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func MarshalToFunc[\$0 interface{}](func(*jsontext.Encoder, \$0, jsonopts.Options) error) *typedArshalers[jsontext.Encoder] #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func MarshalWrite(io.Writer, interface{}, ...jsonopts.Options) error #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func MatchCaseInsensitiveNames(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func OmitZeroStructFields(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func RejectUnknownMembers(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func StringifyNumbers(bool) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func Unmarshal([]uint8, interface{}, ...jsonopts.Options) error #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func UnmarshalDecode(*jsontext.Decoder, interface{}, ...jsonopts.Options) error #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func UnmarshalFromFunc[\$0 interface{}](func(*jsontext.Decoder, \$0, jsonopts.Options) error) *typedArshalers[jsontext.Decoder] #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func UnmarshalFunc[\$0 interface{}](func([]uint8, \$0) error) *typedArshalers[jsontext.Decoder] #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func UnmarshalRead(io.Reader, interface{}, ...jsonopts.Options) error #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func WithMarshalers(*typedArshalers[jsontext.Encoder]) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, func WithUnmarshalers(*typedArshalers[jsontext.Decoder]) jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, method (*SemanticError) Error() string #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, method (*SemanticError) Unwrap() error #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, type Marshaler interface { MarshalJSON } #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, type Marshaler interface, MarshalJSON() ([]uint8, error) #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, type MarshalerTo interface { MarshalJSONTo } #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, type MarshalerTo interface, MarshalJSONTo(*jsontext.Encoder, jsonopts.Options) error #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, type Marshalers = typedArshalers[jsontext.Encoder] #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, type Options = jsonopts.Options #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, type SemanticError struct #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, type SemanticError struct, ByteOffset int64 #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, type SemanticError struct, Err error #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, type SemanticError struct, GoType reflect.Type #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, type SemanticError struct, JSONKind jsontext.Kind #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, type SemanticError struct, JSONPointer jsontext.Pointer #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, type SemanticError struct, JSONValue jsontext.Value #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, type Unmarshaler interface { UnmarshalJSON } #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, type Unmarshaler interface, UnmarshalJSON([]uint8) error #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, type UnmarshalerFrom interface { UnmarshalJSONFrom } #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, type UnmarshalerFrom interface, UnmarshalJSONFrom(*jsontext.Decoder, jsonopts.Options) error #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, type Unmarshalers = typedArshalers[jsontext.Decoder] #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, var ErrUnknownName error #$ISSUE" >> $NEXT +echo "pkg encoding/json/v2, var SkipFunc error #$ISSUE" >> $NEXT +# The following declarations were moved to encoding/json/v2 or encoding/json/jsontext. +EXCEPT="$GOROOT/api/except.txt" +echo "pkg encoding/json, method (*RawMessage) UnmarshalJSON([]uint8) error" >> $EXCEPT +echo "pkg encoding/json, method (RawMessage) MarshalJSON() ([]uint8, error)" >> $EXCEPT +echo "pkg encoding/json, type Marshaler interface { MarshalJSON }" >> $EXCEPT +echo "pkg encoding/json, type Marshaler interface, MarshalJSON() ([]uint8, error)" >> $EXCEPT +echo "pkg encoding/json, type RawMessage []uint8" >> $EXCEPT +echo "pkg encoding/json, type Unmarshaler interface { UnmarshalJSON }" >> $EXCEPT +echo "pkg encoding/json, type Unmarshaler interface, UnmarshalJSON([]uint8) error" >> $EXCEPT + +# Run the tests. +(cd $GOROOT/src; ./all.bash) diff --git a/vendor/github.com/go-json-experiment/json/options.go b/vendor/github.com/go-json-experiment/json/options.go index a43e31e..2d4e378 100644 --- a/vendor/github.com/go-json-experiment/json/options.go +++ b/vendor/github.com/go-json-experiment/json/options.go @@ -61,6 +61,7 @@ import ( // - [Deterministic] affects marshaling only // - [FormatNilSliceAsNull] affects marshaling only // - [FormatNilMapAsNull] affects marshaling only +// - [OmitZeroStructFields] affects marshaling only // - [MatchCaseInsensitiveNames] affects marshaling and unmarshaling // - [DiscardUnknownMembers] affects marshaling only // - [RejectUnknownMembers] affects unmarshaling only @@ -74,9 +75,7 @@ type Options = jsonopts.Options // Properties set in later options override the value of previously set properties. func JoinOptions(srcs ...Options) Options { var dst jsonopts.Struct - for _, src := range srcs { - dst.Join(src) - } + dst.Join(srcs...) return &dst } @@ -88,27 +87,25 @@ func JoinOptions(srcs ...Options) Options { // v, ok := json.GetOption(opts, json.Deterministic) // // Options are most commonly introspected to alter the JSON representation of -// [MarshalerV2.MarshalJSONV2] and [MarshalerV2.MarshalJSONV2] methods, and -// [MarshalFuncV2] and [UnmarshalFuncV2] functions. +// [MarshalerTo.MarshalJSONTo] and [UnmarshalerFrom.UnmarshalJSONFrom] methods, and +// [MarshalToFunc] and [UnmarshalFromFunc] functions. // In such cases, the presence bit should generally be ignored. func GetOption[T any](opts Options, setter func(T) Options) (T, bool) { return jsonopts.GetOption(opts, setter) } // DefaultOptionsV2 is the full set of all options that define v2 semantics. -// It is equivalent to all boolean options under [Options], -// [encoding/json.Options], and [encoding/json/jsontext.Options] -// being set to false. All non-boolean options are set to the zero value, -// except for [jsontext.WithIndent], which defaults to "\t". +// It is equivalent to all options under [Options], [encoding/json.Options], +// and [encoding/json/jsontext.Options] being set to false or the zero value, +// except for the options related to whitespace formatting. func DefaultOptionsV2() Options { return &jsonopts.DefaultOptionsV2 } // StringifyNumbers specifies that numeric Go types should be marshaled // as a JSON string containing the equivalent JSON number value. -// When unmarshaling, numeric Go types can be parsed from either -// a JSON number or a JSON string containing the JSON number -// without any surrounding whitespace. +// When unmarshaling, numeric Go types are parsed from a JSON string +// containing the JSON number without any surrounding whitespace. // // According to RFC 8259, section 6, a JSON implementation may choose to // limit the representation of a JSON number to an IEEE 754 binary64 value. @@ -168,9 +165,25 @@ func FormatNilMapAsNull(v bool) Options { } } +// OmitZeroStructFields specifies that a Go struct should marshal in such a way +// that all struct fields that are zero are omitted from the marshaled output +// if the value is zero as determined by the "IsZero() bool" method if present, +// otherwise based on whether the field is the zero Go value. +// This is semantically equivalent to specifying the `omitzero` tag option +// on every field in a Go struct. +// +// This only affects marshaling and is ignored when unmarshaling. +func OmitZeroStructFields(v bool) Options { + if v { + return jsonflags.OmitZeroStructFields | 1 + } else { + return jsonflags.OmitZeroStructFields | 0 + } +} + // MatchCaseInsensitiveNames specifies that JSON object members are matched // against Go struct fields using a case-insensitive match of the name. -// Go struct fields explicitly marked with `strictcase` or `nocase` +// Go struct fields explicitly marked with `case:strict` or `case:ignore` // always use case-sensitive (or case-insensitive) name matching, // regardless of the value of this option. // diff --git a/vendor/github.com/gorilla/csrf/csrf.go b/vendor/github.com/gorilla/csrf/csrf.go index 97a3925..5dda254 100644 --- a/vendor/github.com/gorilla/csrf/csrf.go +++ b/vendor/github.com/gorilla/csrf/csrf.go @@ -1,10 +1,12 @@ package csrf import ( + "context" "errors" "fmt" "net/http" "net/url" + "slices" "github.com/gorilla/securecookie" ) @@ -22,6 +24,14 @@ const ( errorPrefix string = "gorilla/csrf: " ) +type contextKey string + +// PlaintextHTTPContextKey is the context key used to store whether the request +// is being served via plaintext HTTP. This is used to signal to the middleware +// that strict Referer checking should not be enforced as is done for HTTPS by +// default. +const PlaintextHTTPContextKey contextKey = "plaintext" + var ( // The name value used in form fields. fieldName = tokenKey @@ -41,6 +51,9 @@ var ( // ErrNoReferer is returned when a HTTPS request provides an empty Referer // header. ErrNoReferer = errors.New("referer not supplied") + // ErrBadOrigin is returned when the Origin header is present and is not a + // trusted origin. + ErrBadOrigin = errors.New("origin invalid") // ErrBadReferer is returned when the scheme & host in the URL do not match // the supplied Referer header. ErrBadReferer = errors.New("referer invalid") @@ -242,10 +255,50 @@ func (cs *csrf) ServeHTTP(w http.ResponseWriter, r *http.Request) { // HTTP methods not defined as idempotent ("safe") under RFC7231 require // inspection. if !contains(safeMethods, r.Method) { - // Enforce an origin check for HTTPS connections. As per the Django CSRF - // implementation (https://goo.gl/vKA7GE) the Referer header is almost - // always present for same-domain HTTP requests. - if r.URL.Scheme == "https" { + var isPlaintext bool + val := r.Context().Value(PlaintextHTTPContextKey) + if val != nil { + isPlaintext, _ = val.(bool) + } + + // take a copy of the request URL to avoid mutating the original + // attached to the request. + // set the scheme & host based on the request context as these are not + // populated by default for server requests + // ref: https://pkg.go.dev/net/http#Request + requestURL := *r.URL // shallow clone + + requestURL.Scheme = "https" + if isPlaintext { + requestURL.Scheme = "http" + } + if requestURL.Host == "" { + requestURL.Host = r.Host + } + + // if we have an Origin header, check it against our allowlist + origin := r.Header.Get("Origin") + if origin != "" { + parsedOrigin, err := url.Parse(origin) + if err != nil { + r = envError(r, ErrBadOrigin) + cs.opts.ErrorHandler.ServeHTTP(w, r) + return + } + if !sameOrigin(&requestURL, parsedOrigin) && !slices.Contains(cs.opts.TrustedOrigins, parsedOrigin.Host) { + r = envError(r, ErrBadOrigin) + cs.opts.ErrorHandler.ServeHTTP(w, r) + return + } + } + + // If we are serving via TLS and have no Origin header, prevent against + // CSRF via HTTP machine in the middle attacks by enforcing strict + // Referer origin checks. Consider an attacker who performs a + // successful HTTP Machine-in-the-Middle attack and uses this to inject + // a form and cause submission to our origin. We strictly disallow + // cleartext HTTP origins and evaluate the domain against an allowlist. + if origin == "" && !isPlaintext { // Fetch the Referer value. Call the error handler if it's empty or // otherwise fails to parse. referer, err := url.Parse(r.Referer()) @@ -255,18 +308,17 @@ func (cs *csrf) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - valid := sameOrigin(r.URL, referer) - - if !valid { - for _, trustedOrigin := range cs.opts.TrustedOrigins { - if referer.Host == trustedOrigin { - valid = true - break - } - } + // disallow cleartext HTTP referers when serving via TLS + if referer.Scheme == "http" { + r = envError(r, ErrBadReferer) + cs.opts.ErrorHandler.ServeHTTP(w, r) + return } - if !valid { + // If the request is being served via TLS and the Referer is not the + // same origin, check the domain against our allowlist. We only + // check when we have host information from the referer. + if referer.Host != "" && referer.Host != r.Host && !slices.Contains(cs.opts.TrustedOrigins, referer.Host) { r = envError(r, ErrBadReferer) cs.opts.ErrorHandler.ServeHTTP(w, r) return @@ -308,6 +360,15 @@ func (cs *csrf) ServeHTTP(w http.ResponseWriter, r *http.Request) { contextClear(r) } +// PlaintextHTTPRequest accepts as input a http.Request and returns a new +// http.Request with the PlaintextHTTPContextKey set to true. This is used to +// signal to the CSRF middleware that the request is being served over plaintext +// HTTP and that Referer-based origin allow-listing checks should be skipped. +func PlaintextHTTPRequest(r *http.Request) *http.Request { + ctx := context.WithValue(r.Context(), PlaintextHTTPContextKey, true) + return r.WithContext(ctx) +} + // unauthorizedhandler sets a HTTP 403 Forbidden status and writes the // CSRF failure reason to the response. func unauthorizedHandler(w http.ResponseWriter, r *http.Request) { diff --git a/vendor/github.com/illarion/gonotify/v2/README.md b/vendor/github.com/illarion/gonotify/v2/README.md deleted file mode 100644 index 008999c..0000000 --- a/vendor/github.com/illarion/gonotify/v2/README.md +++ /dev/null @@ -1,67 +0,0 @@ -## Gonotify - -Simple Golang inotify wrapper. - -[![GoDoc](https://godoc.org/github.com/illarion/gonotify/v2?status.svg)](https://godoc.org/github.com/illarion/gonotify/v2) - -### Provides following primitives: - -* Low level - * `Inotify` - wrapper around [inotify(7)](http://man7.org/linux/man-pages/man7/inotify.7.html) - * `InotifyEvent` - generated file/folder event. Contains `Name` (full path), watch descriptior and `Mask` that describes the event. - -* Higher level - * `FileWatcher` - higher level utility, helps to watch the list of files for changes, creation or removal - * `DirWatcher` - higher level utility, recursively watches given root folder for added, removed or changed files. - * `FileEvent` - embeds `InotifyEvent` and keeps additional field `Eof` to notify user that there will be no more events. - -Use `FileWatcher` and `DirWatcher` as an example and build your own utility classes. - - -### Usage - -```go -package main - -import ( - "fmt" - "github.com/illarion/gonotify/v2" - "time" - "context" -) - -func main() { - - ctx, cancel := context.WithCancel(context.Background()) - - watcher, err := gonotify.NewDirWatcher(ctx, gonotify.IN_CREATE|gonotify.IN_CLOSE, "/tmp") - if err != nil { - panic(err) - } - - for { - select { - case event := <-watcher.C: - fmt.Printf("Event: %s\n", event) - - if event.Mask&gonotify.IN_CREATE != 0 { - fmt.Printf("File created: %s\n", event.Name) - } - - if event.Mask&gonotify.IN_CLOSE != 0 { - fmt.Printf("File closed: %s\n", event.Name) - } - - case <-time.After(5 * time.Second): - fmt.Println("Timeout") - cancel() - return - } - } -} - -``` - -## License -MIT. See LICENSE file for more details. - diff --git a/vendor/github.com/illarion/gonotify/v2/inotify.go b/vendor/github.com/illarion/gonotify/v2/inotify.go deleted file mode 100644 index 21be583..0000000 --- a/vendor/github.com/illarion/gonotify/v2/inotify.go +++ /dev/null @@ -1,290 +0,0 @@ -//go:build linux -// +build linux - -package gonotify - -import ( - "context" - "errors" - "fmt" - "path/filepath" - "strings" - "syscall" - "time" - "unsafe" -) - -// max number of events to read at once -const maxEvents = 1024 - -var TimeoutError = errors.New("Inotify timeout") - -type getWatchRequest struct { - pathName string - result chan uint32 -} - -type getPathRequest struct { - wd uint32 - result chan string -} - -type addWatchRequest struct { - pathName string - wd uint32 -} - -// Inotify is the low level wrapper around inotify_init(), inotify_add_watch() and inotify_rm_watch() -type Inotify struct { - // ctx is the context of inotify instance - ctx context.Context - // fd is the file descriptor of inotify instance - fd int - - // getWatchByPathIn is the channel for getting watch descriptor by path - getWatchByPathIn chan getWatchRequest - // getPathByWatchIn is the channel for getting path by watch descriptor - getPathByWatchIn chan getPathRequest - // addWatchIn is the channel for adding watch - addWatchIn chan addWatchRequest - // rmByWdIn is the channel for removing watch by watch descriptor - rmByWdIn chan uint32 - // rmByPathIn is the channel for removing watch by path - rmByPathIn chan string -} - -// NewInotify creates new inotify instance -func NewInotify(ctx context.Context) (*Inotify, error) { - fd, err := syscall.InotifyInit1(syscall.IN_CLOEXEC | syscall.IN_NONBLOCK) - - if err != nil { - return nil, err - } - - inotify := &Inotify{ - ctx: ctx, - fd: fd, - getPathByWatchIn: make(chan getPathRequest), - getWatchByPathIn: make(chan getWatchRequest), - addWatchIn: make(chan addWatchRequest), - rmByWdIn: make(chan uint32), - rmByPathIn: make(chan string), - } - - go func() { - watches := make(map[string]uint32) - paths := make(map[uint32]string) - - for { - select { - case <-ctx.Done(): - for _, w := range watches { - _, err := syscall.InotifyRmWatch(fd, w) - if err != nil { - continue - } - } - syscall.Close(fd) - return - case req := <-inotify.addWatchIn: - watches[req.pathName] = req.wd - paths[req.wd] = req.pathName - case req := <-inotify.getWatchByPathIn: - wd, ok := watches[req.pathName] - if !ok { - close(req.result) - } - req.result <- wd - close(req.result) - case req := <-inotify.getPathByWatchIn: - pathName, ok := paths[req.wd] - if !ok { - close(req.result) - } - req.result <- pathName - close(req.result) - case wd := <-inotify.rmByWdIn: - pathName, ok := paths[wd] - if !ok { - continue - } - delete(watches, pathName) - delete(paths, wd) - case pathName := <-inotify.rmByPathIn: - wd, ok := watches[pathName] - if !ok { - continue - } - delete(watches, pathName) - delete(paths, wd) - } - } - - }() - - return inotify, nil -} - -// AddWatch adds given path to list of watched files / folders -func (i *Inotify) AddWatch(pathName string, mask uint32) error { - w, err := syscall.InotifyAddWatch(i.fd, pathName, mask) - - if err != nil { - return err - } - - select { - case <-i.ctx.Done(): - return i.ctx.Err() - case i.addWatchIn <- addWatchRequest{ - pathName: pathName, - wd: uint32(w)}: - return nil - } - -} - -// RmWd removes watch by watch descriptor -func (i *Inotify) RmWd(wd uint32) error { - - select { - case <-i.ctx.Done(): - return i.ctx.Err() - case i.rmByWdIn <- wd: - return nil - } -} - -// RmWatch removes watch by pathName -func (i *Inotify) RmWatch(pathName string) error { - - select { - case <-i.ctx.Done(): - return i.ctx.Err() - case i.rmByPathIn <- pathName: - return nil - } - -} - -// Read reads portion of InotifyEvents and may fail with an error. If no events are available, it will -// wait forever, until context is cancelled. -func (i *Inotify) Read() ([]InotifyEvent, error) { - for { - evts, err := i.ReadDeadline(time.Now().Add(time.Millisecond * 200)) - if err != nil { - if err == TimeoutError { - continue - } - return evts, err - } - if len(evts) > 0 { - return evts, nil - } - } -} - -// ReadDeadline waits for InotifyEvents until deadline is reached, or context is cancelled. If -// deadline is reached, TimeoutError is returned. -func (i *Inotify) ReadDeadline(deadline time.Time) ([]InotifyEvent, error) { - events := make([]InotifyEvent, 0, maxEvents) - buf := make([]byte, maxEvents*(syscall.SizeofInotifyEvent+syscall.NAME_MAX+1)) - - var n int - var err error - - fdset := &syscall.FdSet{} - - //main: - for { - if i.ctx.Err() != nil { - return events, i.ctx.Err() - } - - now := time.Now() - - if now.After(deadline) { - return events, TimeoutError - } - - diff := deadline.Sub(now) - - timeout := syscall.NsecToTimeval(diff.Nanoseconds()) - - fdset.Bits[0] = 1 << uint(i.fd) - _, err = syscall.Select(i.fd+1, fdset, nil, nil, &timeout) - - if err != nil { - if err == syscall.EINTR { - continue - } - return events, err - } - - if fdset.Bits[0]&(1< 0 { - break - } - } - - if n < syscall.SizeofInotifyEvent { - return events, fmt.Errorf("short inotify read, expected at least one SizeofInotifyEvent %d, got %d", syscall.SizeofInotifyEvent, n) - } - - offset := 0 - - for offset+syscall.SizeofInotifyEvent <= n { - - event := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset])) - var name string - { - nameStart := offset + syscall.SizeofInotifyEvent - nameEnd := offset + syscall.SizeofInotifyEvent + int(event.Len) - - if nameEnd > n { - return events, fmt.Errorf("corrupted inotify event length %d", event.Len) - } - - name = strings.TrimRight(string(buf[nameStart:nameEnd]), "\x00") - offset = nameEnd - } - - req := getPathRequest{ - wd: uint32(event.Wd), - result: make(chan string), - } - - select { - case <-i.ctx.Done(): - return events, i.ctx.Err() - case i.getPathByWatchIn <- req: - - select { - case <-i.ctx.Done(): - return events, i.ctx.Err() - case watchName := <-req.result: - name = filepath.Join(watchName, name) - } - } - - events = append(events, InotifyEvent{ - Wd: uint32(event.Wd), - Name: name, - Mask: event.Mask, - Cookie: event.Cookie, - }) - } - - return events, nil -} diff --git a/vendor/github.com/illarion/gonotify/v2/.gitignore b/vendor/github.com/illarion/gonotify/v3/.gitignore similarity index 100% rename from vendor/github.com/illarion/gonotify/v2/.gitignore rename to vendor/github.com/illarion/gonotify/v3/.gitignore diff --git a/vendor/github.com/illarion/gonotify/v2/LICENSE b/vendor/github.com/illarion/gonotify/v3/LICENSE similarity index 100% rename from vendor/github.com/illarion/gonotify/v2/LICENSE rename to vendor/github.com/illarion/gonotify/v3/LICENSE diff --git a/vendor/github.com/illarion/gonotify/v3/README.md b/vendor/github.com/illarion/gonotify/v3/README.md new file mode 100644 index 0000000..3281cf6 --- /dev/null +++ b/vendor/github.com/illarion/gonotify/v3/README.md @@ -0,0 +1,71 @@ +## Gonotify + +Simple Golang inotify wrapper. + +[![GoDoc](https://godoc.org/github.com/illarion/gonotify/v3?status.svg)](https://godoc.org/github.com/illarion/gonotify/v3) + +### Provides following primitives: + +* Low level + * `Inotify` - wrapper around [inotify(7)](http://man7.org/linux/man-pages/man7/inotify.7.html) + * `InotifyEvent` - generated file/folder event. Contains `Name` (full path), `Wd` - watch descriptor and `Mask` that describes the event. + +* Higher level + * `FileWatcher` - higher level utility, helps to watch the list of files for changes, creation or removal + * `DirWatcher` - higher level utility, recursively watches given root folder for added, removed or changed files. + * `FileEvent` - embeds `InotifyEvent` and keeps additional field `Eof` to notify user that there will be no more events. + +Use `FileWatcher` and `DirWatcher` as an example and build your own utility classes. + +### Usage + +```go +package main + +import ( + "fmt" + "github.com/illarion/gonotify/v3" + "time" + "context" +) + +func main() { + + ctx, cancel := context.WithCancel(context.Background()) + + watcher, err := gonotify.NewDirWatcher(ctx, gonotify.IN_CREATE|gonotify.IN_CLOSE, "/tmp") + if err != nil { + panic(err) + } + + main: + for { + select { + case event := <-watcher.C: + fmt.Printf("Event: %s\n", event) + + if event.Is(gonotify.IN_CREATE) { + fmt.Printf("File created: %s\n", event.Name) + } + + if event.IsAny(gonotify.IN_CLOSE, gonotify.IN_CLOSE_WRITE) { + fmt.Printf("File closed: %s\n", event.Name) + } + + case <-time.After(5 * time.Second): + fmt.Println("Good bye!") + cancel() + break main + } + } + + // Wait for watcher to finish all internal goroutines + <-watcher.Done() + fmt.Println("Watcher is done") + +} +``` + +## License +MIT. See [LICENSE](LICENSE) file for more details. + diff --git a/vendor/github.com/illarion/gonotify/v2/dirwatcher.go b/vendor/github.com/illarion/gonotify/v3/dirwatcher.go similarity index 69% rename from vendor/github.com/illarion/gonotify/v2/dirwatcher.go rename to vendor/github.com/illarion/gonotify/v3/dirwatcher.go index 1fbf795..30236c9 100644 --- a/vendor/github.com/illarion/gonotify/v2/dirwatcher.go +++ b/vendor/github.com/illarion/gonotify/v3/dirwatcher.go @@ -4,27 +4,27 @@ import ( "context" "os" "path/filepath" + "sync" ) // DirWatcher recursively watches the given root folder, waiting for file events. // Events can be masked by providing fileMask. DirWatcher does not generate events for // folders or subfolders. type DirWatcher struct { - C chan FileEvent + C chan FileEvent + done chan struct{} } // NewDirWatcher creates DirWatcher recursively waiting for events in the given root folder and // emitting FileEvents in channel C, that correspond to fileMask. Folder events are ignored (having IN_ISDIR set to 1) func NewDirWatcher(ctx context.Context, fileMask uint32, root string) (*DirWatcher, error) { dw := &DirWatcher{ - C: make(chan FileEvent), + C: make(chan FileEvent), + done: make(chan struct{}), } - ctx, cancel := context.WithCancel(ctx) - i, err := NewInotify(ctx) if err != nil { - cancel() return nil, err } @@ -48,30 +48,54 @@ func NewDirWatcher(ctx context.Context, fileMask uint32, root string) (*DirWatch return nil } - return i.AddWatch(path, IN_ALL_EVENTS) + _, err = i.AddWatch(path, IN_ALL_EVENTS) + return err }) if err != nil { - cancel() return nil, err } events := make(chan FileEvent) + wg := sync.WaitGroup{} + wg.Add(1) go func() { + defer wg.Done() + for _, event := range queue { - events <- event + select { + case <-ctx.Done(): + close(events) + return + case events <- event: + + } } queue = nil for { + select { + case <-ctx.Done(): + close(events) + return + default: + } + raw, err := i.Read() if err != nil { close(events) return } + select { + case <-ctx.Done(): + close(events) + return + default: + } + for _, event := range raw { // Skip ignored events queued from removed watchers @@ -92,11 +116,15 @@ func NewDirWatcher(ctx context.Context, fileMask uint32, root string) (*DirWatch if !f.IsDir() { // fake event, but there can be duplicates of this event provided by real watcher - events <- FileEvent{ + select { + case <-ctx.Done(): + return nil + case events <- FileEvent{ InotifyEvent: InotifyEvent{ Name: path, Mask: IN_CREATE, }, + }: //noop } } @@ -120,24 +148,44 @@ func NewDirWatcher(ctx context.Context, fileMask uint32, root string) (*DirWatch continue } - events <- FileEvent{ + select { + case <-ctx.Done(): + return + case events <- FileEvent{ InotifyEvent: event, + }: //noop } } } }() + wg.Add(1) go func() { + defer wg.Done() + defer close(dw.C) + for { select { case <-ctx.Done(): - return + // drain events + for { + select { + case _, ok := <-events: + if !ok { + return + } + default: + return + } + } case event, ok := <-events: if !ok { - dw.C <- FileEvent{ + select { + case <-ctx.Done(): + case dw.C <- FileEvent{ Eof: true, + }: } - cancel() return } @@ -146,11 +194,25 @@ func NewDirWatcher(ctx context.Context, fileMask uint32, root string) (*DirWatch continue } - dw.C <- event + select { + case dw.C <- event: + case <-ctx.Done(): + return + } } } }() - return dw, nil + go func() { + wg.Wait() + <-i.Done() + close(dw.done) + }() + return dw, nil +} + +// Done returns a channel that is closed when DirWatcher is done +func (dw *DirWatcher) Done() <-chan struct{} { + return dw.done } diff --git a/vendor/github.com/illarion/gonotify/v2/event.go b/vendor/github.com/illarion/gonotify/v3/event.go similarity index 99% rename from vendor/github.com/illarion/gonotify/v2/event.go rename to vendor/github.com/illarion/gonotify/v3/event.go index 45bf64d..e1caef0 100644 --- a/vendor/github.com/illarion/gonotify/v2/event.go +++ b/vendor/github.com/illarion/gonotify/v3/event.go @@ -81,7 +81,7 @@ func InMaskToString(in_mask uint32) string { // InotifyEvent is the go representation of inotify_event found in sys/inotify.h type InotifyEvent struct { // Watch descriptor - Wd uint32 + Wd int // File or directory name Name string // Contains bits that describe the event that occurred diff --git a/vendor/github.com/illarion/gonotify/v2/filewatcher.go b/vendor/github.com/illarion/gonotify/v3/filewatcher.go similarity index 63% rename from vendor/github.com/illarion/gonotify/v2/filewatcher.go rename to vendor/github.com/illarion/gonotify/v3/filewatcher.go index 1089f7b..e3ff468 100644 --- a/vendor/github.com/illarion/gonotify/v2/filewatcher.go +++ b/vendor/github.com/illarion/gonotify/v3/filewatcher.go @@ -3,35 +3,34 @@ package gonotify import ( "context" "path/filepath" + "sync" ) // FileWatcher waits for events generated by filesystem for a specific list of file paths, including // IN_CREATE for not yet existing files and IN_DELETE for removed. type FileWatcher struct { - C chan FileEvent + C chan FileEvent + done chan struct{} } // NewFileWatcher creates FileWatcher with provided inotify mask and list of files to wait events for. func NewFileWatcher(ctx context.Context, mask uint32, files ...string) (*FileWatcher, error) { f := &FileWatcher{ - C: make(chan FileEvent), + C: make(chan FileEvent), + done: make(chan struct{}), } - ctx, cancel := context.WithCancel(ctx) - inotify, err := NewInotify(ctx) if err != nil { - cancel() return nil, err } expectedPaths := make(map[string]bool) for _, file := range files { - err := inotify.AddWatch(filepath.Dir(file), mask) + _, err := inotify.AddWatch(filepath.Dir(file), mask) if err != nil { - cancel() return nil, err } expectedPaths[file] = true @@ -39,11 +38,20 @@ func NewFileWatcher(ctx context.Context, mask uint32, files ...string) (*FileWat events := make(chan FileEvent) + wg := sync.WaitGroup{} + wg.Add(1) go func() { - defer cancel() + defer wg.Done() for { - raw, err := inotify.Read() + select { + case <-ctx.Done(): + close(events) + return + default: + } + + raw, err := inotify.Read() if err != nil { close(events) return @@ -61,8 +69,10 @@ func NewFileWatcher(ctx context.Context, mask uint32, files ...string) (*FileWat } }() + wg.Add(1) go func() { - defer cancel() + defer wg.Done() + defer close(f.C) for { select { case <-ctx.Done(): @@ -70,8 +80,9 @@ func NewFileWatcher(ctx context.Context, mask uint32, files ...string) (*FileWat case event, ok := <-events: if !ok { - f.C <- FileEvent{ - Eof: true, + select { + case <-ctx.Done(): + case f.C <- FileEvent{Eof: true}: } return } @@ -80,10 +91,25 @@ func NewFileWatcher(ctx context.Context, mask uint32, files ...string) (*FileWat continue } - f.C <- event + select { + case <-ctx.Done(): + return + case f.C <- event: + } } } }() + go func() { + <-inotify.Done() + wg.Wait() + close(f.done) + }() + return f, nil } + +// Done returns a channel that is closed when the FileWatcher is done. +func (f *FileWatcher) Done() <-chan struct{} { + return f.done +} diff --git a/vendor/github.com/illarion/gonotify/v3/inotify.go b/vendor/github.com/illarion/gonotify/v3/inotify.go new file mode 100644 index 0000000..4ff8025 --- /dev/null +++ b/vendor/github.com/illarion/gonotify/v3/inotify.go @@ -0,0 +1,527 @@ +//go:build linux +// +build linux + +package gonotify + +import ( + "context" + "errors" + "os" + "path/filepath" + "strings" + "sync" + "syscall" + "time" + "unsafe" + + "github.com/illarion/gonotify/v3/syscallf" +) + +const ( + // maxEvents is the maximum number of events to read in one syscall + maxEvents = 1024 +) + +type addWatchResult struct { + wd int + err error +} + +type addWatchRequest struct { + pathName string + mask uint32 + result chan addWatchResult +} + +type rmWdRequest struct { + wd int + ignored bool // if true, the watch was removed automatically + result chan error +} + +type rmPathRequest struct { + pathName string + result chan error +} + +type eventItem struct { + InotifyEvent + err error +} + +// Inotify is the low level wrapper around inotify_init(), inotify_add_watch() and inotify_rm_watch() +type Inotify struct { + ctx context.Context + done chan struct{} + addWatchIn chan addWatchRequest + rmByWdIn chan rmWdRequest + rmByPathIn chan rmPathRequest + eventsOut chan eventItem + + readMutex sync.Mutex +} + +// NewInotify creates new inotify instance +func NewInotify(ctx context.Context) (*Inotify, error) { + fd, err := syscall.InotifyInit1(syscall.IN_CLOEXEC | syscall.IN_NONBLOCK) + if err != nil { + return nil, err + } + + file := os.NewFile(uintptr(fd), "inotify") + + inotify := &Inotify{ + ctx: ctx, + done: make(chan struct{}), + addWatchIn: make(chan addWatchRequest), + rmByWdIn: make(chan rmWdRequest), + rmByPathIn: make(chan rmPathRequest), + eventsOut: make(chan eventItem, maxEvents), + } + + type getPathRequest struct { + wd int + result chan string + } + + getPathIn := make(chan getPathRequest) + + wg := sync.WaitGroup{} + + wg.Add(1) + go func() { + //defer cancel() + <-ctx.Done() + //file.Close() + wg.Done() + }() + + wg.Add(1) + // read events goroutine. Only this goroutine can read or close the inotify file descriptor + go func() { + defer wg.Done() + defer close(inotify.eventsOut) + + // reusable buffers for reading inotify events. Make sure they're not + // leaked into other goroutines, as they're not thread safe + buf := make([]byte, maxEvents*(syscall.SizeofInotifyEvent+syscall.NAME_MAX+1)) + + for { + + select { + case <-ctx.Done(): + return + default: + } + + var n int + + for { + + select { + case <-ctx.Done(): + return + default: + } + + n, err = file.Read(buf) + if err != nil { + + // if we got an error, we should return + select { + case inotify.eventsOut <- eventItem{ + InotifyEvent: InotifyEvent{}, + err: err, + }: + default: + } + + return + } + + if n > 0 { + break + } + } + + if n < syscall.SizeofInotifyEvent { + select { + case <-ctx.Done(): + return + default: + continue + } + } + + offset := 0 + for offset+syscall.SizeofInotifyEvent <= n { + event := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset])) + var name string + { + nameStart := offset + syscall.SizeofInotifyEvent + nameEnd := offset + syscall.SizeofInotifyEvent + int(event.Len) + + if nameEnd > n { + continue + } + + name = strings.TrimRight(string(buf[nameStart:nameEnd]), "\x00") + offset = nameEnd + } + + req := getPathRequest{wd: int(event.Wd), result: make(chan string)} + var watchName string + + select { + case <-ctx.Done(): + return + case getPathIn <- req: + + select { + case <-ctx.Done(): + return + case watchName = <-req.result: + } + + } + + if watchName == "" { + continue + } + + name = filepath.Join(watchName, name) + + inotifyEvent := InotifyEvent{ + Wd: int(event.Wd), + Name: name, + Mask: event.Mask, + Cookie: event.Cookie, + } + + // watch was removed explicitly or automatically + if inotifyEvent.Is(IN_IGNORED) { + + // remove watch + + result := make(chan error) + + select { + case <-ctx.Done(): + return + case inotify.rmByWdIn <- rmWdRequest{ + wd: int(event.Wd), + ignored: true, + result: result, + }: + case <-time.After(1 * time.Second): + } + + select { + case <-ctx.Done(): + return + case err := <-result: + if err != nil { + // TODO log error + } + } + + continue + + } + + select { + case <-ctx.Done(): + return + case inotify.eventsOut <- eventItem{ + InotifyEvent: inotifyEvent, + err: nil, + }: + } + + } + + } + + }() + + wg.Add(1) + // main goroutine (handle channels) + go func() { + //defer cancel() + defer wg.Done() + + watches := make(map[string]int) + paths := make(map[int]string) + + for { + select { + case <-ctx.Done(): + + // Handle pending requests + draining := true + + for draining { + select { + case req := <-inotify.addWatchIn: + // Send error to addWatch requests + select { + case req.result <- addWatchResult{ + wd: 0, + err: errors.New("Inotify instance closed"), + }: + default: + } + case <-inotify.rmByWdIn: + case <-inotify.addWatchIn: + case <-inotify.rmByPathIn: + case <-getPathIn: + + default: + draining = false + } + } + + for _, w := range watches { + _, err := syscallf.InotifyRmWatch(fd, w) + if err != nil { + continue + } + } + + return + case req := <-inotify.addWatchIn: + wd, err := syscall.InotifyAddWatch(fd, req.pathName, req.mask) + if err == nil { + watches[req.pathName] = wd + paths[wd] = req.pathName + } + select { + case req.result <- addWatchResult{wd: wd, err: err}: + case <-ctx.Done(): + } + case req := <-inotify.rmByWdIn: + pathName, ok := paths[req.wd] + if !ok { + continue + } + + if !req.ignored { + _, err = syscallf.InotifyRmWatch(fd, req.wd) + } + + delete(watches, pathName) + delete(paths, req.wd) + + select { + case req.result <- err: + case <-ctx.Done(): + } + case req := <-inotify.rmByPathIn: + wd, ok := watches[req.pathName] + if !ok { + continue + } + _, err := syscallf.InotifyRmWatch(fd, wd) + + delete(watches, req.pathName) + delete(paths, wd) + + select { + case req.result <- err: + case <-ctx.Done(): + } + case req := <-getPathIn: + wd := paths[req.wd] + select { + case req.result <- wd: + case <-ctx.Done(): + } + } + } + }() + + go func() { + //defer cancel() + wg.Wait() + close(inotify.done) + }() + + return inotify, nil +} + +// Done returns a channel that is closed when Inotify is done +func (i *Inotify) Done() <-chan struct{} { + return i.done +} + +// AddWatch adds given path to list of watched files / folders +func (i *Inotify) AddWatch(pathName string, mask uint32) (int, error) { + + req := addWatchRequest{ + pathName: pathName, + mask: mask, + result: make(chan addWatchResult), + } + + select { + case <-i.ctx.Done(): + return 0, i.ctx.Err() + case i.addWatchIn <- req: + + select { + case <-i.ctx.Done(): + return 0, i.ctx.Err() + case result := <-req.result: + return result.wd, result.err + } + } +} + +// RmWd removes watch by watch descriptor +func (i *Inotify) RmWd(wd int) error { + + req := rmWdRequest{ + wd: wd, + ignored: false, + result: make(chan error), + } + + select { + case <-i.ctx.Done(): + return i.ctx.Err() + case i.rmByWdIn <- req: + } + + select { + case <-i.ctx.Done(): + return i.ctx.Err() + case err := <-req.result: + return err + } + +} + +// RmWatch removes watch by pathName +func (i *Inotify) RmWatch(pathName string) error { + + req := rmPathRequest{ + pathName: pathName, + result: make(chan error), + } + + select { + case <-i.ctx.Done(): + return i.ctx.Err() + case i.rmByPathIn <- req: + } + + select { + case <-i.ctx.Done(): + return i.ctx.Err() + case err := <-req.result: + return err + } +} + +// Read reads portion of InotifyEvents and may fail with an error. If no events are available, it will +// wait forever, until context is cancelled. +func (i *Inotify) Read() ([]InotifyEvent, error) { + i.readMutex.Lock() + defer i.readMutex.Unlock() + + events := make([]InotifyEvent, 0, maxEvents) + + select { + case <-i.ctx.Done(): + return events, i.ctx.Err() + case <-i.Done(): + return events, errors.New("inotify closed") + case evt, ok := <-i.eventsOut: + + if !ok { + return events, errors.New("inotify closed") + } + if evt.err != nil { + return events, evt.err + } + + if evt.InotifyEvent.Wd != 0 { + // append first event + events = append(events, evt.InotifyEvent) + } + + if len(events) >= maxEvents { + return events, nil + } + + // read all available events + read: + for { + + select { + case <-i.ctx.Done(): + return events, i.ctx.Err() + case <-i.Done(): + return events, errors.New("inotify closed") + case evt, ok := <-i.eventsOut: + if !ok { + return events, errors.New("inotify closed") + } + if evt.err != nil { + return events, evt.err + } + + if evt.InotifyEvent.Wd != 0 { + // append event + events = append(events, evt.InotifyEvent) + } + + if len(events) >= maxEvents { + return events, nil + } + + default: + break read + } + + } + + } + + return events, nil +} + +// ReadDeadline waits for InotifyEvents until deadline is reached, or context is cancelled. If +// deadline is reached, it will return all events read until that point. +func (i *Inotify) ReadDeadline(deadline time.Time) ([]InotifyEvent, error) { + i.readMutex.Lock() + defer i.readMutex.Unlock() + + events := make([]InotifyEvent, 0, maxEvents) + + for { + select { + case <-i.ctx.Done(): + return events, i.ctx.Err() + case <-i.Done(): + return events, errors.New("Inotify closed") + case <-time.After(time.Until(deadline)): + return events, nil + case evt, ok := <-i.eventsOut: + if !ok { + return events, errors.New("Inotify closed") + } + if evt.err != nil { + return events, evt.err + } + + events = append(events, evt.InotifyEvent) + + if len(events) >= maxEvents { + return events, nil + } + + } + } + +} diff --git a/vendor/github.com/illarion/gonotify/v3/syscallf/rm_watch.go b/vendor/github.com/illarion/gonotify/v3/syscallf/rm_watch.go new file mode 100644 index 0000000..9024fb3 --- /dev/null +++ b/vendor/github.com/illarion/gonotify/v3/syscallf/rm_watch.go @@ -0,0 +1,17 @@ +//go:build linux + +package syscallf + +import "syscall" + +func InotifyRmWatch(fd int, watchdesc int) (int, error) { + var success int + var err error + + r0, _, e1 := syscall.RawSyscall(syscall.SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0) + success = int(r0) + if e1 != 0 { + err = e1 + } + return success, err +} diff --git a/vendor/github.com/josharian/native/doc.go b/vendor/github.com/josharian/native/doc.go deleted file mode 100644 index 2ca7ddc..0000000 --- a/vendor/github.com/josharian/native/doc.go +++ /dev/null @@ -1,8 +0,0 @@ -// Package native provides easy access to native byte order. -// -// Usage: use native.Endian where you need the native binary.ByteOrder. -// -// Please think twice before using this package. -// It can break program portability. -// Native byte order is usually not the right answer. -package native diff --git a/vendor/github.com/josharian/native/endian_generic.go b/vendor/github.com/josharian/native/endian_generic.go deleted file mode 100644 index c0f0502..0000000 --- a/vendor/github.com/josharian/native/endian_generic.go +++ /dev/null @@ -1,22 +0,0 @@ -package native - -import ( - "encoding/binary" - - "golang.org/x/sys/cpu" -) - -var Endian binary.ByteOrder - -// IsBigEndian records whether the GOARCH's byte order is big endian. -// -// Deprecated: use golang.org/x/sys/cpu.IsBigEndian instead, now that it exists. -const IsBigEndian = cpu.IsBigEndian - -func init() { - if IsBigEndian { - Endian = binary.BigEndian - } else { - Endian = binary.LittleEndian - } -} diff --git a/vendor/github.com/josharian/native/license b/vendor/github.com/josharian/native/license deleted file mode 100644 index 6e617a9..0000000 --- a/vendor/github.com/josharian/native/license +++ /dev/null @@ -1,7 +0,0 @@ -Copyright 2020 Josh Bleecher Snyder - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/josharian/native/readme.md b/vendor/github.com/josharian/native/readme.md deleted file mode 100644 index 24aae1c..0000000 --- a/vendor/github.com/josharian/native/readme.md +++ /dev/null @@ -1,12 +0,0 @@ -# native [![Go Reference](https://pkg.go.dev/badge/github.com/josharian/native.svg)](https://pkg.go.dev/github.com/josharian/native) - -Package native provides easy access to native byte order. - -`go get github.com/josharian/native` - -Usage: Use `native.Endian` where you need the native binary.ByteOrder. - -Please think twice before using this package. -It can break program portability. -Native byte order is usually not the right answer. - diff --git a/vendor/github.com/klauspost/compress/.goreleaser.yml b/vendor/github.com/klauspost/compress/.goreleaser.yml index 4c28dff..4528059 100644 --- a/vendor/github.com/klauspost/compress/.goreleaser.yml +++ b/vendor/github.com/klauspost/compress/.goreleaser.yml @@ -1,9 +1,8 @@ -# This is an example goreleaser.yaml file with some sane defaults. -# Make sure to check the documentation at http://goreleaser.com +version: 2 + before: hooks: - ./gen.sh - - go install mvdan.cc/garble@v0.10.1 builds: - @@ -32,7 +31,6 @@ builds: - mips64le goarm: - 7 - gobinary: garble - id: "s2d" binary: s2d @@ -59,7 +57,6 @@ builds: - mips64le goarm: - 7 - gobinary: garble - id: "s2sx" binary: s2sx @@ -87,7 +84,6 @@ builds: - mips64le goarm: - 7 - gobinary: garble archives: - @@ -103,7 +99,7 @@ archives: checksum: name_template: 'checksums.txt' snapshot: - name_template: "{{ .Tag }}-next" + version_template: "{{ .Tag }}-next" changelog: sort: asc filters: diff --git a/vendor/github.com/klauspost/compress/README.md b/vendor/github.com/klauspost/compress/README.md index 7e83f58..de264c8 100644 --- a/vendor/github.com/klauspost/compress/README.md +++ b/vendor/github.com/klauspost/compress/README.md @@ -16,6 +16,51 @@ This package provides various compression algorithms. # changelog +* Sep 23rd, 2024 - [1.17.10](https://github.com/klauspost/compress/releases/tag/v1.17.10) + * gzhttp: Add TransportAlwaysDecompress option. https://github.com/klauspost/compress/pull/978 + * gzhttp: Add supported decompress request body by @mirecl in https://github.com/klauspost/compress/pull/1002 + * s2: Add EncodeBuffer buffer recycling callback https://github.com/klauspost/compress/pull/982 + * zstd: Improve memory usage on small streaming encodes https://github.com/klauspost/compress/pull/1007 + * flate: read data written with partial flush by @vajexal in https://github.com/klauspost/compress/pull/996 + +* Jun 12th, 2024 - [1.17.9](https://github.com/klauspost/compress/releases/tag/v1.17.9) + * s2: Reduce ReadFrom temporary allocations https://github.com/klauspost/compress/pull/949 + * flate, zstd: Shave some bytes off amd64 matchLen by @greatroar in https://github.com/klauspost/compress/pull/963 + * Upgrade zip/zlib to 1.22.4 upstream https://github.com/klauspost/compress/pull/970 https://github.com/klauspost/compress/pull/971 + * zstd: BuildDict fails with RLE table https://github.com/klauspost/compress/pull/951 + +* Apr 9th, 2024 - [1.17.8](https://github.com/klauspost/compress/releases/tag/v1.17.8) + * zstd: Reject blocks where reserved values are not 0 https://github.com/klauspost/compress/pull/885 + * zstd: Add RLE detection+encoding https://github.com/klauspost/compress/pull/938 + +* Feb 21st, 2024 - [1.17.7](https://github.com/klauspost/compress/releases/tag/v1.17.7) + * s2: Add AsyncFlush method: Complete the block without flushing by @Jille in https://github.com/klauspost/compress/pull/927 + * s2: Fix literal+repeat exceeds dst crash https://github.com/klauspost/compress/pull/930 + +* Feb 5th, 2024 - [1.17.6](https://github.com/klauspost/compress/releases/tag/v1.17.6) + * zstd: Fix incorrect repeat coding in best mode https://github.com/klauspost/compress/pull/923 + * s2: Fix DecodeConcurrent deadlock on errors https://github.com/klauspost/compress/pull/925 + +* Jan 26th, 2024 - [v1.17.5](https://github.com/klauspost/compress/releases/tag/v1.17.5) + * flate: Fix reset with dictionary on custom window encodes https://github.com/klauspost/compress/pull/912 + * zstd: Add Frame header encoding and stripping https://github.com/klauspost/compress/pull/908 + * zstd: Limit better/best default window to 8MB https://github.com/klauspost/compress/pull/913 + * zstd: Speed improvements by @greatroar in https://github.com/klauspost/compress/pull/896 https://github.com/klauspost/compress/pull/910 + * s2: Fix callbacks for skippable blocks and disallow 0xfe (Padding) by @Jille in https://github.com/klauspost/compress/pull/916 https://github.com/klauspost/compress/pull/917 +https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/compress/pull/918 + +* Dec 1st, 2023 - [v1.17.4](https://github.com/klauspost/compress/releases/tag/v1.17.4) + * huff0: Speed up symbol counting by @greatroar in https://github.com/klauspost/compress/pull/887 + * huff0: Remove byteReader by @greatroar in https://github.com/klauspost/compress/pull/886 + * gzhttp: Allow overriding decompression on transport https://github.com/klauspost/compress/pull/892 + * gzhttp: Clamp compression level https://github.com/klauspost/compress/pull/890 + * gzip: Error out if reserved bits are set https://github.com/klauspost/compress/pull/891 + +* Nov 15th, 2023 - [v1.17.3](https://github.com/klauspost/compress/releases/tag/v1.17.3) + * fse: Fix max header size https://github.com/klauspost/compress/pull/881 + * zstd: Improve better/best compression https://github.com/klauspost/compress/pull/877 + * gzhttp: Fix missing content type on Close https://github.com/klauspost/compress/pull/883 + * Oct 22nd, 2023 - [v1.17.2](https://github.com/klauspost/compress/releases/tag/v1.17.2) * zstd: Fix rare *CORRUPTION* output in "best" mode. See https://github.com/klauspost/compress/pull/876 @@ -31,6 +76,10 @@ This package provides various compression algorithms. * s2: Do 2 overlapping match checks https://github.com/klauspost/compress/pull/839 * flate: Add amd64 assembly matchlen https://github.com/klauspost/compress/pull/837 * gzip: Copy bufio.Reader on Reset by @thatguystone in https://github.com/klauspost/compress/pull/860 + +
+ See changes to v1.16.x + * July 1st, 2023 - [v1.16.7](https://github.com/klauspost/compress/releases/tag/v1.16.7) * zstd: Fix default level first dictionary encode https://github.com/klauspost/compress/pull/829 @@ -53,7 +102,7 @@ This package provides various compression algorithms. * zstd: Various minor improvements by @greatroar in https://github.com/klauspost/compress/pull/788 https://github.com/klauspost/compress/pull/794 https://github.com/klauspost/compress/pull/795 * s2: Fix huge block overflow https://github.com/klauspost/compress/pull/779 * s2: Allow CustomEncoder fallback https://github.com/klauspost/compress/pull/780 - * gzhttp: Suppport ResponseWriter Unwrap() in gzhttp handler by @jgimenez in https://github.com/klauspost/compress/pull/799 + * gzhttp: Support ResponseWriter Unwrap() in gzhttp handler by @jgimenez in https://github.com/klauspost/compress/pull/799 * Mar 13, 2023 - [v1.16.1](https://github.com/klauspost/compress/releases/tag/v1.16.1) * zstd: Speed up + improve best encoder by @greatroar in https://github.com/klauspost/compress/pull/776 @@ -69,6 +118,7 @@ This package provides various compression algorithms. * s2: Add LZ4 block converter. https://github.com/klauspost/compress/pull/748 * s2: Support io.ReaderAt in ReadSeeker. https://github.com/klauspost/compress/pull/747 * s2c/s2sx: Use concurrent decoding. https://github.com/klauspost/compress/pull/746 +
See changes to v1.15.x @@ -107,7 +157,7 @@ This package provides various compression algorithms. * zstd: Add [WithDecodeAllCapLimit](https://pkg.go.dev/github.com/klauspost/compress@v1.15.10/zstd#WithDecodeAllCapLimit) https://github.com/klauspost/compress/pull/649 * Add Go 1.19 - deprecate Go 1.16 https://github.com/klauspost/compress/pull/651 * flate: Improve level 5+6 compression https://github.com/klauspost/compress/pull/656 - * zstd: Improve "better" compresssion https://github.com/klauspost/compress/pull/657 + * zstd: Improve "better" compression https://github.com/klauspost/compress/pull/657 * s2: Improve "best" compression https://github.com/klauspost/compress/pull/658 * s2: Improve "better" compression. https://github.com/klauspost/compress/pull/635 * s2: Slightly faster non-assembly decompression https://github.com/klauspost/compress/pull/646 @@ -310,7 +360,7 @@ While the release has been extensively tested, it is recommended to testing when * s2: Fix binaries. * Feb 25, 2021 (v1.11.8) - * s2: Fixed occational out-of-bounds write on amd64. Upgrade recommended. + * s2: Fixed occasional out-of-bounds write on amd64. Upgrade recommended. * s2: Add AMD64 assembly for better mode. 25-50% faster. [#315](https://github.com/klauspost/compress/pull/315) * s2: Less upfront decoder allocation. [#322](https://github.com/klauspost/compress/pull/322) * zstd: Faster "compression" of incompressible data. [#314](https://github.com/klauspost/compress/pull/314) @@ -489,7 +539,7 @@ While the release has been extensively tested, it is recommended to testing when * Feb 19, 2016: Faster bit writer, level -2 is 15% faster, level 1 is 4% faster. * Feb 19, 2016: Handle small payloads faster in level 1-3. * Feb 19, 2016: Added faster level 2 + 3 compression modes. -* Feb 19, 2016: [Rebalanced compression levels](https://blog.klauspost.com/rebalancing-deflate-compression-levels/), so there is a more even progresssion in terms of compression. New default level is 5. +* Feb 19, 2016: [Rebalanced compression levels](https://blog.klauspost.com/rebalancing-deflate-compression-levels/), so there is a more even progression in terms of compression. New default level is 5. * Feb 14, 2016: Snappy: Merge upstream changes. * Feb 14, 2016: Snappy: Fix aggressive skipping. * Feb 14, 2016: Snappy: Update benchmark. @@ -536,6 +586,8 @@ the stateless compress described below. For compression performance, see: [this spreadsheet](https://docs.google.com/spreadsheets/d/1nuNE2nPfuINCZJRMt6wFWhKpToF95I47XjSsc-1rbPQ/edit?usp=sharing). +To disable all assembly add `-tags=noasm`. This works across all packages. + # Stateless compression This package offers stateless compression as a special option for gzip/deflate. @@ -554,7 +606,7 @@ For direct deflate use, NewStatelessWriter and StatelessDeflate are available. S A `bufio.Writer` can of course be used to control write sizes. For example, to use a 4KB buffer: -``` +```go // replace 'ioutil.Discard' with your output. gzw, err := gzip.NewWriterLevel(ioutil.Discard, gzip.StatelessCompression) if err != nil { diff --git a/vendor/github.com/klauspost/compress/fse/decompress.go b/vendor/github.com/klauspost/compress/fse/decompress.go index cc05d0f..0c7dd4f 100644 --- a/vendor/github.com/klauspost/compress/fse/decompress.go +++ b/vendor/github.com/klauspost/compress/fse/decompress.go @@ -15,7 +15,7 @@ const ( // It is possible, but by no way guaranteed that corrupt data will // return an error. // It is up to the caller to verify integrity of the returned data. -// Use a predefined Scrach to set maximum acceptable output size. +// Use a predefined Scratch to set maximum acceptable output size. func Decompress(b []byte, s *Scratch) ([]byte, error) { s, err := s.prepare(b) if err != nil { diff --git a/vendor/github.com/klauspost/compress/huff0/decompress.go b/vendor/github.com/klauspost/compress/huff0/decompress.go index 54bd08b..0f56b02 100644 --- a/vendor/github.com/klauspost/compress/huff0/decompress.go +++ b/vendor/github.com/klauspost/compress/huff0/decompress.go @@ -1136,7 +1136,7 @@ func (s *Scratch) matches(ct cTable, w io.Writer) { errs++ } if errs > 0 { - fmt.Fprintf(w, "%d errros in base, stopping\n", errs) + fmt.Fprintf(w, "%d errors in base, stopping\n", errs) continue } // Ensure that all combinations are covered. @@ -1152,7 +1152,7 @@ func (s *Scratch) matches(ct cTable, w io.Writer) { errs++ } if errs > 20 { - fmt.Fprintf(w, "%d errros, stopping\n", errs) + fmt.Fprintf(w, "%d errors, stopping\n", errs) break } } diff --git a/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go b/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go index 2aa6a95..2754bac 100644 --- a/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go +++ b/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go @@ -51,7 +51,7 @@ func emitCopy(dst []byte, offset, length int) int { i := 0 // The maximum length for a single tagCopy1 or tagCopy2 op is 64 bytes. The // threshold for this loop is a little higher (at 68 = 64 + 4), and the - // length emitted down below is is a little lower (at 60 = 64 - 4), because + // length emitted down below is a little lower (at 60 = 64 - 4), because // it's shorter to encode a length 67 copy as a length 60 tagCopy2 followed // by a length 7 tagCopy1 (which encodes as 3+2 bytes) than to encode it as // a length 64 tagCopy2 followed by a length 3 tagCopy2 (which encodes as diff --git a/vendor/github.com/klauspost/compress/s2sx.mod b/vendor/github.com/klauspost/compress/s2sx.mod index 2263853..5a4412f 100644 --- a/vendor/github.com/klauspost/compress/s2sx.mod +++ b/vendor/github.com/klauspost/compress/s2sx.mod @@ -1,4 +1,4 @@ module github.com/klauspost/compress -go 1.16 +go 1.19 diff --git a/vendor/github.com/klauspost/compress/zstd/blockdec.go b/vendor/github.com/klauspost/compress/zstd/blockdec.go index 9f17ce6..9c28840 100644 --- a/vendor/github.com/klauspost/compress/zstd/blockdec.go +++ b/vendor/github.com/klauspost/compress/zstd/blockdec.go @@ -554,6 +554,9 @@ func (b *blockDec) prepareSequences(in []byte, hist *history) (err error) { if debugDecoder { printf("Compression modes: 0b%b", compMode) } + if compMode&3 != 0 { + return errors.New("corrupt block: reserved bits not zero") + } for i := uint(0); i < 3; i++ { mode := seqCompMode((compMode >> (6 - i*2)) & 3) if debugDecoder { @@ -595,7 +598,9 @@ func (b *blockDec) prepareSequences(in []byte, hist *history) (err error) { printf("RLE set to 0x%x, code: %v", symb, v) } case compModeFSE: - println("Reading table for", tableIndex(i)) + if debugDecoder { + println("Reading table for", tableIndex(i)) + } if seq.fse == nil || seq.fse.preDefined { seq.fse = fseDecoderPool.Get().(*fseDecoder) } diff --git a/vendor/github.com/klauspost/compress/zstd/blockenc.go b/vendor/github.com/klauspost/compress/zstd/blockenc.go index 2cfe925..32a7f40 100644 --- a/vendor/github.com/klauspost/compress/zstd/blockenc.go +++ b/vendor/github.com/klauspost/compress/zstd/blockenc.go @@ -427,6 +427,16 @@ func (b *blockEnc) encodeLits(lits []byte, raw bool) error { return nil } +// encodeRLE will encode an RLE block. +func (b *blockEnc) encodeRLE(val byte, length uint32) { + var bh blockHeader + bh.setLast(b.last) + bh.setSize(length) + bh.setType(blockTypeRLE) + b.output = bh.appendTo(b.output) + b.output = append(b.output, val) +} + // fuzzFseEncoder can be used to fuzz the FSE encoder. func fuzzFseEncoder(data []byte) int { if len(data) > maxSequences || len(data) < 2 { @@ -479,6 +489,16 @@ func (b *blockEnc) encode(org []byte, raw, rawAllLits bool) error { if len(b.sequences) == 0 { return b.encodeLits(b.literals, rawAllLits) } + if len(b.sequences) == 1 && len(org) > 0 && len(b.literals) <= 1 { + // Check common RLE cases. + seq := b.sequences[0] + if seq.litLen == uint32(len(b.literals)) && seq.offset-3 == 1 { + // Offset == 1 and 0 or 1 literals. + b.encodeRLE(org[0], b.sequences[0].matchLen+zstdMinMatch+seq.litLen) + return nil + } + } + // We want some difference to at least account for the headers. saved := b.size - len(b.literals) - (b.size >> 6) if saved < 16 { diff --git a/vendor/github.com/klauspost/compress/zstd/decodeheader.go b/vendor/github.com/klauspost/compress/zstd/decodeheader.go index f6a2409..6a5a298 100644 --- a/vendor/github.com/klauspost/compress/zstd/decodeheader.go +++ b/vendor/github.com/klauspost/compress/zstd/decodeheader.go @@ -95,42 +95,54 @@ type Header struct { // If there isn't enough input, io.ErrUnexpectedEOF is returned. // The FirstBlock.OK will indicate if enough information was available to decode the first block header. func (h *Header) Decode(in []byte) error { + _, err := h.DecodeAndStrip(in) + return err +} + +// DecodeAndStrip will decode the header from the beginning of the stream +// and on success return the remaining bytes. +// This will decode the frame header and the first block header if enough bytes are provided. +// It is recommended to provide at least HeaderMaxSize bytes. +// If the frame header cannot be read an error will be returned. +// If there isn't enough input, io.ErrUnexpectedEOF is returned. +// The FirstBlock.OK will indicate if enough information was available to decode the first block header. +func (h *Header) DecodeAndStrip(in []byte) (remain []byte, err error) { *h = Header{} if len(in) < 4 { - return io.ErrUnexpectedEOF + return nil, io.ErrUnexpectedEOF } h.HeaderSize += 4 b, in := in[:4], in[4:] if string(b) != frameMagic { if string(b[1:4]) != skippableFrameMagic || b[0]&0xf0 != 0x50 { - return ErrMagicMismatch + return nil, ErrMagicMismatch } if len(in) < 4 { - return io.ErrUnexpectedEOF + return nil, io.ErrUnexpectedEOF } h.HeaderSize += 4 h.Skippable = true h.SkippableID = int(b[0] & 0xf) h.SkippableSize = binary.LittleEndian.Uint32(in) - return nil + return in[4:], nil } // Read Window_Descriptor // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#window_descriptor if len(in) < 1 { - return io.ErrUnexpectedEOF + return nil, io.ErrUnexpectedEOF } fhd, in := in[0], in[1:] h.HeaderSize++ h.SingleSegment = fhd&(1<<5) != 0 h.HasCheckSum = fhd&(1<<2) != 0 if fhd&(1<<3) != 0 { - return errors.New("reserved bit set on frame header") + return nil, errors.New("reserved bit set on frame header") } if !h.SingleSegment { if len(in) < 1 { - return io.ErrUnexpectedEOF + return nil, io.ErrUnexpectedEOF } var wd byte wd, in = in[0], in[1:] @@ -148,7 +160,7 @@ func (h *Header) Decode(in []byte) error { size = 4 } if len(in) < int(size) { - return io.ErrUnexpectedEOF + return nil, io.ErrUnexpectedEOF } b, in = in[:size], in[size:] h.HeaderSize += int(size) @@ -178,7 +190,7 @@ func (h *Header) Decode(in []byte) error { if fcsSize > 0 { h.HasFCS = true if len(in) < fcsSize { - return io.ErrUnexpectedEOF + return nil, io.ErrUnexpectedEOF } b, in = in[:fcsSize], in[fcsSize:] h.HeaderSize += int(fcsSize) @@ -199,7 +211,7 @@ func (h *Header) Decode(in []byte) error { // Frame Header done, we will not fail from now on. if len(in) < 3 { - return nil + return in, nil } tmp := in[:3] bh := uint32(tmp[0]) | (uint32(tmp[1]) << 8) | (uint32(tmp[2]) << 16) @@ -209,7 +221,7 @@ func (h *Header) Decode(in []byte) error { cSize := int(bh >> 3) switch blockType { case blockTypeReserved: - return nil + return in, nil case blockTypeRLE: h.FirstBlock.Compressed = true h.FirstBlock.DecompressedSize = cSize @@ -225,5 +237,25 @@ func (h *Header) Decode(in []byte) error { } h.FirstBlock.OK = true - return nil + return in, nil +} + +// AppendTo will append the encoded header to the dst slice. +// There is no error checking performed on the header values. +func (h *Header) AppendTo(dst []byte) ([]byte, error) { + if h.Skippable { + magic := [4]byte{0x50, 0x2a, 0x4d, 0x18} + magic[0] |= byte(h.SkippableID & 0xf) + dst = append(dst, magic[:]...) + f := h.SkippableSize + return append(dst, uint8(f), uint8(f>>8), uint8(f>>16), uint8(f>>24)), nil + } + f := frameHeader{ + ContentSize: h.FrameContentSize, + WindowSize: uint32(h.WindowSize), + SingleSegment: h.SingleSegment, + Checksum: h.HasCheckSum, + DictID: h.DictionaryID, + } + return f.appendTo(dst), nil } diff --git a/vendor/github.com/klauspost/compress/zstd/decoder.go b/vendor/github.com/klauspost/compress/zstd/decoder.go index f04aaa2..bbca172 100644 --- a/vendor/github.com/klauspost/compress/zstd/decoder.go +++ b/vendor/github.com/klauspost/compress/zstd/decoder.go @@ -82,7 +82,7 @@ var ( // can run multiple concurrent stateless decodes. It is even possible to // use stateless decodes while a stream is being decoded. // -// The Reset function can be used to initiate a new stream, which is will considerably +// The Reset function can be used to initiate a new stream, which will considerably // reduce the allocations normally caused by NewReader. func NewReader(r io.Reader, opts ...DOption) (*Decoder, error) { initPredefined() diff --git a/vendor/github.com/klauspost/compress/zstd/dict.go b/vendor/github.com/klauspost/compress/zstd/dict.go index 8d5567f..b7b8316 100644 --- a/vendor/github.com/klauspost/compress/zstd/dict.go +++ b/vendor/github.com/klauspost/compress/zstd/dict.go @@ -273,6 +273,9 @@ func BuildDict(o BuildDictOptions) ([]byte, error) { enc.Encode(&block, b) addValues(&remain, block.literals) litTotal += len(block.literals) + if len(block.sequences) == 0 { + continue + } seqs += len(block.sequences) block.genCodes() addHist(&ll, block.coders.llEnc.Histogram()) @@ -286,6 +289,9 @@ func BuildDict(o BuildDictOptions) ([]byte, error) { if offset == 0 { continue } + if int(offset) >= len(o.History) { + continue + } if offset > 3 { newOffsets[offset-3]++ } else { @@ -336,6 +342,9 @@ func BuildDict(o BuildDictOptions) ([]byte, error) { if seqs/nUsed < 512 { // Use 512 as minimum. nUsed = seqs / 512 + if nUsed == 0 { + nUsed = 1 + } } copyHist := func(dst *fseEncoder, src *[256]int) ([]byte, error) { hist := dst.Histogram() @@ -358,6 +367,28 @@ func BuildDict(o BuildDictOptions) ([]byte, error) { fakeLength += v hist[i] = uint32(v) } + + // Ensure we aren't trying to represent RLE. + if maxCount == fakeLength { + for i := range hist { + if uint8(i) == maxSym { + fakeLength++ + maxSym++ + hist[i+1] = 1 + if maxSym > 1 { + break + } + } + if hist[0] == 0 { + fakeLength++ + hist[i] = 1 + if maxSym > 1 { + break + } + } + } + } + dst.HistogramFinished(maxSym, maxCount) dst.reUsed = false dst.useRLE = false diff --git a/vendor/github.com/klauspost/compress/zstd/enc_best.go b/vendor/github.com/klauspost/compress/zstd/enc_best.go index c81a153..4613724 100644 --- a/vendor/github.com/klauspost/compress/zstd/enc_best.go +++ b/vendor/github.com/klauspost/compress/zstd/enc_best.go @@ -135,8 +135,20 @@ func (e *bestFastEncoder) Encode(blk *blockEnc, src []byte) { break } + // Add block to history s := e.addBlock(src) blk.size = len(src) + + // Check RLE first + if len(src) > zstdMinMatch { + ml := matchLen(src[1:], src) + if ml == len(src)-1 { + blk.literals = append(blk.literals, src[0]) + blk.sequences = append(blk.sequences, seq{litLen: 1, matchLen: uint32(len(src)-1) - zstdMinMatch, offset: 1 + 3}) + return + } + } + if len(src) < minNonLiteralBlockSize { blk.extraLits = len(src) blk.literals = blk.literals[:len(src)] @@ -201,14 +213,6 @@ encodeLoop: if delta >= e.maxMatchOff || delta <= 0 || load3232(src, offset) != first { return } - if debugAsserts { - if offset >= s { - panic(fmt.Sprintf("offset: %d - s:%d - rep: %d - cur :%d - max: %d", offset, s, rep, e.cur, e.maxMatchOff)) - } - if !bytes.Equal(src[s:s+4], src[offset:offset+4]) { - panic(fmt.Sprintf("first match mismatch: %v != %v, first: %08x", src[s:s+4], src[offset:offset+4], first)) - } - } // Try to quick reject if we already have a long match. if m.length > 16 { left := len(src) - int(m.s+m.length) @@ -227,8 +231,10 @@ encodeLoop: } } l := 4 + e.matchlen(s+4, offset+4, src) - if true { + if m.rep <= 0 { // Extend candidate match backwards as far as possible. + // Do not extend repeats as we can assume they are optimal + // and offsets change if s == nextEmit. tMin := s - e.maxMatchOff if tMin < 0 { tMin = 0 @@ -239,7 +245,14 @@ encodeLoop: l++ } } - + if debugAsserts { + if offset >= s { + panic(fmt.Sprintf("offset: %d - s:%d - rep: %d - cur :%d - max: %d", offset, s, rep, e.cur, e.maxMatchOff)) + } + if !bytes.Equal(src[s:s+l], src[offset:offset+l]) { + panic(fmt.Sprintf("second match mismatch: %v != %v, first: %08x", src[s:s+4], src[offset:offset+4], first)) + } + } cand := match{offset: offset, s: s, length: l, rep: rep} cand.estBits(bitsPerByte) if m.est >= highScore || cand.est-m.est+(cand.s-m.s)*bitsPerByte>>10 < 0 { @@ -336,24 +349,31 @@ encodeLoop: } if debugAsserts { + if best.offset >= best.s { + panic(fmt.Sprintf("best.offset > s: %d >= %d", best.offset, best.s)) + } + if best.s < nextEmit { + panic(fmt.Sprintf("s %d < nextEmit %d", best.s, nextEmit)) + } + if best.offset < s-e.maxMatchOff { + panic(fmt.Sprintf("best.offset < s-e.maxMatchOff: %d < %d", best.offset, s-e.maxMatchOff)) + } if !bytes.Equal(src[best.s:best.s+best.length], src[best.offset:best.offset+best.length]) { panic(fmt.Sprintf("match mismatch: %v != %v", src[best.s:best.s+best.length], src[best.offset:best.offset+best.length])) } } // We have a match, we can store the forward value + s = best.s if best.rep > 0 { var seq seq seq.matchLen = uint32(best.length - zstdMinMatch) - if debugAsserts && s < nextEmit { - panic("s < nextEmit") - } addLiterals(&seq, best.s) // Repeat. If bit 4 is set, this is a non-lit repeat. seq.offset = uint32(best.rep & 3) if debugSequences { - println("repeat sequence", seq, "next s:", s) + println("repeat sequence", seq, "next s:", best.s, "off:", best.s-best.offset) } blk.sequences = append(blk.sequences, seq) @@ -396,7 +416,6 @@ encodeLoop: // A 4-byte match has been found. Update recent offsets. // We'll later see if more than 4 bytes. - s = best.s t := best.offset offset1, offset2, offset3 = s-t, offset1, offset2 diff --git a/vendor/github.com/klauspost/compress/zstd/enc_better.go b/vendor/github.com/klauspost/compress/zstd/enc_better.go index 20d25b0..84a79fd 100644 --- a/vendor/github.com/klauspost/compress/zstd/enc_better.go +++ b/vendor/github.com/klauspost/compress/zstd/enc_better.go @@ -102,9 +102,20 @@ func (e *betterFastEncoder) Encode(blk *blockEnc, src []byte) { e.cur = e.maxMatchOff break } - + // Add block to history s := e.addBlock(src) blk.size = len(src) + + // Check RLE first + if len(src) > zstdMinMatch { + ml := matchLen(src[1:], src) + if ml == len(src)-1 { + blk.literals = append(blk.literals, src[0]) + blk.sequences = append(blk.sequences, seq{litLen: 1, matchLen: uint32(len(src)-1) - zstdMinMatch, offset: 1 + 3}) + return + } + } + if len(src) < minNonLiteralBlockSize { blk.extraLits = len(src) blk.literals = blk.literals[:len(src)] @@ -168,9 +179,9 @@ encodeLoop: if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) { // Consider history as well. var seq seq - lenght := 4 + e.matchlen(s+4+repOff, repIndex+4, src) + length := 4 + e.matchlen(s+4+repOff, repIndex+4, src) - seq.matchLen = uint32(lenght - zstdMinMatch) + seq.matchLen = uint32(length - zstdMinMatch) // We might be able to match backwards. // Extend as long as we can. @@ -199,12 +210,12 @@ encodeLoop: // Index match start+1 (long) -> s - 1 index0 := s + repOff - s += lenght + repOff + s += length + repOff nextEmit = s if s >= sLimit { if debugEncoder { - println("repeat ended", s, lenght) + println("repeat ended", s, length) } break encodeLoop @@ -230,9 +241,9 @@ encodeLoop: if false && repIndex >= 0 && load6432(src, repIndex) == load6432(src, s+repOff) { // Consider history as well. var seq seq - lenght := 8 + e.matchlen(s+8+repOff2, repIndex+8, src) + length := 8 + e.matchlen(s+8+repOff2, repIndex+8, src) - seq.matchLen = uint32(lenght - zstdMinMatch) + seq.matchLen = uint32(length - zstdMinMatch) // We might be able to match backwards. // Extend as long as we can. @@ -259,11 +270,11 @@ encodeLoop: } blk.sequences = append(blk.sequences, seq) - s += lenght + repOff2 + s += length + repOff2 nextEmit = s if s >= sLimit { if debugEncoder { - println("repeat ended", s, lenght) + println("repeat ended", s, length) } break encodeLoop @@ -697,9 +708,9 @@ encodeLoop: if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) { // Consider history as well. var seq seq - lenght := 4 + e.matchlen(s+4+repOff, repIndex+4, src) + length := 4 + e.matchlen(s+4+repOff, repIndex+4, src) - seq.matchLen = uint32(lenght - zstdMinMatch) + seq.matchLen = uint32(length - zstdMinMatch) // We might be able to match backwards. // Extend as long as we can. @@ -727,12 +738,12 @@ encodeLoop: blk.sequences = append(blk.sequences, seq) // Index match start+1 (long) -> s - 1 - s += lenght + repOff + s += length + repOff nextEmit = s if s >= sLimit { if debugEncoder { - println("repeat ended", s, lenght) + println("repeat ended", s, length) } break encodeLoop @@ -761,9 +772,9 @@ encodeLoop: if false && repIndex >= 0 && load6432(src, repIndex) == load6432(src, s+repOff) { // Consider history as well. var seq seq - lenght := 8 + e.matchlen(s+8+repOff2, repIndex+8, src) + length := 8 + e.matchlen(s+8+repOff2, repIndex+8, src) - seq.matchLen = uint32(lenght - zstdMinMatch) + seq.matchLen = uint32(length - zstdMinMatch) // We might be able to match backwards. // Extend as long as we can. @@ -790,11 +801,11 @@ encodeLoop: } blk.sequences = append(blk.sequences, seq) - s += lenght + repOff2 + s += length + repOff2 nextEmit = s if s >= sLimit { if debugEncoder { - println("repeat ended", s, lenght) + println("repeat ended", s, length) } break encodeLoop diff --git a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go index a154c18..d36be7b 100644 --- a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go +++ b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go @@ -138,9 +138,9 @@ encodeLoop: if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) { // Consider history as well. var seq seq - lenght := 4 + e.matchlen(s+4+repOff, repIndex+4, src) + length := 4 + e.matchlen(s+4+repOff, repIndex+4, src) - seq.matchLen = uint32(lenght - zstdMinMatch) + seq.matchLen = uint32(length - zstdMinMatch) // We might be able to match backwards. // Extend as long as we can. @@ -166,11 +166,11 @@ encodeLoop: println("repeat sequence", seq, "next s:", s) } blk.sequences = append(blk.sequences, seq) - s += lenght + repOff + s += length + repOff nextEmit = s if s >= sLimit { if debugEncoder { - println("repeat ended", s, lenght) + println("repeat ended", s, length) } break encodeLoop @@ -798,9 +798,9 @@ encodeLoop: if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) { // Consider history as well. var seq seq - lenght := 4 + e.matchlen(s+4+repOff, repIndex+4, src) + length := 4 + e.matchlen(s+4+repOff, repIndex+4, src) - seq.matchLen = uint32(lenght - zstdMinMatch) + seq.matchLen = uint32(length - zstdMinMatch) // We might be able to match backwards. // Extend as long as we can. @@ -826,11 +826,11 @@ encodeLoop: println("repeat sequence", seq, "next s:", s) } blk.sequences = append(blk.sequences, seq) - s += lenght + repOff + s += length + repOff nextEmit = s if s >= sLimit { if debugEncoder { - println("repeat ended", s, lenght) + println("repeat ended", s, length) } break encodeLoop diff --git a/vendor/github.com/klauspost/compress/zstd/encoder.go b/vendor/github.com/klauspost/compress/zstd/encoder.go index 72af7ef..8f8223c 100644 --- a/vendor/github.com/klauspost/compress/zstd/encoder.go +++ b/vendor/github.com/klauspost/compress/zstd/encoder.go @@ -6,6 +6,7 @@ package zstd import ( "crypto/rand" + "errors" "fmt" "io" "math" @@ -149,6 +150,9 @@ func (e *Encoder) ResetContentSize(w io.Writer, size int64) { // and write CRC if requested. func (e *Encoder) Write(p []byte) (n int, err error) { s := &e.state + if s.eofWritten { + return 0, ErrEncoderClosed + } for len(p) > 0 { if len(p)+len(s.filling) < e.o.blockSize { if e.o.crc { @@ -202,7 +206,7 @@ func (e *Encoder) nextBlock(final bool) error { return nil } if final && len(s.filling) > 0 { - s.current = e.EncodeAll(s.filling, s.current[:0]) + s.current = e.encodeAll(s.encoder, s.filling, s.current[:0]) var n2 int n2, s.err = s.w.Write(s.current) if s.err != nil { @@ -288,6 +292,9 @@ func (e *Encoder) nextBlock(final bool) error { s.filling, s.current, s.previous = s.previous[:0], s.filling, s.current s.nInput += int64(len(s.current)) s.wg.Add(1) + if final { + s.eofWritten = true + } go func(src []byte) { if debugEncoder { println("Adding block,", len(src), "bytes, final:", final) @@ -303,9 +310,6 @@ func (e *Encoder) nextBlock(final bool) error { blk := enc.Block() enc.Encode(blk, src) blk.last = final - if final { - s.eofWritten = true - } // Wait for pending writes. s.wWg.Wait() if s.writeErr != nil { @@ -401,12 +405,20 @@ func (e *Encoder) Flush() error { if len(s.filling) > 0 { err := e.nextBlock(false) if err != nil { + // Ignore Flush after Close. + if errors.Is(s.err, ErrEncoderClosed) { + return nil + } return err } } s.wg.Wait() s.wWg.Wait() if s.err != nil { + // Ignore Flush after Close. + if errors.Is(s.err, ErrEncoderClosed) { + return nil + } return s.err } return s.writeErr @@ -422,6 +434,9 @@ func (e *Encoder) Close() error { } err := e.nextBlock(true) if err != nil { + if errors.Is(s.err, ErrEncoderClosed) { + return nil + } return err } if s.frameContentSize > 0 { @@ -459,6 +474,11 @@ func (e *Encoder) Close() error { } _, s.err = s.w.Write(frame) } + if s.err == nil { + s.err = ErrEncoderClosed + return nil + } + return s.err } @@ -469,6 +489,15 @@ func (e *Encoder) Close() error { // Data compressed with EncodeAll can be decoded with the Decoder, // using either a stream or DecodeAll. func (e *Encoder) EncodeAll(src, dst []byte) []byte { + e.init.Do(e.initialize) + enc := <-e.encoders + defer func() { + e.encoders <- enc + }() + return e.encodeAll(enc, src, dst) +} + +func (e *Encoder) encodeAll(enc encoder, src, dst []byte) []byte { if len(src) == 0 { if e.o.fullZero { // Add frame header. @@ -491,13 +520,7 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte { } return dst } - e.init.Do(e.initialize) - enc := <-e.encoders - defer func() { - // Release encoder reference to last block. - // If a non-single block is needed the encoder will reset again. - e.encoders <- enc - }() + // Use single segments when above minimum window and below window size. single := len(src) <= e.o.windowSize && len(src) > MinWindowSize if e.o.single != nil { diff --git a/vendor/github.com/klauspost/compress/zstd/encoder_options.go b/vendor/github.com/klauspost/compress/zstd/encoder_options.go index faaf819..20671dc 100644 --- a/vendor/github.com/klauspost/compress/zstd/encoder_options.go +++ b/vendor/github.com/klauspost/compress/zstd/encoder_options.go @@ -94,7 +94,7 @@ func WithEncoderConcurrency(n int) EOption { // The value must be a power of two between MinWindowSize and MaxWindowSize. // A larger value will enable better compression but allocate more memory and, // for above-default values, take considerably longer. -// The default value is determined by the compression level. +// The default value is determined by the compression level and max 8MB. func WithWindowSize(n int) EOption { return func(o *encoderOptions) error { switch { @@ -232,9 +232,9 @@ func WithEncoderLevel(l EncoderLevel) EOption { case SpeedDefault: o.windowSize = 8 << 20 case SpeedBetterCompression: - o.windowSize = 16 << 20 + o.windowSize = 8 << 20 case SpeedBestCompression: - o.windowSize = 32 << 20 + o.windowSize = 8 << 20 } } if !o.customALEntropy { diff --git a/vendor/github.com/klauspost/compress/zstd/framedec.go b/vendor/github.com/klauspost/compress/zstd/framedec.go index 53e160f..e47af66 100644 --- a/vendor/github.com/klauspost/compress/zstd/framedec.go +++ b/vendor/github.com/klauspost/compress/zstd/framedec.go @@ -146,7 +146,9 @@ func (d *frameDec) reset(br byteBuffer) error { } return err } - printf("raw: %x, mantissa: %d, exponent: %d\n", wd, wd&7, wd>>3) + if debugDecoder { + printf("raw: %x, mantissa: %d, exponent: %d\n", wd, wd&7, wd>>3) + } windowLog := 10 + (wd >> 3) windowBase := uint64(1) << windowLog windowAdd := (windowBase / 8) * uint64(wd&0x7) diff --git a/vendor/github.com/klauspost/compress/zstd/frameenc.go b/vendor/github.com/klauspost/compress/zstd/frameenc.go index 2f5d5ed..667ca06 100644 --- a/vendor/github.com/klauspost/compress/zstd/frameenc.go +++ b/vendor/github.com/klauspost/compress/zstd/frameenc.go @@ -76,7 +76,7 @@ func (f frameHeader) appendTo(dst []byte) []byte { if f.SingleSegment { dst = append(dst, uint8(f.ContentSize)) } - // Unless SingleSegment is set, framessizes < 256 are nto stored. + // Unless SingleSegment is set, framessizes < 256 are not stored. case 1: f.ContentSize -= 256 dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8)) diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go b/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go index 332e51f..8adfebb 100644 --- a/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go +++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go @@ -20,10 +20,9 @@ func (s *fseDecoder) buildDtable() error { if v == -1 { s.dt[highThreshold].setAddBits(uint8(i)) highThreshold-- - symbolNext[i] = 1 - } else { - symbolNext[i] = uint16(v) + v = 1 } + symbolNext[i] = uint16(v) } } @@ -35,10 +34,12 @@ func (s *fseDecoder) buildDtable() error { for ss, v := range s.norm[:s.symbolLen] { for i := 0; i < int(v); i++ { s.dt[position].setAddBits(uint8(ss)) - position = (position + step) & tableMask - for position > highThreshold { + for { // lowprob area position = (position + step) & tableMask + if position <= highThreshold { + break + } } } } diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s index 17901e0..ae7d4d3 100644 --- a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s +++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s @@ -162,12 +162,12 @@ finalize: MOVD h, ret+24(FP) RET -// func writeBlocks(d *Digest, b []byte) int +// func writeBlocks(s *Digest, b []byte) int TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40 LDP ·primes+0(SB), (prime1, prime2) // Load state. Assume v[1-4] are stored contiguously. - MOVD d+0(FP), digest + MOVD s+0(FP), digest LDP 0(digest), (v1, v2) LDP 16(digest), (v3, v4) diff --git a/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s b/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s index 9a7655c..0782b86 100644 --- a/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s +++ b/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s @@ -5,7 +5,6 @@ #include "textflag.h" // func matchLen(a []byte, b []byte) int -// Requires: BMI TEXT ·matchLen(SB), NOSPLIT, $0-56 MOVQ a_base+0(FP), AX MOVQ b_base+24(FP), CX @@ -17,17 +16,16 @@ TEXT ·matchLen(SB), NOSPLIT, $0-56 JB matchlen_match4_standalone matchlen_loopback_standalone: - MOVQ (AX)(SI*1), BX - XORQ (CX)(SI*1), BX - TESTQ BX, BX - JZ matchlen_loop_standalone + MOVQ (AX)(SI*1), BX + XORQ (CX)(SI*1), BX + JZ matchlen_loop_standalone #ifdef GOAMD64_v3 TZCNTQ BX, BX #else BSFQ BX, BX #endif - SARQ $0x03, BX + SHRL $0x03, BX LEAL (SI)(BX*1), SI JMP gen_match_len_end diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go index 8adabd8..c59f17e 100644 --- a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go @@ -146,7 +146,7 @@ func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) { return true, fmt.Errorf("output bigger than max block size (%d)", maxBlockSize) default: - return true, fmt.Errorf("sequenceDecs_decode returned erronous code %d", errCode) + return true, fmt.Errorf("sequenceDecs_decode returned erroneous code %d", errCode) } s.seqSize += ctx.litRemain @@ -292,7 +292,7 @@ func (s *sequenceDecs) decode(seqs []seqVals) error { return io.ErrUnexpectedEOF } - return fmt.Errorf("sequenceDecs_decode_amd64 returned erronous code %d", errCode) + return fmt.Errorf("sequenceDecs_decode_amd64 returned erroneous code %d", errCode) } if ctx.litRemain < 0 { diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s index 974b997..f5591fa 100644 --- a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s @@ -157,8 +157,7 @@ sequenceDecs_decode_amd64_ll_update_zero: // Update Literal Length State MOVBQZX DI, R14 - SHRQ $0x10, DI - MOVWQZX DI, DI + SHRL $0x10, DI LEAQ (BX)(R14*1), CX MOVQ DX, R15 MOVQ CX, BX @@ -177,8 +176,7 @@ sequenceDecs_decode_amd64_ll_update_zero: // Update Match Length State MOVBQZX R8, R14 - SHRQ $0x10, R8 - MOVWQZX R8, R8 + SHRL $0x10, R8 LEAQ (BX)(R14*1), CX MOVQ DX, R15 MOVQ CX, BX @@ -197,8 +195,7 @@ sequenceDecs_decode_amd64_ll_update_zero: // Update Offset State MOVBQZX R9, R14 - SHRQ $0x10, R9 - MOVWQZX R9, R9 + SHRL $0x10, R9 LEAQ (BX)(R14*1), CX MOVQ DX, R15 MOVQ CX, BX @@ -459,8 +456,7 @@ sequenceDecs_decode_56_amd64_ll_update_zero: // Update Literal Length State MOVBQZX DI, R14 - SHRQ $0x10, DI - MOVWQZX DI, DI + SHRL $0x10, DI LEAQ (BX)(R14*1), CX MOVQ DX, R15 MOVQ CX, BX @@ -479,8 +475,7 @@ sequenceDecs_decode_56_amd64_ll_update_zero: // Update Match Length State MOVBQZX R8, R14 - SHRQ $0x10, R8 - MOVWQZX R8, R8 + SHRL $0x10, R8 LEAQ (BX)(R14*1), CX MOVQ DX, R15 MOVQ CX, BX @@ -499,8 +494,7 @@ sequenceDecs_decode_56_amd64_ll_update_zero: // Update Offset State MOVBQZX R9, R14 - SHRQ $0x10, R9 - MOVWQZX R9, R9 + SHRL $0x10, R9 LEAQ (BX)(R14*1), CX MOVQ DX, R15 MOVQ CX, BX @@ -772,11 +766,10 @@ sequenceDecs_decode_bmi2_fill_2_end: BZHIQ R14, R15, R15 // Update Offset State - BZHIQ R8, R15, CX - SHRXQ R8, R15, R15 - MOVQ $0x00001010, R14 - BEXTRQ R14, R8, R8 - ADDQ CX, R8 + BZHIQ R8, R15, CX + SHRXQ R8, R15, R15 + SHRL $0x10, R8 + ADDQ CX, R8 // Load ctx.ofTable MOVQ ctx+16(FP), CX @@ -784,11 +777,10 @@ sequenceDecs_decode_bmi2_fill_2_end: MOVQ (CX)(R8*8), R8 // Update Match Length State - BZHIQ DI, R15, CX - SHRXQ DI, R15, R15 - MOVQ $0x00001010, R14 - BEXTRQ R14, DI, DI - ADDQ CX, DI + BZHIQ DI, R15, CX + SHRXQ DI, R15, R15 + SHRL $0x10, DI + ADDQ CX, DI // Load ctx.mlTable MOVQ ctx+16(FP), CX @@ -796,10 +788,9 @@ sequenceDecs_decode_bmi2_fill_2_end: MOVQ (CX)(DI*8), DI // Update Literal Length State - BZHIQ SI, R15, CX - MOVQ $0x00001010, R14 - BEXTRQ R14, SI, SI - ADDQ CX, SI + BZHIQ SI, R15, CX + SHRL $0x10, SI + ADDQ CX, SI // Load ctx.llTable MOVQ ctx+16(FP), CX @@ -1032,11 +1023,10 @@ sequenceDecs_decode_56_bmi2_fill_end: BZHIQ R14, R15, R15 // Update Offset State - BZHIQ R8, R15, CX - SHRXQ R8, R15, R15 - MOVQ $0x00001010, R14 - BEXTRQ R14, R8, R8 - ADDQ CX, R8 + BZHIQ R8, R15, CX + SHRXQ R8, R15, R15 + SHRL $0x10, R8 + ADDQ CX, R8 // Load ctx.ofTable MOVQ ctx+16(FP), CX @@ -1044,11 +1034,10 @@ sequenceDecs_decode_56_bmi2_fill_end: MOVQ (CX)(R8*8), R8 // Update Match Length State - BZHIQ DI, R15, CX - SHRXQ DI, R15, R15 - MOVQ $0x00001010, R14 - BEXTRQ R14, DI, DI - ADDQ CX, DI + BZHIQ DI, R15, CX + SHRXQ DI, R15, R15 + SHRL $0x10, DI + ADDQ CX, DI // Load ctx.mlTable MOVQ ctx+16(FP), CX @@ -1056,10 +1045,9 @@ sequenceDecs_decode_56_bmi2_fill_end: MOVQ (CX)(DI*8), DI // Update Literal Length State - BZHIQ SI, R15, CX - MOVQ $0x00001010, R14 - BEXTRQ R14, SI, SI - ADDQ CX, SI + BZHIQ SI, R15, CX + SHRL $0x10, SI + ADDQ CX, SI // Load ctx.llTable MOVQ ctx+16(FP), CX @@ -1826,7 +1814,7 @@ TEXT ·sequenceDecs_decodeSync_amd64(SB), $64-32 MOVQ 40(SP), AX ADDQ AX, 48(SP) - // Calculate poiter to s.out[cap(s.out)] (a past-end pointer) + // Calculate pointer to s.out[cap(s.out)] (a past-end pointer) ADDQ R10, 32(SP) // outBase += outPosition @@ -1967,8 +1955,7 @@ sequenceDecs_decodeSync_amd64_ll_update_zero: // Update Literal Length State MOVBQZX DI, R13 - SHRQ $0x10, DI - MOVWQZX DI, DI + SHRL $0x10, DI LEAQ (BX)(R13*1), CX MOVQ DX, R14 MOVQ CX, BX @@ -1987,8 +1974,7 @@ sequenceDecs_decodeSync_amd64_ll_update_zero: // Update Match Length State MOVBQZX R8, R13 - SHRQ $0x10, R8 - MOVWQZX R8, R8 + SHRL $0x10, R8 LEAQ (BX)(R13*1), CX MOVQ DX, R14 MOVQ CX, BX @@ -2007,8 +1993,7 @@ sequenceDecs_decodeSync_amd64_ll_update_zero: // Update Offset State MOVBQZX R9, R13 - SHRQ $0x10, R9 - MOVWQZX R9, R9 + SHRL $0x10, R9 LEAQ (BX)(R13*1), CX MOVQ DX, R14 MOVQ CX, BX @@ -2391,7 +2376,7 @@ TEXT ·sequenceDecs_decodeSync_bmi2(SB), $64-32 MOVQ 40(SP), CX ADDQ CX, 48(SP) - // Calculate poiter to s.out[cap(s.out)] (a past-end pointer) + // Calculate pointer to s.out[cap(s.out)] (a past-end pointer) ADDQ R9, 32(SP) // outBase += outPosition @@ -2514,11 +2499,10 @@ sequenceDecs_decodeSync_bmi2_fill_2_end: BZHIQ R13, R14, R14 // Update Offset State - BZHIQ R8, R14, CX - SHRXQ R8, R14, R14 - MOVQ $0x00001010, R13 - BEXTRQ R13, R8, R8 - ADDQ CX, R8 + BZHIQ R8, R14, CX + SHRXQ R8, R14, R14 + SHRL $0x10, R8 + ADDQ CX, R8 // Load ctx.ofTable MOVQ ctx+16(FP), CX @@ -2526,11 +2510,10 @@ sequenceDecs_decodeSync_bmi2_fill_2_end: MOVQ (CX)(R8*8), R8 // Update Match Length State - BZHIQ DI, R14, CX - SHRXQ DI, R14, R14 - MOVQ $0x00001010, R13 - BEXTRQ R13, DI, DI - ADDQ CX, DI + BZHIQ DI, R14, CX + SHRXQ DI, R14, R14 + SHRL $0x10, DI + ADDQ CX, DI // Load ctx.mlTable MOVQ ctx+16(FP), CX @@ -2538,10 +2521,9 @@ sequenceDecs_decodeSync_bmi2_fill_2_end: MOVQ (CX)(DI*8), DI // Update Literal Length State - BZHIQ SI, R14, CX - MOVQ $0x00001010, R13 - BEXTRQ R13, SI, SI - ADDQ CX, SI + BZHIQ SI, R14, CX + SHRL $0x10, SI + ADDQ CX, SI // Load ctx.llTable MOVQ ctx+16(FP), CX @@ -2914,7 +2896,7 @@ TEXT ·sequenceDecs_decodeSync_safe_amd64(SB), $64-32 MOVQ 40(SP), AX ADDQ AX, 48(SP) - // Calculate poiter to s.out[cap(s.out)] (a past-end pointer) + // Calculate pointer to s.out[cap(s.out)] (a past-end pointer) ADDQ R10, 32(SP) // outBase += outPosition @@ -3055,8 +3037,7 @@ sequenceDecs_decodeSync_safe_amd64_ll_update_zero: // Update Literal Length State MOVBQZX DI, R13 - SHRQ $0x10, DI - MOVWQZX DI, DI + SHRL $0x10, DI LEAQ (BX)(R13*1), CX MOVQ DX, R14 MOVQ CX, BX @@ -3075,8 +3056,7 @@ sequenceDecs_decodeSync_safe_amd64_ll_update_zero: // Update Match Length State MOVBQZX R8, R13 - SHRQ $0x10, R8 - MOVWQZX R8, R8 + SHRL $0x10, R8 LEAQ (BX)(R13*1), CX MOVQ DX, R14 MOVQ CX, BX @@ -3095,8 +3075,7 @@ sequenceDecs_decodeSync_safe_amd64_ll_update_zero: // Update Offset State MOVBQZX R9, R13 - SHRQ $0x10, R9 - MOVWQZX R9, R9 + SHRL $0x10, R9 LEAQ (BX)(R13*1), CX MOVQ DX, R14 MOVQ CX, BX @@ -3581,7 +3560,7 @@ TEXT ·sequenceDecs_decodeSync_safe_bmi2(SB), $64-32 MOVQ 40(SP), CX ADDQ CX, 48(SP) - // Calculate poiter to s.out[cap(s.out)] (a past-end pointer) + // Calculate pointer to s.out[cap(s.out)] (a past-end pointer) ADDQ R9, 32(SP) // outBase += outPosition @@ -3704,11 +3683,10 @@ sequenceDecs_decodeSync_safe_bmi2_fill_2_end: BZHIQ R13, R14, R14 // Update Offset State - BZHIQ R8, R14, CX - SHRXQ R8, R14, R14 - MOVQ $0x00001010, R13 - BEXTRQ R13, R8, R8 - ADDQ CX, R8 + BZHIQ R8, R14, CX + SHRXQ R8, R14, R14 + SHRL $0x10, R8 + ADDQ CX, R8 // Load ctx.ofTable MOVQ ctx+16(FP), CX @@ -3716,11 +3694,10 @@ sequenceDecs_decodeSync_safe_bmi2_fill_2_end: MOVQ (CX)(R8*8), R8 // Update Match Length State - BZHIQ DI, R14, CX - SHRXQ DI, R14, R14 - MOVQ $0x00001010, R13 - BEXTRQ R13, DI, DI - ADDQ CX, DI + BZHIQ DI, R14, CX + SHRXQ DI, R14, R14 + SHRL $0x10, DI + ADDQ CX, DI // Load ctx.mlTable MOVQ ctx+16(FP), CX @@ -3728,10 +3705,9 @@ sequenceDecs_decodeSync_safe_bmi2_fill_2_end: MOVQ (CX)(DI*8), DI // Update Literal Length State - BZHIQ SI, R14, CX - MOVQ $0x00001010, R13 - BEXTRQ R13, SI, SI - ADDQ CX, SI + BZHIQ SI, R14, CX + SHRL $0x10, SI + ADDQ CX, SI // Load ctx.llTable MOVQ ctx+16(FP), CX diff --git a/vendor/github.com/klauspost/compress/zstd/zstd.go b/vendor/github.com/klauspost/compress/zstd/zstd.go index 4be7cc7..066bef2 100644 --- a/vendor/github.com/klauspost/compress/zstd/zstd.go +++ b/vendor/github.com/klauspost/compress/zstd/zstd.go @@ -88,6 +88,10 @@ var ( // Close has been called. ErrDecoderClosed = errors.New("decoder used after Close") + // ErrEncoderClosed will be returned if the Encoder was used after + // Close has been called. + ErrEncoderClosed = errors.New("encoder used after Close") + // ErrDecoderNilInput is returned when a nil Reader was provided // and an operation other than Reset/DecodeAll/Close was attempted. ErrDecoderNilInput = errors.New("nil input provided as reader") diff --git a/vendor/github.com/mdlayher/netlink/README.md b/vendor/github.com/mdlayher/netlink/README.md index 768d214..c41de0d 100644 --- a/vendor/github.com/mdlayher/netlink/README.md +++ b/vendor/github.com/mdlayher/netlink/README.md @@ -165,11 +165,19 @@ flowchart LR click go-onewire "https://github.com/SpComb/go-onewire" end + subgraph "NETLINK_SOCK_DIAG" + direction LR + + go-diag["github.com/florianl/go-diag"] + click go-diag "https://github.com/florianl/go-diag" + end + NETLINK_CONNECTOR --> netlink NETLINK_CRYPTO --> netlink NETLINK_GENERIC --> netlink NETLINK_KOBJECT_UEVENT --> netlink NETLINK_NETFILTER --> netlink NETLINK_ROUTE --> netlink + NETLINK_SOCK_DIAG --> netlink NETLINK_W1 --> netlink ``` diff --git a/vendor/github.com/mdlayher/netlink/attribute.go b/vendor/github.com/mdlayher/netlink/attribute.go index 4d3cfd3..1c81c32 100644 --- a/vendor/github.com/mdlayher/netlink/attribute.go +++ b/vendor/github.com/mdlayher/netlink/attribute.go @@ -6,7 +6,6 @@ import ( "fmt" "math" - "github.com/josharian/native" "github.com/mdlayher/netlink/nlenc" ) @@ -168,7 +167,7 @@ type AttributeDecoder struct { func NewAttributeDecoder(b []byte) (*AttributeDecoder, error) { ad := &AttributeDecoder{ // By default, use native byte order. - ByteOrder: native.Endian, + ByteOrder: binary.NativeEndian, b: b, } @@ -485,7 +484,7 @@ type AttributeEncoder struct { // NewAttributeEncoder creates an AttributeEncoder that encodes Attributes. func NewAttributeEncoder() *AttributeEncoder { - return &AttributeEncoder{ByteOrder: native.Endian} + return &AttributeEncoder{ByteOrder: binary.NativeEndian} } // Uint8 encodes uint8 data into an Attribute specified by typ. diff --git a/vendor/github.com/mdlayher/netlink/nlenc/doc.go b/vendor/github.com/mdlayher/netlink/nlenc/doc.go index 3b42119..990d12e 100644 --- a/vendor/github.com/mdlayher/netlink/nlenc/doc.go +++ b/vendor/github.com/mdlayher/netlink/nlenc/doc.go @@ -4,12 +4,10 @@ package nlenc import ( "encoding/binary" - - "github.com/josharian/native" ) // NativeEndian returns the native byte order of this system. func NativeEndian() binary.ByteOrder { // TODO(mdlayher): consider deprecating and removing this function for v2. - return native.Endian + return binary.NativeEndian } diff --git a/vendor/github.com/tailscale/golang-x-crypto/LICENSE b/vendor/github.com/tailscale/golang-x-crypto/LICENSE deleted file mode 100644 index 6a66aea..0000000 --- a/vendor/github.com/tailscale/golang-x-crypto/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/tailscale/golang-x-crypto/PATENTS b/vendor/github.com/tailscale/golang-x-crypto/PATENTS deleted file mode 100644 index 7330990..0000000 --- a/vendor/github.com/tailscale/golang-x-crypto/PATENTS +++ /dev/null @@ -1,22 +0,0 @@ -Additional IP Rights Grant (Patents) - -"This implementation" means the copyrightable works distributed by -Google as part of the Go project. - -Google hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) -patent license to make, have made, use, offer to sell, sell, import, -transfer and otherwise run, modify and propagate the contents of this -implementation of Go, where such license applies only to those patent -claims, both currently owned or controlled by Google and acquired in -the future, licensable by Google that are necessarily infringed by this -implementation of Go. This grant does not include claims that would be -infringed only as a consequence of further modification of this -implementation. If you or your agent or exclusive licensee institute or -order or agree to the institution of patent litigation against any -entity (including a cross-claim or counterclaim in a lawsuit) alleging -that this implementation of Go or any code incorporated within this -implementation of Go constitutes direct or contributory patent -infringement, or inducement of patent infringement, then any patent -rights granted to you under this License for this implementation of Go -shall terminate as of the date such litigation is filed. diff --git a/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/mac_noasm.go b/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/mac_noasm.go deleted file mode 100644 index 333da28..0000000 --- a/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/mac_noasm.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build (!amd64 && !ppc64le && !s390x) || !gc || purego - -package poly1305 - -type mac struct{ macGeneric } diff --git a/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/poly1305.go b/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/poly1305.go deleted file mode 100644 index 4aaea81..0000000 --- a/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/poly1305.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package poly1305 implements Poly1305 one-time message authentication code as -// specified in https://cr.yp.to/mac/poly1305-20050329.pdf. -// -// Poly1305 is a fast, one-time authentication function. It is infeasible for an -// attacker to generate an authenticator for a message without the key. However, a -// key must only be used for a single message. Authenticating two different -// messages with the same key allows an attacker to forge authenticators for other -// messages with the same key. -// -// Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was -// used with a fixed key in order to generate one-time keys from an nonce. -// However, in this package AES isn't used and the one-time key is specified -// directly. -package poly1305 - -import "crypto/subtle" - -// TagSize is the size, in bytes, of a poly1305 authenticator. -const TagSize = 16 - -// Sum generates an authenticator for msg using a one-time key and puts the -// 16-byte result into out. Authenticating two different messages with the same -// key allows an attacker to forge messages at will. -func Sum(out *[16]byte, m []byte, key *[32]byte) { - h := New(key) - h.Write(m) - h.Sum(out[:0]) -} - -// Verify returns true if mac is a valid authenticator for m with the given key. -func Verify(mac *[16]byte, m []byte, key *[32]byte) bool { - var tmp [16]byte - Sum(&tmp, m, key) - return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1 -} - -// New returns a new MAC computing an authentication -// tag of all data written to it with the given key. -// This allows writing the message progressively instead -// of passing it as a single slice. Common users should use -// the Sum function instead. -// -// The key must be unique for each message, as authenticating -// two different messages with the same key allows an attacker -// to forge messages at will. -func New(key *[32]byte) *MAC { - m := &MAC{} - initialize(key, &m.macState) - return m -} - -// MAC is an io.Writer computing an authentication tag -// of the data written to it. -// -// MAC cannot be used like common hash.Hash implementations, -// because using a poly1305 key twice breaks its security. -// Therefore writing data to a running MAC after calling -// Sum or Verify causes it to panic. -type MAC struct { - mac // platform-dependent implementation - - finalized bool -} - -// Size returns the number of bytes Sum will return. -func (h *MAC) Size() int { return TagSize } - -// Write adds more data to the running message authentication code. -// It never returns an error. -// -// It must not be called after the first call of Sum or Verify. -func (h *MAC) Write(p []byte) (n int, err error) { - if h.finalized { - panic("poly1305: write to MAC after Sum or Verify") - } - return h.mac.Write(p) -} - -// Sum computes the authenticator of all data written to the -// message authentication code. -func (h *MAC) Sum(b []byte) []byte { - var mac [TagSize]byte - h.mac.Sum(&mac) - h.finalized = true - return append(b, mac[:]...) -} - -// Verify returns whether the authenticator of all data written to -// the message authentication code matches the expected value. -func (h *MAC) Verify(expected []byte) bool { - var mac [TagSize]byte - h.mac.Sum(&mac) - h.finalized = true - return subtle.ConstantTimeCompare(expected, mac[:]) == 1 -} diff --git a/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_amd64.go b/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_amd64.go deleted file mode 100644 index 164cd47..0000000 --- a/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_amd64.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gc && !purego - -package poly1305 - -//go:noescape -func update(state *macState, msg []byte) - -// mac is a wrapper for macGeneric that redirects calls that would have gone to -// updateGeneric to update. -// -// Its Write and Sum methods are otherwise identical to the macGeneric ones, but -// using function pointers would carry a major performance cost. -type mac struct{ macGeneric } - -func (h *mac) Write(p []byte) (int, error) { - nn := len(p) - if h.offset > 0 { - n := copy(h.buffer[h.offset:], p) - if h.offset+n < TagSize { - h.offset += n - return nn, nil - } - p = p[n:] - h.offset = 0 - update(&h.macState, h.buffer[:]) - } - if n := len(p) - (len(p) % TagSize); n > 0 { - update(&h.macState, p[:n]) - p = p[n:] - } - if len(p) > 0 { - h.offset += copy(h.buffer[h.offset:], p) - } - return nn, nil -} - -func (h *mac) Sum(out *[16]byte) { - state := h.macState - if h.offset > 0 { - update(&state, h.buffer[:h.offset]) - } - finalize(out, &state.h, &state.s) -} diff --git a/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_amd64.s b/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_amd64.s deleted file mode 100644 index e0d3c64..0000000 --- a/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_amd64.s +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gc && !purego - -#include "textflag.h" - -#define POLY1305_ADD(msg, h0, h1, h2) \ - ADDQ 0(msg), h0; \ - ADCQ 8(msg), h1; \ - ADCQ $1, h2; \ - LEAQ 16(msg), msg - -#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3) \ - MOVQ r0, AX; \ - MULQ h0; \ - MOVQ AX, t0; \ - MOVQ DX, t1; \ - MOVQ r0, AX; \ - MULQ h1; \ - ADDQ AX, t1; \ - ADCQ $0, DX; \ - MOVQ r0, t2; \ - IMULQ h2, t2; \ - ADDQ DX, t2; \ - \ - MOVQ r1, AX; \ - MULQ h0; \ - ADDQ AX, t1; \ - ADCQ $0, DX; \ - MOVQ DX, h0; \ - MOVQ r1, t3; \ - IMULQ h2, t3; \ - MOVQ r1, AX; \ - MULQ h1; \ - ADDQ AX, t2; \ - ADCQ DX, t3; \ - ADDQ h0, t2; \ - ADCQ $0, t3; \ - \ - MOVQ t0, h0; \ - MOVQ t1, h1; \ - MOVQ t2, h2; \ - ANDQ $3, h2; \ - MOVQ t2, t0; \ - ANDQ $0xFFFFFFFFFFFFFFFC, t0; \ - ADDQ t0, h0; \ - ADCQ t3, h1; \ - ADCQ $0, h2; \ - SHRQ $2, t3, t2; \ - SHRQ $2, t3; \ - ADDQ t2, h0; \ - ADCQ t3, h1; \ - ADCQ $0, h2 - -// func update(state *[7]uint64, msg []byte) -TEXT ·update(SB), $0-32 - MOVQ state+0(FP), DI - MOVQ msg_base+8(FP), SI - MOVQ msg_len+16(FP), R15 - - MOVQ 0(DI), R8 // h0 - MOVQ 8(DI), R9 // h1 - MOVQ 16(DI), R10 // h2 - MOVQ 24(DI), R11 // r0 - MOVQ 32(DI), R12 // r1 - - CMPQ R15, $16 - JB bytes_between_0_and_15 - -loop: - POLY1305_ADD(SI, R8, R9, R10) - -multiply: - POLY1305_MUL(R8, R9, R10, R11, R12, BX, CX, R13, R14) - SUBQ $16, R15 - CMPQ R15, $16 - JAE loop - -bytes_between_0_and_15: - TESTQ R15, R15 - JZ done - MOVQ $1, BX - XORQ CX, CX - XORQ R13, R13 - ADDQ R15, SI - -flush_buffer: - SHLQ $8, BX, CX - SHLQ $8, BX - MOVB -1(SI), R13 - XORQ R13, BX - DECQ SI - DECQ R15 - JNZ flush_buffer - - ADDQ BX, R8 - ADCQ CX, R9 - ADCQ $0, R10 - MOVQ $16, R15 - JMP multiply - -done: - MOVQ R8, 0(DI) - MOVQ R9, 8(DI) - MOVQ R10, 16(DI) - RET diff --git a/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_generic.go b/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_generic.go deleted file mode 100644 index ec2202b..0000000 --- a/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_generic.go +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file provides the generic implementation of Sum and MAC. Other files -// might provide optimized assembly implementations of some of this code. - -package poly1305 - -import ( - "encoding/binary" - "math/bits" -) - -// Poly1305 [RFC 7539] is a relatively simple algorithm: the authentication tag -// for a 64 bytes message is approximately -// -// s + m[0:16] * r⁴ + m[16:32] * r³ + m[32:48] * r² + m[48:64] * r mod 2¹³⁰ - 5 -// -// for some secret r and s. It can be computed sequentially like -// -// for len(msg) > 0: -// h += read(msg, 16) -// h *= r -// h %= 2¹³⁰ - 5 -// return h + s -// -// All the complexity is about doing performant constant-time math on numbers -// larger than any available numeric type. - -func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) { - h := newMACGeneric(key) - h.Write(msg) - h.Sum(out) -} - -func newMACGeneric(key *[32]byte) macGeneric { - m := macGeneric{} - initialize(key, &m.macState) - return m -} - -// macState holds numbers in saturated 64-bit little-endian limbs. That is, -// the value of [x0, x1, x2] is x[0] + x[1] * 2⁶⁴ + x[2] * 2¹²⁸. -type macState struct { - // h is the main accumulator. It is to be interpreted modulo 2¹³⁰ - 5, but - // can grow larger during and after rounds. It must, however, remain below - // 2 * (2¹³⁰ - 5). - h [3]uint64 - // r and s are the private key components. - r [2]uint64 - s [2]uint64 -} - -type macGeneric struct { - macState - - buffer [TagSize]byte - offset int -} - -// Write splits the incoming message into TagSize chunks, and passes them to -// update. It buffers incomplete chunks. -func (h *macGeneric) Write(p []byte) (int, error) { - nn := len(p) - if h.offset > 0 { - n := copy(h.buffer[h.offset:], p) - if h.offset+n < TagSize { - h.offset += n - return nn, nil - } - p = p[n:] - h.offset = 0 - updateGeneric(&h.macState, h.buffer[:]) - } - if n := len(p) - (len(p) % TagSize); n > 0 { - updateGeneric(&h.macState, p[:n]) - p = p[n:] - } - if len(p) > 0 { - h.offset += copy(h.buffer[h.offset:], p) - } - return nn, nil -} - -// Sum flushes the last incomplete chunk from the buffer, if any, and generates -// the MAC output. It does not modify its state, in order to allow for multiple -// calls to Sum, even if no Write is allowed after Sum. -func (h *macGeneric) Sum(out *[TagSize]byte) { - state := h.macState - if h.offset > 0 { - updateGeneric(&state, h.buffer[:h.offset]) - } - finalize(out, &state.h, &state.s) -} - -// [rMask0, rMask1] is the specified Poly1305 clamping mask in little-endian. It -// clears some bits of the secret coefficient to make it possible to implement -// multiplication more efficiently. -const ( - rMask0 = 0x0FFFFFFC0FFFFFFF - rMask1 = 0x0FFFFFFC0FFFFFFC -) - -// initialize loads the 256-bit key into the two 128-bit secret values r and s. -func initialize(key *[32]byte, m *macState) { - m.r[0] = binary.LittleEndian.Uint64(key[0:8]) & rMask0 - m.r[1] = binary.LittleEndian.Uint64(key[8:16]) & rMask1 - m.s[0] = binary.LittleEndian.Uint64(key[16:24]) - m.s[1] = binary.LittleEndian.Uint64(key[24:32]) -} - -// uint128 holds a 128-bit number as two 64-bit limbs, for use with the -// bits.Mul64 and bits.Add64 intrinsics. -type uint128 struct { - lo, hi uint64 -} - -func mul64(a, b uint64) uint128 { - hi, lo := bits.Mul64(a, b) - return uint128{lo, hi} -} - -func add128(a, b uint128) uint128 { - lo, c := bits.Add64(a.lo, b.lo, 0) - hi, c := bits.Add64(a.hi, b.hi, c) - if c != 0 { - panic("poly1305: unexpected overflow") - } - return uint128{lo, hi} -} - -func shiftRightBy2(a uint128) uint128 { - a.lo = a.lo>>2 | (a.hi&3)<<62 - a.hi = a.hi >> 2 - return a -} - -// updateGeneric absorbs msg into the state.h accumulator. For each chunk m of -// 128 bits of message, it computes -// -// h₊ = (h + m) * r mod 2¹³⁰ - 5 -// -// If the msg length is not a multiple of TagSize, it assumes the last -// incomplete chunk is the final one. -func updateGeneric(state *macState, msg []byte) { - h0, h1, h2 := state.h[0], state.h[1], state.h[2] - r0, r1 := state.r[0], state.r[1] - - for len(msg) > 0 { - var c uint64 - - // For the first step, h + m, we use a chain of bits.Add64 intrinsics. - // The resulting value of h might exceed 2¹³⁰ - 5, but will be partially - // reduced at the end of the multiplication below. - // - // The spec requires us to set a bit just above the message size, not to - // hide leading zeroes. For full chunks, that's 1 << 128, so we can just - // add 1 to the most significant (2¹²⁸) limb, h2. - if len(msg) >= TagSize { - h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0) - h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(msg[8:16]), c) - h2 += c + 1 - - msg = msg[TagSize:] - } else { - var buf [TagSize]byte - copy(buf[:], msg) - buf[len(msg)] = 1 - - h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0) - h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(buf[8:16]), c) - h2 += c - - msg = nil - } - - // Multiplication of big number limbs is similar to elementary school - // columnar multiplication. Instead of digits, there are 64-bit limbs. - // - // We are multiplying a 3 limbs number, h, by a 2 limbs number, r. - // - // h2 h1 h0 x - // r1 r0 = - // ---------------- - // h2r0 h1r0 h0r0 <-- individual 128-bit products - // + h2r1 h1r1 h0r1 - // ------------------------ - // m3 m2 m1 m0 <-- result in 128-bit overlapping limbs - // ------------------------ - // m3.hi m2.hi m1.hi m0.hi <-- carry propagation - // + m3.lo m2.lo m1.lo m0.lo - // ------------------------------- - // t4 t3 t2 t1 t0 <-- final result in 64-bit limbs - // - // The main difference from pen-and-paper multiplication is that we do - // carry propagation in a separate step, as if we wrote two digit sums - // at first (the 128-bit limbs), and then carried the tens all at once. - - h0r0 := mul64(h0, r0) - h1r0 := mul64(h1, r0) - h2r0 := mul64(h2, r0) - h0r1 := mul64(h0, r1) - h1r1 := mul64(h1, r1) - h2r1 := mul64(h2, r1) - - // Since h2 is known to be at most 7 (5 + 1 + 1), and r0 and r1 have their - // top 4 bits cleared by rMask{0,1}, we know that their product is not going - // to overflow 64 bits, so we can ignore the high part of the products. - // - // This also means that the product doesn't have a fifth limb (t4). - if h2r0.hi != 0 { - panic("poly1305: unexpected overflow") - } - if h2r1.hi != 0 { - panic("poly1305: unexpected overflow") - } - - m0 := h0r0 - m1 := add128(h1r0, h0r1) // These two additions don't overflow thanks again - m2 := add128(h2r0, h1r1) // to the 4 masked bits at the top of r0 and r1. - m3 := h2r1 - - t0 := m0.lo - t1, c := bits.Add64(m1.lo, m0.hi, 0) - t2, c := bits.Add64(m2.lo, m1.hi, c) - t3, _ := bits.Add64(m3.lo, m2.hi, c) - - // Now we have the result as 4 64-bit limbs, and we need to reduce it - // modulo 2¹³⁰ - 5. The special shape of this Crandall prime lets us do - // a cheap partial reduction according to the reduction identity - // - // c * 2¹³⁰ + n = c * 5 + n mod 2¹³⁰ - 5 - // - // because 2¹³⁰ = 5 mod 2¹³⁰ - 5. Partial reduction since the result is - // likely to be larger than 2¹³⁰ - 5, but still small enough to fit the - // assumptions we make about h in the rest of the code. - // - // See also https://speakerdeck.com/gtank/engineering-prime-numbers?slide=23 - - // We split the final result at the 2¹³⁰ mark into h and cc, the carry. - // Note that the carry bits are effectively shifted left by 2, in other - // words, cc = c * 4 for the c in the reduction identity. - h0, h1, h2 = t0, t1, t2&maskLow2Bits - cc := uint128{t2 & maskNotLow2Bits, t3} - - // To add c * 5 to h, we first add cc = c * 4, and then add (cc >> 2) = c. - - h0, c = bits.Add64(h0, cc.lo, 0) - h1, c = bits.Add64(h1, cc.hi, c) - h2 += c - - cc = shiftRightBy2(cc) - - h0, c = bits.Add64(h0, cc.lo, 0) - h1, c = bits.Add64(h1, cc.hi, c) - h2 += c - - // h2 is at most 3 + 1 + 1 = 5, making the whole of h at most - // - // 5 * 2¹²⁸ + (2¹²⁸ - 1) = 6 * 2¹²⁸ - 1 - } - - state.h[0], state.h[1], state.h[2] = h0, h1, h2 -} - -const ( - maskLow2Bits uint64 = 0x0000000000000003 - maskNotLow2Bits uint64 = ^maskLow2Bits -) - -// select64 returns x if v == 1 and y if v == 0, in constant time. -func select64(v, x, y uint64) uint64 { return ^(v-1)&x | (v-1)&y } - -// [p0, p1, p2] is 2¹³⁰ - 5 in little endian order. -const ( - p0 = 0xFFFFFFFFFFFFFFFB - p1 = 0xFFFFFFFFFFFFFFFF - p2 = 0x0000000000000003 -) - -// finalize completes the modular reduction of h and computes -// -// out = h + s mod 2¹²⁸ -func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) { - h0, h1, h2 := h[0], h[1], h[2] - - // After the partial reduction in updateGeneric, h might be more than - // 2¹³⁰ - 5, but will be less than 2 * (2¹³⁰ - 5). To complete the reduction - // in constant time, we compute t = h - (2¹³⁰ - 5), and select h as the - // result if the subtraction underflows, and t otherwise. - - hMinusP0, b := bits.Sub64(h0, p0, 0) - hMinusP1, b := bits.Sub64(h1, p1, b) - _, b = bits.Sub64(h2, p2, b) - - // h = h if h < p else h - p - h0 = select64(b, h0, hMinusP0) - h1 = select64(b, h1, hMinusP1) - - // Finally, we compute the last Poly1305 step - // - // tag = h + s mod 2¹²⁸ - // - // by just doing a wide addition with the 128 low bits of h and discarding - // the overflow. - h0, c := bits.Add64(h0, s[0], 0) - h1, _ = bits.Add64(h1, s[1], c) - - binary.LittleEndian.PutUint64(out[0:8], h0) - binary.LittleEndian.PutUint64(out[8:16], h1) -} diff --git a/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_ppc64le.go b/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_ppc64le.go deleted file mode 100644 index 4aec487..0000000 --- a/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_ppc64le.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gc && !purego - -package poly1305 - -//go:noescape -func update(state *macState, msg []byte) - -// mac is a wrapper for macGeneric that redirects calls that would have gone to -// updateGeneric to update. -// -// Its Write and Sum methods are otherwise identical to the macGeneric ones, but -// using function pointers would carry a major performance cost. -type mac struct{ macGeneric } - -func (h *mac) Write(p []byte) (int, error) { - nn := len(p) - if h.offset > 0 { - n := copy(h.buffer[h.offset:], p) - if h.offset+n < TagSize { - h.offset += n - return nn, nil - } - p = p[n:] - h.offset = 0 - update(&h.macState, h.buffer[:]) - } - if n := len(p) - (len(p) % TagSize); n > 0 { - update(&h.macState, p[:n]) - p = p[n:] - } - if len(p) > 0 { - h.offset += copy(h.buffer[h.offset:], p) - } - return nn, nil -} - -func (h *mac) Sum(out *[16]byte) { - state := h.macState - if h.offset > 0 { - update(&state, h.buffer[:h.offset]) - } - finalize(out, &state.h, &state.s) -} diff --git a/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_ppc64le.s b/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_ppc64le.s deleted file mode 100644 index d2ca5de..0000000 --- a/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_ppc64le.s +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gc && !purego - -#include "textflag.h" - -// This was ported from the amd64 implementation. - -#define POLY1305_ADD(msg, h0, h1, h2, t0, t1, t2) \ - MOVD (msg), t0; \ - MOVD 8(msg), t1; \ - MOVD $1, t2; \ - ADDC t0, h0, h0; \ - ADDE t1, h1, h1; \ - ADDE t2, h2; \ - ADD $16, msg - -#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3, t4, t5) \ - MULLD r0, h0, t0; \ - MULLD r0, h1, t4; \ - MULHDU r0, h0, t1; \ - MULHDU r0, h1, t5; \ - ADDC t4, t1, t1; \ - MULLD r0, h2, t2; \ - ADDZE t5; \ - MULHDU r1, h0, t4; \ - MULLD r1, h0, h0; \ - ADD t5, t2, t2; \ - ADDC h0, t1, t1; \ - MULLD h2, r1, t3; \ - ADDZE t4, h0; \ - MULHDU r1, h1, t5; \ - MULLD r1, h1, t4; \ - ADDC t4, t2, t2; \ - ADDE t5, t3, t3; \ - ADDC h0, t2, t2; \ - MOVD $-4, t4; \ - MOVD t0, h0; \ - MOVD t1, h1; \ - ADDZE t3; \ - ANDCC $3, t2, h2; \ - AND t2, t4, t0; \ - ADDC t0, h0, h0; \ - ADDE t3, h1, h1; \ - SLD $62, t3, t4; \ - SRD $2, t2; \ - ADDZE h2; \ - OR t4, t2, t2; \ - SRD $2, t3; \ - ADDC t2, h0, h0; \ - ADDE t3, h1, h1; \ - ADDZE h2 - -DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF -DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC -GLOBL ·poly1305Mask<>(SB), RODATA, $16 - -// func update(state *[7]uint64, msg []byte) -TEXT ·update(SB), $0-32 - MOVD state+0(FP), R3 - MOVD msg_base+8(FP), R4 - MOVD msg_len+16(FP), R5 - - MOVD 0(R3), R8 // h0 - MOVD 8(R3), R9 // h1 - MOVD 16(R3), R10 // h2 - MOVD 24(R3), R11 // r0 - MOVD 32(R3), R12 // r1 - - CMP R5, $16 - BLT bytes_between_0_and_15 - -loop: - POLY1305_ADD(R4, R8, R9, R10, R20, R21, R22) - -multiply: - POLY1305_MUL(R8, R9, R10, R11, R12, R16, R17, R18, R14, R20, R21) - ADD $-16, R5 - CMP R5, $16 - BGE loop - -bytes_between_0_and_15: - CMP R5, $0 - BEQ done - MOVD $0, R16 // h0 - MOVD $0, R17 // h1 - -flush_buffer: - CMP R5, $8 - BLE just1 - - MOVD $8, R21 - SUB R21, R5, R21 - - // Greater than 8 -- load the rightmost remaining bytes in msg - // and put into R17 (h1) - MOVD (R4)(R21), R17 - MOVD $16, R22 - - // Find the offset to those bytes - SUB R5, R22, R22 - SLD $3, R22 - - // Shift to get only the bytes in msg - SRD R22, R17, R17 - - // Put 1 at high end - MOVD $1, R23 - SLD $3, R21 - SLD R21, R23, R23 - OR R23, R17, R17 - - // Remainder is 8 - MOVD $8, R5 - -just1: - CMP R5, $8 - BLT less8 - - // Exactly 8 - MOVD (R4), R16 - - CMP R17, $0 - - // Check if we've already set R17; if not - // set 1 to indicate end of msg. - BNE carry - MOVD $1, R17 - BR carry - -less8: - MOVD $0, R16 // h0 - MOVD $0, R22 // shift count - CMP R5, $4 - BLT less4 - MOVWZ (R4), R16 - ADD $4, R4 - ADD $-4, R5 - MOVD $32, R22 - -less4: - CMP R5, $2 - BLT less2 - MOVHZ (R4), R21 - SLD R22, R21, R21 - OR R16, R21, R16 - ADD $16, R22 - ADD $-2, R5 - ADD $2, R4 - -less2: - CMP R5, $0 - BEQ insert1 - MOVBZ (R4), R21 - SLD R22, R21, R21 - OR R16, R21, R16 - ADD $8, R22 - -insert1: - // Insert 1 at end of msg - MOVD $1, R21 - SLD R22, R21, R21 - OR R16, R21, R16 - -carry: - // Add new values to h0, h1, h2 - ADDC R16, R8 - ADDE R17, R9 - ADDZE R10, R10 - MOVD $16, R5 - ADD R5, R4 - BR multiply - -done: - // Save h0, h1, h2 in state - MOVD R8, 0(R3) - MOVD R9, 8(R3) - MOVD R10, 16(R3) - RET diff --git a/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_s390x.go b/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_s390x.go deleted file mode 100644 index e1d033a..0000000 --- a/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_s390x.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gc && !purego - -package poly1305 - -import ( - "golang.org/x/sys/cpu" -) - -// updateVX is an assembly implementation of Poly1305 that uses vector -// instructions. It must only be called if the vector facility (vx) is -// available. -// -//go:noescape -func updateVX(state *macState, msg []byte) - -// mac is a replacement for macGeneric that uses a larger buffer and redirects -// calls that would have gone to updateGeneric to updateVX if the vector -// facility is installed. -// -// A larger buffer is required for good performance because the vector -// implementation has a higher fixed cost per call than the generic -// implementation. -type mac struct { - macState - - buffer [16 * TagSize]byte // size must be a multiple of block size (16) - offset int -} - -func (h *mac) Write(p []byte) (int, error) { - nn := len(p) - if h.offset > 0 { - n := copy(h.buffer[h.offset:], p) - if h.offset+n < len(h.buffer) { - h.offset += n - return nn, nil - } - p = p[n:] - h.offset = 0 - if cpu.S390X.HasVX { - updateVX(&h.macState, h.buffer[:]) - } else { - updateGeneric(&h.macState, h.buffer[:]) - } - } - - tail := len(p) % len(h.buffer) // number of bytes to copy into buffer - body := len(p) - tail // number of bytes to process now - if body > 0 { - if cpu.S390X.HasVX { - updateVX(&h.macState, p[:body]) - } else { - updateGeneric(&h.macState, p[:body]) - } - } - h.offset = copy(h.buffer[:], p[body:]) // copy tail bytes - can be 0 - return nn, nil -} - -func (h *mac) Sum(out *[TagSize]byte) { - state := h.macState - remainder := h.buffer[:h.offset] - - // Use the generic implementation if we have 2 or fewer blocks left - // to sum. The vector implementation has a higher startup time. - if cpu.S390X.HasVX && len(remainder) > 2*TagSize { - updateVX(&state, remainder) - } else if len(remainder) > 0 { - updateGeneric(&state, remainder) - } - finalize(out, &state.h, &state.s) -} diff --git a/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_s390x.s b/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_s390x.s deleted file mode 100644 index 0fe3a7c..0000000 --- a/vendor/github.com/tailscale/golang-x-crypto/internal/poly1305/sum_s390x.s +++ /dev/null @@ -1,503 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gc && !purego - -#include "textflag.h" - -// This implementation of Poly1305 uses the vector facility (vx) -// to process up to 2 blocks (32 bytes) per iteration using an -// algorithm based on the one described in: -// -// NEON crypto, Daniel J. Bernstein & Peter Schwabe -// https://cryptojedi.org/papers/neoncrypto-20120320.pdf -// -// This algorithm uses 5 26-bit limbs to represent a 130-bit -// value. These limbs are, for the most part, zero extended and -// placed into 64-bit vector register elements. Each vector -// register is 128-bits wide and so holds 2 of these elements. -// Using 26-bit limbs allows us plenty of headroom to accommodate -// accumulations before and after multiplication without -// overflowing either 32-bits (before multiplication) or 64-bits -// (after multiplication). -// -// In order to parallelise the operations required to calculate -// the sum we use two separate accumulators and then sum those -// in an extra final step. For compatibility with the generic -// implementation we perform this summation at the end of every -// updateVX call. -// -// To use two accumulators we must multiply the message blocks -// by r² rather than r. Only the final message block should be -// multiplied by r. -// -// Example: -// -// We want to calculate the sum (h) for a 64 byte message (m): -// -// h = m[0:16]r⁴ + m[16:32]r³ + m[32:48]r² + m[48:64]r -// -// To do this we split the calculation into the even indices -// and odd indices of the message. These form our SIMD 'lanes': -// -// h = m[ 0:16]r⁴ + m[32:48]r² + <- lane 0 -// m[16:32]r³ + m[48:64]r <- lane 1 -// -// To calculate this iteratively we refactor so that both lanes -// are written in terms of r² and r: -// -// h = (m[ 0:16]r² + m[32:48])r² + <- lane 0 -// (m[16:32]r² + m[48:64])r <- lane 1 -// ^ ^ -// | coefficients for second iteration -// coefficients for first iteration -// -// So in this case we would have two iterations. In the first -// both lanes are multiplied by r². In the second only the -// first lane is multiplied by r² and the second lane is -// instead multiplied by r. This gives use the odd and even -// powers of r that we need from the original equation. -// -// Notation: -// -// h - accumulator -// r - key -// m - message -// -// [a, b] - SIMD register holding two 64-bit values -// [a, b, c, d] - SIMD register holding four 32-bit values -// xᵢ[n] - limb n of variable x with bit width i -// -// Limbs are expressed in little endian order, so for 26-bit -// limbs x₂₆[4] will be the most significant limb and x₂₆[0] -// will be the least significant limb. - -// masking constants -#define MOD24 V0 // [0x0000000000ffffff, 0x0000000000ffffff] - mask low 24-bits -#define MOD26 V1 // [0x0000000003ffffff, 0x0000000003ffffff] - mask low 26-bits - -// expansion constants (see EXPAND macro) -#define EX0 V2 -#define EX1 V3 -#define EX2 V4 - -// key (r², r or 1 depending on context) -#define R_0 V5 -#define R_1 V6 -#define R_2 V7 -#define R_3 V8 -#define R_4 V9 - -// precalculated coefficients (5r², 5r or 0 depending on context) -#define R5_1 V10 -#define R5_2 V11 -#define R5_3 V12 -#define R5_4 V13 - -// message block (m) -#define M_0 V14 -#define M_1 V15 -#define M_2 V16 -#define M_3 V17 -#define M_4 V18 - -// accumulator (h) -#define H_0 V19 -#define H_1 V20 -#define H_2 V21 -#define H_3 V22 -#define H_4 V23 - -// temporary registers (for short-lived values) -#define T_0 V24 -#define T_1 V25 -#define T_2 V26 -#define T_3 V27 -#define T_4 V28 - -GLOBL ·constants<>(SB), RODATA, $0x30 -// EX0 -DATA ·constants<>+0x00(SB)/8, $0x0006050403020100 -DATA ·constants<>+0x08(SB)/8, $0x1016151413121110 -// EX1 -DATA ·constants<>+0x10(SB)/8, $0x060c0b0a09080706 -DATA ·constants<>+0x18(SB)/8, $0x161c1b1a19181716 -// EX2 -DATA ·constants<>+0x20(SB)/8, $0x0d0d0d0d0d0f0e0d -DATA ·constants<>+0x28(SB)/8, $0x1d1d1d1d1d1f1e1d - -// MULTIPLY multiplies each lane of f and g, partially reduced -// modulo 2¹³⁰ - 5. The result, h, consists of partial products -// in each lane that need to be reduced further to produce the -// final result. -// -// h₁₃₀ = (f₁₃₀g₁₃₀) % 2¹³⁰ + (5f₁₃₀g₁₃₀) / 2¹³⁰ -// -// Note that the multiplication by 5 of the high bits is -// achieved by precalculating the multiplication of four of the -// g coefficients by 5. These are g51-g54. -#define MULTIPLY(f0, f1, f2, f3, f4, g0, g1, g2, g3, g4, g51, g52, g53, g54, h0, h1, h2, h3, h4) \ - VMLOF f0, g0, h0 \ - VMLOF f0, g3, h3 \ - VMLOF f0, g1, h1 \ - VMLOF f0, g4, h4 \ - VMLOF f0, g2, h2 \ - VMLOF f1, g54, T_0 \ - VMLOF f1, g2, T_3 \ - VMLOF f1, g0, T_1 \ - VMLOF f1, g3, T_4 \ - VMLOF f1, g1, T_2 \ - VMALOF f2, g53, h0, h0 \ - VMALOF f2, g1, h3, h3 \ - VMALOF f2, g54, h1, h1 \ - VMALOF f2, g2, h4, h4 \ - VMALOF f2, g0, h2, h2 \ - VMALOF f3, g52, T_0, T_0 \ - VMALOF f3, g0, T_3, T_3 \ - VMALOF f3, g53, T_1, T_1 \ - VMALOF f3, g1, T_4, T_4 \ - VMALOF f3, g54, T_2, T_2 \ - VMALOF f4, g51, h0, h0 \ - VMALOF f4, g54, h3, h3 \ - VMALOF f4, g52, h1, h1 \ - VMALOF f4, g0, h4, h4 \ - VMALOF f4, g53, h2, h2 \ - VAG T_0, h0, h0 \ - VAG T_3, h3, h3 \ - VAG T_1, h1, h1 \ - VAG T_4, h4, h4 \ - VAG T_2, h2, h2 - -// REDUCE performs the following carry operations in four -// stages, as specified in Bernstein & Schwabe: -// -// 1: h₂₆[0]->h₂₆[1] h₂₆[3]->h₂₆[4] -// 2: h₂₆[1]->h₂₆[2] h₂₆[4]->h₂₆[0] -// 3: h₂₆[0]->h₂₆[1] h₂₆[2]->h₂₆[3] -// 4: h₂₆[3]->h₂₆[4] -// -// The result is that all of the limbs are limited to 26-bits -// except for h₂₆[1] and h₂₆[4] which are limited to 27-bits. -// -// Note that although each limb is aligned at 26-bit intervals -// they may contain values that exceed 2²⁶ - 1, hence the need -// to carry the excess bits in each limb. -#define REDUCE(h0, h1, h2, h3, h4) \ - VESRLG $26, h0, T_0 \ - VESRLG $26, h3, T_1 \ - VN MOD26, h0, h0 \ - VN MOD26, h3, h3 \ - VAG T_0, h1, h1 \ - VAG T_1, h4, h4 \ - VESRLG $26, h1, T_2 \ - VESRLG $26, h4, T_3 \ - VN MOD26, h1, h1 \ - VN MOD26, h4, h4 \ - VESLG $2, T_3, T_4 \ - VAG T_3, T_4, T_4 \ - VAG T_2, h2, h2 \ - VAG T_4, h0, h0 \ - VESRLG $26, h2, T_0 \ - VESRLG $26, h0, T_1 \ - VN MOD26, h2, h2 \ - VN MOD26, h0, h0 \ - VAG T_0, h3, h3 \ - VAG T_1, h1, h1 \ - VESRLG $26, h3, T_2 \ - VN MOD26, h3, h3 \ - VAG T_2, h4, h4 - -// EXPAND splits the 128-bit little-endian values in0 and in1 -// into 26-bit big-endian limbs and places the results into -// the first and second lane of d₂₆[0:4] respectively. -// -// The EX0, EX1 and EX2 constants are arrays of byte indices -// for permutation. The permutation both reverses the bytes -// in the input and ensures the bytes are copied into the -// destination limb ready to be shifted into their final -// position. -#define EXPAND(in0, in1, d0, d1, d2, d3, d4) \ - VPERM in0, in1, EX0, d0 \ - VPERM in0, in1, EX1, d2 \ - VPERM in0, in1, EX2, d4 \ - VESRLG $26, d0, d1 \ - VESRLG $30, d2, d3 \ - VESRLG $4, d2, d2 \ - VN MOD26, d0, d0 \ // [in0₂₆[0], in1₂₆[0]] - VN MOD26, d3, d3 \ // [in0₂₆[3], in1₂₆[3]] - VN MOD26, d1, d1 \ // [in0₂₆[1], in1₂₆[1]] - VN MOD24, d4, d4 \ // [in0₂₆[4], in1₂₆[4]] - VN MOD26, d2, d2 // [in0₂₆[2], in1₂₆[2]] - -// func updateVX(state *macState, msg []byte) -TEXT ·updateVX(SB), NOSPLIT, $0 - MOVD state+0(FP), R1 - LMG msg+8(FP), R2, R3 // R2=msg_base, R3=msg_len - - // load EX0, EX1 and EX2 - MOVD $·constants<>(SB), R5 - VLM (R5), EX0, EX2 - - // generate masks - VGMG $(64-24), $63, MOD24 // [0x00ffffff, 0x00ffffff] - VGMG $(64-26), $63, MOD26 // [0x03ffffff, 0x03ffffff] - - // load h (accumulator) and r (key) from state - VZERO T_1 // [0, 0] - VL 0(R1), T_0 // [h₆₄[0], h₆₄[1]] - VLEG $0, 16(R1), T_1 // [h₆₄[2], 0] - VL 24(R1), T_2 // [r₆₄[0], r₆₄[1]] - VPDI $0, T_0, T_2, T_3 // [h₆₄[0], r₆₄[0]] - VPDI $5, T_0, T_2, T_4 // [h₆₄[1], r₆₄[1]] - - // unpack h and r into 26-bit limbs - // note: h₆₄[2] may have the low 3 bits set, so h₂₆[4] is a 27-bit value - VN MOD26, T_3, H_0 // [h₂₆[0], r₂₆[0]] - VZERO H_1 // [0, 0] - VZERO H_3 // [0, 0] - VGMG $(64-12-14), $(63-12), T_0 // [0x03fff000, 0x03fff000] - 26-bit mask with low 12 bits masked out - VESLG $24, T_1, T_1 // [h₆₄[2]<<24, 0] - VERIMG $-26&63, T_3, MOD26, H_1 // [h₂₆[1], r₂₆[1]] - VESRLG $+52&63, T_3, H_2 // [h₂₆[2], r₂₆[2]] - low 12 bits only - VERIMG $-14&63, T_4, MOD26, H_3 // [h₂₆[1], r₂₆[1]] - VESRLG $40, T_4, H_4 // [h₂₆[4], r₂₆[4]] - low 24 bits only - VERIMG $+12&63, T_4, T_0, H_2 // [h₂₆[2], r₂₆[2]] - complete - VO T_1, H_4, H_4 // [h₂₆[4], r₂₆[4]] - complete - - // replicate r across all 4 vector elements - VREPF $3, H_0, R_0 // [r₂₆[0], r₂₆[0], r₂₆[0], r₂₆[0]] - VREPF $3, H_1, R_1 // [r₂₆[1], r₂₆[1], r₂₆[1], r₂₆[1]] - VREPF $3, H_2, R_2 // [r₂₆[2], r₂₆[2], r₂₆[2], r₂₆[2]] - VREPF $3, H_3, R_3 // [r₂₆[3], r₂₆[3], r₂₆[3], r₂₆[3]] - VREPF $3, H_4, R_4 // [r₂₆[4], r₂₆[4], r₂₆[4], r₂₆[4]] - - // zero out lane 1 of h - VLEIG $1, $0, H_0 // [h₂₆[0], 0] - VLEIG $1, $0, H_1 // [h₂₆[1], 0] - VLEIG $1, $0, H_2 // [h₂₆[2], 0] - VLEIG $1, $0, H_3 // [h₂₆[3], 0] - VLEIG $1, $0, H_4 // [h₂₆[4], 0] - - // calculate 5r (ignore least significant limb) - VREPIF $5, T_0 - VMLF T_0, R_1, R5_1 // [5r₂₆[1], 5r₂₆[1], 5r₂₆[1], 5r₂₆[1]] - VMLF T_0, R_2, R5_2 // [5r₂₆[2], 5r₂₆[2], 5r₂₆[2], 5r₂₆[2]] - VMLF T_0, R_3, R5_3 // [5r₂₆[3], 5r₂₆[3], 5r₂₆[3], 5r₂₆[3]] - VMLF T_0, R_4, R5_4 // [5r₂₆[4], 5r₂₆[4], 5r₂₆[4], 5r₂₆[4]] - - // skip r² calculation if we are only calculating one block - CMPBLE R3, $16, skip - - // calculate r² - MULTIPLY(R_0, R_1, R_2, R_3, R_4, R_0, R_1, R_2, R_3, R_4, R5_1, R5_2, R5_3, R5_4, M_0, M_1, M_2, M_3, M_4) - REDUCE(M_0, M_1, M_2, M_3, M_4) - VGBM $0x0f0f, T_0 - VERIMG $0, M_0, T_0, R_0 // [r₂₆[0], r²₂₆[0], r₂₆[0], r²₂₆[0]] - VERIMG $0, M_1, T_0, R_1 // [r₂₆[1], r²₂₆[1], r₂₆[1], r²₂₆[1]] - VERIMG $0, M_2, T_0, R_2 // [r₂₆[2], r²₂₆[2], r₂₆[2], r²₂₆[2]] - VERIMG $0, M_3, T_0, R_3 // [r₂₆[3], r²₂₆[3], r₂₆[3], r²₂₆[3]] - VERIMG $0, M_4, T_0, R_4 // [r₂₆[4], r²₂₆[4], r₂₆[4], r²₂₆[4]] - - // calculate 5r² (ignore least significant limb) - VREPIF $5, T_0 - VMLF T_0, R_1, R5_1 // [5r₂₆[1], 5r²₂₆[1], 5r₂₆[1], 5r²₂₆[1]] - VMLF T_0, R_2, R5_2 // [5r₂₆[2], 5r²₂₆[2], 5r₂₆[2], 5r²₂₆[2]] - VMLF T_0, R_3, R5_3 // [5r₂₆[3], 5r²₂₆[3], 5r₂₆[3], 5r²₂₆[3]] - VMLF T_0, R_4, R5_4 // [5r₂₆[4], 5r²₂₆[4], 5r₂₆[4], 5r²₂₆[4]] - -loop: - CMPBLE R3, $32, b2 // 2 or fewer blocks remaining, need to change key coefficients - - // load next 2 blocks from message - VLM (R2), T_0, T_1 - - // update message slice - SUB $32, R3 - MOVD $32(R2), R2 - - // unpack message blocks into 26-bit big-endian limbs - EXPAND(T_0, T_1, M_0, M_1, M_2, M_3, M_4) - - // add 2¹²⁸ to each message block value - VLEIB $4, $1, M_4 - VLEIB $12, $1, M_4 - -multiply: - // accumulate the incoming message - VAG H_0, M_0, M_0 - VAG H_3, M_3, M_3 - VAG H_1, M_1, M_1 - VAG H_4, M_4, M_4 - VAG H_2, M_2, M_2 - - // multiply the accumulator by the key coefficient - MULTIPLY(M_0, M_1, M_2, M_3, M_4, R_0, R_1, R_2, R_3, R_4, R5_1, R5_2, R5_3, R5_4, H_0, H_1, H_2, H_3, H_4) - - // carry and partially reduce the partial products - REDUCE(H_0, H_1, H_2, H_3, H_4) - - CMPBNE R3, $0, loop - -finish: - // sum lane 0 and lane 1 and put the result in lane 1 - VZERO T_0 - VSUMQG H_0, T_0, H_0 - VSUMQG H_3, T_0, H_3 - VSUMQG H_1, T_0, H_1 - VSUMQG H_4, T_0, H_4 - VSUMQG H_2, T_0, H_2 - - // reduce again after summation - // TODO(mundaym): there might be a more efficient way to do this - // now that we only have 1 active lane. For example, we could - // simultaneously pack the values as we reduce them. - REDUCE(H_0, H_1, H_2, H_3, H_4) - - // carry h[1] through to h[4] so that only h[4] can exceed 2²⁶ - 1 - // TODO(mundaym): in testing this final carry was unnecessary. - // Needs a proof before it can be removed though. - VESRLG $26, H_1, T_1 - VN MOD26, H_1, H_1 - VAQ T_1, H_2, H_2 - VESRLG $26, H_2, T_2 - VN MOD26, H_2, H_2 - VAQ T_2, H_3, H_3 - VESRLG $26, H_3, T_3 - VN MOD26, H_3, H_3 - VAQ T_3, H_4, H_4 - - // h is now < 2(2¹³⁰ - 5) - // Pack each lane in h₂₆[0:4] into h₁₂₈[0:1]. - VESLG $26, H_1, H_1 - VESLG $26, H_3, H_3 - VO H_0, H_1, H_0 - VO H_2, H_3, H_2 - VESLG $4, H_2, H_2 - VLEIB $7, $48, H_1 - VSLB H_1, H_2, H_2 - VO H_0, H_2, H_0 - VLEIB $7, $104, H_1 - VSLB H_1, H_4, H_3 - VO H_3, H_0, H_0 - VLEIB $7, $24, H_1 - VSRLB H_1, H_4, H_1 - - // update state - VSTEG $1, H_0, 0(R1) - VSTEG $0, H_0, 8(R1) - VSTEG $1, H_1, 16(R1) - RET - -b2: // 2 or fewer blocks remaining - CMPBLE R3, $16, b1 - - // Load the 2 remaining blocks (17-32 bytes remaining). - MOVD $-17(R3), R0 // index of final byte to load modulo 16 - VL (R2), T_0 // load full 16 byte block - VLL R0, 16(R2), T_1 // load final (possibly partial) block and pad with zeros to 16 bytes - - // The Poly1305 algorithm requires that a 1 bit be appended to - // each message block. If the final block is less than 16 bytes - // long then it is easiest to insert the 1 before the message - // block is split into 26-bit limbs. If, on the other hand, the - // final message block is 16 bytes long then we append the 1 bit - // after expansion as normal. - MOVBZ $1, R0 - MOVD $-16(R3), R3 // index of byte in last block to insert 1 at (could be 16) - CMPBEQ R3, $16, 2(PC) // skip the insertion if the final block is 16 bytes long - VLVGB R3, R0, T_1 // insert 1 into the byte at index R3 - - // Split both blocks into 26-bit limbs in the appropriate lanes. - EXPAND(T_0, T_1, M_0, M_1, M_2, M_3, M_4) - - // Append a 1 byte to the end of the second to last block. - VLEIB $4, $1, M_4 - - // Append a 1 byte to the end of the last block only if it is a - // full 16 byte block. - CMPBNE R3, $16, 2(PC) - VLEIB $12, $1, M_4 - - // Finally, set up the coefficients for the final multiplication. - // We have previously saved r and 5r in the 32-bit even indexes - // of the R_[0-4] and R5_[1-4] coefficient registers. - // - // We want lane 0 to be multiplied by r² so that can be kept the - // same. We want lane 1 to be multiplied by r so we need to move - // the saved r value into the 32-bit odd index in lane 1 by - // rotating the 64-bit lane by 32. - VGBM $0x00ff, T_0 // [0, 0xffffffffffffffff] - mask lane 1 only - VERIMG $32, R_0, T_0, R_0 // [_, r²₂₆[0], _, r₂₆[0]] - VERIMG $32, R_1, T_0, R_1 // [_, r²₂₆[1], _, r₂₆[1]] - VERIMG $32, R_2, T_0, R_2 // [_, r²₂₆[2], _, r₂₆[2]] - VERIMG $32, R_3, T_0, R_3 // [_, r²₂₆[3], _, r₂₆[3]] - VERIMG $32, R_4, T_0, R_4 // [_, r²₂₆[4], _, r₂₆[4]] - VERIMG $32, R5_1, T_0, R5_1 // [_, 5r²₂₆[1], _, 5r₂₆[1]] - VERIMG $32, R5_2, T_0, R5_2 // [_, 5r²₂₆[2], _, 5r₂₆[2]] - VERIMG $32, R5_3, T_0, R5_3 // [_, 5r²₂₆[3], _, 5r₂₆[3]] - VERIMG $32, R5_4, T_0, R5_4 // [_, 5r²₂₆[4], _, 5r₂₆[4]] - - MOVD $0, R3 - BR multiply - -skip: - CMPBEQ R3, $0, finish - -b1: // 1 block remaining - - // Load the final block (1-16 bytes). This will be placed into - // lane 0. - MOVD $-1(R3), R0 - VLL R0, (R2), T_0 // pad to 16 bytes with zeros - - // The Poly1305 algorithm requires that a 1 bit be appended to - // each message block. If the final block is less than 16 bytes - // long then it is easiest to insert the 1 before the message - // block is split into 26-bit limbs. If, on the other hand, the - // final message block is 16 bytes long then we append the 1 bit - // after expansion as normal. - MOVBZ $1, R0 - CMPBEQ R3, $16, 2(PC) - VLVGB R3, R0, T_0 - - // Set the message block in lane 1 to the value 0 so that it - // can be accumulated without affecting the final result. - VZERO T_1 - - // Split the final message block into 26-bit limbs in lane 0. - // Lane 1 will be contain 0. - EXPAND(T_0, T_1, M_0, M_1, M_2, M_3, M_4) - - // Append a 1 byte to the end of the last block only if it is a - // full 16 byte block. - CMPBNE R3, $16, 2(PC) - VLEIB $4, $1, M_4 - - // We have previously saved r and 5r in the 32-bit even indexes - // of the R_[0-4] and R5_[1-4] coefficient registers. - // - // We want lane 0 to be multiplied by r so we need to move the - // saved r value into the 32-bit odd index in lane 0. We want - // lane 1 to be set to the value 1. This makes multiplication - // a no-op. We do this by setting lane 1 in every register to 0 - // and then just setting the 32-bit index 3 in R_0 to 1. - VZERO T_0 - MOVD $0, R0 - MOVD $0x10111213, R12 - VLVGP R12, R0, T_1 // [_, 0x10111213, _, 0x00000000] - VPERM T_0, R_0, T_1, R_0 // [_, r₂₆[0], _, 0] - VPERM T_0, R_1, T_1, R_1 // [_, r₂₆[1], _, 0] - VPERM T_0, R_2, T_1, R_2 // [_, r₂₆[2], _, 0] - VPERM T_0, R_3, T_1, R_3 // [_, r₂₆[3], _, 0] - VPERM T_0, R_4, T_1, R_4 // [_, r₂₆[4], _, 0] - VPERM T_0, R5_1, T_1, R5_1 // [_, 5r₂₆[1], _, 0] - VPERM T_0, R5_2, T_1, R5_2 // [_, 5r₂₆[2], _, 0] - VPERM T_0, R5_3, T_1, R5_3 // [_, 5r₂₆[3], _, 0] - VPERM T_0, R5_4, T_1, R5_4 // [_, 5r₂₆[4], _, 0] - - // Set the value of lane 1 to be 1. - VLEIF $3, $1, R_0 // [_, r₂₆[0], _, 1] - - MOVD $0, R3 - BR multiply diff --git a/vendor/github.com/tailscale/peercred/peercred_solaris.go b/vendor/github.com/tailscale/peercred/peercred_solaris.go new file mode 100644 index 0000000..aa84dda --- /dev/null +++ b/vendor/github.com/tailscale/peercred/peercred_solaris.go @@ -0,0 +1,53 @@ +// Copyright (c) 2021 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 peercred + +import ( + "fmt" + "net" + "strconv" + + "golang.org/x/sys/unix" +) + +func init() { + osGet = getSolaris +} + +func getSolaris(c net.Conn) (*Creds, error) { + switch c := c.(type) { + case *net.UnixConn: + return getUnix(c) + case *net.TCPConn: + // TODO: Need ideas + } + return nil, ErrUnsupportedConnType +} + +func getUnix(c *net.UnixConn) (*Creds, error) { + raw, err := c.SyscallConn() + if err != nil { + return nil, fmt.Errorf("SyscallConn: %w", err) + } + + var creds *unix.Ucred + cerr := raw.Control(func(fd uintptr) { + creds, err = unix.GetPeerUcred(fd) + if err != nil { + err = fmt.Errorf("unix.GetPeerUcred: %w", err) + return + } + }) + if cerr != nil { + return nil, fmt.Errorf("raw.Control: %w", cerr) + } + if err != nil { + return nil, err + } + return &Creds{ + pid: creds.Getpid(), + uid: strconv.FormatUint(uint64(creds.Geteuid()), 10), + }, nil +} diff --git a/vendor/github.com/tailscale/web-client-prebuilt/build/assets/index-BbZBz4S-.js.gz b/vendor/github.com/tailscale/web-client-prebuilt/build/assets/index-BbZBz4S-.js.gz new file mode 100644 index 0000000000000000000000000000000000000000..4105e0f980db9028be2ffdce4eecf75da8164b80 GIT binary patch literal 92422 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�ZQ)9F}Q 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%0A{jI8s)P?|Wi$h_7_CKt7pU2NyvHi=_rGF1_ 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 diff --git a/vendor/github.com/tailscale/web-client-prebuilt/build/assets/index-DUHvXbWu.js.gz b/vendor/github.com/tailscale/web-client-prebuilt/build/assets/index-DUHvXbWu.js.gz deleted file mode 100644 index 522bd1748118ef6edce697e0c2c9db052aca4505..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 93284 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 z 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 D|D&`L diff --git a/vendor/github.com/tailscale/web-client-prebuilt/build/assets/index-DVk8gqX9.css.gz b/vendor/github.com/tailscale/web-client-prebuilt/build/assets/index-DVk8gqX9.css.gz new file mode 100644 index 0000000000000000000000000000000000000000..bd292baab6cd600273ef44e4633a7b44d77600ce GIT binary patch literal 7797 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 P|Npf#ns - - + +