├── .dockerignore ├── .github ├── CODEOWNERS ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yml └── workflows │ ├── api-breakage.yml │ ├── benchmark.yml │ ├── ci.yml │ ├── codeql.yml │ ├── gen-docs.yml │ ├── swift-nightly.yml │ └── validate.yml ├── .gitignore ├── .jazzy.yaml ├── .mailmap ├── .spi.yml ├── .swift-format ├── Benchmark ├── Package.swift ├── README.md └── Sources │ └── soto-benchmark │ ├── AWSClientSuite.swift │ ├── AWSSignerV4Suite.swift │ ├── EncoderSuites.swift │ └── main.swift ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── CONTRIBUTORS.txt ├── Dockerfile ├── LICENSE ├── NOTICE.txt ├── Package.swift ├── README.md ├── SECURITY.md ├── SotoCore.docc ├── SotoCore │ ├── AWSClient.md │ ├── Articles │ │ ├── CredentialProviders.md │ │ └── ServiceObjects.md │ └── SotoCore.md └── SotoSignerV4 │ ├── AWSSigner.md │ └── SotoSignerV4.md ├── Sources ├── CSotoExpat │ ├── AUTHORS │ ├── COPYING │ ├── Makefile.am │ ├── ascii.h │ ├── asciitab.h │ ├── expat_config.h │ ├── iasciitab.h │ ├── include │ │ ├── expat.h │ │ ├── expat_external.h │ │ └── expat_prefix_symbols.h │ ├── internal.h │ ├── latin1tab.h │ ├── libexpat.def │ ├── libexpatw.def │ ├── nametab.h │ ├── siphash.h │ ├── utf8tab.h │ ├── winconfig.h │ ├── xmlparse.c │ ├── xmlrole.c │ ├── xmlrole.h │ ├── xmltok.c │ ├── xmltok.h │ ├── xmltok_impl.c │ ├── xmltok_impl.h │ └── xmltok_ns.c ├── INIParser │ └── INIParser.swift ├── SotoCore │ ├── AWSClient+Paginate.swift │ ├── AWSClient.swift │ ├── AWSEndpointDiscovery.swift │ ├── AWSService.swift │ ├── AWSServiceConfig.swift │ ├── AWSShapes │ │ ├── Base64Data.swift │ │ ├── Document.swift │ │ └── EventPayload.swift │ ├── Concurrency │ │ ├── AnyAsyncSequence.swift │ │ ├── ByteBufferSequence.swift │ │ ├── EventStream.swift │ │ ├── ExpiringValue.swift │ │ ├── FixedSizeByteBufferAsyncSequence.swift │ │ └── Sequence+concurrentMap.swift │ ├── Credential │ │ ├── ConfigFileCredentialProvider.swift │ │ ├── ConfigFileLoader.swift │ │ ├── Credential+IsEmpty.swift │ │ ├── CredentialProvider.swift │ │ ├── CredentialProviderError.swift │ │ ├── CredentialProviderSelector.swift │ │ ├── DeferredCredentialProvider.swift │ │ ├── EmptyCredential.swift │ │ ├── ExpiringCredential.swift │ │ ├── MetaDataCredentialProvider.swift │ │ ├── NullCredentialProvider.swift │ │ ├── RotatingCredentialProvider.swift │ │ ├── RuntimeSelectorCredentialProvider.swift │ │ ├── STSAssumeRole.swift │ │ ├── StaticCredential+CredentialProvider.swift │ │ └── StaticCredential+Environment.swift │ ├── Doc │ │ ├── ARN.swift │ │ ├── AWSShape.swift │ │ ├── EndpointVariant.swift │ │ ├── Environment.swift │ │ ├── Region.swift │ │ └── ServiceProtocol.swift │ ├── Encoder │ │ ├── CodableProperties │ │ │ ├── CodableProperties.swift │ │ │ ├── CollectionCoders.swift │ │ │ ├── DateCoders.swift │ │ │ └── EC2ArrayCoder.swift │ │ ├── EventStreamDecoder.swift │ │ ├── QueryEncoder.swift │ │ ├── RequestContainer.swift │ │ └── ResponseContainer.swift │ ├── Errors │ │ ├── ClientErrors.swift │ │ ├── Error.swift │ │ └── ServerErrors.swift │ ├── Exports.swift │ ├── HTTP │ │ ├── AWSHTTPBody.swift │ │ ├── AWSHTTPClient.swift │ │ ├── AWSHTTPRequest.swift │ │ ├── AWSHTTPResponse+HAL.swift │ │ ├── AWSHTTPResponse.swift │ │ ├── AsyncHTTPClient.swift │ │ └── S3SignedAsyncSequence.swift │ ├── Middleware │ │ ├── Middleware.swift │ │ ├── Middleware │ │ │ ├── EditHeadersMiddleware.swift │ │ │ ├── EndpointDiscoveryMiddleware.swift │ │ │ ├── ErrorHandlingMiddleware.swift │ │ │ ├── LoggingMiddleware.swift │ │ │ ├── RetryMiddleware.swift │ │ │ ├── S3Middleware.swift │ │ │ ├── SigningMiddleware.swift │ │ │ ├── TracingMiddleware.swift │ │ │ └── TreeHashMiddleware.swift │ │ └── MiddlewareStack.swift │ ├── RetryPolicy.swift │ ├── Utils │ │ ├── UnsafeTransfer.swift │ │ ├── base64.swift │ │ └── crc32.swift │ └── Waiters │ │ ├── AWSClient+Waiter.swift │ │ └── Matcher.swift ├── SotoSignerV4 │ ├── HexEncoding.swift │ ├── SigV4a.swift │ ├── credentials.swift │ ├── exports.swift │ └── signer.swift ├── SotoTestUtils │ ├── Environment.swift │ ├── TestServer.swift │ └── TestUtils.swift └── SotoXML │ ├── Expat.swift │ ├── XML.swift │ ├── XMLDecoder.swift │ └── XMLEncoder.swift ├── Tests ├── INIParserTests │ └── INIParserTests.swift ├── SotoCoreTests │ ├── AWSClientTests.swift │ ├── AWSRequestTests.swift │ ├── AWSResponseTests.swift │ ├── AWSServiceTests.swift │ ├── CRCTests.swift │ ├── Concurrency │ │ ├── AsyncSequenceTests.swift │ │ ├── Count.swift │ │ ├── ExpiringValueTests.swift │ │ └── Sequence+concurrentMapTests.swift │ ├── Credential │ │ ├── ConfigFileCredentialProviderTests.swift │ │ ├── ConfigFileLoaderTests.swift │ │ ├── CredentialProviderTests.swift │ │ ├── MetaDataCredentialProviderTests.swift │ │ ├── RotatingCredentialProviderTests.swift │ │ ├── RuntimeSelectorCredentialProviderTests.swift │ │ ├── STSAssumeRoleTests.swift │ │ └── StaticCredential+EnvironmentTests.swift │ ├── Doc │ │ ├── ARNTests.swift │ │ ├── EnvironmentTests.swift │ │ └── RegionTests.swift │ ├── EndpointDiscoveryTests.swift │ ├── LoggingTests.swift │ ├── MiddlewareTests.swift │ ├── PaginateTests.swift │ ├── PayloadTests.swift │ ├── QueryEncoderTests.swift │ ├── TestTracer.swift │ ├── TimeStampTests.swift │ ├── TracingTests.swift │ ├── ValidationTests.swift │ └── WaiterTests.swift ├── SotoSignerV4Tests │ ├── AWSSignerTests.swift │ └── SigV4aTests.swift └── SotoXMLTests │ ├── XMLCoderTests.swift │ └── XMLTests.swift └── scripts ├── build-docc.sh ├── build-docs.sh ├── commit-docs.sh ├── expat-symbols.sh ├── generate-contributors-list.sh ├── generate-docs.sh ├── generate-errors.swift ├── generate-region-test.swift ├── generate-region.swift ├── templates ├── generate-errors │ └── generate-errors.stencil └── generate-region │ ├── Region-Tests.stencil │ └── Region.stencil └── validate.sh /.dockerignore: -------------------------------------------------------------------------------- 1 | .build 2 | .git -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @adam-fowler @0xTim -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: adam-fowler 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve the functionality of Soto! 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. If you can include a link to redacted requests or responses, that would be very helpful as well! 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. ... 16 | 2. ... 17 | 18 | **Expected behavior** 19 | A clear and concise description of what you expected to happen. 20 | 21 | **Setup (please complete the following information):** 22 | - OS: [e.g. Linux] 23 | - Version of Soto [e.g. 5.0] 24 | - Authentication mechanism [hard-coded credentials, IAM Instance Profile on EC2, etc] 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for Soto 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | ignore: 8 | - dependency-name: "codecov/codecov-action" 9 | update-types: ["version-update:semver-major"] 10 | groups: 11 | dependencies: 12 | patterns: 13 | - "*" 14 | - package-ecosystem: "swift" 15 | directory: "/" 16 | schedule: 17 | interval: "weekly" 18 | open-pull-requests-limit: 6 19 | allow: 20 | - dependency-type: all 21 | groups: 22 | all-dependencies: 23 | patterns: 24 | - "*" 25 | -------------------------------------------------------------------------------- /.github/workflows/api-breakage.yml: -------------------------------------------------------------------------------- 1 | name: API breaking changes 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | workflow_dispatch: 8 | 9 | jobs: 10 | linux: 11 | runs-on: ubuntu-latest 12 | timeout-minutes: 15 13 | container: 14 | image: swift:latest 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | # https://github.com/actions/checkout/issues/766 21 | - name: Mark the workspace as safe 22 | run: git config --global --add safe.directory ${GITHUB_WORKSPACE} 23 | - name: API breaking changes 24 | run: | 25 | swift package diagnose-api-breaking-changes origin/${GITHUB_BASE_REF} 26 | -------------------------------------------------------------------------------- /.github/workflows/benchmark.yml: -------------------------------------------------------------------------------- 1 | name: Benchmark 2 | 3 | on: 4 | pull_request: 5 | workflow_dispatch: 6 | 7 | jobs: 8 | macos: 9 | runs-on: macOS-latest 10 | timeout-minutes: 15 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v4 14 | with: 15 | fetch-depth: 1 16 | - name: Benchmark 17 | run: | 18 | cd Benchmark 19 | swift run -c release 20 | 21 | linux: 22 | runs-on: ubuntu-latest 23 | timeout-minutes: 15 24 | strategy: 25 | matrix: 26 | image: 27 | - 'swift:latest' 28 | container: 29 | image: ${{ matrix.image }} 30 | steps: 31 | - name: Checkout 32 | uses: actions/checkout@v4 33 | - name: Benchmark 34 | run: | 35 | cd Benchmark 36 | swift run -c release 37 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - 6.x.x 8 | pull_request: 9 | release: 10 | types: [published] 11 | workflow_dispatch: 12 | 13 | env: 14 | ENABLE_TIMING_TESTS: "false" 15 | AWS_LOG_LEVEL: "trace" 16 | SOTO_CORE_STRICT_CONCURRENCY: "true" 17 | 18 | jobs: 19 | macos: 20 | runs-on: macOS-14 21 | timeout-minutes: 15 22 | steps: 23 | - name: Checkout 24 | uses: actions/checkout@v4 25 | - name: SPM tests 26 | run: swift test --enable-code-coverage --parallel 27 | - name: Convert coverage files 28 | run: | 29 | xcrun llvm-cov export -format "lcov" \ 30 | .build/debug/soto-corePackageTests.xctest/Contents/MacOs/soto-corePackageTests \ 31 | -ignore-filename-regex="\/Tests\/" \ 32 | -instr-profile=.build/debug/codecov/default.profdata > info.lcov 33 | - name: Upload to codecov.io 34 | uses: codecov/codecov-action@v4 35 | with: 36 | files: info.lcov 37 | token: ${{ secrets.CODECOV_TOKEN }} 38 | linux: 39 | runs-on: ubuntu-latest 40 | timeout-minutes: 15 41 | strategy: 42 | matrix: 43 | image: 44 | - 'swift:5.10' 45 | - 'swift:6.0' 46 | - 'swift:6.1' 47 | container: 48 | image: ${{ matrix.image }} 49 | steps: 50 | - name: Checkout 51 | uses: actions/checkout@v4 52 | - name: Test 53 | run: | 54 | swift --version 55 | swift test --enable-code-coverage 56 | - name: Convert coverage files 57 | run: | 58 | llvm-cov export -format="lcov" \ 59 | .build/debug/soto-corePackageTests.xctest \ 60 | -ignore-filename-regex="\/Tests\/" \ 61 | -instr-profile .build/debug/codecov/default.profdata > info.lcov 62 | - name: Upload to codecov.io 63 | uses: codecov/codecov-action@v4 64 | with: 65 | files: info.lcov 66 | token: ${{ secrets.CODECOV_TOKEN }} 67 | android: 68 | name: Android 69 | runs-on: ubuntu-latest 70 | timeout-minutes: 15 71 | strategy: 72 | fail-fast: false 73 | steps: 74 | - name: "Checkout" 75 | uses: actions/checkout@v4 76 | - name: "Build for Android" 77 | uses: skiptools/swift-android-action@v2 78 | with: 79 | build-tests: true 80 | run-tests: false 81 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | analyze: 11 | name: Analyze 12 | runs-on: macos-latest 13 | timeout-minutes: 15 14 | permissions: 15 | security-events: write 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | language: [ 'swift' ] 21 | 22 | steps: 23 | - name: Checkout repository 24 | uses: actions/checkout@v4 25 | 26 | - name: Initialize CodeQL 27 | uses: github/codeql-action/init@v3 28 | with: 29 | languages: ${{ matrix.language }} 30 | 31 | - name: Build 32 | run: swift build 33 | 34 | - name: Perform CodeQL Analysis 35 | uses: github/codeql-action/analyze@v3 36 | -------------------------------------------------------------------------------- /.github/workflows/gen-docs.yml: -------------------------------------------------------------------------------- 1 | name: Generate Documentation 2 | 3 | on: 4 | release: 5 | types: [published] 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | timeout-minutes: 15 13 | container: 14 | image: swift:latest 15 | 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | with: 20 | fetch-depth: 0 21 | - name: Install rsync 📚 22 | run: | 23 | apt-get update && apt-get install -y rsync bc 24 | - name: Build 25 | env: 26 | DOCC: docc 27 | run: | 28 | ./scripts/build-docc.sh 29 | - name: Deploy 🚀 30 | uses: JamesIves/github-pages-deploy-action@v4 31 | with: 32 | folder: docs/soto-core/7.x.x 33 | target-folder: 7.x.x 34 | 35 | -------------------------------------------------------------------------------- /.github/workflows/swift-nightly.yml: -------------------------------------------------------------------------------- 1 | name: Swift nightly build 2 | 3 | on: 4 | schedule: 5 | - cron: '0 1 * * 0' 6 | workflow_dispatch: 7 | 8 | env: 9 | AWS_ENABLE_LOGGING : "true" 10 | 11 | jobs: 12 | linux: 13 | runs-on: ubuntu-latest 14 | timeout-minutes: 15 15 | strategy: 16 | matrix: 17 | tag: ['nightly-focal', 'nightly-jammy', 'nightly-amazonlinux2'] 18 | container: 19 | image: swiftlang/swift:${{ matrix.tag }} 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v4 23 | - name: Test 24 | run: swift test --enable-test-discovery 25 | -------------------------------------------------------------------------------- /.github/workflows/validate.yml: -------------------------------------------------------------------------------- 1 | name: Validity Check 2 | 3 | on: 4 | pull_request: 5 | 6 | jobs: 7 | validate: 8 | runs-on: ubuntu-latest 9 | timeout-minutes: 15 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v4 13 | with: 14 | fetch-depth: 1 15 | - name: run script 16 | run: ./scripts/validate.sh 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .build 3 | .swiftpm 4 | .vscode 5 | .devcontainer 6 | /Packages 7 | /*.xcodeproj 8 | Package.resolved 9 | /build 10 | /docs 11 | 12 | -------------------------------------------------------------------------------- /.jazzy.yaml: -------------------------------------------------------------------------------- 1 | sourcekitten_sourcefile: 2 | - sourcekitten/SotoCore.json 3 | author_url: https://github.com/soto-project 4 | github_url: https://github.com/soto-project/soto-core 5 | copyright: '© Copyright (c) 2020 Soto project authors' 6 | readme: README.md 7 | -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | Jonathan McAllister 2 | Jonathan McAllister 3 | Jonathan McAllister Jonny McAllister 4 | Yuki Takei Yuki Takei 5 | Yuki Takei noppoman 6 | Roland Möller Ro-M 7 | Martin Redington Martin Redington 8 | Tim Condon <0xtimc@gmail.com> Tim Condon <0xTim@users.noreply.github.com> 9 | -------------------------------------------------------------------------------- /.spi.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | external_links: 3 | documentation: "https://soto-project.github.io/soto-core/" 4 | -------------------------------------------------------------------------------- /.swift-format: -------------------------------------------------------------------------------- 1 | { 2 | "version" : 1, 3 | "indentation" : { 4 | "spaces" : 4 5 | }, 6 | "tabWidth" : 4, 7 | "fileScopedDeclarationPrivacy" : { 8 | "accessLevel" : "private" 9 | }, 10 | "spacesAroundRangeFormationOperators" : false, 11 | "indentConditionalCompilationBlocks" : false, 12 | "indentSwitchCaseLabels" : false, 13 | "lineBreakAroundMultilineExpressionChainComponents" : false, 14 | "lineBreakBeforeControlFlowKeywords" : false, 15 | "lineBreakBeforeEachArgument" : true, 16 | "lineBreakBeforeEachGenericRequirement" : true, 17 | "lineLength" : 150, 18 | "maximumBlankLines" : 1, 19 | "respectsExistingLineBreaks" : true, 20 | "prioritizeKeepingFunctionOutputTogether" : true, 21 | "multiElementCollectionTrailingCommas" : true, 22 | "rules" : { 23 | "AllPublicDeclarationsHaveDocumentation" : false, 24 | "AlwaysUseLiteralForEmptyCollectionInit" : false, 25 | "AlwaysUseLowerCamelCase" : false, 26 | "AmbiguousTrailingClosureOverload" : true, 27 | "BeginDocumentationCommentWithOneLineSummary" : false, 28 | "DoNotUseSemicolons" : true, 29 | "DontRepeatTypeInStaticProperties" : true, 30 | "FileScopedDeclarationPrivacy" : true, 31 | "FullyIndirectEnum" : true, 32 | "GroupNumericLiterals" : true, 33 | "IdentifiersMustBeASCII" : true, 34 | "NeverForceUnwrap" : false, 35 | "NeverUseForceTry" : false, 36 | "NeverUseImplicitlyUnwrappedOptionals" : false, 37 | "NoAccessLevelOnExtensionDeclaration" : true, 38 | "NoAssignmentInExpressions" : true, 39 | "NoBlockComments" : true, 40 | "NoCasesWithOnlyFallthrough" : true, 41 | "NoEmptyTrailingClosureParentheses" : true, 42 | "NoLabelsInCasePatterns" : true, 43 | "NoLeadingUnderscores" : false, 44 | "NoParensAroundConditions" : true, 45 | "NoVoidReturnOnFunctionSignature" : true, 46 | "OmitExplicitReturns" : true, 47 | "OneCasePerLine" : true, 48 | "OneVariableDeclarationPerLine" : true, 49 | "OnlyOneTrailingClosureArgument" : true, 50 | "OrderedImports" : true, 51 | "ReplaceForEachWithForLoop" : true, 52 | "ReturnVoidInsteadOfEmptyTuple" : true, 53 | "UseEarlyExits" : false, 54 | "UseExplicitNilCheckInConditions" : false, 55 | "UseLetInEveryBoundCaseVariable" : false, 56 | "UseShorthandTypeNames" : true, 57 | "UseSingleLinePropertyGetter" : false, 58 | "UseSynthesizedInitializer" : false, 59 | "UseTripleSlashForDocumentationComments" : true, 60 | "UseWhereClausesInForLoops" : false, 61 | "ValidateDocumentationComments" : false 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Benchmark/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.2 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "soto-benchmark", 8 | dependencies: [ 9 | .package(url: "https://github.com/soto-project/soto-core", .branch("main")), 10 | .package(name: "Benchmark", url: "https://github.com/google/swift-benchmark", from: "0.1.0"), 11 | ], 12 | targets: [ 13 | .target( 14 | name: "soto-benchmark", 15 | dependencies: [ 16 | .product(name: "SotoCore", package: "soto-core"), 17 | .product(name: "Benchmark", package: "Benchmark"), 18 | ] 19 | ) 20 | ] 21 | ) 22 | -------------------------------------------------------------------------------- /Benchmark/README.md: -------------------------------------------------------------------------------- 1 | # soto-benchmark 2 | 3 | Benchmark testing for soto-core 4 | -------------------------------------------------------------------------------- /Benchmark/Sources/soto-benchmark/AWSSignerV4Suite.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2020 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Benchmark 16 | import Foundation 17 | import SotoSignerV4 18 | 19 | let awsSignerV4Suite = BenchmarkSuite(name: "AWSSignerV4", settings: Iterations(1000), WarmupIterations(2)) { suite in 20 | let string = "testing, testing, 1,2,1,2" 21 | let credentials: Credential = StaticCredential(accessKeyId: "MYACCESSKEY", secretAccessKey: "MYSECRETACCESSKEY") 22 | let signer = AWSSigner(credentials: credentials, name: "s3", region: "eu-west-1") 23 | 24 | suite.benchmark("sign-headers") { 25 | _ = signer.signHeaders( 26 | url: URL(string: "https://test-bucket.s3.amazonaws.com/test-put.txt")!, 27 | method: .GET, 28 | headers: ["Content-Type": "application/x-www-form-urlencoded; charset=utf-8"], 29 | body: .string(string) 30 | ) 31 | } 32 | 33 | suite.benchmark("sign-url") { 34 | _ = signer.signURL( 35 | url: URL(string: "https://test-bucket.s3.amazonaws.com/test-put.txt")!, 36 | method: .GET, 37 | body: .string(string), 38 | expires: .hours(1) 39 | ) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Benchmark/Sources/soto-benchmark/EncoderSuites.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2020 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Benchmark 16 | import Foundation 17 | import SotoCore 18 | internal import SotoXML 19 | 20 | protocol EncoderProtocol { 21 | associatedtype Output 22 | func encode(_ type: Input) throws -> Output 23 | } 24 | 25 | extension XMLEncoder: EncoderProtocol { 26 | typealias Output = XML.Element 27 | func encode(_ value: some Encodable) throws -> Output { 28 | try self.encode(value, name: "BenchmarkTest") 29 | } 30 | } 31 | 32 | extension QueryEncoder: EncoderProtocol { 33 | typealias Output = String? 34 | func encode(_ value: some Encodable) throws -> Output { 35 | try self.encode(value, name: "BenchmarkTest") 36 | } 37 | } 38 | 39 | struct Numbers: Codable { 40 | let b: Bool 41 | let i: Int 42 | let f: Float 43 | let d: Double 44 | } 45 | 46 | struct Strings: Codable { 47 | let s: String 48 | let s2: String? 49 | } 50 | 51 | struct Arrays: Codable { 52 | let a1: [Int] 53 | let a2: [String] 54 | } 55 | 56 | struct Dictionaries: Codable { 57 | let d: [String: Int] 58 | } 59 | 60 | /// Generic suite of benchmark tests for an Encoder. 61 | func encoderSuite(for encoder: some EncoderProtocol, suite: BenchmarkSuite) { 62 | let numbers = Numbers(b: true, i: 3478, f: 34.4633, d: 9585) 63 | suite.benchmark("numbers") { 64 | _ = try encoder.encode(numbers) 65 | } 66 | 67 | let strings = Strings(s: "Benchmark string", s2: "optional") 68 | suite.benchmark("strings") { 69 | _ = try encoder.encode(strings) 70 | } 71 | 72 | let arrays = Arrays(a1: [234, 23, 55, 1], a2: ["Benchmark", "string"]) 73 | suite.benchmark("arrays") { 74 | _ = try encoder.encode(arrays) 75 | } 76 | 77 | let dictionaries = Dictionaries(d: ["benchmark": 1, "tests": 2, "again": 6]) 78 | suite.benchmark("dictionaries") { 79 | _ = try encoder.encode(dictionaries) 80 | } 81 | } 82 | 83 | /// Suite of benchmark tests for XMLEncoder 84 | let xmlEncoderSuite = BenchmarkSuite(name: "XMLEncoder", settings: Iterations(10000), WarmupIterations(10)) { suite in 85 | encoderSuite(for: XMLEncoder(), suite: suite) 86 | } 87 | 88 | /// Suite of benchmark tests to XMLDecoder 89 | let xmlDecoderSuite = BenchmarkSuite(name: "XMLDecoder", settings: Iterations(10000), WarmupIterations(10)) { suite in 90 | let xml = #"hellogoodbyegoodbyegoodbye"# 91 | suite.benchmark("loadXML") { 92 | let result = try XML.Element(xmlString: xml) 93 | } 94 | 95 | if let numbers = try? XML.Element(xmlString: #"true3622223.142.777776"#) { 96 | suite.benchmark("numbers") { 97 | _ = try XMLDecoder().decode(Numbers.self, from: numbers) 98 | } 99 | } 100 | 101 | if let strings = try? XML.Element(xmlString: #"Benchmark testing DecoderString version 2"#) { 102 | suite.benchmark("strings") { 103 | _ = try XMLDecoder().decode(Strings.self, from: strings) 104 | } 105 | } 106 | 107 | if let arrays = try? XML.Element(xmlString: #"238928768234test"#) { 108 | suite.benchmark("arrays") { 109 | _ = try XMLDecoder().decode(Arrays.self, from: arrays) 110 | } 111 | } 112 | } 113 | 114 | /// Suite of benchmark tests for XMLEncoder 115 | let queryEncoderSuite = BenchmarkSuite(name: "QueryEncoder", settings: Iterations(10000), WarmupIterations(10)) { suite in 116 | encoderSuite(for: QueryEncoder(), suite: suite) 117 | } 118 | -------------------------------------------------------------------------------- /Benchmark/Sources/soto-benchmark/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2020 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Benchmark 16 | 17 | let suites = [ 18 | awsSignerV4Suite, 19 | queryEncoderSuite, 20 | xmlEncoderSuite, 21 | xmlDecoderSuite, 22 | awsClientSuite, 23 | ] 24 | 25 | Benchmark.main(suites) 26 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | All developers should feel welcome and encouraged to contribute to Soto. Because of this we have adopted the code of conduct defined by [contributor-covenant.org](https://www.contributor-covenant.org). This document is used across many open source 4 | communities, and we think it articulates our values well. The full text is copied below: 5 | 6 | ## Contributor Code of Conduct v1.3 7 | 8 | As contributors and maintainers of this project, and in the interest of 9 | fostering an open and welcoming community, we pledge to respect all people who 10 | contribute through reporting issues, posting feature requests, updating 11 | documentation, submitting pull requests or patches, and other activities. 12 | 13 | We are committed to making participation in this project a harassment-free 14 | experience for everyone, regardless of level of experience, gender, gender 15 | identity and expression, sexual orientation, disability, personal appearance, 16 | body size, race, ethnicity, age, religion, or nationality. 17 | 18 | Examples of unacceptable behavior by participants include: 19 | 20 | * The use of sexualized language or imagery 21 | * Personal attacks 22 | * Trolling or insulting/derogatory comments 23 | * Public or private harassment 24 | * Publishing other's private information, such as physical or electronic 25 | addresses, without explicit permission 26 | * Other unethical or unprofessional conduct 27 | 28 | Project maintainers have the right and responsibility to remove, edit, or 29 | reject comments, commits, code, wiki edits, issues, and other contributions 30 | that are not aligned to this Code of Conduct, or to ban temporarily or 31 | permanently any contributor for other behaviors that they deem inappropriate, 32 | threatening, offensive, or harmful. 33 | 34 | By adopting this Code of Conduct, project maintainers commit themselves to 35 | fairly and consistently applying these principles to every aspect of managing 36 | this project. Project maintainers who do not follow or enforce the Code of 37 | Conduct may be permanently removed from the project team. 38 | 39 | This Code of Conduct applies both within project spaces and in public spaces 40 | when an individual is representing the project or its community. 41 | 42 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 43 | reported by contacting a project maintainer at [INSERT EMAIL ADDRESS]. All 44 | complaints will be reviewed and investigated and will result in a response that 45 | is deemed necessary and appropriate to the circumstances. Maintainers are 46 | obligated to maintain confidentiality with regard to the reporter of an 47 | incident. 48 | 49 | 50 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 51 | version 1.3.0, available at https://www.contributor-covenant.org/version/1/3/0/code-of-conduct.html 52 | 53 | [homepage]: https://www.contributor-covenant.org 54 | 55 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Legal 4 | By submitting a pull request, you represent that you have the right to license your contribution to the community, and agree by submitting the patch 5 | that your contributions are licensed under the Apache 2.0 license (see [LICENSE](LICENSE)). 6 | 7 | ## Contributor Conduct 8 | All contributors are expected to adhere to the project's [Code of Conduct](CODE_OF_CONDUCT.md). 9 | 10 | ## Submitting a bug or issue 11 | Please ensure to include the following in your bug report 12 | - A consise description of the issue, what happened and what you expected. 13 | - Simple reproduction steps 14 | - Version of the library you are using 15 | - Contextual information (Swift version, OS etc) 16 | 17 | ## Submitting a Pull Request 18 | 19 | Please ensure to include the following in your Pull Request 20 | - A description of what you are trying to do. What the PR provides to the library, additional functionality, fixing a bug etc 21 | - A description of the code changes 22 | - Documentation on how these changes are being tested 23 | - Additional tests to show your code working and to ensure future changes don't break your code. 24 | 25 | Please keep you PRs to a minimal number of changes. If a PR is large try to split it up into smaller PRs. Don't move code around unnecessarily it makes comparing old with new very hard. 26 | 27 | The main development branch of the repository is `main`. Each major version release has it's own branch named "version number".x.x eg `7.x.x` . If you are submitting code for an older version then you should use the version branch as the base for your code changes. 28 | 29 | ### Formatting 30 | 31 | We use Apple's swift-format for formatting code. PRs will not be accepted if they haven't be formatted. 32 | 33 | All new files need to include the following file header at the top 34 | ```swift 35 | //===----------------------------------------------------------------------===// 36 | // 37 | // This source file is part of the Soto for AWS open source project 38 | // 39 | // Copyright (c) 2017-2024 the Soto project authors 40 | // Licensed under Apache License v2.0 41 | // 42 | // See LICENSE.txt for license information 43 | // See CONTRIBUTORS.txt for the list of Soto project authors 44 | // 45 | // SPDX-License-Identifier: Apache-2.0 46 | // 47 | //===----------------------------------------------------------------------===// 48 | ``` 49 | Please ensure the dates are correct in the header. 50 | -------------------------------------------------------------------------------- /CONTRIBUTORS.txt: -------------------------------------------------------------------------------- 1 | For the purpose of tracking copyright, this is the list of individuals and 2 | organizations who have contributed source code to soto-core. 3 | 4 | For employees of an organization/company where the copyright of work done 5 | by employees of that company is held by the company itself, only the company 6 | needs to be listed here. 7 | 8 | ## COPYRIGHT HOLDERS 9 | 10 | ### Contributors 11 | 12 | - AbdelAli <153457962+AbdAlAlii@users.noreply.github.com> 13 | - Adam Fowler 14 | - Eneko Alonso 15 | - Fabian Fett 16 | - Iceman 17 | - Jeff 18 | - Joe Smith 19 | - Jonathan McAllister 20 | - Kyle Ishie 21 | - Luis Padron 22 | - Mahdi Bahrami 23 | - Martin Redington 24 | - Oliver O'Neill 25 | - Roland Möller 26 | - Sébastien Stormacq 27 | - Tim Condon <0xtimc@gmail.com> 28 | - Yifei Teng 29 | - Yuki Takei 30 | - dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 31 | - giginet 32 | 33 | **Updating this list** 34 | 35 | Please do not edit this file manually. It is generated using `./scripts/generate_contributors_list.sh`. If a name is misspelled or appearing multiple times: add an entry in `./.mailmap` 36 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # ================================ 2 | # Build image 3 | # ================================ 4 | FROM swift:5.4 as build 5 | 6 | WORKDIR /build 7 | 8 | # First just resolve dependencies. 9 | # This creates a cached layer that can be reused 10 | # as long as your Package.swift/Package.resolved 11 | # files do not change. 12 | COPY ./Package.* ./ 13 | RUN swift package resolve 14 | 15 | # Copy entire repo into container 16 | COPY . . 17 | 18 | RUN swift test --enable-test-discovery --sanitize=thread 19 | 20 | -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2020 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | This product contains a copy of INIParser from PerfectlySoft 16 | 17 | * LICENSE (Apache License 2.0): 18 | * https://github.com/PerfectlySoft/Perfect-INIParser/blob/master/LICENSE 19 | * HOMEPAGE: 20 | * https://github.com/PerfectlySoft/Perfect-INIParser 21 | 22 | This product contains a copy of libexpat 23 | 24 | * LICENSE (MIT): 25 | * https://github.com/libexpat/libexpat/blob/master/expat/COPYING 26 | * HOMEPAGE: 27 | * https://libexpat.github.io/ 28 | 29 | This product contains a copy of base64.swift from swift-extras-base64 30 | 31 | * LICENSE (Apache License 2.0): 32 | * https://github.com/swift-extras/swift-extras-base64/blob/main/LICENSE 33 | * HOMEPAGE: 34 | * https://github.com/swift-extras/swift-extras-base64 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Soto Core 2 | 3 | [Swift 5.8](https://swift.org) 4 | [](https://github.com/soto-project/soto-core/actions) 5 | [Codecov Result](https://codecov.io/gh/soto-project/soto-core) 6 | 7 | The core framework for [Soto](https://github.com/soto-project/soto) the Swift SDK for AWS. This is the underlying driver for executing requests to AWS, but you should be using one of the libraries provided by Soto instead of this! 8 | 9 | Documentation for the core library can be found [here](https://soto-project.github.io/soto-core). Documentation for Soto can be found [here](https://soto.codes). 10 | 11 | ## Contributing 12 | 13 | We welcome and encourage contributions from all developers. Please read [CONTRIBUTING.md](CONTRIBUTING.md) for our contributing guidelines. 14 | 15 | ## License 16 | 17 | `soto-core` is released under the Apache 2.0 license. See [LICENSE](LICENSE) for details. 18 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Currently we support versions 6.0 and above of Soto. These will receive security updates as and when needed. 6 | 7 | ## Reporting a Vulnerability 8 | 9 | If you believe you have found a security vulnerability in Soto please do not post this in a public forum, do not create a GitHub Issue. Instead you should email [security@soto.codes](mailto:security@soto.codes) with details of the issue. 10 | 11 | #### What happens next? 12 | 13 | * A member of the team will acknowledge receipt of the report within 5 14 | working days. This may include a request for additional 15 | information about reproducing the vulnerability. 16 | * We will privately inform the Swift Server Work Group ([SSWG][sswg]) of the 17 | vulnerability within 10 days of the report as per their [security 18 | guidelines][sswg-security]. 19 | * Once we have identified a fix we may ask you to validate it. We aim to do this 20 | within 30 days, but this may not always be possible, for example when the 21 | vulnerability is internal to Amazon Web Services(AWS). In this situation we will 22 | forward the issue to AWS. 23 | * We will decide on a planned release date and let you know when it is. 24 | * Once the fix has been released we will publish a security advisory on GitHub 25 | and the [SSWG][sswg] will announce the vulnerability on the [Swift 26 | forums][swift-forums-sec]. 27 | 28 | [sswg]: https://github.com/swift-server/sswg 29 | [sswg-security]: https://github.com/swift-server/sswg/blob/main/process/incubation.md#security-best-practices 30 | [swift-forums-sec]: https://forums.swift.org/c/server/security-updates/ 31 | -------------------------------------------------------------------------------- /SotoCore.docc/SotoCore/SotoCore.md: -------------------------------------------------------------------------------- 1 | # ``SotoCore`` 2 | 3 | The core framework for Soto, a Swift SDK for AWS 4 | 5 | ## Overview 6 | 7 | SotoCore is the underlying driver for executing requests for the Soto Swift SDK for AWS. You will most likely be using this via one of libraries in [Soto](https://github.com/soto-project/soto). Much of the public APIs here you will never need to know as they are used internally by the Soto service libraries. But there are a few objects that are used. 8 | 9 | ## Topics 10 | 11 | ### Articles 12 | 13 | - 14 | - 15 | 16 | ### Client 17 | 18 | - ``AWSClient`` 19 | 20 | ### Services 21 | 22 | - ``AWSService`` 23 | - ``AWSServiceConfig`` 24 | - ``AWSServiceErrorType`` 25 | - ``ServiceProtocol`` 26 | - ``Region`` 27 | - ``AWSPartition`` 28 | - ``EndpointVariantType`` 29 | 30 | ### Middleware 31 | 32 | - ``AWSMiddlewareProtocol`` 33 | - ``AWSMiddleware`` 34 | - ``AWSMiddlewareBuilder`` 35 | - ``AWSMiddlewareStack(_:)`` 36 | - ``AWSMiddlewareContext`` 37 | - ``AWSMiddlewareNextHandler`` 38 | - ``AWSEditHeadersMiddleware`` 39 | - ``AWSLoggingMiddleware`` 40 | - ``AWSTracingMiddleware`` 41 | - ``EndpointDiscoveryMiddleware`` 42 | - ``S3Middleware`` 43 | - ``TreeHashMiddleware`` 44 | 45 | ### Credentials 46 | 47 | - ``CredentialProvider`` 48 | - ``NullCredentialProvider`` 49 | - ``ExpiringCredential`` 50 | - ``CredentialProviderFactory`` 51 | - ``DeferredCredentialProvider`` 52 | - ``RotatingCredentialProvider`` 53 | - ``RotatingCredential`` 54 | - ``CredentialProviderError`` 55 | - ``EmptyCredential`` 56 | 57 | ### Retry 58 | 59 | - ``RetryPolicy`` 60 | - ``RetryPolicyFactory`` 61 | - ``RetryStatus`` 62 | 63 | ### Endpoints 64 | 65 | - ``AWSEndpoints`` 66 | - ``AWSEndpointStorage`` 67 | 68 | ### Errors 69 | 70 | - ``AWSErrorType`` 71 | - ``AWSErrorContext`` 72 | - ``AWSClientError`` 73 | - ``AWSServerError`` 74 | - ``AWSResponseError`` 75 | - ``AWSRawError`` 76 | - ``HeaderDecodingError`` 77 | 78 | ### API Input/Outputs 79 | 80 | - ``AWSShape`` 81 | - ``AWSEncodableShape`` 82 | - ``AWSDecodableShape`` 83 | - ``AWSErrorShape`` 84 | - ``AWSShapeOptions`` 85 | - ``AWSBase64Data`` 86 | - ``AWSDocument`` 87 | - ``AWSPaginateToken`` 88 | 89 | ### Waiters 90 | 91 | - ``AWSWaiterMatcher`` 92 | - ``AWSErrorCodeMatcher`` 93 | - ``AWSErrorStatusMatcher`` 94 | - ``AWSSuccessMatcher`` 95 | - ``JMESPathMatcher`` 96 | - ``JMESAllPathMatcher`` 97 | - ``JMESAnyPathMatcher`` 98 | 99 | ### Encoding/Decoding 100 | 101 | - ``QueryEncoder`` 102 | - ``CustomCoding`` 103 | - ``OptionalCustomCoding`` 104 | - ``CustomCoder`` 105 | - ``CustomDecoder`` 106 | - ``CustomEncoder`` 107 | - ``OptionalCustomCodingWrapper`` 108 | - ``ArrayCoder`` 109 | - ``DictionaryCoder`` 110 | - ``ArrayCoderProperties`` 111 | - ``DictionaryCoderProperties`` 112 | - ``StandardArrayCoder`` 113 | - ``StandardDictionaryCoder`` 114 | - ``StandardArrayCoderProperties`` 115 | - ``StandardDictionaryCoderProperties`` 116 | - ``EC2ArrayCoder`` 117 | - ``EC2StandardArrayCoder`` 118 | - ``DateFormatCoder`` 119 | - ``ISO8601DateCoder`` 120 | - ``HTTPHeaderDateCoder`` 121 | - ``UnixEpochDateCoder`` 122 | 123 | ### CRC32 124 | 125 | - ``soto_crc32(_:bytes:)`` 126 | - ``soto_crc32c(_:bytes:)`` 127 | - ``CRC32`` 128 | 129 | ### HTTP Client 130 | 131 | - ``AWSHTTPClient`` 132 | - ``AWSHTTPRequest`` 133 | - ``AWSHTTPResponse`` 134 | - ``AWSHTTPBody`` 135 | 136 | ### Event streams 137 | 138 | - ``AWSEventStream`` 139 | - ``AWSEventPayload`` 140 | - ``AWSEventStreamError`` 141 | 142 | ## See Also 143 | 144 | - ``SotoSignerV4`` 145 | -------------------------------------------------------------------------------- /SotoCore.docc/SotoSignerV4/AWSSigner.md: -------------------------------------------------------------------------------- 1 | # ``SotoSignerV4/AWSSigner`` 2 | 3 | ## Topics 4 | 5 | ### Initializers 6 | 7 | - ``init(credentials:name:region:)`` 8 | 9 | ### Instance Properties 10 | 11 | - ``credentials`` 12 | - ``name`` 13 | - ``region`` 14 | 15 | ### Signing 16 | 17 | - ``signURL(url:method:headers:body:expires:omitSecurityToken:date:)`` 18 | - ``signHeaders(url:method:headers:body:omitSecurityToken:date:)`` 19 | - ``processURL(url:)`` 20 | - ``BodyData`` 21 | 22 | ### Signing streamed data 23 | 24 | - ``startSigningChunks(url:method:headers:date:)`` 25 | - ``signChunk(body:signingData:)`` 26 | - ``ChunkedSigningData`` 27 | -------------------------------------------------------------------------------- /SotoCore.docc/SotoSignerV4/SotoSignerV4.md: -------------------------------------------------------------------------------- 1 | # ``SotoSignerV4`` 2 | 3 | Sign HTTP requests before sending them to AWS either by generating a signed URL or a set of signed headers. 4 | 5 | ## Overview 6 | 7 | ### Initialisation 8 | 9 | To create a `AWSSigner` you need a set of credentials, a signing name and a AWS region. 10 | 11 | ```swift 12 | let credentials: Credential = StaticCredential( 13 | accessKeyId: "_MYACCESSKEY_", 14 | secretAccessKey: "_MYSECRETACCESSKEY_" 15 | ) 16 | let signer = AWSSigner(credentials: credentials, name: "s3", region: "eu-west-1") 17 | ``` 18 | 19 | ### Signed URLs 20 | 21 | A signed URL includes the signature as query parameter `X-Amz-Signature`. The method `signURL` will create a signed URL. 22 | 23 | ```swift 24 | let url = URL(string: "https://my-bucket.s3.eu-west-1.awsamazon.com/file")! 25 | let signedURL = signer.signURL(url: url, method: .GET, expires: .minutes(60)) 26 | ``` 27 | 28 | ### Signed Headers 29 | 30 | Instead of returning a signed URL you can add an additional `authorization` header which includes the signature. Use the method `signHeaders` to create a set of signed headers which you can use with the rest of your request. 31 | 32 | ```swift 33 | let signedHeaders = signer.signHeaders(url: url, method: .GET, headers: headers, body: .byteBuffer(body)) 34 | ``` 35 | 36 | ### Processing requests 37 | 38 | Some request URLs need to be processed before signing. The signer expects query parameters to be alphabetically sorted and that paths have been percent encoded. You can use `processURL` to do this work for you. 39 | 40 | ```swift 41 | let url = URL(string: "https://my-bucket.s3.eu-west-1.awsamazon.com/file")! 42 | let processedURL = signer.processURL(url)! 43 | let signedURL = signer.signURL(url: processedURL, method: .GET, expires: .minutes(60)) 44 | ``` 45 | 46 | You can find out more about the AWS signing process [here](https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html). 47 | 48 | ## Topics 49 | 50 | ### Signer 51 | 52 | - ``AWSSigner`` 53 | 54 | ### Credentials 55 | 56 | - ``Credential`` 57 | - ``StaticCredential`` 58 | 59 | ## See Also 60 | 61 | - ``SotoCore`` -------------------------------------------------------------------------------- /Sources/CSotoExpat/AUTHORS: -------------------------------------------------------------------------------- 1 | Expat is brought to you by: 2 | 3 | Clark Cooper 4 | Fred L. Drake, Jr. 5 | Greg Stein 6 | James Clark 7 | Karl Waclawek 8 | Rhodri James 9 | Sebastian Pipping 10 | Steven Solie 11 | -------------------------------------------------------------------------------- /Sources/CSotoExpat/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper 2 | Copyright (c) 2001-2019 Expat maintainers 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included 13 | in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Sources/CSotoExpat/Makefile.am: -------------------------------------------------------------------------------- 1 | # 2 | # __ __ _ 3 | # ___\ \/ /_ __ __ _| |_ 4 | # / _ \\ /| '_ \ / _` | __| 5 | # | __// \| |_) | (_| | |_ 6 | # \___/_/\_\ .__/ \__,_|\__| 7 | # |_| XML parser 8 | # 9 | # Copyright (c) 2017 Expat development team 10 | # Licensed under the MIT license: 11 | # 12 | # Permission is hereby granted, free of charge, to any person obtaining 13 | # a copy of this software and associated documentation files (the 14 | # "Software"), to deal in the Software without restriction, including 15 | # without limitation the rights to use, copy, modify, merge, publish, 16 | # distribute, sublicense, and/or sell copies of the Software, and to permit 17 | # persons to whom the Software is furnished to do so, subject to the 18 | # following conditions: 19 | # 20 | # The above copyright notice and this permission notice shall be included 21 | # in all copies or substantial portions of the Software. 22 | # 23 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 26 | # NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 27 | # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 28 | # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 29 | # USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | include_HEADERS = \ 32 | ../expat_config.h \ 33 | expat.h \ 34 | expat_external.h 35 | 36 | lib_LTLIBRARIES = libexpat.la 37 | 38 | libexpat_la_LDFLAGS = \ 39 | @AM_LDFLAGS@ \ 40 | -no-undefined \ 41 | -version-info @LIBCURRENT@:@LIBREVISION@:@LIBAGE@ 42 | 43 | libexpat_la_SOURCES = \ 44 | xmlparse.c \ 45 | xmltok.c \ 46 | xmlrole.c 47 | 48 | doc_DATA = \ 49 | ../AUTHORS \ 50 | ../Changes 51 | 52 | install-data-hook: 53 | cd "$(DESTDIR)$(docdir)" && $(am__mv) Changes changelog 54 | 55 | uninstall-local: 56 | $(RM) "$(DESTDIR)$(docdir)/changelog" 57 | 58 | EXTRA_DIST = \ 59 | ascii.h \ 60 | asciitab.h \ 61 | expat_external.h \ 62 | expat.h \ 63 | iasciitab.h \ 64 | internal.h \ 65 | latin1tab.h \ 66 | libexpat.def \ 67 | libexpatw.def \ 68 | nametab.h \ 69 | siphash.h \ 70 | utf8tab.h \ 71 | winconfig.h \ 72 | xmlrole.h \ 73 | xmltok.h \ 74 | xmltok_impl.c \ 75 | xmltok_impl.h \ 76 | xmltok_ns.c 77 | -------------------------------------------------------------------------------- /Sources/CSotoExpat/ascii.h: -------------------------------------------------------------------------------- 1 | /* 2 | __ __ _ 3 | ___\ \/ /_ __ __ _| |_ 4 | / _ \\ /| '_ \ / _` | __| 5 | | __// \| |_) | (_| | |_ 6 | \___/_/\_\ .__/ \__,_|\__| 7 | |_| XML parser 8 | 9 | Copyright (c) 1997-2000 Thai Open Source Software Center Ltd 10 | Copyright (c) 2000-2017 Expat development team 11 | Licensed under the MIT license: 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining 14 | a copy of this software and associated documentation files (the 15 | "Software"), to deal in the Software without restriction, including 16 | without limitation the rights to use, copy, modify, merge, publish, 17 | distribute, sublicense, and/or sell copies of the Software, and to permit 18 | persons to whom the Software is furnished to do so, subject to the 19 | following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included 22 | in all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 27 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 28 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 29 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 30 | USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | */ 32 | 33 | #define ASCII_A 0x41 34 | #define ASCII_B 0x42 35 | #define ASCII_C 0x43 36 | #define ASCII_D 0x44 37 | #define ASCII_E 0x45 38 | #define ASCII_F 0x46 39 | #define ASCII_G 0x47 40 | #define ASCII_H 0x48 41 | #define ASCII_I 0x49 42 | #define ASCII_J 0x4A 43 | #define ASCII_K 0x4B 44 | #define ASCII_L 0x4C 45 | #define ASCII_M 0x4D 46 | #define ASCII_N 0x4E 47 | #define ASCII_O 0x4F 48 | #define ASCII_P 0x50 49 | #define ASCII_Q 0x51 50 | #define ASCII_R 0x52 51 | #define ASCII_S 0x53 52 | #define ASCII_T 0x54 53 | #define ASCII_U 0x55 54 | #define ASCII_V 0x56 55 | #define ASCII_W 0x57 56 | #define ASCII_X 0x58 57 | #define ASCII_Y 0x59 58 | #define ASCII_Z 0x5A 59 | 60 | #define ASCII_a 0x61 61 | #define ASCII_b 0x62 62 | #define ASCII_c 0x63 63 | #define ASCII_d 0x64 64 | #define ASCII_e 0x65 65 | #define ASCII_f 0x66 66 | #define ASCII_g 0x67 67 | #define ASCII_h 0x68 68 | #define ASCII_i 0x69 69 | #define ASCII_j 0x6A 70 | #define ASCII_k 0x6B 71 | #define ASCII_l 0x6C 72 | #define ASCII_m 0x6D 73 | #define ASCII_n 0x6E 74 | #define ASCII_o 0x6F 75 | #define ASCII_p 0x70 76 | #define ASCII_q 0x71 77 | #define ASCII_r 0x72 78 | #define ASCII_s 0x73 79 | #define ASCII_t 0x74 80 | #define ASCII_u 0x75 81 | #define ASCII_v 0x76 82 | #define ASCII_w 0x77 83 | #define ASCII_x 0x78 84 | #define ASCII_y 0x79 85 | #define ASCII_z 0x7A 86 | 87 | #define ASCII_0 0x30 88 | #define ASCII_1 0x31 89 | #define ASCII_2 0x32 90 | #define ASCII_3 0x33 91 | #define ASCII_4 0x34 92 | #define ASCII_5 0x35 93 | #define ASCII_6 0x36 94 | #define ASCII_7 0x37 95 | #define ASCII_8 0x38 96 | #define ASCII_9 0x39 97 | 98 | #define ASCII_TAB 0x09 99 | #define ASCII_SPACE 0x20 100 | #define ASCII_EXCL 0x21 101 | #define ASCII_QUOT 0x22 102 | #define ASCII_AMP 0x26 103 | #define ASCII_APOS 0x27 104 | #define ASCII_MINUS 0x2D 105 | #define ASCII_PERIOD 0x2E 106 | #define ASCII_COLON 0x3A 107 | #define ASCII_SEMI 0x3B 108 | #define ASCII_LT 0x3C 109 | #define ASCII_EQUALS 0x3D 110 | #define ASCII_GT 0x3E 111 | #define ASCII_LSQB 0x5B 112 | #define ASCII_RSQB 0x5D 113 | #define ASCII_UNDERSCORE 0x5F 114 | #define ASCII_LPAREN 0x28 115 | #define ASCII_RPAREN 0x29 116 | #define ASCII_FF 0x0C 117 | #define ASCII_SLASH 0x2F 118 | #define ASCII_HASH 0x23 119 | #define ASCII_PIPE 0x7C 120 | #define ASCII_COMMA 0x2C 121 | -------------------------------------------------------------------------------- /Sources/CSotoExpat/asciitab.h: -------------------------------------------------------------------------------- 1 | /* 2 | __ __ _ 3 | ___\ \/ /_ __ __ _| |_ 4 | / _ \\ /| '_ \ / _` | __| 5 | | __// \| |_) | (_| | |_ 6 | \___/_/\_\ .__/ \__,_|\__| 7 | |_| XML parser 8 | 9 | Copyright (c) 1997-2000 Thai Open Source Software Center Ltd 10 | Copyright (c) 2000-2017 Expat development team 11 | Licensed under the MIT license: 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining 14 | a copy of this software and associated documentation files (the 15 | "Software"), to deal in the Software without restriction, including 16 | without limitation the rights to use, copy, modify, merge, publish, 17 | distribute, sublicense, and/or sell copies of the Software, and to permit 18 | persons to whom the Software is furnished to do so, subject to the 19 | following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included 22 | in all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 27 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 28 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 29 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 30 | USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | */ 32 | 33 | /* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, 34 | /* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, 35 | /* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, 36 | /* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML, 37 | /* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, 38 | /* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, 39 | /* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, 40 | /* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, 41 | /* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, 42 | /* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, 43 | /* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, 44 | /* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, 45 | /* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, 46 | /* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, 47 | /* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, 48 | /* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, 49 | /* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, 50 | /* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, 51 | /* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 52 | /* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 53 | /* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 54 | /* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 55 | /* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, 56 | /* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, 57 | /* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, 58 | /* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, 59 | /* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 60 | /* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 61 | /* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 62 | /* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 63 | /* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, 64 | /* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, 65 | -------------------------------------------------------------------------------- /Sources/CSotoExpat/expat_config.h: -------------------------------------------------------------------------------- 1 | /* expat_config.h. Generated from expat_config.h.in by configure. */ 2 | /* expat_config.h.in. Generated from configure.ac by autoheader. */ 3 | 4 | /* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */ 5 | #define BYTEORDER 1234 6 | 7 | /* Define to 1 if you have the `arc4random' function. */ 8 | /* #undef HAVE_ARC4RANDOM */ 9 | 10 | /* Define to 1 if you have the `arc4random_buf' function. */ 11 | /* #undef HAVE_ARC4RANDOM_BUF */ 12 | 13 | /* Define to 1 if you have the `bcopy' function. */ 14 | #define HAVE_BCOPY 1 15 | 16 | /* Define to 1 if you have the header file. */ 17 | #define HAVE_DLFCN_H 1 18 | 19 | /* Define to 1 if you have the header file. */ 20 | #define HAVE_FCNTL_H 1 21 | 22 | /* Define to 1 if you have the `getpagesize' function. */ 23 | #define HAVE_GETPAGESIZE 1 24 | 25 | /* Define to 1 if you have the `getrandom' function. */ 26 | /* #undef HAVE_GETRANDOM */ 27 | 28 | /* Define to 1 if you have the header file. */ 29 | #define HAVE_INTTYPES_H 1 30 | 31 | /* Define to 1 if you have the `bsd' library (-lbsd). */ 32 | /* #undef HAVE_LIBBSD */ 33 | 34 | /* Define to 1 if you have the `memmove' function. */ 35 | #define HAVE_MEMMOVE 1 36 | 37 | /* Define to 1 if you have the header file. */ 38 | #define HAVE_MEMORY_H 1 39 | 40 | /* Define to 1 if you have a working `mmap' system call. */ 41 | #define HAVE_MMAP 1 42 | 43 | /* Define to 1 if you have the header file. */ 44 | #define HAVE_STDINT_H 1 45 | 46 | /* Define to 1 if you have the header file. */ 47 | #define HAVE_STDLIB_H 1 48 | 49 | /* Define to 1 if you have the header file. */ 50 | #define HAVE_STRINGS_H 1 51 | 52 | /* Define to 1 if you have the header file. */ 53 | #define HAVE_STRING_H 1 54 | 55 | /* Define to 1 if you have `syscall' and `SYS_getrandom'. */ 56 | /* #undef HAVE_SYSCALL_GETRANDOM */ 57 | 58 | /* Define to 1 if you have the header file. */ 59 | #define HAVE_SYS_PARAM_H 1 60 | 61 | /* Define to 1 if you have the header file. */ 62 | #define HAVE_SYS_STAT_H 1 63 | 64 | /* Define to 1 if you have the header file. */ 65 | #define HAVE_SYS_TYPES_H 1 66 | 67 | /* Define to 1 if you have the header file. */ 68 | #define HAVE_UNISTD_H 1 69 | 70 | /* Define to the sub-directory where libtool stores uninstalled libraries. */ 71 | #define LT_OBJDIR ".libs/" 72 | 73 | /* Name of package */ 74 | #define PACKAGE "expat" 75 | 76 | /* Define to the address where bug reports for this package should be sent. */ 77 | #define PACKAGE_BUGREPORT "expat-bugs@libexpat.org" 78 | 79 | /* Define to the full name of this package. */ 80 | #define PACKAGE_NAME "expat" 81 | 82 | /* Define to the full name and version of this package. */ 83 | #define PACKAGE_STRING "expat 2.2.9" 84 | 85 | /* Define to the one symbol short name of this package. */ 86 | #define PACKAGE_TARNAME "expat" 87 | 88 | /* Define to the home page for this package. */ 89 | #define PACKAGE_URL "" 90 | 91 | /* Define to the version of this package. */ 92 | #define PACKAGE_VERSION "2.2.9" 93 | 94 | /* Define to 1 if you have the ANSI C header files. */ 95 | #define STDC_HEADERS 1 96 | 97 | /* Version number of package */ 98 | #define VERSION "2.2.9" 99 | 100 | /* whether byteorder is bigendian */ 101 | /* #undef WORDS_BIGENDIAN */ 102 | 103 | /* Define to specify how much context to retain around the current parse 104 | point. */ 105 | #define XML_CONTEXT_BYTES 1024 106 | 107 | /* Define to include code reading entropy from `/dev/urandom'. */ 108 | #define XML_DEV_URANDOM 1 109 | 110 | /* Define to make parameter entity parsing functionality available. */ 111 | /* Do not need DTD code in Soto */ 112 | /*#define XML_DTD 1*/ 113 | 114 | /* Define to make XML Namespaces functionality available. */ 115 | /*#define XML_NS 1*/ 116 | 117 | /* Define to empty if `const' does not conform to ANSI C. */ 118 | /* #undef const */ 119 | 120 | /* Define to `long int' if does not define. */ 121 | /* #undef off_t */ 122 | 123 | /* Define to `unsigned int' if does not define. */ 124 | /* #undef size_t */ 125 | -------------------------------------------------------------------------------- /Sources/CSotoExpat/iasciitab.h: -------------------------------------------------------------------------------- 1 | /* 2 | __ __ _ 3 | ___\ \/ /_ __ __ _| |_ 4 | / _ \\ /| '_ \ / _` | __| 5 | | __// \| |_) | (_| | |_ 6 | \___/_/\_\ .__/ \__,_|\__| 7 | |_| XML parser 8 | 9 | Copyright (c) 1997-2000 Thai Open Source Software Center Ltd 10 | Copyright (c) 2000-2017 Expat development team 11 | Licensed under the MIT license: 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining 14 | a copy of this software and associated documentation files (the 15 | "Software"), to deal in the Software without restriction, including 16 | without limitation the rights to use, copy, modify, merge, publish, 17 | distribute, sublicense, and/or sell copies of the Software, and to permit 18 | persons to whom the Software is furnished to do so, subject to the 19 | following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included 22 | in all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 27 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 28 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 29 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 30 | USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | */ 32 | 33 | /* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */ 34 | /* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, 35 | /* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, 36 | /* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, 37 | /* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML, 38 | /* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, 39 | /* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, 40 | /* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, 41 | /* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, 42 | /* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, 43 | /* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, 44 | /* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, 45 | /* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, 46 | /* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, 47 | /* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, 48 | /* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, 49 | /* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, 50 | /* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, 51 | /* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, 52 | /* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 53 | /* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 54 | /* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 55 | /* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 56 | /* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, 57 | /* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, 58 | /* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, 59 | /* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, 60 | /* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 61 | /* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 62 | /* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 63 | /* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 64 | /* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, 65 | /* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, 66 | -------------------------------------------------------------------------------- /Sources/CSotoExpat/latin1tab.h: -------------------------------------------------------------------------------- 1 | /* 2 | __ __ _ 3 | ___\ \/ /_ __ __ _| |_ 4 | / _ \\ /| '_ \ / _` | __| 5 | | __// \| |_) | (_| | |_ 6 | \___/_/\_\ .__/ \__,_|\__| 7 | |_| XML parser 8 | 9 | Copyright (c) 1997-2000 Thai Open Source Software Center Ltd 10 | Copyright (c) 2000-2017 Expat development team 11 | Licensed under the MIT license: 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining 14 | a copy of this software and associated documentation files (the 15 | "Software"), to deal in the Software without restriction, including 16 | without limitation the rights to use, copy, modify, merge, publish, 17 | distribute, sublicense, and/or sell copies of the Software, and to permit 18 | persons to whom the Software is furnished to do so, subject to the 19 | following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included 22 | in all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 27 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 28 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 29 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 30 | USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | */ 32 | 33 | /* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, 34 | /* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, 35 | /* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, 36 | /* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, 37 | /* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, 38 | /* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, 39 | /* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, 40 | /* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, 41 | /* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, 42 | /* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, 43 | /* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, 44 | /* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, 45 | /* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, 46 | /* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME, 47 | /* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, 48 | /* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, 49 | /* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 50 | /* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 51 | /* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 52 | /* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 53 | /* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 54 | /* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, 55 | /* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 56 | /* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 57 | /* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 58 | /* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 59 | /* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 60 | /* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 61 | /* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 62 | /* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, 63 | /* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 64 | /* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, 65 | -------------------------------------------------------------------------------- /Sources/CSotoExpat/libexpat.def: -------------------------------------------------------------------------------- 1 | ; DEF file for MS VC++ 2 | 3 | LIBRARY 4 | EXPORTS 5 | XML_DefaultCurrent @1 6 | XML_ErrorString @2 7 | XML_ExpatVersion @3 8 | XML_ExpatVersionInfo @4 9 | XML_ExternalEntityParserCreate @5 10 | XML_GetBase @6 11 | XML_GetBuffer @7 12 | XML_GetCurrentByteCount @8 13 | XML_GetCurrentByteIndex @9 14 | XML_GetCurrentColumnNumber @10 15 | XML_GetCurrentLineNumber @11 16 | XML_GetErrorCode @12 17 | XML_GetIdAttributeIndex @13 18 | XML_GetInputContext @14 19 | XML_GetSpecifiedAttributeCount @15 20 | XML_Parse @16 21 | XML_ParseBuffer @17 22 | XML_ParserCreate @18 23 | XML_ParserCreateNS @19 24 | XML_ParserCreate_MM @20 25 | XML_ParserFree @21 26 | XML_SetAttlistDeclHandler @22 27 | XML_SetBase @23 28 | XML_SetCdataSectionHandler @24 29 | XML_SetCharacterDataHandler @25 30 | XML_SetCommentHandler @26 31 | XML_SetDefaultHandler @27 32 | XML_SetDefaultHandlerExpand @28 33 | XML_SetDoctypeDeclHandler @29 34 | XML_SetElementDeclHandler @30 35 | XML_SetElementHandler @31 36 | XML_SetEncoding @32 37 | XML_SetEndCdataSectionHandler @33 38 | XML_SetEndDoctypeDeclHandler @34 39 | XML_SetEndElementHandler @35 40 | XML_SetEndNamespaceDeclHandler @36 41 | XML_SetEntityDeclHandler @37 42 | XML_SetExternalEntityRefHandler @38 43 | XML_SetExternalEntityRefHandlerArg @39 44 | XML_SetNamespaceDeclHandler @40 45 | XML_SetNotStandaloneHandler @41 46 | XML_SetNotationDeclHandler @42 47 | XML_SetParamEntityParsing @43 48 | XML_SetProcessingInstructionHandler @44 49 | XML_SetReturnNSTriplet @45 50 | XML_SetStartCdataSectionHandler @46 51 | XML_SetStartDoctypeDeclHandler @47 52 | XML_SetStartElementHandler @48 53 | XML_SetStartNamespaceDeclHandler @49 54 | XML_SetUnknownEncodingHandler @50 55 | XML_SetUnparsedEntityDeclHandler @51 56 | XML_SetUserData @52 57 | XML_SetXmlDeclHandler @53 58 | XML_UseParserAsHandlerArg @54 59 | ; added with version 1.95.3 60 | XML_ParserReset @55 61 | XML_SetSkippedEntityHandler @56 62 | ; added with version 1.95.5 63 | XML_GetFeatureList @57 64 | XML_UseForeignDTD @58 65 | ; added with version 1.95.6 66 | XML_FreeContentModel @59 67 | XML_MemMalloc @60 68 | XML_MemRealloc @61 69 | XML_MemFree @62 70 | ; added with version 1.95.8 71 | XML_StopParser @63 72 | XML_ResumeParser @64 73 | XML_GetParsingStatus @65 74 | ; added with version 2.1.1 75 | ; XML_GetAttributeInfo @66 76 | XML_SetHashSalt @67 77 | ; added with version 2.2.5 78 | _INTERNAL_trim_to_complete_utf8_characters @68 79 | -------------------------------------------------------------------------------- /Sources/CSotoExpat/libexpatw.def: -------------------------------------------------------------------------------- 1 | ; DEF file for MS VC++ 2 | 3 | LIBRARY 4 | EXPORTS 5 | XML_DefaultCurrent @1 6 | XML_ErrorString @2 7 | XML_ExpatVersion @3 8 | XML_ExpatVersionInfo @4 9 | XML_ExternalEntityParserCreate @5 10 | XML_GetBase @6 11 | XML_GetBuffer @7 12 | XML_GetCurrentByteCount @8 13 | XML_GetCurrentByteIndex @9 14 | XML_GetCurrentColumnNumber @10 15 | XML_GetCurrentLineNumber @11 16 | XML_GetErrorCode @12 17 | XML_GetIdAttributeIndex @13 18 | XML_GetInputContext @14 19 | XML_GetSpecifiedAttributeCount @15 20 | XML_Parse @16 21 | XML_ParseBuffer @17 22 | XML_ParserCreate @18 23 | XML_ParserCreateNS @19 24 | XML_ParserCreate_MM @20 25 | XML_ParserFree @21 26 | XML_SetAttlistDeclHandler @22 27 | XML_SetBase @23 28 | XML_SetCdataSectionHandler @24 29 | XML_SetCharacterDataHandler @25 30 | XML_SetCommentHandler @26 31 | XML_SetDefaultHandler @27 32 | XML_SetDefaultHandlerExpand @28 33 | XML_SetDoctypeDeclHandler @29 34 | XML_SetElementDeclHandler @30 35 | XML_SetElementHandler @31 36 | XML_SetEncoding @32 37 | XML_SetEndCdataSectionHandler @33 38 | XML_SetEndDoctypeDeclHandler @34 39 | XML_SetEndElementHandler @35 40 | XML_SetEndNamespaceDeclHandler @36 41 | XML_SetEntityDeclHandler @37 42 | XML_SetExternalEntityRefHandler @38 43 | XML_SetExternalEntityRefHandlerArg @39 44 | XML_SetNamespaceDeclHandler @40 45 | XML_SetNotStandaloneHandler @41 46 | XML_SetNotationDeclHandler @42 47 | XML_SetParamEntityParsing @43 48 | XML_SetProcessingInstructionHandler @44 49 | XML_SetReturnNSTriplet @45 50 | XML_SetStartCdataSectionHandler @46 51 | XML_SetStartDoctypeDeclHandler @47 52 | XML_SetStartElementHandler @48 53 | XML_SetStartNamespaceDeclHandler @49 54 | XML_SetUnknownEncodingHandler @50 55 | XML_SetUnparsedEntityDeclHandler @51 56 | XML_SetUserData @52 57 | XML_SetXmlDeclHandler @53 58 | XML_UseParserAsHandlerArg @54 59 | ; added with version 1.95.3 60 | XML_ParserReset @55 61 | XML_SetSkippedEntityHandler @56 62 | ; added with version 1.95.5 63 | XML_GetFeatureList @57 64 | XML_UseForeignDTD @58 65 | ; added with version 1.95.6 66 | XML_FreeContentModel @59 67 | XML_MemMalloc @60 68 | XML_MemRealloc @61 69 | XML_MemFree @62 70 | ; added with version 1.95.8 71 | XML_StopParser @63 72 | XML_ResumeParser @64 73 | XML_GetParsingStatus @65 74 | ; added with version 2.1.1 75 | ; XML_GetAttributeInfo @66 76 | XML_SetHashSalt @67 77 | ; added with version 2.2.5 78 | _INTERNAL_trim_to_complete_utf8_characters @68 79 | -------------------------------------------------------------------------------- /Sources/CSotoExpat/utf8tab.h: -------------------------------------------------------------------------------- 1 | /* 2 | __ __ _ 3 | ___\ \/ /_ __ __ _| |_ 4 | / _ \\ /| '_ \ / _` | __| 5 | | __// \| |_) | (_| | |_ 6 | \___/_/\_\ .__/ \__,_|\__| 7 | |_| XML parser 8 | 9 | Copyright (c) 1997-2000 Thai Open Source Software Center Ltd 10 | Copyright (c) 2000-2017 Expat development team 11 | Licensed under the MIT license: 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining 14 | a copy of this software and associated documentation files (the 15 | "Software"), to deal in the Software without restriction, including 16 | without limitation the rights to use, copy, modify, merge, publish, 17 | distribute, sublicense, and/or sell copies of the Software, and to permit 18 | persons to whom the Software is furnished to do so, subject to the 19 | following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included 22 | in all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 27 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 28 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 29 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 30 | USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | */ 32 | 33 | /* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, 34 | /* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, 35 | /* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, 36 | /* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, 37 | /* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, 38 | /* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, 39 | /* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, 40 | /* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, 41 | /* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, 42 | /* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, 43 | /* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, 44 | /* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, 45 | /* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, 46 | /* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, 47 | /* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, 48 | /* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, 49 | /* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, 50 | /* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, 51 | /* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, 52 | /* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, 53 | /* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, 54 | /* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, 55 | /* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, 56 | /* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, 57 | /* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, 58 | /* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, 59 | /* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, 60 | /* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, 61 | /* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4, 62 | /* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML, 63 | /* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, 64 | /* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM, 65 | -------------------------------------------------------------------------------- /Sources/CSotoExpat/winconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | __ __ _ 3 | ___\ \/ /_ __ __ _| |_ 4 | / _ \\ /| '_ \ / _` | __| 5 | | __// \| |_) | (_| | |_ 6 | \___/_/\_\ .__/ \__,_|\__| 7 | |_| XML parser 8 | 9 | Copyright (c) 1997-2000 Thai Open Source Software Center Ltd 10 | Copyright (c) 2000-2017 Expat development team 11 | Licensed under the MIT license: 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining 14 | a copy of this software and associated documentation files (the 15 | "Software"), to deal in the Software without restriction, including 16 | without limitation the rights to use, copy, modify, merge, publish, 17 | distribute, sublicense, and/or sell copies of the Software, and to permit 18 | persons to whom the Software is furnished to do so, subject to the 19 | following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included 22 | in all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 27 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 28 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 29 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 30 | USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | */ 32 | 33 | #ifndef WINCONFIG_H 34 | #define WINCONFIG_H 35 | 36 | #define WIN32_LEAN_AND_MEAN 37 | #include 38 | #undef WIN32_LEAN_AND_MEAN 39 | 40 | #include 41 | #include 42 | 43 | #if defined(HAVE_EXPAT_CONFIG_H) /* e.g. MinGW */ 44 | # include 45 | #else /* !defined(HAVE_EXPAT_CONFIG_H) */ 46 | 47 | # define XML_NS 1 48 | # define XML_DTD 1 49 | # define XML_CONTEXT_BYTES 1024 50 | 51 | /* we will assume all Windows platforms are little endian */ 52 | # define BYTEORDER 1234 53 | 54 | #endif /* !defined(HAVE_EXPAT_CONFIG_H) */ 55 | 56 | #endif /* ndef WINCONFIG_H */ 57 | -------------------------------------------------------------------------------- /Sources/CSotoExpat/xmltok_impl.h: -------------------------------------------------------------------------------- 1 | /* 2 | __ __ _ 3 | ___\ \/ /_ __ __ _| |_ 4 | / _ \\ /| '_ \ / _` | __| 5 | | __// \| |_) | (_| | |_ 6 | \___/_/\_\ .__/ \__,_|\__| 7 | |_| XML parser 8 | 9 | Copyright (c) 1997-2000 Thai Open Source Software Center Ltd 10 | Copyright (c) 2000-2017 Expat development team 11 | Licensed under the MIT license: 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining 14 | a copy of this software and associated documentation files (the 15 | "Software"), to deal in the Software without restriction, including 16 | without limitation the rights to use, copy, modify, merge, publish, 17 | distribute, sublicense, and/or sell copies of the Software, and to permit 18 | persons to whom the Software is furnished to do so, subject to the 19 | following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included 22 | in all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 27 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 28 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 29 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 30 | USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | */ 32 | 33 | enum { 34 | BT_NONXML, /* e.g. noncharacter-FFFF */ 35 | BT_MALFORM, /* illegal, with regard to encoding */ 36 | BT_LT, /* less than = "<" */ 37 | BT_AMP, /* ampersand = "&" */ 38 | BT_RSQB, /* right square bracket = "[" */ 39 | BT_LEAD2, /* lead byte of a 2-byte UTF-8 character */ 40 | BT_LEAD3, /* lead byte of a 3-byte UTF-8 character */ 41 | BT_LEAD4, /* lead byte of a 4-byte UTF-8 character */ 42 | BT_TRAIL, /* trailing unit, e.g. second 16-bit unit of a 4-byte char. */ 43 | BT_CR, /* carriage return = "\r" */ 44 | BT_LF, /* line feed = "\n" */ 45 | BT_GT, /* greater than = ">" */ 46 | BT_QUOT, /* quotation character = "\"" */ 47 | BT_APOS, /* aposthrophe = "'" */ 48 | BT_EQUALS, /* equal sign = "=" */ 49 | BT_QUEST, /* question mark = "?" */ 50 | BT_EXCL, /* exclamation mark = "!" */ 51 | BT_SOL, /* solidus, slash = "/" */ 52 | BT_SEMI, /* semicolon = ";" */ 53 | BT_NUM, /* number sign = "#" */ 54 | BT_LSQB, /* left square bracket = "[" */ 55 | BT_S, /* white space, e.g. "\t", " "[, "\r"] */ 56 | BT_NMSTRT, /* non-hex name start letter = "G".."Z" + "g".."z" + "_" */ 57 | BT_COLON, /* colon = ":" */ 58 | BT_HEX, /* hex letter = "A".."F" + "a".."f" */ 59 | BT_DIGIT, /* digit = "0".."9" */ 60 | BT_NAME, /* dot and middle dot = "." + chr(0xb7) */ 61 | BT_MINUS, /* minus = "-" */ 62 | BT_OTHER, /* known not to be a name or name start character */ 63 | BT_NONASCII, /* might be a name or name start character */ 64 | BT_PERCNT, /* percent sign = "%" */ 65 | BT_LPAR, /* left parenthesis = "(" */ 66 | BT_RPAR, /* right parenthesis = "(" */ 67 | BT_AST, /* asterisk = "*" */ 68 | BT_PLUS, /* plus sign = "+" */ 69 | BT_COMMA, /* comma = "," */ 70 | BT_VERBAR /* vertical bar = "|" */ 71 | }; 72 | 73 | #include 74 | -------------------------------------------------------------------------------- /Sources/SotoCore/AWSClient+Paginate.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Logging 16 | import NIOCore 17 | 18 | /// Protocol for all AWSShapes that can be paginated. 19 | /// Adds an initialiser that does a copy but inserts a new integer based pagination token 20 | public protocol AWSPaginateToken: AWSShape { 21 | associatedtype Token 22 | func usingPaginationToken(_ token: Token) -> Self 23 | } 24 | 25 | extension AWSClient { 26 | /// Used to access paginated results. 27 | public struct PaginatorSequence: AsyncSequence where Input.Token: Equatable { 28 | public typealias Element = Output 29 | let input: Input 30 | let command: (Input, Logger) async throws -> Output 31 | let inputKey: KeyPath? 32 | let outputKey: KeyPath 33 | let moreResultsKey: KeyPath? 34 | let logger: Logger 35 | 36 | /// Initialize PaginatorSequence 37 | /// - Parameters: 38 | /// - input: Initial Input value 39 | /// - command: Command to be paginated 40 | /// - inputKey: Optional KeyPath for Input token to compare against new key from Output 41 | /// - outputKey: KeyPath for Output token used to read new Output 42 | /// - moreResultsKey: Optional KeyPath for value indicating whether there are more results 43 | /// - logger: Logger 44 | public init( 45 | input: Input, 46 | command: @escaping ((Input, Logger) async throws -> Output), 47 | inputKey: KeyPath? = nil, 48 | outputKey: KeyPath, 49 | moreResultsKey: KeyPath? = nil, 50 | logger: Logger = AWSClient.loggingDisabled 51 | ) { 52 | self.input = input 53 | self.command = command 54 | self.outputKey = outputKey 55 | self.inputKey = inputKey 56 | self.moreResultsKey = moreResultsKey 57 | self.logger = AWSClient.loggingDisabled 58 | } 59 | 60 | /// Iterator for iterating over `PaginatorSequence` 61 | public struct AsyncIterator: AsyncIteratorProtocol { 62 | var input: Input? 63 | let sequence: PaginatorSequence 64 | 65 | init(sequence: PaginatorSequence) { 66 | self.sequence = sequence 67 | self.input = sequence.input 68 | } 69 | 70 | public mutating func next() async throws -> Output? { 71 | if let input { 72 | let output = try await self.sequence.command(input, self.sequence.logger) 73 | if let token = output[keyPath: sequence.outputKey], 74 | sequence.inputKey == nil || token != input[keyPath: sequence.inputKey!], 75 | sequence.moreResultsKey == nil || output[keyPath: sequence.moreResultsKey!] == true 76 | { 77 | self.input = input.usingPaginationToken(token) 78 | } else { 79 | self.input = nil 80 | } 81 | return output 82 | } 83 | return nil 84 | } 85 | } 86 | 87 | /// Make async iterator 88 | public func makeAsyncIterator() -> AsyncIterator { 89 | AsyncIterator(sequence: self) 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Sources/SotoCore/AWSEndpointDiscovery.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2021-2022 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Logging 16 | import NIOConcurrencyHelpers 17 | import NIOCore 18 | 19 | import struct Foundation.Date 20 | import struct Foundation.TimeInterval 21 | 22 | /// Endpoint list 23 | public struct AWSEndpoints { 24 | public struct Endpoint { 25 | public init(address: String, cachePeriodInMinutes: Int64) { 26 | self.address = address 27 | self.cachePeriodInMinutes = cachePeriodInMinutes 28 | } 29 | 30 | /// An endpoint address. 31 | let address: String 32 | /// The TTL for the endpoint, in minutes. 33 | let cachePeriodInMinutes: Int64 34 | } 35 | 36 | public init(endpoints: [Endpoint]) { 37 | self.endpoints = endpoints 38 | } 39 | 40 | let endpoints: [Endpoint] 41 | } 42 | 43 | /// Endpoint Storage attached to a Service 44 | public struct AWSEndpointStorage: Sendable { 45 | let endpoint: ExpiringValue 46 | 47 | // TODO: Initialise endpoint storage with an endpoint 48 | public init() { 49 | // Set endpoint to renew 3 minutes before it expires 50 | self.endpoint = .init(threshold: 3 * 60) 51 | } 52 | 53 | public func getValue(getExpiringValue: @escaping @Sendable () async throws -> (String, Date)) async throws -> String { 54 | try await self.endpoint.getValue(getExpiringValue: getExpiringValue) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/SotoCore/AWSShapes/Base64Data.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2022 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | /// Holds request or response data that is encoded as base64 during transit 16 | public struct AWSBase64Data: Sendable, Codable, Equatable { 17 | let base64String: String 18 | 19 | /// Initialise AWSBase64Data 20 | /// - Parameter base64String: base64 encoded data 21 | private init(base64String: String) { 22 | self.base64String = base64String 23 | } 24 | 25 | /// construct `AWSBase64Data` from raw data 26 | public static func data(_ data: some Collection) -> Self { 27 | .init(base64String: String(_base64Encoding: data, options: [])) 28 | } 29 | 30 | /// construct `AWSBase64Data` from base64 encoded data 31 | public static func base64(_ base64String: String) -> Self { 32 | .init(base64String: base64String) 33 | } 34 | 35 | /// Codable decode 36 | public init(from decoder: Decoder) throws { 37 | let container = try decoder.singleValueContainer() 38 | self.base64String = try container.decode(String.self) 39 | } 40 | 41 | /// Codable encode 42 | public func encode(to encoder: Encoder) throws { 43 | var container = encoder.singleValueContainer() 44 | try container.encode(self.base64String) 45 | } 46 | 47 | /// size of base64 data 48 | public var base64count: Int { 49 | self.base64String.count 50 | } 51 | 52 | /// return blob as Data 53 | public func decoded() -> [UInt8]? { 54 | try? self.base64String._base64Decoded() 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/SotoCore/AWSShapes/Document.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | /// Document value that can hold arbitrary data 16 | /// 17 | /// (See https://smithy.io/2.0/spec/simple-types.html#document) 18 | public enum AWSDocument: Sendable, Codable, Equatable { 19 | case string(String) 20 | case double(Double) 21 | case integer(Int) 22 | case boolean(Bool) 23 | case array([AWSDocument]) 24 | case map([String: AWSDocument]) 25 | case null 26 | 27 | public init(from decoder: any Decoder) throws { 28 | let container = try decoder.singleValueContainer() 29 | if let string = try? container.decode(String.self) { 30 | self = .string(string) 31 | } else if let integer = try? container.decode(Int.self) { 32 | self = .integer(integer) 33 | } else if let double = try? container.decode(Double.self) { 34 | self = .double(double) 35 | } else if let boolean = try? container.decode(Bool.self) { 36 | self = .boolean(boolean) 37 | } else if let array = try? container.decode([AWSDocument].self) { 38 | self = .array(array) 39 | } else if let map = try? container.decode([String: AWSDocument].self) { 40 | self = .map(map) 41 | } else if container.decodeNil() { 42 | self = .null 43 | } else { 44 | throw DecodingError.typeMismatch(AWSDocument.self, .init(codingPath: decoder.codingPath, debugDescription: "Failed to decode")) 45 | } 46 | } 47 | 48 | public func encode(to encoder: any Encoder) throws { 49 | var container = encoder.singleValueContainer() 50 | switch self { 51 | case .string(let value): try container.encode(value) 52 | case .integer(let value): try container.encode(value) 53 | case .double(let value): try container.encode(value) 54 | case .boolean(let value): try container.encode(value) 55 | case .array(let value): try container.encode(value) 56 | case .map(let value): try container.encode(value) 57 | case .null: try container.encodeNil() 58 | } 59 | } 60 | } 61 | 62 | extension AWSDocument: ExpressibleByStringLiteral { 63 | public init(stringLiteral value: StringLiteralType) { 64 | self = .string(value) 65 | } 66 | } 67 | extension AWSDocument: ExpressibleByIntegerLiteral { 68 | public init(integerLiteral value: IntegerLiteralType) { 69 | self = .integer(value) 70 | } 71 | } 72 | extension AWSDocument: ExpressibleByFloatLiteral { 73 | public init(floatLiteral value: FloatLiteralType) { 74 | self = .double(value) 75 | } 76 | } 77 | extension AWSDocument: ExpressibleByBooleanLiteral { 78 | public init(booleanLiteral value: BooleanLiteralType) { 79 | self = .boolean(value) 80 | } 81 | } 82 | extension AWSDocument: ExpressibleByArrayLiteral { 83 | public init(arrayLiteral values: AWSDocument...) { 84 | self = .array(values) 85 | } 86 | } 87 | extension AWSDocument: ExpressibleByDictionaryLiteral { 88 | public init(dictionaryLiteral values: (String, AWSDocument)...) { 89 | self = .map(.init(values) { first, _ in first }) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Sources/SotoCore/AWSShapes/EventPayload.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | /// Event payload type. To aid encoding and decoding 16 | public struct AWSEventPayload: Sendable, Codable, Equatable { 17 | public let buffer: ByteBuffer 18 | 19 | /// Initialise AWSEventPayload 20 | /// - Parameter payload: Event Payload 21 | private init(buffer: ByteBuffer) { 22 | self.buffer = buffer 23 | } 24 | 25 | /// Codable decode 26 | public init(from decoder: Decoder) throws { 27 | let response = decoder.userInfo[.awsEvent]! as! EventDecodingContainer 28 | self.buffer = response.decodePayload() 29 | } 30 | 31 | /// Codable encode 32 | public func encode(to encoder: Encoder) throws { 33 | preconditionFailure("Event encoding is not supported yet") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/SotoCore/Concurrency/AnyAsyncSequence.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | //===----------------------------------------------------------------------===// 15 | // 16 | // This source file is part of the AsyncHTTPClient open source project 17 | // 18 | // Copyright (c) 2022 Apple Inc. and the AsyncHTTPClient project authors 19 | // Licensed under Apache License v2.0 20 | // 21 | // See LICENSE.txt for license information 22 | // See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors 23 | // 24 | // SPDX-License-Identifier: Apache-2.0 25 | // 26 | //===----------------------------------------------------------------------===// 27 | 28 | public struct AnyAsyncSequence: Sendable, AsyncSequence { 29 | public typealias AsyncIteratorNextCallback = () async throws -> Element? 30 | 31 | public struct AsyncIterator: AsyncIteratorProtocol { 32 | @usableFromInline let nextCallback: AsyncIteratorNextCallback 33 | 34 | @inlinable init(nextCallback: @escaping AsyncIteratorNextCallback) { 35 | self.nextCallback = nextCallback 36 | } 37 | 38 | @inlinable public mutating func next() async throws -> Element? { 39 | try await self.nextCallback() 40 | } 41 | } 42 | 43 | @usableFromInline var makeAsyncIteratorCallback: @Sendable () -> AsyncIteratorNextCallback 44 | 45 | @inlinable public init( 46 | _ asyncSequence: SequenceOfBytes 47 | ) where SequenceOfBytes: AsyncSequence & Sendable, SequenceOfBytes.Element == Element { 48 | self.makeAsyncIteratorCallback = { 49 | var iterator = asyncSequence.makeAsyncIterator() 50 | return { 51 | try await iterator.next() 52 | } 53 | } 54 | } 55 | 56 | @inlinable public func makeAsyncIterator() -> AsyncIterator { 57 | .init(nextCallback: self.makeAsyncIteratorCallback()) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Sources/SotoCore/Concurrency/ByteBufferSequence.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import NIOCore 16 | import NIOPosix 17 | 18 | /// Provide ByteBuffer as an AsyncSequence of equal size blocks 19 | public struct ByteBufferAsyncSequence: AsyncSequence, Sendable { 20 | public typealias Element = ByteBuffer 21 | 22 | @usableFromInline 23 | let byteBuffer: ByteBuffer 24 | @usableFromInline 25 | let chunkSize: Int 26 | 27 | @inlinable 28 | init( 29 | _ byteBuffer: ByteBuffer, 30 | chunkSize: Int 31 | ) { 32 | self.byteBuffer = byteBuffer 33 | self.chunkSize = chunkSize 34 | } 35 | 36 | public struct AsyncIterator: AsyncIteratorProtocol { 37 | @usableFromInline 38 | var byteBuffer: ByteBuffer 39 | @usableFromInline 40 | let chunkSize: Int 41 | 42 | @inlinable 43 | internal init(byteBuffer: ByteBuffer, chunkSize: Int) { 44 | self.byteBuffer = byteBuffer 45 | self.chunkSize = chunkSize 46 | } 47 | 48 | @inlinable 49 | public mutating func next() async throws -> ByteBuffer? { 50 | let size = Swift.min(self.chunkSize, self.byteBuffer.readableBytes) 51 | if size > 0 { 52 | return self.byteBuffer.readSlice(length: size) 53 | } 54 | return nil 55 | } 56 | } 57 | 58 | @inlinable 59 | public func makeAsyncIterator() -> AsyncIterator { 60 | .init(byteBuffer: self.byteBuffer, chunkSize: self.chunkSize) 61 | } 62 | } 63 | 64 | extension ByteBuffer { 65 | @inlinable 66 | public func asyncSequence(chunkSize: Int) -> ByteBufferAsyncSequence { 67 | ByteBufferAsyncSequence(self, chunkSize: chunkSize) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Sources/SotoCore/Concurrency/EventStream.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Foundation 16 | import NIOCore 17 | 18 | /// AsyncSequence of Event stream events 19 | public struct AWSEventStream: Sendable { 20 | let base: AnyAsyncSequence 21 | 22 | /// Initialise AWSEventStream from an AsyncSequence of ByteBuffers 23 | init(_ base: BaseSequence) where BaseSequence.Element == ByteBuffer { 24 | self.base = .init(base) 25 | } 26 | } 27 | 28 | extension AWSEventStream: Decodable where Event: Decodable { 29 | public init(from decoder: Decoder) throws { 30 | let responseContainer = decoder.userInfo[.awsResponse]! as! ResponseDecodingContainer 31 | self.init(responseContainer.response.body) 32 | } 33 | } 34 | 35 | extension AWSEventStream: Encodable where Event: Encodable { 36 | public func encode(to encoder: Encoder) throws { 37 | preconditionFailure("Encoding EventStreams is unsupported") 38 | } 39 | } 40 | 41 | /// If Event is decodable then conform AWSEventStream to AsyncSequence 42 | extension AWSEventStream: AsyncSequence where Event: Decodable { 43 | public typealias Element = Event 44 | 45 | public struct AsyncIterator: AsyncIteratorProtocol { 46 | enum State { 47 | case idle 48 | case remainingBuffer(ByteBuffer) 49 | } 50 | 51 | var baseIterator: AnyAsyncSequence.AsyncIterator 52 | var state: State = .idle 53 | 54 | public mutating func next() async throws -> Event? { 55 | var accumulatedBuffer: ByteBuffer? = nil 56 | var buffer: ByteBuffer? 57 | // get buffer either from what is remaining from last buffer or a new buffer from 58 | // the ByteBuffer sequence 59 | switch self.state { 60 | case .idle: 61 | buffer = try await self.baseIterator.next() 62 | case .remainingBuffer(let remainingBuffer): 63 | buffer = remainingBuffer 64 | } 65 | while var validBuffer = buffer { 66 | // have we already accumulated some buffer, if so append new buffer onto the end 67 | if var validAccumulatedBuffer = accumulatedBuffer { 68 | validAccumulatedBuffer.writeBuffer(&validBuffer) 69 | validBuffer = validAccumulatedBuffer 70 | accumulatedBuffer = validAccumulatedBuffer 71 | } else { 72 | accumulatedBuffer = validBuffer 73 | } 74 | 75 | if let event = try readEvent(&validBuffer) { 76 | if validBuffer.readableBytes > 0 { 77 | self.state = .remainingBuffer(validBuffer) 78 | } else { 79 | self.state = .idle 80 | } 81 | return event 82 | } 83 | buffer = try await self.baseIterator.next() 84 | } 85 | 86 | return nil 87 | } 88 | 89 | /// Read event from buffer 90 | func readEvent(_ buffer: inout ByteBuffer) throws -> Event? { 91 | do { 92 | let event = try EventStreamDecoder().decode(Event.self, from: &buffer) 93 | return event 94 | } catch InternalAWSEventStreamError.needMoreData { 95 | return nil 96 | } 97 | } 98 | } 99 | 100 | public func makeAsyncIterator() -> AsyncIterator { 101 | .init(baseIterator: self.base.makeAsyncIterator()) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Sources/SotoCore/Concurrency/FixedSizeByteBufferAsyncSequence.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import NIOCore 16 | 17 | /// An AsyncSequence that returns fixed size ByteBuffers from an AsyncSequence of ByteBuffers 18 | public struct FixedSizeByteBufferAsyncSequence: AsyncSequence where Base.Element == ByteBuffer { 19 | public typealias Element = ByteBuffer 20 | 21 | public let byteBufferSequence: Base 22 | public let chunkSize: Int 23 | 24 | public struct AsyncIterator: AsyncIteratorProtocol { 25 | var iterator: Base.AsyncIterator 26 | let chunkSize: Int 27 | var currentByteBuffer: ByteBuffer? 28 | 29 | @usableFromInline 30 | init(sequence: FixedSizeByteBufferAsyncSequence) { 31 | self.iterator = sequence.byteBufferSequence.makeAsyncIterator() 32 | self.chunkSize = sequence.chunkSize 33 | } 34 | 35 | public mutating func next() async throws -> ByteBuffer? { 36 | // get current bytebuffer or first buffer from source sequence 37 | var byteBuffer: ByteBuffer 38 | if let currentByteBuffer = self.currentByteBuffer { 39 | byteBuffer = currentByteBuffer 40 | } else { 41 | if let firstByteBuffer = try await iterator.next() { 42 | byteBuffer = firstByteBuffer 43 | } else { 44 | return nil 45 | } 46 | } 47 | byteBuffer.reserveCapacity(self.chunkSize) 48 | 49 | // while current byte buffer does not contain enough bytes read from source sequence 50 | while byteBuffer.readableBytes < self.chunkSize { 51 | if var nextByteBuffer = try await iterator.next() { 52 | // if next byte buffer has enough bytes to create a chunk 53 | if var slice = nextByteBuffer.readSlice(length: self.chunkSize - byteBuffer.readableBytes) { 54 | byteBuffer.writeBuffer(&slice) 55 | self.currentByteBuffer = nextByteBuffer 56 | return byteBuffer 57 | } else { 58 | byteBuffer.writeBuffer(&nextByteBuffer) 59 | } 60 | } else { 61 | // no more byte buffers are available from the source sequence so return what is left 62 | self.currentByteBuffer = nil 63 | // don't return a ByteBuffer if it is empty 64 | if byteBuffer.readableBytes > 0 { 65 | return byteBuffer 66 | } else { 67 | return nil 68 | } 69 | } 70 | } 71 | let chunkByteBuffer = byteBuffer.readSlice(length: self.chunkSize) 72 | self.currentByteBuffer = byteBuffer 73 | return chunkByteBuffer 74 | } 75 | } 76 | 77 | /// Make async iterator 78 | public __consuming func makeAsyncIterator() -> AsyncIterator { 79 | AsyncIterator(sequence: self) 80 | } 81 | } 82 | 83 | extension FixedSizeByteBufferAsyncSequence: Sendable where Base: Sendable {} 84 | 85 | extension AsyncSequence where Element == ByteBuffer { 86 | /// Return an AsyncSequence that returns ByteBuffers of a fixed size 87 | /// - Parameter chunkSize: Size of each chunk 88 | public func fixedSizeSequence(chunkSize: Int) -> FixedSizeByteBufferAsyncSequence { 89 | .init(byteBufferSequence: self, chunkSize: chunkSize) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Sources/SotoCore/Credential/Credential+IsEmpty.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import SotoSignerV4 16 | 17 | extension Credential { 18 | func isEmpty() -> Bool { 19 | self.accessKeyId.isEmpty || self.secretAccessKey.isEmpty 20 | } 21 | 22 | func getStaticCredential() -> StaticCredential { 23 | .init(accessKeyId: accessKeyId, secretAccessKey: secretAccessKey, sessionToken: sessionToken) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/SotoCore/Credential/CredentialProviderError.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | public struct CredentialProviderError: Error, Equatable { 16 | enum _CredentialProviderError: Equatable { 17 | case noProvider 18 | case tokenIdFileFailedToLoad 19 | } 20 | 21 | let error: _CredentialProviderError 22 | 23 | public static var noProvider: CredentialProviderError { .init(error: .noProvider) } 24 | public static var tokenIdFileFailedToLoad: CredentialProviderError { .init(error: .tokenIdFileFailedToLoad) } 25 | } 26 | 27 | extension CredentialProviderError: CustomStringConvertible { 28 | public var description: String { 29 | switch self.error { 30 | case .noProvider: 31 | return "No credential provider found." 32 | case .tokenIdFileFailedToLoad: 33 | return "WebIdentity token id file failed to load." 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sources/SotoCore/Credential/CredentialProviderSelector.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Logging 16 | import NIOConcurrencyHelpers 17 | import NIOCore 18 | import SotoSignerV4 19 | 20 | /// Protocol for CredentialProvider that uses an internal CredentialProvider generated by another Task 21 | protocol CredentialProviderSelector: CredentialProvider, AnyObject { 22 | func getCredentialProviderTask() async throws -> CredentialProvider 23 | func cancelCredentialProviderTask() 24 | } 25 | 26 | extension CredentialProviderSelector { 27 | func getCredential(logger: Logger) async throws -> Credential { 28 | try await withTaskCancellationHandler { 29 | let provider = try await getCredentialProviderTask() 30 | return try await provider.getCredential(logger: logger) 31 | } onCancel: { 32 | cancelCredentialProviderTask() 33 | } 34 | } 35 | 36 | func shutdown() async throws { 37 | cancelCredentialProviderTask() 38 | if let provider = try? await getCredentialProviderTask() { 39 | try await provider.shutdown() 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Sources/SotoCore/Credential/DeferredCredentialProvider.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Logging 16 | import NIOConcurrencyHelpers 17 | import NIOCore 18 | 19 | /// Wrap and store result from another credential provider. 20 | /// 21 | /// Used for wrapping another credential provider whose `getCredential` method doesn't return instantly and 22 | /// is only needed to be called once. After the wrapped `CredentialProvider` has generated a credential this is 23 | /// returned instead of calling the wrapped `CredentialProvider's` `getCredentials` again. 24 | public final class DeferredCredentialProvider: CredentialProvider { 25 | private let getCredentialTask: Task 26 | private let provider: CredentialProvider 27 | 28 | /// Create `DeferredCredentialProvider`. 29 | /// - Parameters: 30 | /// - context: Context including HTTP client and logger 31 | /// - provider: Credential provider to wrap 32 | public init(context: CredentialProviderFactory.Context, provider: CredentialProvider) { 33 | let description = "\(type(of: self))(\(provider.description))" 34 | self.getCredentialTask = Task { 35 | let credentials = try await provider.getCredential(logger: context.logger) 36 | context.logger.debug("AWS credentials ready", metadata: ["aws-credential-provider": .string(description)]) 37 | return credentials 38 | } 39 | self.provider = provider 40 | } 41 | 42 | /// Shutdown credential provider 43 | public func shutdown() async throws { 44 | self.getCredentialTask.cancel() 45 | // ensure internal credential provider is not still running 46 | _ = try? await self.getCredential(logger: AWSClient.loggingDisabled) 47 | try await self.provider.shutdown() 48 | } 49 | 50 | /// Return credentials 51 | /// - Parameter logger: Logger 52 | /// - Returns: Credentials 53 | public func getCredential(logger: Logger) async throws -> Credential { 54 | try await withTaskCancellationHandler { 55 | try await self.getCredentialTask.value 56 | } onCancel: { 57 | self.getCredentialTask.cancel() 58 | } 59 | } 60 | } 61 | 62 | extension DeferredCredentialProvider: CustomStringConvertible { 63 | public var description: String { "\(type(of: self))(\(self.provider.description))" } 64 | } 65 | -------------------------------------------------------------------------------- /Sources/SotoCore/Credential/EmptyCredential.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | /// Empty credentials 16 | public struct EmptyCredential: CredentialProvider, Credential { 17 | public var accessKeyId: String { "" } 18 | public var secretAccessKey: String { "" } 19 | public var sessionToken: String? { nil } 20 | 21 | public func getCredential(logger: Logger) async throws -> any Credential { 22 | self 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/SotoCore/Credential/ExpiringCredential.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import SotoSignerV4 16 | 17 | import struct Foundation.Date 18 | import struct Foundation.TimeInterval 19 | 20 | /// Credential provider whose credentials expire over tiem. 21 | public protocol ExpiringCredential: Credential { 22 | var expiration: Date { get } 23 | } 24 | 25 | extension ExpiringCredential { 26 | /// Will credential expire within a certain time 27 | public func isExpiring(within interval: TimeInterval) -> Bool { 28 | self.expiration.timeIntervalSinceNow < interval 29 | } 30 | 31 | /// Has credential expired 32 | public var isExpired: Bool { 33 | self.isExpiring(within: 0) 34 | } 35 | } 36 | 37 | /// Basic implementation of a struct conforming to ExpiringCredential. 38 | public struct RotatingCredential: ExpiringCredential { 39 | public init(accessKeyId: String, secretAccessKey: String, sessionToken: String?, expiration: Date) { 40 | self.accessKeyId = accessKeyId 41 | self.secretAccessKey = secretAccessKey 42 | self.sessionToken = sessionToken 43 | self.expiration = expiration 44 | } 45 | 46 | public let accessKeyId: String 47 | public let secretAccessKey: String 48 | public let sessionToken: String? 49 | public let expiration: Date 50 | } 51 | -------------------------------------------------------------------------------- /Sources/SotoCore/Credential/NullCredentialProvider.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Logging 16 | import NIOCore 17 | import SotoSignerV4 18 | 19 | /// Credential provider that always fails 20 | public struct NullCredentialProvider: CredentialProvider { 21 | public init() {} 22 | 23 | public func getCredential(logger: Logger) async throws -> Credential { 24 | throw CredentialProviderError.noProvider 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/SotoCore/Credential/RuntimeSelectorCredentialProvider.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Logging 16 | import NIOConcurrencyHelpers 17 | import NIOCore 18 | import SotoSignerV4 19 | 20 | /// get credentials from a list of possible credential providers. Goes through list of providers from start to end 21 | /// attempting to get credentials. Once it finds a `CredentialProvider` that supplies credentials use that 22 | /// one 23 | final class RuntimeSelectorCredentialProvider: CredentialProviderSelector { 24 | private let getProviderTask: Task 25 | 26 | init(providers: [CredentialProviderFactory], context: CredentialProviderFactory.Context) { 27 | self.getProviderTask = Task { 28 | try await Self.setupInternalProvider(providers: providers, context: context) 29 | } 30 | } 31 | 32 | func getCredentialProviderTask() async throws -> CredentialProvider { 33 | try await self.getProviderTask.value 34 | } 35 | 36 | func cancelCredentialProviderTask() { 37 | self.getProviderTask.cancel() 38 | } 39 | 40 | /// goes through list of providers. If provider is able to provide credentials then use that one, otherwise move onto the next 41 | /// provider in the list 42 | private static func setupInternalProvider( 43 | providers: [CredentialProviderFactory], 44 | context: CredentialProviderFactory.Context 45 | ) async throws -> CredentialProvider { 46 | for providerFactory in providers { 47 | let provider = providerFactory.createProvider(context: context) 48 | do { 49 | _ = try await provider.getCredential(logger: context.logger) 50 | context.logger.debug("Select credential provider", metadata: ["aws-credential-provider": .string("\(provider)")]) 51 | return provider 52 | } catch { 53 | try? await provider.shutdown() 54 | context.logger.log( 55 | level: context.options.errorLogLevel, 56 | "Select credential provider failed", 57 | metadata: ["aws-credential-provider": .string("\(provider)")] 58 | ) 59 | } 60 | } 61 | return NullCredentialProvider() 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Sources/SotoCore/Credential/StaticCredential+CredentialProvider.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Logging 16 | import SotoSignerV4 17 | 18 | extension StaticCredential: CredentialProvider { 19 | /// Return static credential 20 | public func getCredential(logger: Logger) async throws -> Credential { 21 | self 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/SotoCore/Credential/StaticCredential+Environment.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import SotoSignerV4 16 | 17 | extension StaticCredential { 18 | /// construct static credentaisl from environment variables `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` 19 | /// and `AWS_SESSION_TOKEN` if it exists 20 | static func fromEnvironment() -> CredentialProvider? { 21 | guard let accessKeyId = Environment["AWS_ACCESS_KEY_ID"] else { 22 | return nil 23 | } 24 | guard let secretAccessKey = Environment["AWS_SECRET_ACCESS_KEY"] else { 25 | return nil 26 | } 27 | 28 | return StaticCredential( 29 | accessKeyId: accessKeyId, 30 | secretAccessKey: secretAccessKey, 31 | sessionToken: Environment["AWS_SESSION_TOKEN"] 32 | ) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/SotoCore/Doc/ARN.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2024 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | /// Amazon Resource Name (ARN). A unique identifier assigned to AWS resource 16 | /// 17 | /// Comes in one of the following forms 18 | /// - arn:partition:service:region:account-id:resource-id 19 | /// - arn:partition:service:region:account-id:resource-type/resource-id 20 | /// - arn:partition:service:region:account-id:resource-type:resource-id 21 | public struct ARN { 22 | public init?(string: S) where S.SubSequence == Substring { 23 | let split = string.split(separator: ":", omittingEmptySubsequences: false) 24 | guard split.count >= 6 else { return nil } 25 | guard split[0] == "arn" else { return nil } 26 | guard let partition = AWSPartition(rawValue: String(split[1])) else { return nil } 27 | self.partition = partition 28 | self.service = split[2] 29 | self.region = split[3].count > 0 ? Region(rawValue: String(split[3])) : nil 30 | if let region { 31 | guard region.partition == self.partition else { return nil } 32 | } 33 | self.accountId = split[4].count > 0 ? split[4] : nil 34 | guard self.accountId?.first(where: { !$0.isNumber }) == nil else { return nil } 35 | if split.count == 6 { 36 | let resourceSplit = split[5].split(separator: "/", maxSplits: 1) 37 | if resourceSplit.count == 1 { 38 | self.resourceType = nil 39 | self.resourceId = resourceSplit[0] 40 | } else { 41 | self.resourceType = resourceSplit[0] 42 | self.resourceId = resourceSplit[1] 43 | } 44 | } else if split.count == 7 { 45 | self.resourceType = split[5] 46 | self.resourceId = split[6] 47 | } else { 48 | return nil 49 | } 50 | } 51 | 52 | public let partition: AWSPartition 53 | public let service: Substring 54 | public let region: Region? 55 | public let accountId: Substring? 56 | public let resourceId: Substring 57 | public let resourceType: Substring? 58 | } 59 | -------------------------------------------------------------------------------- /Sources/SotoCore/Doc/EndpointVariant.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2022 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | /// Endpoint variant types 16 | public struct EndpointVariantType: OptionSet, Hashable { 17 | public typealias RawValue = Int 18 | public let rawValue: Int 19 | 20 | public init(rawValue: RawValue) { 21 | self.rawValue = rawValue 22 | } 23 | 24 | public static let fips: Self = .init(rawValue: AWSServiceConfig.Options.useFipsEndpoint.rawValue) 25 | public static let dualstack: Self = .init(rawValue: AWSServiceConfig.Options.useDualStackEndpoint.rawValue) 26 | 27 | public static let all: Self = [.fips, .dualstack] 28 | } 29 | 30 | extension EndpointVariantType: CustomStringConvertible { 31 | public var description: String { 32 | var elements: [String] = [] 33 | if self.contains(.fips) { 34 | elements.append("FIPS") 35 | } 36 | if self.contains(.dualstack) { 37 | elements.append("dualstack") 38 | } 39 | return elements.joined(separator: ", ") 40 | } 41 | } 42 | 43 | /// extend AWSServiceConfig options to generate endpoint variant options 44 | extension AWSServiceConfig.Options { 45 | var endpointVariant: EndpointVariantType { 46 | .init(rawValue: self.rawValue).intersection(EndpointVariantType.all) 47 | } 48 | } 49 | 50 | extension EndpointVariantType: Sendable {} 51 | -------------------------------------------------------------------------------- /Sources/SotoCore/Doc/Environment.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2020 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #if canImport(Glibc) 16 | import Glibc 17 | #elseif canImport(Musl) 18 | import Musl 19 | #elseif canImport(Darwin) 20 | import Darwin.C 21 | #elseif canImport(Android) 22 | import Android 23 | #else 24 | #error("Unsupported platform") 25 | #endif 26 | 27 | enum Environment { 28 | static subscript(_ name: String) -> String? { 29 | guard let value = getenv(name) else { 30 | return nil 31 | } 32 | return String(cString: value) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/SotoCore/Doc/ServiceProtocol.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2022 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | /// Communication protocol 16 | public enum ServiceProtocol { 17 | case json(version: String) 18 | case restjson 19 | case restxml 20 | case query 21 | case ec2 22 | } 23 | 24 | extension ServiceProtocol { 25 | public var contentType: String { 26 | switch self { 27 | case .json(let version): 28 | return "application/x-amz-json-\(version)" 29 | case .restjson: 30 | return "application/json" 31 | case .restxml: 32 | return "application/octet-stream" 33 | case .query, .ec2: 34 | return "application/x-www-form-urlencoded; charset=utf-8" 35 | } 36 | } 37 | } 38 | 39 | extension ServiceProtocol: Sendable {} 40 | -------------------------------------------------------------------------------- /Sources/SotoCore/Encoder/CodableProperties/EC2ArrayCoder.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | /// Coder for encoding/decoding Arrays for EC2 service. This is extended to support encoding and 16 | /// decoding based on whether `Element` is `Encodable` or `Decodable`. 17 | /// 18 | /// EC2 requires a special case array encoder as it flattens arrays on encode, while still expecting 19 | /// them to have array elements on decode. 20 | public struct EC2ArrayCoder: CustomCoder { 21 | public typealias CodableValue = [Element] 22 | } 23 | 24 | /// Standard EC2 Array Coder with element name "member" 25 | public typealias EC2StandardArrayCoder = EC2ArrayCoder 26 | 27 | /// CodingKey used by Encoder property wrappers 28 | private struct _EncodingWrapperKey: CodingKey { 29 | public var stringValue: String 30 | public var intValue: Int? 31 | 32 | public init?(stringValue: String) { 33 | self.stringValue = stringValue 34 | self.intValue = nil 35 | } 36 | 37 | public init?(intValue: Int) { 38 | self.stringValue = "\(intValue)" 39 | self.intValue = intValue 40 | } 41 | 42 | public init(stringValue: String, intValue: Int?) { 43 | self.stringValue = stringValue 44 | self.intValue = intValue 45 | } 46 | } 47 | 48 | /// extend to support decoding 49 | extension EC2ArrayCoder: CustomDecoder where Element: Decodable { 50 | public static func decode(from decoder: Decoder) throws -> CodableValue { 51 | let topLevelContainer = try decoder.container(keyedBy: _EncodingWrapperKey.self) 52 | var values: [Element] = [] 53 | let memberKey = _EncodingWrapperKey(stringValue: Properties.member, intValue: nil) 54 | guard topLevelContainer.contains(memberKey) else { return values } 55 | 56 | var container = try topLevelContainer.nestedUnkeyedContainer(forKey: memberKey) 57 | while !container.isAtEnd { 58 | try values.append(container.decode(Element.self)) 59 | } 60 | return values 61 | } 62 | } 63 | 64 | /// extend to support encoding (flatten the array) 65 | extension EC2ArrayCoder: CustomEncoder where Element: Encodable { 66 | public static func encode(value: CodableValue, to encoder: Encoder) throws { 67 | try value.encode(to: encoder) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Sources/SotoCore/Errors/Error.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2022 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import NIOHTTP1 16 | 17 | /// Standard Error type returned by Soto. 18 | /// 19 | /// Initialized with error code and message. 20 | public protocol AWSErrorType: Error, CustomStringConvertible { 21 | /// initialize error 22 | init?(errorCode: String, context: AWSErrorContext) 23 | /// Error code return by AWS 24 | var errorCode: String { get } 25 | /// additional context information related to the error 26 | var context: AWSErrorContext? { get } 27 | } 28 | 29 | extension AWSErrorType { 30 | public var localizedDescription: String { 31 | "\(self)" 32 | } 33 | 34 | public var message: String? { 35 | context?.message 36 | } 37 | } 38 | 39 | /// Service that has extended error information 40 | public protocol AWSServiceErrorType: AWSErrorType { 41 | static var errorCodeMap: [String: AWSErrorShape.Type] { get } 42 | } 43 | 44 | /// Additional information about error 45 | public struct AWSErrorContext { 46 | public let message: String 47 | public let responseCode: HTTPResponseStatus 48 | public let headers: HTTPHeaders 49 | public let additionalFields: [String: String] 50 | public let extendedError: AWSErrorShape? 51 | 52 | internal init( 53 | message: String, 54 | responseCode: HTTPResponseStatus, 55 | headers: HTTPHeaders = [:], 56 | additionalFields: [String: String] = [:], 57 | extendedError: AWSErrorShape? = nil 58 | ) { 59 | self.message = message 60 | self.responseCode = responseCode 61 | self.headers = headers 62 | self.additionalFields = additionalFields 63 | self.extendedError = extendedError 64 | } 65 | } 66 | 67 | /// Response Error type returned by Soto if the error code is unrecognised 68 | public struct AWSResponseError: AWSErrorType { 69 | public let errorCode: String 70 | public let context: AWSErrorContext? 71 | 72 | public init(errorCode: String) { 73 | self.errorCode = errorCode 74 | self.context = nil 75 | } 76 | 77 | public init(errorCode: String, context: AWSErrorContext) { 78 | self.errorCode = errorCode 79 | self.context = context 80 | } 81 | 82 | public var description: String { 83 | "\(self.errorCode): \(self.message ?? "")" 84 | } 85 | } 86 | 87 | /// Raw unprocessed error. 88 | /// 89 | /// Used when we cannot extract an error code from the AWS response. Returns full body of error response 90 | public struct AWSRawError: Error, CustomStringConvertible { 91 | public let rawBody: String? 92 | public let context: AWSErrorContext 93 | 94 | init(rawBody: String?, context: AWSErrorContext) { 95 | self.rawBody = rawBody 96 | self.context = context 97 | } 98 | 99 | public var description: String { 100 | "Unhandled error, code: \(self.context.responseCode)\(self.rawBody.map { ", body: \($0)" } ?? "")" 101 | } 102 | } 103 | 104 | extension AWSErrorContext: Sendable {} 105 | -------------------------------------------------------------------------------- /Sources/SotoCore/Errors/ServerErrors.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2020 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | // THIS FILE IS AUTOMATICALLY GENERATED by https://github.com/soto-project/soto-core/scripts/generate-errors.swift. DO NOT EDIT. 16 | 17 | import NIOHTTP1 18 | 19 | public struct AWSServerError: AWSErrorType { 20 | enum Code: String { 21 | case internalFailure = "InternalFailure" 22 | case serviceUnavailable = "ServiceUnavailable" 23 | } 24 | 25 | private let error: Code 26 | public let context: AWSErrorContext? 27 | 28 | /// initialize AWSServerError 29 | public init?(errorCode: String, context: AWSErrorContext) { 30 | var errorCode = errorCode 31 | // remove "Exception" suffix 32 | if errorCode.hasSuffix("Exception") { 33 | errorCode = String(errorCode.dropLast(9)) 34 | } 35 | guard let error = Code(rawValue: errorCode) else { return nil } 36 | self.error = error 37 | self.context = context 38 | } 39 | 40 | internal init(_ error: Code, context: AWSErrorContext? = nil) { 41 | self.error = error 42 | self.context = context 43 | } 44 | 45 | /// return error code string 46 | public var errorCode: String { self.error.rawValue } 47 | 48 | // The request processing has failed because of an unknown error, exception or failure. 49 | public static var internalFailure: AWSServerError { .init(.internalFailure) } 50 | // The request has failed due to a temporary failure of the server. 51 | public static var serviceUnavailable: AWSServerError { .init(.serviceUnavailable) } 52 | } 53 | 54 | extension AWSServerError: Equatable { 55 | public static func == (lhs: AWSServerError, rhs: AWSServerError) -> Bool { 56 | lhs.error == rhs.error 57 | } 58 | } 59 | 60 | extension AWSServerError: CustomStringConvertible { 61 | public var description: String { 62 | "\(self.error.rawValue): \(message ?? "")" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Sources/SotoCore/Exports.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2020 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #if swift(>=5.8) 16 | @_exported @_documentation(visibility: internal) import protocol SotoSignerV4.Credential 17 | @_exported @_documentation(visibility: internal) import struct SotoSignerV4.StaticCredential 18 | 19 | @_exported @_documentation(visibility: internal) import struct Logging.Logger 20 | 21 | @_exported @_documentation(visibility: internal) import struct NIOCore.ByteBuffer 22 | @_exported @_documentation(visibility: internal) import struct NIOCore.ByteBufferAllocator 23 | @_exported @_documentation(visibility: internal) import struct NIOCore.TimeAmount 24 | 25 | @_exported @_documentation(visibility: internal) import struct NIOHTTP1.HTTPHeaders 26 | @_exported @_documentation(visibility: internal) import enum NIOHTTP1.HTTPMethod 27 | #else 28 | @_exported import protocol SotoSignerV4.Credential 29 | @_exported import struct SotoSignerV4.StaticCredential 30 | 31 | @_exported import struct Logging.Logger 32 | 33 | @_exported import struct NIOCore.ByteBuffer 34 | @_exported import struct NIOCore.ByteBufferAllocator 35 | @_exported import struct NIOCore.TimeAmount 36 | 37 | @_exported import struct NIOHTTP1.HTTPHeaders 38 | @_exported import enum NIOHTTP1.HTTPMethod 39 | #endif 40 | -------------------------------------------------------------------------------- /Sources/SotoCore/HTTP/AWSHTTPClient.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2024 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | /// Protocol for HTTP clients that work with Soto 16 | public protocol AWSHTTPClient: Sendable { 17 | /// Execute an HTTP request 18 | func execute( 19 | request: AWSHTTPRequest, 20 | timeout: TimeAmount, 21 | logger: Logger 22 | ) async throws -> AWSHTTPResponse 23 | /// Shutdown client if Soto created it 24 | func shutdown() async throws 25 | } 26 | 27 | extension AWSHTTPClient { 28 | public func shutdown() async throws {} 29 | } 30 | -------------------------------------------------------------------------------- /Sources/SotoCore/HTTP/AWSHTTPResponse+HAL.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2020 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import NIOCore 16 | 17 | import struct Foundation.Data 18 | import class Foundation.JSONSerialization 19 | 20 | // AWS HAL services I know of are APIGateway, Pinpoint, Greengrass 21 | extension AWSHTTPResponse { 22 | /// return if body is hypertext application language 23 | var isHypertextApplicationLanguage: Bool { 24 | guard let contentType = self.headers["content-type"].first, 25 | contentType.contains("hal+json") 26 | else { 27 | return false 28 | } 29 | return true 30 | } 31 | 32 | /// process hal+json data. Extract properties from HAL 33 | func getHypertextApplicationLanguageDictionary() throws -> Data { 34 | guard case .byteBuffer(let buffer) = self.body.storage else { return Data("{}".utf8) } 35 | // extract embedded resources from HAL 36 | let jsonObject = try JSONSerialization.jsonObject(with: buffer, options: []) 37 | guard var dictionary = jsonObject as? [String: Any] else { return Data("{}".utf8) } 38 | guard let embedded = dictionary["_embedded"], 39 | let embeddedDictionary = embedded as? [String: Any] 40 | else { 41 | return try JSONSerialization.data(withJSONObject: dictionary) 42 | } 43 | 44 | // remove _links and _embedded elements of dictionary to reduce the size of the new dictionary 45 | dictionary["_links"] = nil 46 | dictionary["_embedded"] = nil 47 | // merge embedded resources into original dictionary 48 | dictionary.merge(embeddedDictionary) { first, _ in first } 49 | return try JSONSerialization.data(withJSONObject: dictionary) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/SotoCore/HTTP/AsyncHTTPClient.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2024 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import AsyncHTTPClient 16 | import Logging 17 | import NIOCore 18 | import NIOHTTP1 19 | 20 | extension AsyncHTTPClient.HTTPClient: AWSHTTPClient { 21 | /// Execute HTTP request 22 | /// - Parameters: 23 | /// - request: HTTP request 24 | /// - timeout: If execution is idle for longer than timeout then throw error 25 | /// - eventLoop: eventLoop to run request on 26 | /// - Returns: EventLoopFuture that will be fulfilled with request response 27 | public func execute( 28 | request: AWSHTTPRequest, 29 | timeout: TimeAmount, 30 | logger: Logger 31 | ) async throws -> AWSHTTPResponse { 32 | let requestBody: HTTPClientRequest.Body? 33 | 34 | switch request.body.storage { 35 | case .byteBuffer(let byteBuffer): 36 | requestBody = .bytes(byteBuffer) 37 | case .asyncSequence(let sequence, let length): 38 | requestBody = .stream( 39 | sequence, 40 | length: length.map { .known(Int64($0)) } ?? .unknown 41 | ) 42 | } 43 | var httpRequest = HTTPClientRequest(url: request.url.absoluteString) 44 | httpRequest.method = request.method 45 | httpRequest.headers = request.headers 46 | httpRequest.body = requestBody 47 | 48 | do { 49 | let response = try await self.execute(httpRequest, timeout: timeout, logger: logger) 50 | return .init( 51 | status: response.status, 52 | headers: response.headers, 53 | body: .init(asyncSequence: response.body, length: nil) 54 | ) 55 | } catch let error as HTTPClientError where error == .bodyLengthMismatch { 56 | throw AWSClient.ClientError.bodyLengthMismatch 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Sources/SotoCore/Middleware/Middleware/EditHeadersMiddleware.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2022-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import NIOHTTP1 16 | 17 | /// Middleware for editing header values sent to AWS service. 18 | public struct AWSEditHeadersMiddleware: AWSMiddlewareProtocol { 19 | public enum HeaderEdit { 20 | case add(name: String, value: String) 21 | case replace(name: String, value: String) 22 | case remove(name: String) 23 | } 24 | 25 | @usableFromInline 26 | let edits: [HeaderEdit] 27 | 28 | public init(_ edits: [HeaderEdit]) { 29 | self.edits = edits 30 | } 31 | 32 | public init(_ edits: HeaderEdit...) { 33 | self.init(edits) 34 | } 35 | 36 | @inlinable 37 | public func handle(_ request: AWSHTTPRequest, context: AWSMiddlewareContext, next: AWSMiddlewareNextHandler) async throws -> AWSHTTPResponse { 38 | var request = request 39 | for edit in self.edits { 40 | switch edit { 41 | case .add(let name, let value): 42 | request.headers.add(name: name, value: value) 43 | case .replace(let name, let value): 44 | request.headers.replaceOrAdd(name: name, value: value) 45 | case .remove(let name): 46 | request.headers.remove(name: name) 47 | } 48 | } 49 | return try await next(request, context) 50 | } 51 | } 52 | 53 | extension AWSEditHeadersMiddleware: Sendable {} 54 | extension AWSEditHeadersMiddleware.HeaderEdit: Sendable {} 55 | -------------------------------------------------------------------------------- /Sources/SotoCore/Middleware/Middleware/EndpointDiscoveryMiddleware.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Logging 16 | import NIOHTTP1 17 | @_spi(SotoInternal) import SotoSignerV4 18 | 19 | import struct Foundation.Date 20 | import struct Foundation.TimeInterval 21 | import struct Foundation.URL 22 | 23 | #if os(Linux) 24 | @preconcurrency import struct Foundation.CharacterSet 25 | #else 26 | import struct Foundation.CharacterSet 27 | #endif 28 | 29 | /// Middleware that runs an endpoint discovery function to set service endpoint 30 | /// prior to running operation 31 | public struct EndpointDiscoveryMiddleware: AWSMiddlewareProtocol { 32 | let storage: AWSEndpointStorage 33 | let discover: @Sendable (Logger) async throws -> AWSEndpoints 34 | let isRequired: Bool 35 | 36 | public init(storage: AWSEndpointStorage, discover: @escaping @Sendable (Logger) async throws -> AWSEndpoints, required: Bool) { 37 | self.storage = storage 38 | self.discover = discover 39 | self.isRequired = required 40 | } 41 | 42 | public func handle(_ request: AWSHTTPRequest, context: AWSMiddlewareContext, next: AWSMiddlewareNextHandler) async throws -> AWSHTTPResponse { 43 | let isEnabled = context.serviceConfig.options.contains(.enableEndpointDiscovery) 44 | guard isEnabled || self.isRequired else { 45 | return try await next(request, context) 46 | } 47 | if let endpoint = try await getEndpoint(logger: context.logger) { 48 | var request = request 49 | var path = request.url.path 50 | // add trailing "/" back if it was present 51 | if request.url.pathWithSlash.hasSuffix("/"), path != "/" { 52 | path += "/" 53 | } 54 | // add percent encoding back into path as converting from URL to String has removed it 55 | let percentEncodedUrlPath = self.urlEncodePath(path) 56 | var urlString = "\(endpoint)\(percentEncodedUrlPath)" 57 | if let query = request.url.query { 58 | urlString += "?\(query)" 59 | } 60 | request.url = URL(string: urlString)! 61 | return try await next(request, context) 62 | } 63 | return try await next(request, context) 64 | } 65 | 66 | func getEndpoint(logger: Logger) async throws -> String? { 67 | do { 68 | return try await self.storage.getValue { 69 | logger.trace("Request endpoint") 70 | do { 71 | let response = try await discover(logger) 72 | let index = Int.random(in: 0.. String { 93 | value.addingPercentEncoding(withAllowedCharacters: self.pathAllowedCharacters) ?? value 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Sources/SotoCore/Middleware/Middleware/ErrorHandlingMiddleware.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Logging 16 | import NIOHTTP1 17 | import SotoSignerV4 18 | 19 | /// Middleware that throws errors for non 2xx responses from AWS 20 | struct ErrorHandlingMiddleware: AWSMiddlewareProtocol { 21 | let options: AWSClient.Options 22 | 23 | func handle(_ request: AWSHTTPRequest, context: AWSMiddlewareContext, next: AWSMiddlewareNextHandler) async throws -> AWSHTTPResponse { 24 | let response = try await next(request, context) 25 | 26 | // if response has an HTTP status code outside 2xx then throw an error 27 | guard (200..<300).contains(response.status.code) else { 28 | let error = await self.createError(for: response, context: context) 29 | throw error 30 | } 31 | 32 | return response 33 | } 34 | 35 | /// Create error from HTTPResponse. This is only called if we received an unsuccessful http status code. 36 | internal func createError(for response: AWSHTTPResponse, context: AWSMiddlewareContext) async -> Error { 37 | // if we can create an AWSResponse and create an error from it return that 38 | var response = response 39 | do { 40 | try await response.collateBody() 41 | } catch { 42 | // else return "Unhandled error message" with rawBody attached 43 | let context = AWSErrorContext( 44 | message: "Unhandled Error", 45 | responseCode: response.status, 46 | headers: response.headers 47 | ) 48 | return AWSRawError(rawBody: nil, context: context) 49 | } 50 | if let error = response.generateError( 51 | serviceConfig: context.serviceConfig, 52 | logLevel: self.options.errorLogLevel, 53 | logger: context.logger 54 | ) { 55 | return error 56 | } else { 57 | // else return "Unhandled error message" with rawBody attached 58 | let context = AWSErrorContext( 59 | message: "Unhandled Error", 60 | responseCode: response.status, 61 | headers: response.headers 62 | ) 63 | let responseBody: String? 64 | switch response.body.storage { 65 | case .byteBuffer(let buffer): 66 | responseBody = String(buffer: buffer) 67 | default: 68 | responseBody = nil 69 | } 70 | return AWSRawError(rawBody: responseBody, context: context) 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Sources/SotoCore/Middleware/Middleware/LoggingMiddleware.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Foundation 16 | import Logging 17 | import NIOHTTP1 18 | 19 | /// Middleware that outputs the contents of requests being sent to AWS and the contents of the responses received. 20 | public struct AWSLoggingMiddleware: AWSMiddlewareProtocol { 21 | @usableFromInline 22 | let log: @Sendable (@autoclosure () -> String) -> Void 23 | 24 | public typealias LoggingFunction = @Sendable (String) -> Void 25 | /// initialize AWSLoggingMiddleware 26 | /// - parameters: 27 | /// - log: Function to call with logging output 28 | public init(log: @escaping LoggingFunction = { print($0) }) { 29 | self.log = { log($0()) } 30 | } 31 | 32 | /// initialize AWSLoggingMiddleware to use Logger 33 | /// - Parameters: 34 | /// - logger: Logger to use 35 | /// - logLevel: Log level to output at 36 | public init(logger: Logger, logLevel: Logger.Level = .info) { 37 | self.log = { logger.log(level: logLevel, "\($0())") } 38 | } 39 | 40 | @inlinable 41 | public func handle(_ request: AWSHTTPRequest, context: AWSMiddlewareContext, next: AWSMiddlewareNextHandler) async throws -> AWSHTTPResponse { 42 | self.log( 43 | "Request:\n" + " \(context.operation)\n" + " \(request.method) \(request.url)\n" 44 | + " Headers: \(self.getHeadersOutput(request.headers))\n" + " Body: \(self.getBodyOutput(request.body))" 45 | ) 46 | let response = try await next(request, context) 47 | self.log( 48 | "Response:\n" + " Status : \(response.status.code)\n" 49 | + " Headers: \(self.getHeadersOutput(HTTPHeaders(response.headers.map { ($0, "\($1)") })))\n" 50 | + " Body: \(self.getBodyOutput(response.body))" 51 | ) 52 | return response 53 | } 54 | 55 | @usableFromInline 56 | func getBodyOutput(_ body: AWSHTTPBody) -> String { 57 | var output = "" 58 | switch body.storage { 59 | case .byteBuffer(let buffer): 60 | output += "\n " 61 | output += "\(String(buffer: buffer))" 62 | default: 63 | output += "binary data" 64 | } 65 | return output 66 | } 67 | 68 | @usableFromInline 69 | func getHeadersOutput(_ headers: HTTPHeaders) -> String { 70 | if headers.count == 0 { 71 | return "[]" 72 | } 73 | var output = "[" 74 | for header in headers { 75 | output += "\n \(header.name) : \(header.value)" 76 | } 77 | return output + "\n ]" 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Sources/SotoCore/Middleware/Middleware/RetryMiddleware.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Logging 16 | import NIOHTTP1 17 | import SotoSignerV4 18 | 19 | /// Middleware that performs retries of the next middleware whenever it throws errors based on a retry policy 20 | struct RetryMiddleware: AWSMiddlewareProtocol { 21 | @usableFromInline 22 | let retryPolicy: RetryPolicy 23 | 24 | @inlinable 25 | func handle(_ request: AWSHTTPRequest, context: AWSMiddlewareContext, next: AWSMiddlewareNextHandler) async throws -> AWSHTTPResponse { 26 | var attempt = 0 27 | while true { 28 | do { 29 | try Task.checkCancellation() 30 | return try await next(request, context) 31 | } catch { 32 | // If request is streaming then do not allow a retry 33 | if request.body.isStreaming { 34 | throw error 35 | } 36 | // If I get a retry wait time for this error then attempt to retry request 37 | if case .retry(let retryTime) = self.retryPolicy.getRetryWaitTime(error: error, attempt: attempt) { 38 | context.logger.trace( 39 | "Retrying request", 40 | metadata: [ 41 | "aws-retry-time": "\(Double(retryTime.nanoseconds) / 1_000_000_000)" 42 | ] 43 | ) 44 | try await Task.sleep(nanoseconds: UInt64(retryTime.nanoseconds)) 45 | } else { 46 | throw error 47 | } 48 | } 49 | attempt += 1 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Sources/SotoCore/Middleware/Middleware/SigningMiddleware.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Logging 16 | import NIOHTTP1 17 | import SotoSignerV4 18 | 19 | /// Middleware that SigV4 signs an HTTP request 20 | struct SigningMiddleware: AWSMiddlewareProtocol { 21 | @usableFromInline 22 | let credentialProvider: any CredentialProvider 23 | @usableFromInline 24 | let algorithm: AWSSigner.Algorithm 25 | 26 | @inlinable 27 | func handle(_ request: AWSHTTPRequest, context: AWSMiddlewareContext, next: AWSMiddlewareNextHandler) async throws -> AWSHTTPResponse { 28 | var request = request 29 | // construct signer 30 | let signer = AWSSigner( 31 | credentials: context.credential, 32 | name: context.serviceConfig.signingName, 33 | region: context.serviceConfig.region.rawValue, 34 | algorithm: algorithm 35 | ) 36 | request.signHeaders(signer: signer, serviceConfig: context.serviceConfig) 37 | return try await next(request, context) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/SotoCore/Middleware/Middleware/TracingMiddleware.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Tracing 16 | 17 | /// Middleware for adding tracing to AWS calls. 18 | /// 19 | /// This currently only adds attributes for the basic common attributes as detailed 20 | /// in https://github.com/open-telemetry/semantic-conventions/blob/main/docs/cloud-providers/aws-sdk.md 21 | public struct AWSTracingMiddleware: AWSMiddlewareProtocol { 22 | public init() {} 23 | 24 | public func handle( 25 | _ request: AWSHTTPRequest, 26 | context: AWSMiddlewareContext, 27 | next: AWSMiddlewareNextHandler 28 | ) async throws -> AWSHTTPResponse { 29 | try await InstrumentationSystem.tracer.withSpan( 30 | "\(context.serviceConfig.serviceName).\(context.operation)", 31 | ofKind: .client 32 | ) { span in 33 | span.updateAttributes { attributes in 34 | attributes["rpc.system"] = "aws-sdk" 35 | attributes["rpc.method"] = context.operation 36 | attributes["rpc.service"] = context.serviceConfig.serviceName 37 | } 38 | let response = try await next(request, context) 39 | 40 | span.attributes["aws.request_id"] = response.headers["x-amz-request-id"].first ?? response.headers["x-amz-requestid"].first 41 | 42 | return response 43 | } 44 | } 45 | } 46 | 47 | extension Span { 48 | /// Update Span attributes in a block instead of individually 49 | /// 50 | /// Updating a span attribute will involve some type of thread synchronisation 51 | /// primitive to avoid multiple threads updating the attributes at the same 52 | /// time. If you update each attributes individually this could cause slowdown. 53 | /// This function updates the attributes in one call to avoid hitting the 54 | /// thread synchronisation code multiple times 55 | /// 56 | /// - Parameter update: closure used to update span attributes 57 | func updateAttributes(_ update: (inout SpanAttributes) -> Void) { 58 | var attributes = self.attributes 59 | update(&attributes) 60 | self.attributes = attributes 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Sources/SotoCore/Middleware/MiddlewareStack.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | @resultBuilder 16 | public enum AWSMiddlewareBuilder { 17 | public static func buildBlock(_ m0: M0) -> M0 { 18 | m0 19 | } 20 | 21 | public static func buildPartialBlock(first: M0) -> M0 { 22 | first 23 | } 24 | 25 | public static func buildPartialBlock( 26 | accumulated m0: some AWSMiddlewareProtocol, 27 | next m1: some AWSMiddlewareProtocol 28 | ) -> some AWSMiddlewareProtocol { 29 | AWSMiddleware2(m0, m1) 30 | } 31 | } 32 | 33 | public func AWSMiddlewareStack(@AWSMiddlewareBuilder _ builder: () -> some AWSMiddlewareProtocol) -> some AWSMiddlewareProtocol { 34 | builder() 35 | } 36 | -------------------------------------------------------------------------------- /Sources/SotoCore/Utils/UnsafeTransfer.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2022 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | //===----------------------------------------------------------------------===// 16 | // 17 | // This source file is part of the SwiftNIO open source project 18 | // 19 | // Copyright (c) 2021-2022 Apple Inc. and the SwiftNIO project authors 20 | // Licensed under Apache License v2.0 21 | // 22 | // See LICENSE.txt for license information 23 | // See CONTRIBUTORS.txt for the list of SwiftNIO project authors 24 | // 25 | // SPDX-License-Identifier: Apache-2.0 26 | // 27 | //===----------------------------------------------------------------------===// 28 | 29 | /// ``UnsafeTransfer`` can be used to make non-`Sendable` values `Sendable`. 30 | /// As the name implies, the usage of this is unsafe because it disables the sendable checking of the compiler. 31 | /// It can be used similar to `@unsafe Sendable` but for values instead of types. 32 | @usableFromInline 33 | struct UnsafeTransfer { 34 | @usableFromInline 35 | var wrappedValue: Wrapped 36 | 37 | @inlinable 38 | init(_ wrappedValue: Wrapped) { 39 | self.wrappedValue = wrappedValue 40 | } 41 | } 42 | 43 | extension UnsafeTransfer: @unchecked Sendable {} 44 | 45 | extension UnsafeTransfer: Equatable where Wrapped: Equatable {} 46 | extension UnsafeTransfer: Hashable where Wrapped: Hashable {} 47 | 48 | /// ``UnsafeMutableTransferBox`` can be used to make non-`Sendable` values `Sendable` and mutable. 49 | /// It can be used to capture local mutable values in a `@Sendable` closure and mutate them from within the closure. 50 | /// As the name implies, the usage of this is unsafe because it disables the sendable checking of the compiler and does not add any synchronisation. 51 | @usableFromInline 52 | final class UnsafeMutableTransferBox { 53 | @usableFromInline 54 | var wrappedValue: Wrapped 55 | 56 | @inlinable 57 | init(_ wrappedValue: Wrapped) { 58 | self.wrappedValue = wrappedValue 59 | } 60 | } 61 | 62 | extension UnsafeMutableTransferBox: @unchecked Sendable {} 63 | -------------------------------------------------------------------------------- /Sources/SotoSignerV4/credentials.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2022 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | /// Protocol for providing credential details for accessing AWS services 16 | public protocol Credential: Sendable { 17 | var accessKeyId: String { get } 18 | var secretAccessKey: String { get } 19 | var sessionToken: String? { get } 20 | } 21 | 22 | /// basic version of Credential where you supply the credentials 23 | public struct StaticCredential: Credential, Equatable { 24 | public let accessKeyId: String 25 | public let secretAccessKey: String 26 | public let sessionToken: String? 27 | 28 | public init(accessKeyId: String, secretAccessKey: String, sessionToken: String? = nil) { 29 | self.accessKeyId = accessKeyId 30 | self.secretAccessKey = secretAccessKey 31 | self.sessionToken = sessionToken 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/SotoSignerV4/exports.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2020 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | @_exported import struct NIOCore.ByteBuffer 16 | @_exported import struct NIOCore.ByteBufferAllocator 17 | @_exported import struct NIOCore.TimeAmount 18 | @_exported import struct NIOHTTP1.HTTPHeaders 19 | @_exported import enum NIOHTTP1.HTTPMethod 20 | -------------------------------------------------------------------------------- /Sources/SotoTestUtils/Environment.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2020 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #if canImport(Glibc) 16 | import Glibc 17 | #elseif canImport(Musl) 18 | import Musl 19 | #elseif canImport(Darwin) 20 | import Darwin.C 21 | #elseif canImport(Android) 22 | import Android 23 | #else 24 | #error("Unsupported platform") 25 | #endif 26 | 27 | internal enum Environment { 28 | internal static subscript(_ name: String) -> String? { 29 | guard let value = getenv(name) else { 30 | return nil 31 | } 32 | return String(cString: value) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Tests/INIParserTests/INIParserTests.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2020 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import XCTest 16 | 17 | @testable import INIParser 18 | 19 | class INIParserTests: XCTestCase { 20 | func testExample() { 21 | let raw = """ 22 | ; last modified 1 April 2017 by Rockford Wei 23 | ## This is another comment 24 | freeVar1 = 1 25 | freeVar2 = 2; 26 | url = http://example.com/results?limit=10 27 | [owner] 28 | name = Rocky 29 | organization = PerfectlySoft 30 | ; 31 | [database] 32 | server = 192.0.2.42 ; use IP address in case network name resolution is not working 33 | port = 143 34 | file = \"中文.dat ' ' \" 35 | [汉化] 36 | 变量1 = 🇨🇳 ;使用utf8 37 | 变量2 = 加拿大。 38 | [ 乱死了 ] 39 | foo = bar 40 | """ 41 | 42 | var ini: INIParser? 43 | XCTAssertNoThrow(ini = try INIParser(raw)) 44 | 45 | XCTAssertEqual(ini?.anonymousSection["freeVar1"] ?? "", "1") 46 | XCTAssertEqual(ini?.anonymousSection["freeVar2"] ?? "", "2") 47 | XCTAssertEqual(ini?.anonymousSection["url"] ?? "", "http://example.com/results?limit=10") 48 | XCTAssertEqual(ini?.sections["owner"]?["name"] ?? "", "Rocky") 49 | XCTAssertEqual(ini?.sections["owner"]?["organization"] ?? "", "PerfectlySoft") 50 | XCTAssertEqual(ini?.sections["database"]?["server"] ?? "", "192.0.2.42") 51 | XCTAssertEqual(ini?.sections["database"]?["port"] ?? "", "143") 52 | XCTAssertEqual(ini?.sections["database"]?["file"] ?? "", "\"中文.dat \' \' \"") 53 | XCTAssertEqual(ini?.sections["汉化"]?["变量1"] ?? "", "🇨🇳") 54 | XCTAssertEqual(ini?.sections["汉化"]?["变量2"] ?? "", "加拿大。") 55 | XCTAssertNotNil(ini?.sections[" 乱死了 "]) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Tests/SotoCoreTests/CRCTests.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2022 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Foundation 16 | import SotoCore 17 | import SotoTestUtils 18 | import XCTest 19 | 20 | final class CRCTests: XCTestCase { 21 | func testCRC32() { 22 | XCTAssertEqual(soto_crc32(0, bytes: "".utf8), 0) 23 | XCTAssertEqual(soto_crc32(0, bytes: "a".utf8), 0xE8B7_BE43) 24 | XCTAssertEqual(soto_crc32(0, bytes: "abc".utf8), 0x3524_41C2) 25 | XCTAssertEqual(soto_crc32(0, bytes: "message digest".utf8), 0x2015_9D7F) 26 | XCTAssertEqual(soto_crc32(0, bytes: "abcdefghijklmnopqrstuvwxyz".utf8), 0x4C27_50BD) 27 | } 28 | 29 | func testCRC32C() { 30 | XCTAssertEqual(soto_crc32c(0, bytes: "".utf8), 0) 31 | XCTAssertEqual(soto_crc32c(0, bytes: "a".utf8), 0xC1D0_4330) 32 | XCTAssertEqual(soto_crc32c(0, bytes: "foo".utf8), 0xCFC4_AE1D) 33 | XCTAssertEqual(soto_crc32c(0, bytes: "hello world".utf8), 0xC994_65AA) 34 | XCTAssertEqual(soto_crc32c(0, bytes: [UInt8](repeating: 0, count: 32)), 0x8A91_36AA) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Tests/SotoCoreTests/Concurrency/AsyncSequenceTests.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import NIOCore 16 | import SotoCore 17 | import SotoTestUtils 18 | import XCTest 19 | 20 | final class AsyncSequenceTests: XCTestCase { 21 | func testFixedSizeByteBufferSequence( 22 | bufferSize: Int, 23 | generatedByteBufferSizeRange: Range, 24 | fixedChunkSize: Int 25 | ) async throws { 26 | let bytes = createRandomBuffer(23, 4, size: bufferSize) 27 | let buffer = ByteBufferAllocator().buffer(bytes: bytes) 28 | let seq = TestByteBufferSequence(source: buffer, range: generatedByteBufferSizeRange) 29 | let chunkedSequence = seq.fixedSizeSequence(chunkSize: fixedChunkSize) 30 | var result = ByteBufferAllocator().buffer(capacity: bufferSize) 31 | var prevChunk: ByteBuffer? 32 | for try await chunk in chunkedSequence { 33 | // doing this so I don't check the length of the last chunk 34 | if let prevChunk { 35 | XCTAssertEqual(prevChunk.readableBytes, fixedChunkSize) 36 | } 37 | result.writeImmutableBuffer(chunk) 38 | prevChunk = chunk 39 | } 40 | XCTAssertEqual(buffer, result) 41 | } 42 | 43 | func testFixedSizeByteBufferLargerChunkSize() async throws { 44 | try await self.testFixedSizeByteBufferSequence(bufferSize: 16000, generatedByteBufferSizeRange: 1..<1000, fixedChunkSize: 4096) 45 | } 46 | 47 | func testFixedSizeByteBufferSmallerChunkSize() async throws { 48 | try await self.testFixedSizeByteBufferSequence(bufferSize: 16000, generatedByteBufferSizeRange: 500..<1000, fixedChunkSize: 256) 49 | } 50 | 51 | func testFixedSizeByteBufferSimilarSizedChunkSize() async throws { 52 | try await self.testFixedSizeByteBufferSequence(bufferSize: 16000, generatedByteBufferSizeRange: 1..<1000, fixedChunkSize: 500) 53 | } 54 | 55 | func testFixedSizeByteBufferBufferSizeIsMultipleOfChunkSize() async throws { 56 | try await self.testFixedSizeByteBufferSequence(bufferSize: 1000, generatedByteBufferSizeRange: 1..<200, fixedChunkSize: 250) 57 | try await self.testFixedSizeByteBufferSequence(bufferSize: 1000, generatedByteBufferSizeRange: 500..<1000, fixedChunkSize: 250) 58 | } 59 | 60 | func testFixedSizeByteBufferBufferSizeIsEqualToChunkSize() async throws { 61 | try await self.testFixedSizeByteBufferSequence(bufferSize: 1000, generatedByteBufferSizeRange: 500..<1000, fixedChunkSize: 1000) 62 | try await self.testFixedSizeByteBufferSequence(bufferSize: 1000, generatedByteBufferSizeRange: 1000..<1001, fixedChunkSize: 1000) 63 | } 64 | 65 | func testFixedSizeByteBufferShortSequence() async throws { 66 | try await self.testFixedSizeByteBufferSequence(bufferSize: 250, generatedByteBufferSizeRange: 500..<1000, fixedChunkSize: 1000) 67 | } 68 | } 69 | 70 | struct TestByteBufferSequence: AsyncSequence { 71 | typealias Element = ByteBuffer 72 | let source: ByteBuffer 73 | let range: Range 74 | 75 | struct AsyncIterator: AsyncIteratorProtocol { 76 | var source: ByteBuffer 77 | var range: Range 78 | 79 | mutating func next() async throws -> ByteBuffer? { 80 | let size = Swift.min(Int.random(in: self.range), self.source.readableBytes) 81 | if size == 0 { 82 | return nil 83 | } else { 84 | return self.source.readSlice(length: size) 85 | } 86 | } 87 | } 88 | 89 | /// Make async iterator 90 | public func makeAsyncIterator() -> AsyncIterator { 91 | AsyncIterator(source: self.source, range: self.range) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Tests/SotoCoreTests/Concurrency/Count.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | // Count type for testing concurrency primitives 16 | actor Count { 17 | var value: Int 18 | 19 | init(_ value: Int = 0) { 20 | self.value = value 21 | } 22 | 23 | func set(_ rhs: Int) { 24 | self.value = rhs 25 | } 26 | 27 | @discardableResult func add(_ rhs: Int) -> Int { 28 | self.value += rhs 29 | return self.value 30 | } 31 | 32 | @discardableResult func mul(_ rhs: Int) -> Int { 33 | self.value *= rhs 34 | return self.value 35 | } 36 | 37 | @discardableResult func min(_ rhs: Int) -> Int { 38 | self.value = Swift.min(self.value, rhs) 39 | return self.value 40 | } 41 | 42 | @discardableResult func max(_ rhs: Int) -> Int { 43 | self.value = Swift.max(self.value, rhs) 44 | return self.value 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Tests/SotoCoreTests/Concurrency/ExpiringValueTests.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import Atomics 16 | import XCTest 17 | 18 | @testable import SotoCore 19 | 20 | final class ExpiringValueTests: XCTestCase { 21 | /// Test value returned from closure is given back 22 | func testValue() async throws { 23 | let expiringValue = ExpiringValue() 24 | let value = try await expiringValue.getValue { 25 | try await Task.sleep(nanoseconds: 1000) 26 | return (1, Date()) 27 | } 28 | XCTAssertEqual(value, 1) 29 | } 30 | 31 | /// Test an expired value is updated 32 | func testExpiredValue() async throws { 33 | let expiringValue = ExpiringValue(0, expires: Date()) 34 | let value = try await expiringValue.getValue { 35 | try await Task.sleep(nanoseconds: 1000) 36 | return (1, Date()) 37 | } 38 | XCTAssertEqual(value, 1) 39 | } 40 | 41 | /// Test when a value is just about to expire it returns current value and kicks off 42 | /// new task to get new value 43 | func testJustAboutToExpireValue() async throws { 44 | let expiringValue = ExpiringValue(0, expires: Date() + 1, threshold: 3) 45 | let (stream, source) = AsyncStream.makeStream() 46 | let value = try await expiringValue.getValue { 47 | source.finish() 48 | try await Task.sleep(nanoseconds: 1000) 49 | return (1, Date()) 50 | } 51 | await stream.first { _ in true } 52 | // test it return current value 53 | XCTAssertEqual(value, 0) 54 | } 55 | 56 | /// Test closure is not called if value has not expired 57 | func testClosureNotCalled() async throws { 58 | let called = ManagedAtomic(false) 59 | let expiringValue = ExpiringValue(0, expires: Date.distantFuture, threshold: 1) 60 | let value = try await expiringValue.getValue { 61 | called.store(true, ordering: .relaxed) 62 | try await Task.sleep(nanoseconds: 1000) 63 | return (1, Date()) 64 | } 65 | XCTAssertEqual(value, 0) 66 | XCTAssertEqual(called.load(ordering: .relaxed), false) 67 | } 68 | 69 | /// Test closure is only called once even though we asked for value 100 times 70 | func testClosureCalledOnce() async throws { 71 | let callCount = ManagedAtomic(0) 72 | let expiringValue = ExpiringValue() 73 | try await withThrowingTaskGroup(of: Int.self) { group in 74 | for _ in 0..<100 { 75 | group.addTask { 76 | try await expiringValue.getValue { 77 | callCount.wrappingIncrement(by: 1, ordering: .relaxed) 78 | try await Task.sleep(nanoseconds: 100_000) 79 | return (123, Date.distantFuture) 80 | } 81 | } 82 | } 83 | for try await result in group { 84 | XCTAssertEqual(result, 123) 85 | } 86 | } 87 | XCTAssertEqual(callCount.load(ordering: .relaxed), 1) 88 | } 89 | 90 | /// Test value returned from closure is given back 91 | func testInitialClosure() async throws { 92 | let expiringValue = ExpiringValue { 93 | try await Task.sleep(nanoseconds: 1000) 94 | return (1, Date() + 3) 95 | } 96 | let value = try await expiringValue.getValue { 97 | return (2, Date()) 98 | } 99 | XCTAssertEqual(value, 1) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Tests/SotoCoreTests/Concurrency/Sequence+concurrentMapTests.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import SotoCore 16 | import XCTest 17 | 18 | final class MapTests: XCTestCase { 19 | func testConcurrentMap() async throws { 20 | let array = Array(0..<800) 21 | let result = try await array.concurrentMap { value -> Int in 22 | try await Task.sleep(nanoseconds: UInt64.random(in: 1000..<100_000)) 23 | return value 24 | } 25 | 26 | XCTAssertEqual(result, array) 27 | } 28 | 29 | func testConcurrentMapWithString() async throws { 30 | let array = Array(0..<800) 31 | let result = try await array.concurrentMap { value -> String in 32 | try await Task.sleep(nanoseconds: UInt64.random(in: 1000..<100_000)) 33 | return String(value) 34 | } 35 | 36 | XCTAssertEqual(result, array.map { String($0) }) 37 | } 38 | 39 | func testConcurrentMapConcurrency() async throws { 40 | let count = Count(0) 41 | let maxCount = Count(0) 42 | 43 | let array = Array(0..<800) 44 | let result = try await array.concurrentMap { value -> Int in 45 | let c = await count.add(1) 46 | await maxCount.max(c) 47 | try await Task.sleep(nanoseconds: UInt64.random(in: 1000..<100_000)) 48 | await count.add(-1) 49 | return value 50 | } 51 | 52 | XCTAssertEqual(result, array) 53 | let maxValue = await maxCount.value 54 | XCTAssertGreaterThan(maxValue, 1) 55 | } 56 | 57 | func testConcurrentMapConcurrencyWithMaxTasks() async throws { 58 | let count = Count(0) 59 | let maxCount = Count(0) 60 | 61 | let array = Array(0..<800) 62 | let result = try await array.concurrentMap(maxConcurrentTasks: 4) { value -> Int in 63 | let c = await count.add(1) 64 | await maxCount.max(c) 65 | try await Task.sleep(nanoseconds: UInt64.random(in: 1000..<100_000)) 66 | await count.add(-1) 67 | return value 68 | } 69 | 70 | XCTAssertEqual(result, array) 71 | let maxValue = await maxCount.value 72 | XCTAssertLessThanOrEqual(maxValue, 4) 73 | XCTAssertGreaterThan(maxValue, 1) 74 | } 75 | 76 | func testConcurrentMapErrorThrowing() async throws { 77 | struct TaskError: Error {} 78 | 79 | do { 80 | _ = try await (1...8).concurrentMap { element -> Int in 81 | if element == 4 { 82 | throw TaskError() 83 | } 84 | return element 85 | } 86 | XCTFail("Should have failed") 87 | } catch is TaskError { 88 | } catch { 89 | XCTFail("Error: \(error)") 90 | } 91 | } 92 | 93 | func testConcurrentMapCancellation() async throws { 94 | let count = Count(1) 95 | 96 | let array = Array((1...8).reversed()) 97 | let task = Task { 98 | _ = try await array.concurrentMap { value -> Int in 99 | try await Task.sleep(nanoseconds: numericCast(value) * 1000 * 100) 100 | await count.mul(value) 101 | return value 102 | } 103 | } 104 | try await Task.sleep(nanoseconds: 1 * 1000 * 100) 105 | task.cancel() 106 | let value = await count.value 107 | XCTAssertNotEqual(value, 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Tests/SotoCoreTests/Credential/StaticCredential+EnvironmentTests.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import XCTest 16 | 17 | @testable import SotoCore 18 | 19 | #if canImport(Glibc) 20 | import Glibc 21 | #elseif canImport(Musl) 22 | import Musl 23 | #elseif canImport(Darwin) 24 | import Darwin.C 25 | #elseif canImport(Android) 26 | import Android 27 | #else 28 | #error("Unsupported platform") 29 | #endif 30 | 31 | extension Environment { 32 | static func set(_ value: String, for name: String) { 33 | guard setenv(name, value, 1) == 0 else { 34 | XCTFail() 35 | return 36 | } 37 | } 38 | 39 | static func unset(name: String) { 40 | XCTAssertEqual(unsetenv(name), 0) 41 | } 42 | } 43 | 44 | class StaticCredential_EnvironmentTests: XCTestCase { 45 | func testSuccess() async throws { 46 | let accessKeyId = "AWSACCESSKEYID" 47 | let secretAccessKet = "AWSSECRETACCESSKEY" 48 | let sessionToken = "AWSSESSIONTOKEN" 49 | 50 | Environment.set(accessKeyId, for: "AWS_ACCESS_KEY_ID") 51 | Environment.set(secretAccessKet, for: "AWS_SECRET_ACCESS_KEY") 52 | Environment.set(sessionToken, for: "AWS_SESSION_TOKEN") 53 | defer { 54 | Environment.unset(name: "AWS_ACCESS_KEY_ID") 55 | Environment.unset(name: "AWS_SECRET_ACCESS_KEY") 56 | Environment.unset(name: "AWS_SESSION_TOKEN") 57 | } 58 | 59 | let staticCredentials = StaticCredential.fromEnvironment() 60 | let cred = try await staticCredentials?.getCredential(logger: .init(label: #function)) 61 | 62 | XCTAssertEqual(cred?.accessKeyId, accessKeyId) 63 | XCTAssertEqual(cred?.secretAccessKey, secretAccessKet) 64 | XCTAssertEqual(cred?.sessionToken, sessionToken) 65 | } 66 | 67 | func testFailWithoutAccessKeyId() { 68 | let secretAccessKet = "AWSSECRETACCESSKEY" 69 | let sessionToken = "AWSSESSIONTOKEN" 70 | 71 | Environment.set(secretAccessKet, for: "AWS_SECRET_ACCESS_KEY") 72 | Environment.set(sessionToken, for: "AWS_SESSION_TOKEN") 73 | defer { 74 | Environment.unset(name: "AWS_ACCESS_KEY_ID") 75 | Environment.unset(name: "AWS_SECRET_ACCESS_KEY") 76 | } 77 | 78 | let cred = StaticCredential.fromEnvironment() 79 | 80 | XCTAssertNil(cred) 81 | } 82 | 83 | func testFailWithoutSecretAccessKey() { 84 | let accessKeyId = "AWSACCESSKEYID" 85 | let sessionToken = "AWSSESSIONTOKEN" 86 | 87 | Environment.set(accessKeyId, for: "AWS_ACCESS_KEY_ID") 88 | Environment.set(sessionToken, for: "AWS_SESSION_TOKEN") 89 | defer { 90 | Environment.unset(name: "AWS_ACCESS_KEY_ID") 91 | Environment.unset(name: "AWS_SECRET_ACCESS_KEY") 92 | } 93 | 94 | let cred = StaticCredential.fromEnvironment() 95 | 96 | XCTAssertNil(cred) 97 | } 98 | 99 | func testSuccessWithoutSessionToken() async throws { 100 | let accessKeyId = "AWSACCESSKEYID" 101 | let secretAccessKet = "AWSSECRETACCESSKEY" 102 | 103 | Environment.set(accessKeyId, for: "AWS_ACCESS_KEY_ID") 104 | Environment.set(secretAccessKet, for: "AWS_SECRET_ACCESS_KEY") 105 | defer { 106 | Environment.unset(name: "AWS_ACCESS_KEY_ID") 107 | Environment.unset(name: "AWS_SECRET_ACCESS_KEY") 108 | } 109 | 110 | let staticCredentials = StaticCredential.fromEnvironment() 111 | let cred = try await staticCredentials?.getCredential(logger: .init(label: #function)) 112 | 113 | XCTAssertEqual(cred?.accessKeyId, accessKeyId) 114 | XCTAssertEqual(cred?.secretAccessKey, secretAccessKet) 115 | XCTAssertNil(cred?.sessionToken) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /Tests/SotoCoreTests/Doc/ARNTests.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2020 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #if compiler(>=6.0) 16 | 17 | import SotoCore 18 | import Testing 19 | 20 | struct ARNTests { 21 | @Test 22 | func testValidARNWithoutResourceType() throws { 23 | let arn = try #require(ARN(string: "arn:aws:sns:us-east-1:123456789012:example-sns-topic-name")) 24 | #expect(arn.partition == .aws) 25 | #expect(arn.service == "sns") 26 | #expect(arn.region == .useast1) 27 | #expect(arn.accountId == "123456789012") 28 | #expect(arn.resourceId == "example-sns-topic-name") 29 | #expect(arn.resourceType == nil) 30 | } 31 | 32 | @Test(arguments: [ 33 | "arn:aws:ec2:us-west-1:123456789012:vpc/vpc-0e9801d129EXAMPLE", 34 | "arn:aws:ec2:us-west-1:123456789012:vpc:vpc-0e9801d129EXAMPLE", 35 | ]) 36 | func testValidARNWithoutWithResourceType(arnString: String) throws { 37 | let arn = try #require(ARN(string: arnString)) 38 | #expect(arn.partition == .aws) 39 | #expect(arn.service == "ec2") 40 | #expect(arn.region == .uswest1) 41 | #expect(arn.accountId == "123456789012") 42 | #expect(arn.resourceId == "vpc-0e9801d129EXAMPLE") 43 | #expect(arn.resourceType == "vpc") 44 | } 45 | 46 | @Test 47 | func testValidARNWithoutRegion() throws { 48 | let arn = try #require(ARN(string: "arn:aws:iam::123456789012:user/adam")) 49 | #expect(arn.partition == .aws) 50 | #expect(arn.service == "iam") 51 | #expect(arn.region == nil) 52 | #expect(arn.accountId == "123456789012") 53 | #expect(arn.resourceId == "adam") 54 | #expect(arn.resourceType == "user") 55 | } 56 | 57 | @Test 58 | func testValidARNWithoutAccountID() throws { 59 | let arn = try #require(ARN(string: "arn:aws:s3:::my_corporate_bucket/*")) 60 | #expect(arn.partition == .aws) 61 | #expect(arn.service == "s3") 62 | #expect(arn.region == nil) 63 | #expect(arn.accountId == nil) 64 | #expect(arn.resourceId == "*") 65 | #expect(arn.resourceType == "my_corporate_bucket") 66 | } 67 | 68 | } 69 | #endif 70 | -------------------------------------------------------------------------------- /Tests/SotoCoreTests/Doc/EnvironmentTests.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2020 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import XCTest 16 | 17 | @testable import SotoCore 18 | 19 | class EnvironmentTests: XCTestCase { 20 | func testGetPathFromEnvironment() { 21 | let path = Environment["PATH"] 22 | XCTAssertNotNil(path) 23 | XCTAssertNotEqual(path, "") 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Tests/SotoCoreTests/TracingTests.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2023 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import NIOPosix 16 | import SotoCore 17 | import SotoTestUtils 18 | import Tracing 19 | import XCTest 20 | 21 | @testable import Instrumentation 22 | 23 | final class TracingTests: XCTestCase { 24 | func wait(for expectations: [XCTestExpectation], timeout: TimeInterval) async { 25 | await fulfillment(of: expectations, timeout: timeout) 26 | } 27 | 28 | func testTracingMiddleware() async throws { 29 | let expectation = expectation(description: "Expected span to be ended.") 30 | 31 | let tracer = TestTracer { 32 | _ in expectation.fulfill() 33 | } 34 | InstrumentationSystem.bootstrapInternal(tracer) 35 | 36 | let awsServer = AWSTestServer(serviceProtocol: .json) 37 | let config = createServiceConfig( 38 | service: "TestService", 39 | serviceProtocol: .json(version: "1.1"), 40 | endpoint: awsServer.address, 41 | middlewares: AWSTracingMiddleware() 42 | ) 43 | let client = createAWSClient( 44 | credentialProvider: .empty 45 | ) 46 | defer { 47 | XCTAssertNoThrow(try client.syncShutdown()) 48 | XCTAssertNoThrow(try awsServer.stop()) 49 | } 50 | async let response: Void = client.execute( 51 | operation: "TestOperation", 52 | path: "/", 53 | httpMethod: .POST, 54 | serviceConfig: config, 55 | logger: TestEnvironment.logger 56 | ) 57 | 58 | try awsServer.processRaw { _ in 59 | let response = AWSTestServer.Response(httpStatus: .ok, headers: ["x-amz-request-id": "test-request-1"], body: nil) 60 | return .result(response) 61 | } 62 | 63 | _ = try await response 64 | 65 | await self.wait(for: [expectation], timeout: 1.0) 66 | 67 | let span = try tracer.spans.withLockedValue { 68 | try XCTUnwrap($0.first) 69 | } 70 | 71 | XCTAssertEqual(span.operationName, "TestService.TestOperation") 72 | XCTAssertTrue(span.recordedErrors.isEmpty) 73 | 74 | XCTAssertSpanAttributesEqual( 75 | span.attributes, 76 | [ 77 | "rpc.system": "aws-sdk", 78 | "rpc.method": "TestOperation", 79 | "rpc.service": "TestService", 80 | "aws.request_id": "test-request-1", 81 | ] 82 | ) 83 | } 84 | } 85 | 86 | private func XCTAssertSpanAttributesEqual( 87 | _ lhs: @autoclosure () -> SpanAttributes, 88 | _ rhs: @autoclosure () -> [String: SpanAttribute], 89 | file: StaticString = #filePath, 90 | line: UInt = #line 91 | ) { 92 | var rhs = rhs() 93 | 94 | lhs().forEach { key, attribute in 95 | if let rhsValue = rhs.removeValue(forKey: key) { 96 | if rhsValue != attribute { 97 | XCTFail( 98 | #""\#(key)" was expected to be "\#(rhsValue)" but is actually "\#(attribute)"."#, 99 | file: file, 100 | line: line 101 | ) 102 | } 103 | } else { 104 | XCTFail( 105 | #"Did not specify expected value for "\#(key)", actual value is "\#(attribute)"."#, 106 | file: file, 107 | line: line 108 | ) 109 | } 110 | } 111 | 112 | if !rhs.isEmpty { 113 | XCTFail(#"Expected attributes "\#(rhs.keys)" are not present in actual attributes."#, file: file, line: line) 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Tests/SotoSignerV4Tests/SigV4aTests.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2025 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | import SotoSignerV4 16 | @_spi(SotoInternal) import SotoSignerV4 17 | import XCTest 18 | 19 | final class SigV4aTests: XCTestCase { 20 | 21 | func testCompareConstantTime() { 22 | 23 | let lhs1: [UInt8] = [0x00, 0x00, 0x00] 24 | let rhs1: [UInt8] = [0x00, 0x00, 0x01] 25 | let lhs2: [UInt8] = [0xAB, 0xCD, 0x80, 0xFF, 0x01, 0x0A] 26 | let rhs2: [UInt8] = [0xAB, 0xCD, 0x80, 0xFF, 0x01, 0x0A] 27 | let lhs3: [UInt8] = [0xFF, 0xCD, 0x80, 0xFF, 0x01, 0x0A] 28 | let rhs3: [UInt8] = [0xFE, 0xCD, 0x80, 0xFF, 0x01, 0x0A] 29 | 30 | XCTAssertEqual(SigV4aKeyPair.compareConstantTime(lhs: lhs1, rhs: rhs1), -1) 31 | XCTAssertEqual(SigV4aKeyPair.compareConstantTime(lhs: lhs2, rhs: rhs2), 0) 32 | XCTAssertEqual(SigV4aKeyPair.compareConstantTime(lhs: lhs3, rhs: rhs3), 1) 33 | 34 | } 35 | 36 | func testAddOne() { 37 | XCTAssertEqual([0x00, 0x00, 0x00].addingOne(), [0x00, 0x00, 0x01]) 38 | XCTAssertEqual([0x00, 0x00, 0xFF].addingOne(), [0x00, 0x01, 0x00]) 39 | XCTAssertEqual([0x00, 0xFF, 0xFF].addingOne(), [0x01, 0x00, 0x00]) 40 | XCTAssertEqual([0xFF, 0xFF, 0xFF, 0xFF].addingOne(), [0x00, 0x00, 0x00, 0x00]) 41 | } 42 | 43 | func testDerivedStaticKey() { 44 | let accessKey = "AKISORANDOMAASORANDOM" 45 | let secretAccessKey = "q+jcrXGc+0zWN6uzclKVhvMmUsIfRPa4rlRandom" 46 | 47 | let expectedPrivateKeyHex = "7fd3bd010c0d9c292141c2b77bfbde1042c92e6836fff749d1269ec890fca1bd" 48 | 49 | let credential = StaticCredential(accessKeyId: accessKey, secretAccessKey: secretAccessKey) 50 | 51 | let result = SigV4aKeyPair(credential: credential) 52 | XCTAssertEqual(result.key.rawRepresentation.hexDigest(), expectedPrivateKeyHex) 53 | } 54 | 55 | func testDeriveLongKey() { 56 | let accessKey = """ 57 | AKISORANDOMAASORANDOMFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\ 58 | FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\ 59 | FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFf 60 | """ 61 | let secretAccessKey = "q+jcrXGc+0zWN6uzclKVhvMmUsIfRPa4rlRandom" 62 | 63 | let expectedPrivateKeyHex = "bc0fd68955922f2cccd5c27f8aa04394a467ef1076d889b66569c6d2e764faf3" 64 | 65 | let credential = StaticCredential(accessKeyId: accessKey, secretAccessKey: secretAccessKey) 66 | 67 | let result = SigV4aKeyPair(credential: credential) 68 | XCTAssertEqual(result.key.rawRepresentation.hexDigest(), expectedPrivateKeyHex) 69 | XCTAssertEqual(String(decoding: HexEncoding(result.key.rawRepresentation), as: Unicode.UTF8.self), expectedPrivateKeyHex) 70 | } 71 | 72 | func testHexEncoding() { 73 | XCTAssertEqual(String(decoding: HexEncoding([0]), as: Unicode.UTF8.self), "00") 74 | XCTAssertEqual(String(decoding: HexEncoding([1]), as: Unicode.UTF8.self), "01") 75 | XCTAssertEqual(String(decoding: HexEncoding([254]), as: Unicode.UTF8.self), "fe") 76 | XCTAssertEqual(String(decoding: HexEncoding([255]), as: Unicode.UTF8.self), "ff") 77 | XCTAssertEqual(String(decoding: HexEncoding([254, 255, 0]), as: Unicode.UTF8.self), "feff00") 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /scripts/build-docc.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eux 3 | 4 | TEMP_DIR="$(pwd)/temp" 5 | 6 | cleanup() 7 | { 8 | if [ -n "$TEMP_DIR" ]; then 9 | rm -rf $TEMP_DIR 10 | fi 11 | } 12 | trap cleanup exit $? 13 | 14 | DOCC=${DOCC:-} 15 | if [[ -z "$DOCC" ]]; then 16 | if [[ "$(uname)" == "Darwin" ]]; then 17 | DOCC=$(xcrun --find docc) 18 | else 19 | DOCC=$(which docc) 20 | fi 21 | fi 22 | echo "Found docc here ${DOCC}" 23 | VERSION=7.x.x 24 | SG_FOLDER=.build/symbol-graphs 25 | SOTOCORE_SG_FOLDER=.build/soto-core-symbol-graphs 26 | OUTPUT_PATH=docs/soto-core/$VERSION 27 | 28 | BUILD_SYMBOLS=1 29 | 30 | while getopts 's' option 31 | do 32 | case $option in 33 | s) BUILD_SYMBOLS=0;; 34 | esac 35 | done 36 | 37 | if [ -z "${DOCC_HTML_DIR:-}" ]; then 38 | git clone https://github.com/apple/swift-docc-render-artifact $TEMP_DIR/swift-docc-render-artifact 39 | export DOCC_HTML_DIR="$TEMP_DIR/swift-docc-render-artifact/dist" 40 | fi 41 | 42 | if test "$BUILD_SYMBOLS" == 1; then 43 | # build symbol graphs 44 | mkdir -p $SG_FOLDER 45 | swift build \ 46 | -Xswiftc -emit-symbol-graph \ 47 | -Xswiftc -emit-symbol-graph-dir -Xswiftc $SG_FOLDER 48 | # Copy SotoCore symbol graph into separate folder 49 | mkdir -p $SOTOCORE_SG_FOLDER 50 | cp $SG_FOLDER/SotoCore* $SOTOCORE_SG_FOLDER 51 | cp $SG_FOLDER/SotoSignerV4* $SOTOCORE_SG_FOLDER 52 | fi 53 | 54 | # Build documentation 55 | mkdir -p $OUTPUT_PATH 56 | rm -rf $OUTPUT_PATH/* 57 | $DOCC convert SotoCore.docc \ 58 | --transform-for-static-hosting \ 59 | --hosting-base-path /soto-core/$VERSION \ 60 | --fallback-display-name SotoCore \ 61 | --fallback-bundle-identifier codes.soto.soto-core \ 62 | --fallback-bundle-version 1 \ 63 | --additional-symbol-graph-dir $SOTOCORE_SG_FOLDER \ 64 | --output-path $OUTPUT_PATH 65 | -------------------------------------------------------------------------------- /scripts/build-docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ##===----------------------------------------------------------------------===## 3 | ## 4 | ## This source file is part of the Soto for AWS open source project 5 | ## 6 | ## Copyright (c) 2020 the Soto project authors 7 | ## Licensed under Apache License v2.0 8 | ## 9 | ## See LICENSE.txt for license information 10 | ## See CONTRIBUTORS.txt for the list of Soto project authors 11 | ## 12 | ## SPDX-License-Identifier: Apache-2.0 13 | ## 14 | ##===----------------------------------------------------------------------===## 15 | 16 | set -eux 17 | 18 | # make temp directory 19 | mkdir -p sourcekitten 20 | 21 | # generate source kitten json 22 | sourcekitten doc --spm --module-name "SotoCore" > sourcekitten/SotoCore.json; 23 | 24 | # generate documentation with jazzy 25 | jazzy --clean 26 | 27 | # tidy up 28 | rm -rf sourcekitten 29 | rm -rf docs/docsets 30 | -------------------------------------------------------------------------------- /scripts/commit-docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ##===----------------------------------------------------------------------===## 3 | ## 4 | ## This source file is part of the Soto for AWS open source project 5 | ## 6 | ## Copyright (c) 2020 the Soto project authors 7 | ## Licensed under Apache License v2.0 8 | ## 9 | ## See LICENSE.txt for license information 10 | ## See CONTRIBUTORS.txt for the list of Soto project authors 11 | ## 12 | ## SPDX-License-Identifier: Apache-2.0 13 | ## 14 | ##===----------------------------------------------------------------------===## 15 | 16 | set -eux 17 | 18 | FOLDER=5.x.x 19 | 20 | # stash everything that isn't in docs, store result in STASH_RESULT 21 | STASH_RESULT=$(git stash push -- ":(exclude)docs") 22 | # get branch name 23 | CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) 24 | REVISION_HASH=$(git rev-parse HEAD) 25 | 26 | git checkout gh-pages 27 | # copy contents of docs to docs/current replacing the ones that are already there 28 | rm -rf "$FOLDER" 29 | mv docs/ "$FOLDER"/ 30 | # commit 31 | git add --all "$FOLDER" 32 | git commit -m "Documentation for https://github.com/soto-project/soto-core/tree/$REVISION_HASH" 33 | git push 34 | # return to branch 35 | git checkout $CURRENT_BRANCH 36 | 37 | if [ "$STASH_RESULT" != "No local changes to save" ]; then 38 | git stash pop 39 | fi 40 | 41 | -------------------------------------------------------------------------------- /scripts/expat-symbols.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ##===----------------------------------------------------------------------===## 3 | ## 4 | ## This source file is part of the Soto for AWS open source project 5 | ## 6 | ## Copyright (c) 2020 the Soto project authors 7 | ## Licensed under Apache License v2.0 8 | ## 9 | ## See LICENSE.txt for license information 10 | ## See CONTRIBUTORS.txt for the list of Soto project authors 11 | ## 12 | ## SPDX-License-Identifier: Apache-2.0 13 | ## 14 | ##===----------------------------------------------------------------------===## 15 | 16 | EXPAT_PREFIX_FILE="Sources/CSotoExpat/include/expat_prefix_symbols.h" 17 | 18 | # build CSotoExpat 19 | swift build --product CSotoExpat --enable-test-discovery 20 | 21 | # get public symbols 22 | find .build/x86_64-apple-macosx/debug/CSotoExpat.build -name "*.o" -exec nm -gUj {} \; > symbols.txt 23 | 24 | cat > "$EXPAT_PREFIX_FILE" << "EOF" 25 | //===----------------------------------------------------------------------===// 26 | // 27 | // This source file is part of the Soto for AWS open source project 28 | // 29 | // Copyright (c) 2017-2020 the Soto project authors 30 | // Licensed under Apache License v2.0 31 | // 32 | // See LICENSE.txt for license information 33 | // See CONTRIBUTORS.txt for the list of Soto project authors 34 | // 35 | // SPDX-License-Identifier: Apache-2.0 36 | // 37 | //===----------------------------------------------------------------------===// 38 | 39 | #ifndef _EXPAT_PREFIX_SYMBOLS_H_ 40 | #define _EXPAT_PREFIX_SYMBOLS_H_ 41 | 42 | #define EXPAT_PREFIX Soto 43 | #define EXPAT_ADD_PREFIX(a, b) a ## _ ## b 44 | 45 | EOF 46 | 47 | for i in $( cat symbols.txt ); do 48 | SYMBOL="${i:1}" 49 | echo "#define $SYMBOL EXPAT_ADD_PREFIX(EXPAT_PREFIX, $SYMBOL)" >> "$EXPAT_PREFIX_FILE" 50 | done 51 | 52 | cat >> "$EXPAT_PREFIX_FILE" << "EOF" 53 | 54 | #endif // _EXPAT_PREFIX_SYMBOLS_H_ 55 | EOF 56 | -------------------------------------------------------------------------------- /scripts/generate-contributors-list.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ##===----------------------------------------------------------------------===## 3 | ## 4 | ## This source file is part of the SwiftNIO open source project 5 | ## 6 | ## Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors 7 | ## Licensed under Apache License v2.0 8 | ## 9 | ## See LICENSE.txt for license information 10 | ## See CONTRIBUTORS.txt for the list of SwiftNIO project authors 11 | ## 12 | ## SPDX-License-Identifier: Apache-2.0 13 | ## 14 | ##===----------------------------------------------------------------------===## 15 | 16 | set -eu 17 | here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 18 | contributors=$( cd "$here"/.. && git shortlog -es | cut -f2 | sed 's/^/- /' ) 19 | 20 | cat > "$here/../CONTRIBUTORS.txt" <<- EOF 21 | For the purpose of tracking copyright, this is the list of individuals and 22 | organizations who have contributed source code to soto-core. 23 | 24 | For employees of an organization/company where the copyright of work done 25 | by employees of that company is held by the company itself, only the company 26 | needs to be listed here. 27 | 28 | ## COPYRIGHT HOLDERS 29 | 30 | ### Contributors 31 | 32 | $contributors 33 | 34 | **Updating this list** 35 | 36 | Please do not edit this file manually. It is generated using \`./scripts/generate_contributors_list.sh\`. If a name is misspelled or appearing multiple times: add an entry in \`./.mailmap\` 37 | EOF 38 | -------------------------------------------------------------------------------- /scripts/generate-docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ##===----------------------------------------------------------------------===## 3 | ## 4 | ## This source file is part of the Soto for AWS open source project 5 | ## 6 | ## Copyright (c) 2020 the Soto project authors 7 | ## Licensed under Apache License v2.0 8 | ## 9 | ## See LICENSE.txt for license information 10 | ## See CONTRIBUTORS.txt for the list of Soto project authors 11 | ## 12 | ## SPDX-License-Identifier: Apache-2.0 13 | ## 14 | ##===----------------------------------------------------------------------===## 15 | 16 | set -eux 17 | 18 | DIRNAME=$(dirname "$0") 19 | 20 | source "$DIRNAME"/build-docs.sh 21 | source "$DIRNAME"/commit-docs.sh 22 | 23 | -------------------------------------------------------------------------------- /scripts/generate-region-test.swift: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env swift sh 2 | //===----------------------------------------------------------------------===// 3 | // 4 | // This source file is part of the Soto for AWS open source project 5 | // 6 | // Copyright (c) 2017-2020 the Soto project authors 7 | // Licensed under Apache License v2.0 8 | // 9 | // See LICENSE.txt for license information 10 | // See CONTRIBUTORS.txt for the list of Soto project authors 11 | // 12 | // SPDX-License-Identifier: Apache-2.0 13 | // 14 | //===----------------------------------------------------------------------===// 15 | 16 | import Foundation 17 | import SotoCore // soto-project/soto-core ~> 5.0.0-beta.3.0 18 | import SotoSSM // soto-project/soto ~> 5.0.0-beta.3.0 19 | import Stencil // soto-project/Stencil 20 | 21 | let REGION_PATH = "/aws/service/global-infrastructure/regions" 22 | 23 | print("Loading Region List") 24 | struct RegionDesc { 25 | let `enum`: String 26 | let name: String 27 | } 28 | 29 | var regionDescs: [RegionDesc] = [] 30 | 31 | let client = AWSClient() 32 | let ssm = SSM(client: client, region: Region.euwest1) 33 | let request = SSM.GetParametersByPathRequest( 34 | path: REGION_PATH 35 | ) 36 | do { 37 | var result = try ssm.getParametersByPath(request).wait() 38 | while result.nextToken != nil { 39 | for p in result.parameters! { 40 | regionDescs.append( 41 | RegionDesc(enum: p.value!.filter { $0.isLetter || $0.isNumber }, name: p.value!) 42 | ) 43 | } 44 | let request = SSM.GetParametersByPathRequest( 45 | nextToken: result.nextToken, 46 | path: REGION_PATH 47 | ) 48 | result = try ssm.getParametersByPath(request).wait() 49 | } 50 | } catch (let error) { 51 | print("Failed with \(error)") 52 | } 53 | 54 | print("Loading templates") 55 | let fsLoader = FileSystemLoader(paths: ["./scripts/templates/generate-region"]) 56 | let environment = Environment(loader: fsLoader) 57 | 58 | print("Creating RegionTests.swift") 59 | 60 | let context: [String: Any] = [ 61 | "regions": regionDescs.sorted { $0.name < $1.name } 62 | ] 63 | 64 | let regionsFile = try environment.renderTemplate(name: "Region-Tests.stencil", context: context) 65 | try Data(regionsFile.utf8).write(to: URL(fileURLWithPath: "Tests/SotoCoreTests/Doc/RegionTests.swift")) 66 | 67 | print("Done") 68 | -------------------------------------------------------------------------------- /scripts/templates/generate-errors/generate-errors.stencil: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2022 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | // THIS FILE IS AUTOMATICALLY GENERATED by https://github.com/soto-project/soto-core/scripts/generate-errors.swift. DO NOT EDIT. 16 | 17 | import NIOHTTP1 18 | 19 | public struct {{name}}: AWSErrorType { 20 | enum Code: String { 21 | {%for error in errors %} 22 | case {{error.enum}} = "{{error.name}}" 23 | {%endfor %} 24 | } 25 | 26 | private let error: Code 27 | public let context: AWSErrorContext? 28 | 29 | /// initialize {{name}} 30 | public init?(errorCode: String, context: AWSErrorContext) { 31 | var errorCode = errorCode 32 | // remove "Exception" suffix 33 | if errorCode.hasSuffix("Exception") { 34 | errorCode = String(errorCode.dropLast(9)) 35 | } 36 | guard let error = Code(rawValue: errorCode) else { return nil } 37 | self.error = error 38 | self.context = context 39 | } 40 | 41 | internal init(_ error: Code, context: AWSErrorContext? = nil) { 42 | self.error = error 43 | self.context = context 44 | } 45 | 46 | /// return error code string 47 | public var errorCode: String { self.error.rawValue } 48 | 49 | {%for error in errors %} 50 | // {{error.description}} 51 | public static var {{error.enum}}: {{name}} { .init(.{{error.enum}}) } 52 | {%endfor %} 53 | } 54 | 55 | extension {{name}}: Equatable { 56 | public static func == (lhs: {{name}}, rhs: {{name}}) -> Bool { 57 | lhs.error == rhs.error 58 | } 59 | } 60 | 61 | extension {{name}}: CustomStringConvertible { 62 | public var description: String { 63 | return "\(self.error.rawValue): \(message ?? "")" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /scripts/templates/generate-region/Region-Tests.stencil: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2022 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | // THIS FILE IS AUTOMATICALLY GENERATED by https://github.com/soto-project/soto-core/scripts/generate-region-tests.swift. DO NOT EDIT. 16 | 17 | import SotoCore 18 | import XCTest 19 | 20 | class RegionTests: XCTestCase { 21 | 22 | private func testStringToOneRegion(regionName: String, regionEnum: Region) { 23 | let region = Region(awsRegionName: regionName) 24 | XCTAssertNotNil(region) 25 | XCTAssert(region! == regionEnum) 26 | } 27 | 28 | func testStringToRegion() { 29 | 30 | {%for region in regions %} 31 | self.testStringToOneRegion(regionName: "{{region.name}}", regionEnum: Region.{{region.enum}}) 32 | {%endfor %} 33 | } 34 | 35 | func testStringToInvalidRegion() { 36 | XCTAssertNil(Region(awsRegionName: "xxx")) 37 | } 38 | 39 | func testRegionEnumRawValue() { 40 | let region = Region(rawValue: "my-region") 41 | if Region.other("my-region") == region { 42 | XCTAssertEqual(region.rawValue, "my-region") 43 | } else { 44 | XCTFail("Did not construct Region.other()") 45 | } 46 | } 47 | 48 | func testRegionEnumExistingRegion() { 49 | var region : Region 50 | 51 | {%for region in regions %} 52 | region = Region(rawValue: "{{region.name}}") 53 | if Region.{{region.enum}} == region { 54 | XCTAssertEqual(region.rawValue, "{{region.name}}") 55 | } else { 56 | XCTFail("Did not construct Region(rawValue:) for {{region.name}}") 57 | } 58 | 59 | {%endfor %} 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /scripts/templates/generate-region/Region.stencil: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Soto for AWS open source project 4 | // 5 | // Copyright (c) 2017-2022 the Soto project authors 6 | // Licensed under Apache License v2.0 7 | // 8 | // See LICENSE.txt for license information 9 | // See CONTRIBUTORS.txt for the list of Soto project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | // THIS FILE IS AUTOMATICALLY GENERATED by https://github.com/soto-project/soto-core/scripts/generate-region.swift. DO NOT EDIT. 16 | 17 | /// Enumeration for all AWS server regions 18 | public struct Region: Sendable, RawRepresentable, Equatable { 19 | public var rawValue: String 20 | 21 | public init(rawValue: String) { 22 | self.rawValue = rawValue 23 | } 24 | 25 | {%for region in regions %} 26 | // {{region.description}} 27 | public static var {{region.enum}}: Region { .init(rawValue: "{{region.name}}") } 28 | {%endfor %} 29 | // other region 30 | public static func other(_ name: String) -> Region { .init(rawValue: name) } 31 | } 32 | 33 | public extension Region { 34 | var partition: AWSPartition { 35 | switch self { 36 | {%for region in regions %} 37 | case .{{region.enum}}: return .{{region.partition}} 38 | {%endfor %} 39 | default: return .aws 40 | } 41 | } 42 | } 43 | 44 | extension Region: CustomStringConvertible { 45 | public var description: String { return self.rawValue } 46 | } 47 | 48 | extension Region: Codable {} 49 | 50 | /// Enumeration for all AWS partitions 51 | public struct AWSPartition: Sendable, RawRepresentable, Equatable, Hashable { 52 | enum InternalPartition: String { 53 | {%for partition in partitions %} 54 | case {{partition.name}} 55 | {%endfor %} 56 | } 57 | 58 | private var partition: InternalPartition 59 | 60 | public var rawValue: String { return self.partition.rawValue } 61 | 62 | public init?(rawValue: String) { 63 | guard let partition = InternalPartition(rawValue: rawValue) else { return nil } 64 | self.partition = partition 65 | } 66 | 67 | private init(partition: InternalPartition) { 68 | self.partition = partition 69 | } 70 | 71 | {%for partition in partitions %} 72 | // {{partition.description}} 73 | public static var {{partition.name}}: AWSPartition { .init(partition: .{{partition.name}}) } 74 | {%endfor %} 75 | } 76 | 77 | public extension AWSPartition { 78 | var dnsSuffix: String { 79 | switch self.partition { 80 | {%for partition in partitions %} 81 | case .{{partition.name}}: return "{{partition.dnsSuffix}}" 82 | {%endfor %} 83 | } 84 | } 85 | 86 | func defaultEndpoint(region: Region, service: String) -> String { 87 | switch self.partition { 88 | {%for partition in partitions %} 89 | case .{{partition.name}}: return "{{partition.hostname}}" 90 | {%endfor %} 91 | } 92 | } 93 | } 94 | 95 | // allows to create a Region from a String 96 | // it will only create a Region if the provided 97 | // region name is valid. 98 | public extension Region { 99 | init?(awsRegionName: String) { 100 | self.init(rawValue: awsRegionName) 101 | switch self { 102 | {%for region in regions %} 103 | {%if forloop.first %} 104 | case .{{region.enum}}, 105 | {%endif %} 106 | {%if not forloop.first and not forloop.last%} 107 | .{{region.enum}}, 108 | {%endif %} 109 | {%if forloop.last %} 110 | .{{region.enum}}: 111 | {%endif %} 112 | {%endfor %} 113 | return 114 | default: 115 | return nil 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /scripts/validate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ##===----------------------------------------------------------------------===## 3 | ## 4 | ## This source file is part of the SwiftNIO open source project 5 | ## 6 | ## Copyright (c) 2017-2023 Apple Inc. and the SwiftNIO project authors 7 | ## Licensed under Apache License v2.0 8 | ## 9 | ## See LICENSE.txt for license information 10 | ## See CONTRIBUTORS.txt for the list of SwiftNIO project authors 11 | ## 12 | ## SPDX-License-Identifier: Apache-2.0 13 | ## 14 | ##===----------------------------------------------------------------------===## 15 | 16 | set -eu 17 | here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 18 | 19 | function replace_acceptable_years() { 20 | # this needs to replace all acceptable forms with 'YEARS' 21 | sed -e 's/20[12][8901234567]-20[12][8901234567]/YEARS/' -e 's/20[12][8901234567]/YEARS/' -e '/^#!/ d' 22 | } 23 | 24 | printf "=> Checking format... " 25 | FIRST_OUT="$(git status --porcelain)" 26 | git ls-files -z '*.swift' | xargs -0 swift format format --parallel --in-place 27 | git diff --exit-code '*.swift' 28 | 29 | SECOND_OUT="$(git status --porcelain)" 30 | if [[ "$FIRST_OUT" != "$SECOND_OUT" ]]; then 31 | printf "\033[0;31mformatting issues!\033[0m\n" 32 | git --no-pager diff 33 | exit 1 34 | else 35 | printf "\033[0;32mokay.\033[0m\n" 36 | fi 37 | 38 | printf "=> Checking license headers... " 39 | tmp=$(mktemp /tmp/.soto-core-validate_XXXXXX) 40 | 41 | for language in swift-or-c; do 42 | declare -a matching_files 43 | declare -a exceptions 44 | expections=( ) 45 | matching_files=( -name '*' ) 46 | case "$language" in 47 | swift-or-c) 48 | exceptions=( -path '*Sources/INIParser/*' -o -path '*Sources/CSotoExpat/*' -o -path '*Benchmark/.build/*' -o -name Package.swift) 49 | matching_files=( -name '*.swift' -o -name '*.c' -o -name '*.h' ) 50 | cat > "$tmp" <<"EOF" 51 | //===----------------------------------------------------------------------===// 52 | // 53 | // This source file is part of the Soto for AWS open source project 54 | // 55 | // Copyright (c) YEARS the Soto project authors 56 | // Licensed under Apache License v2.0 57 | // 58 | // See LICENSE.txt for license information 59 | // See CONTRIBUTORS.txt for the list of Soto project authors 60 | // 61 | // SPDX-License-Identifier: Apache-2.0 62 | // 63 | //===----------------------------------------------------------------------===// 64 | EOF 65 | ;; 66 | bash) 67 | matching_files=( -name '*.sh' ) 68 | cat > "$tmp" <<"EOF" 69 | ##===----------------------------------------------------------------------===## 70 | ## 71 | ## This source file is part of the Soto for AWS open source project 72 | ## 73 | ## Copyright (c) YEARS the Soto project authors 74 | ## Licensed under Apache License v2.0 75 | ## 76 | ## See LICENSE.txt for license information 77 | ## See CONTRIBUTORS.txt for the list of Soto project authors 78 | ## 79 | ## SPDX-License-Identifier: Apache-2.0 80 | ## 81 | ##===----------------------------------------------------------------------===## 82 | EOF 83 | ;; 84 | *) 85 | echo >&2 "ERROR: unknown language '$language'" 86 | ;; 87 | esac 88 | 89 | lines_to_compare=$(cat "$tmp" | wc -l | tr -d " ") 90 | # need to read one more line as we remove the '#!' line 91 | lines_to_read=$(expr "$lines_to_compare" + 1) 92 | expected_sha=$(cat "$tmp" | shasum) 93 | 94 | ( 95 | cd "$here/.." 96 | find . \ 97 | \( \! -path './.build/*' -a \ 98 | \( "${matching_files[@]}" \) -a \ 99 | \( \! \( "${exceptions[@]}" \) \) \) | while read line; do 100 | if [[ "$(cat "$line" | head -n $lines_to_read | replace_acceptable_years | head -n $lines_to_compare | shasum)" != "$expected_sha" ]]; then 101 | printf "\033[0;31mmissing headers in file '$line'!\033[0m\n" 102 | diff -u <(cat "$line" | head -n $lines_to_read | replace_acceptable_years | head -n $lines_to_compare) "$tmp" 103 | exit 1 104 | fi 105 | done 106 | printf "\033[0;32mokay.\033[0m\n" 107 | ) 108 | done 109 | 110 | rm "$tmp" 111 | --------------------------------------------------------------------------------