├── .swiftformatignore ├── .spi.yml ├── .editorconfig ├── .gitignore ├── CODE_OF_CONDUCT.md ├── .github ├── release.yml ├── ISSUE_TEMPLATE │ └── config.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── pull_request_label.yml │ ├── main.yml │ └── pull_request.yml ├── .licenseignore ├── CONTRIBUTORS.txt ├── Sources └── OpenAPIAsyncHTTPClient │ ├── Documentation.docc │ └── Documentation.md │ └── AsyncHTTPClientTransport.swift ├── NOTICE.txt ├── SECURITY.md ├── .swift-format ├── README.md ├── CONTRIBUTING.md ├── Package.swift ├── Tests └── OpenAPIAsyncHTTPClientTests │ └── Test_AsyncHTTPClientTransport.swift └── LICENSE.txt /.swiftformatignore: -------------------------------------------------------------------------------- 1 | **Package.swift 2 | -------------------------------------------------------------------------------- /.spi.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | builder: 3 | configs: 4 | - documentation_targets: 5 | - OpenAPIAsyncHTTPClient 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | DerivedData/ 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | .vscode 9 | /Package.resolved 10 | .ci/ 11 | .docc-build/ 12 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | The code of conduct for this project can be found at https://swift.org/code-of-conduct. 4 | 5 | 6 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | categories: 3 | - title: SemVer Major 4 | labels: 5 | - ⚠️ semver/major 6 | - title: SemVer Minor 7 | labels: 8 | - 🆕 semver/minor 9 | - title: SemVer Patch 10 | labels: 11 | - 🔨 semver/patch 12 | - title: Other Changes 13 | labels: 14 | - semver/none 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: 🐞 Open an issue on the Swift OpenAPI Generator repository 4 | url: https://github.com/apple/swift-openapi-generator/issues 5 | about: > 6 | Issues for all repositories in the Swift OpenAPI Generator project are centralized in the swift-openapi-generator repository. 7 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Motivation 2 | 3 | _[Explain here the context, and why you're making that change. What is the problem you're trying to solve.]_ 4 | 5 | ### Modifications 6 | 7 | _[Describe the modifications you've made.]_ 8 | 9 | ### Result 10 | 11 | _[After your change, what will change.]_ 12 | 13 | ### Test Plan 14 | 15 | _[Describe the steps you took, or will take, to qualify the change - such as adjusting tests and manual testing.]_ 16 | -------------------------------------------------------------------------------- /.github/workflows/pull_request_label.yml: -------------------------------------------------------------------------------- 1 | name: PR label 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: 7 | pull_request: 8 | types: [labeled, unlabeled, opened, reopened, synchronize] 9 | 10 | jobs: 11 | semver-label-check: 12 | name: Semantic version label check 13 | runs-on: ubuntu-latest 14 | timeout-minutes: 1 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | with: 19 | persist-credentials: false 20 | - name: Check for Semantic Version label 21 | uses: apple/swift-nio/.github/actions/pull_request_semver_label_checker@main 22 | -------------------------------------------------------------------------------- /.licenseignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | **/.gitignore 3 | .licenseignore 4 | .gitattributes 5 | .git-blame-ignore-revs 6 | .mailfilter 7 | .mailmap 8 | .spi.yml 9 | .swift-format 10 | .swiftformatignore 11 | .editorconfig 12 | .github/* 13 | *.md 14 | *.txt 15 | *.yml 16 | *.yaml 17 | *.json 18 | Package.swift 19 | **/Package.swift 20 | Package@-*.swift 21 | **/Package@-*.swift 22 | Package.resolved 23 | **/Package.resolved 24 | Makefile 25 | *.modulemap 26 | **/*.modulemap 27 | **/*.docc/* 28 | *.xcprivacy 29 | **/*.xcprivacy 30 | *.symlink 31 | **/*.symlink 32 | Dockerfile 33 | **/Dockerfile 34 | Snippets/* 35 | dev/git.commit.template 36 | .unacceptablelanguageignore 37 | -------------------------------------------------------------------------------- /CONTRIBUTORS.txt: -------------------------------------------------------------------------------- 1 | For the purpose of tracking copyright, this is the list of individuals and 2 | organizations who have contributed source code to SwiftOpenAPIGenerator. 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 | - Apple Inc. (all contributors with '@apple.com') 11 | 12 | ### Contributors 13 | 14 | - David Nadoba 15 | - Honza Dvorsky 16 | - Si Beaumont 17 | 18 | **Updating this list** 19 | 20 | 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` 21 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Main 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: 7 | push: 8 | branches: [main] 9 | schedule: 10 | - cron: "0 8,20 * * *" 11 | 12 | jobs: 13 | unit-tests: 14 | name: Unit tests 15 | uses: apple/swift-nio/.github/workflows/unit_tests.yml@main 16 | with: 17 | linux_6_0_arguments_override: "-Xswiftc -warnings-as-errors --explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" 18 | linux_6_1_arguments_override: "-Xswiftc -warnings-as-errors --explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" 19 | linux_6_2_arguments_override: "-Xswiftc -warnings-as-errors --explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" 20 | linux_nightly_next_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" 21 | linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" 22 | 23 | static-sdk: 24 | name: Static SDK 25 | # Workaround https://github.com/nektos/act/issues/1875 26 | uses: apple/swift-nio/.github/workflows/static_sdk.yml@main 27 | 28 | release-builds: 29 | name: Release builds 30 | uses: apple/swift-nio/.github/workflows/release_builds.yml@main 31 | -------------------------------------------------------------------------------- /Sources/OpenAPIAsyncHTTPClient/Documentation.docc/Documentation.md: -------------------------------------------------------------------------------- 1 | # ``OpenAPIAsyncHTTPClient`` 2 | 3 | Send HTTP requests to the server using the AsyncHTTPClient library. 4 | 5 | ## Overview 6 | 7 | A client transport that uses the [HTTPClient](https://swiftpackageindex.com/swift-server/async-http-client/documentation/asynchttpclient/httpclient) type from the [AsyncHTTPClient](https://github.com/swift-server/async-http-client) library to perform HTTP operations. 8 | 9 | Use the transport with client code generated by [Swift OpenAPI Generator](https://github.com/apple/swift-openapi-generator). 10 | 11 | ### Supported platforms and minimum versions 12 | | macOS | Linux | iOS | tvOS | watchOS | visionOS | 13 | | :-: | :-: | :-: | :-: | :-: | :-: | 14 | | ✅ 10.15+ | ✅ | ✅ 13+ | ✅ 13+ | ✅ 6+ | ✅ 1+ | 15 | 16 | ### Usage 17 | 18 | Add the package dependency in your `Package.swift`: 19 | 20 | ```swift 21 | .package(url: "https://github.com/swift-server/swift-openapi-async-http-client", from: "1.0.0"), 22 | ``` 23 | 24 | Next, in your target, add `OpenAPIAsyncHTTPClient` to your dependencies: 25 | 26 | ```swift 27 | .target(name: "MyTarget", dependencies: [ 28 | .product(name: "OpenAPIAsyncHTTPClient", package: "swift-openapi-async-http-client"), 29 | ]), 30 | ``` 31 | 32 | Then, to get started, check out ``AsyncHTTPClientTransport``. 33 | 34 | ## Topics 35 | 36 | ### Usage 37 | 38 | - ``AsyncHTTPClientTransport`` 39 | -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | 2 | The SwiftOpenAPIGenerator Project 3 | ================================= 4 | 5 | Please visit the SwiftOpenAPIGenerator web site for more information: 6 | 7 | * https://github.com/swift-server/swift-openapi-async-http-client 8 | 9 | Copyright 2023 The SwiftOpenAPIGenerator Project 10 | 11 | The SwiftOpenAPIGenerator Project licenses this file to you under the Apache 12 | License, version 2.0 (the "License"); you may not use this file except in 13 | compliance with the License. You may obtain a copy of the License at: 14 | 15 | https://www.apache.org/licenses/LICENSE-2.0 16 | 17 | Unless required by applicable law or agreed to in writing, software 18 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 19 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 20 | License for the specific language governing permissions and limitations 21 | under the License. 22 | 23 | Also, please refer to each LICENSE.txt file, which is located in 24 | the 'license' directory of the distribution file, for the license terms of the 25 | components that this product depends on. 26 | 27 | ------------------------------------------------------------------------------- 28 | 29 | This product contains derivations of various scripts from SwiftNIO. 30 | 31 | * LICENSE (Apache License 2.0): 32 | * https://www.apache.org/licenses/LICENSE-2.0 33 | * HOMEPAGE: 34 | * https://github.com/apple/swift-nio 35 | -------------------------------------------------------------------------------- /.github/workflows/pull_request.yml: -------------------------------------------------------------------------------- 1 | name: PR 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: 7 | pull_request: 8 | types: [opened, reopened, synchronize] 9 | 10 | jobs: 11 | soundness: 12 | name: Soundness 13 | uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main 14 | with: 15 | license_header_check_project_name: "SwiftOpenAPIGenerator" 16 | 17 | unit-tests: 18 | name: Unit tests 19 | uses: apple/swift-nio/.github/workflows/unit_tests.yml@main 20 | with: 21 | linux_6_0_arguments_override: "-Xswiftc -warnings-as-errors --explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" 22 | linux_6_1_arguments_override: "-Xswiftc -warnings-as-errors --explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" 23 | linux_6_2_arguments_override: "-Xswiftc -warnings-as-errors --explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" 24 | linux_nightly_next_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" 25 | linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" 26 | 27 | cxx-interop: 28 | name: Cxx interop 29 | uses: apple/swift-nio/.github/workflows/cxx_interop.yml@main 30 | 31 | swift-6-language-mode: 32 | name: Cxx interop 33 | uses: apple/swift-nio/.github/workflows/swift_6_language_mode.yml@main 34 | 35 | static-sdk: 36 | name: Static SDK 37 | # Workaround https://github.com/nektos/act/issues/1875 38 | uses: apple/swift-nio/.github/workflows/static_sdk.yml@main 39 | 40 | release-builds: 41 | name: Release builds 42 | uses: apple/swift-nio/.github/workflows/release_builds.yml@main 43 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security 2 | 3 | This document specifies the security process for the SwiftOpenAPIGenerator project. 4 | 5 | ## Disclosures 6 | 7 | ### Private Disclosure Process 8 | 9 | The SwiftOpenAPIGenerator team asks that known and suspected vulnerabilities be privately 10 | and responsibly disclosed by emailing [sswg-security-reports@forums.swift.org](mailto:sswg-security-reports@forums.swift.org) 11 | with the details usually included with bug reports. 12 | **Do not file a public issue.** 13 | 14 | #### When to report a vulnerability 15 | 16 | * You think you have discovered a potential security vulnerability in SwiftOpenAPIGenerator or any of the SwiftOpenAPIGenerator projects. 17 | * You are unsure how a vulnerability affects SwiftOpenAPIGenerator or any of the SwiftOpenAPIGenerator projects. 18 | 19 | #### What happens next? 20 | 21 | * A member of the team will acknowledge receipt of the report within 3 22 | working days (United States). This may include a request for additional 23 | information about reproducing the vulnerability. 24 | * We will privately inform the Swift Server Work Group ([SSWG][sswg]) of the 25 | vulnerability within 10 days of the report as per their [security 26 | guidelines][sswg-security]. 27 | * Once we have identified a fix we may ask you to validate it. We aim to do this 28 | within 30 days. In some cases this may not be possible, for example when the 29 | vulnerability exists at the protocol level and the industry must coordinate on 30 | the disclosure process. 31 | * If a CVE number is required, one will be requested from [MITRE][mitre] 32 | providing you with full credit for the discovery. 33 | * We will decide on a planned release date and let you know when it is. 34 | * Prior to release, we will inform major dependents that a security-related 35 | patch is impending. 36 | * Once the fix has been released we will publish a security advisory on GitHub 37 | and the [SSWG][sswg] will announce the vulnerability on the [Swift 38 | forums][swift-forums-sec]. 39 | 40 | [sswg]: https://github.com/swift-server/sswg 41 | [sswg-security]: https://github.com/swift-server/sswg/blob/main/process/incubation.md#security-best-practices 42 | [swift-forums-sec]: https://forums.swift.org/c/server/security-updates/ 43 | [mitre]: https://cveform.mitre.org/ 44 | -------------------------------------------------------------------------------- /.swift-format: -------------------------------------------------------------------------------- 1 | { 2 | "fileScopedDeclarationPrivacy" : { 3 | "accessLevel" : "private" 4 | }, 5 | "indentation" : { 6 | "spaces" : 4 7 | }, 8 | "indentConditionalCompilationBlocks" : false, 9 | "indentSwitchCaseLabels" : false, 10 | "lineBreakAroundMultilineExpressionChainComponents" : true, 11 | "lineBreakBeforeControlFlowKeywords" : false, 12 | "lineBreakBeforeEachArgument" : true, 13 | "lineBreakBeforeEachGenericRequirement" : true, 14 | "lineLength" : 120, 15 | "maximumBlankLines" : 1, 16 | "prioritizeKeepingFunctionOutputTogether" : false, 17 | "respectsExistingLineBreaks" : false, 18 | "rules" : { 19 | "AllPublicDeclarationsHaveDocumentation" : true, 20 | "AlwaysUseLowerCamelCase" : false, 21 | "AmbiguousTrailingClosureOverload" : true, 22 | "BeginDocumentationCommentWithOneLineSummary" : false, 23 | "DoNotUseSemicolons" : true, 24 | "DontRepeatTypeInStaticProperties" : false, 25 | "FileScopedDeclarationPrivacy" : true, 26 | "FullyIndirectEnum" : true, 27 | "GroupNumericLiterals" : true, 28 | "IdentifiersMustBeASCII" : true, 29 | "NeverForceUnwrap" : false, 30 | "NeverUseForceTry" : false, 31 | "NeverUseImplicitlyUnwrappedOptionals" : false, 32 | "NoAccessLevelOnExtensionDeclaration" : false, 33 | "NoAssignmentInExpressions" : true, 34 | "NoBlockComments" : true, 35 | "NoCasesWithOnlyFallthrough" : true, 36 | "NoEmptyTrailingClosureParentheses" : true, 37 | "NoLabelsInCasePatterns" : false, 38 | "NoLeadingUnderscores" : false, 39 | "NoParensAroundConditions" : true, 40 | "NoVoidReturnOnFunctionSignature" : true, 41 | "OneCasePerLine" : true, 42 | "OneVariableDeclarationPerLine" : true, 43 | "OnlyOneTrailingClosureArgument" : true, 44 | "OrderedImports" : false, 45 | "ReturnVoidInsteadOfEmptyTuple" : true, 46 | "UseEarlyExits" : true, 47 | "UseLetInEveryBoundCaseVariable" : false, 48 | "UseShorthandTypeNames" : true, 49 | "UseSingleLinePropertyGetter" : false, 50 | "UseSynthesizedInitializer" : true, 51 | "UseTripleSlashForDocumentationComments" : true, 52 | "UseWhereClausesInForLoops" : false, 53 | "ValidateDocumentationComments" : true 54 | }, 55 | "spacesAroundRangeFormationOperators" : false, 56 | "tabWidth" : 8, 57 | "version" : 1 58 | } 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AsyncHTTPClient Transport for Swift OpenAPI Generator 2 | 3 | [![](https://img.shields.io/badge/docc-read_documentation-blue)](https://swiftpackageindex.com/swift-server/swift-openapi-async-http-client/documentation) 4 | [![](https://img.shields.io/github/v/release/swift-server/swift-openapi-async-http-client)](https://github.com/swift-server/swift-openapi-async-http-client/releases) 5 | [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fswift-server%2Fswift-openapi-async-http-client%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/swift-server/swift-openapi-async-http-client) 6 | [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fswift-server%2Fswift-openapi-async-http-client%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/swift-server/swift-openapi-async-http-client) 7 | 8 | A client transport that uses the [HTTPClient](https://swiftpackageindex.com/swift-server/async-http-client/documentation/asynchttpclient/httpclient) type from the [AsyncHTTPClient](https://github.com/swift-server/async-http-client) library to perform HTTP operations. 9 | 10 | Use the transport with client code generated by [Swift OpenAPI Generator](https://github.com/apple/swift-openapi-generator). 11 | 12 | ## Supported platforms and minimum versions 13 | | macOS | Linux | iOS | tvOS | watchOS | visionOS | 14 | | :-: | :-: | :-: | :-: | :-: | :-: | 15 | | ✅ 10.15+ | ✅ | ✅ 13+ | ✅ 13+ | ✅ 6+ | ✅ 1+ | 16 | 17 | ## Swift version compatibility 18 | | Swift | Package Version | 19 | | :----------: | :-------------: | 20 | | 6.0+ | 1.3.0+ | 21 | | 5.10 - 5.11 | 1.0.0 - 1.2.0 | 22 | 23 | ## Usage 24 | 25 | Add the package dependency in your `Package.swift`: 26 | 27 | ```swift 28 | .package(url: "https://github.com/swift-server/swift-openapi-async-http-client", from: "1.0.0"), 29 | ``` 30 | 31 | Next, in your target, add `OpenAPIAsyncHTTPClient` to your dependencies: 32 | 33 | ```swift 34 | .target(name: "MyTarget", dependencies: [ 35 | .product(name: "OpenAPIAsyncHTTPClient", package: "swift-openapi-async-http-client"), 36 | ]), 37 | ``` 38 | 39 | Then, to get started, check out `AsyncHTTPClientTransport`. 40 | 41 | ## Documentation 42 | 43 | To learn more, check out the full [documentation](https://swiftpackageindex.com/swift-server/swift-openapi-async-http-client/documentation). 44 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Legal 2 | 3 | By submitting a pull request, you represent that you have the right to license 4 | your contribution to Apple and the community, and agree by submitting the patch 5 | that your contributions are licensed under the Apache 2.0 license (see 6 | `LICENSE.txt`). 7 | 8 | ## How to submit a bug report 9 | 10 | Please report any issues related to this library in the [swift-openapi-generator](https://github.com/apple/swift-openapi-generator/issues) repository. 11 | 12 | Specify the following: 13 | 14 | * Commit hash 15 | * Contextual information (e.g. what you were trying to achieve with swift-openapi-async-http-client) 16 | * Simplest possible steps to reproduce 17 | * More complex the steps are, lower the priority will be. 18 | * A pull request with failing test case is preferred, but it's just fine to paste the test case into the issue description. 19 | * Anything that might be relevant in your opinion, such as: 20 | * Swift version or the output of `swift --version` 21 | * OS version and the output of `uname -a` 22 | * Network configuration 23 | 24 | ### Example 25 | 26 | ``` 27 | Commit hash: b17a8a9f0f814c01a56977680cb68d8a779c951f 28 | 29 | Context: 30 | While testing my application that uses with swift-openapi-async-http-client, I noticed that ... 31 | 32 | Steps to reproduce: 33 | 1. ... 34 | 2. ... 35 | 3. ... 36 | 4. ... 37 | 38 | $ swift --version 39 | Swift version 4.0.2 (swift-4.0.2-RELEASE) 40 | Target: x86_64-unknown-linux-gnu 41 | 42 | Operating system: Ubuntu Linux 16.04 64-bit 43 | 44 | $ uname -a 45 | Linux beefy.machine 4.4.0-101-generic #124-Ubuntu SMP Fri Nov 10 18:29:59 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux 46 | 47 | My system has IPv6 disabled. 48 | ``` 49 | 50 | ## Writing a Patch 51 | 52 | A good patch is: 53 | 54 | 1. Concise, and contains as few changes as needed to achieve the end result. 55 | 2. Tested, ensuring that any tests provided failed before the patch and pass after it. 56 | 3. Documented, adding API documentation as needed to cover new functions and properties. 57 | 4. Accompanied by a great commit message, using our commit message template. 58 | 59 | ### Run CI checks locally 60 | 61 | You can run the GitHub Actions workflows locally using 62 | [act](https://github.com/nektos/act). For detailed steps on how to do this please see [https://github.com/swiftlang/github-workflows?tab=readme-ov-file#running-workflows-locally](https://github.com/swiftlang/github-workflows?tab=readme-ov-file#running-workflows-locally). 63 | 64 | ## How to contribute your work 65 | 66 | Please open a pull request at https://github.com/swift-server/swift-openapi-async-http-client. Make sure the CI passes, and then wait for code review. 67 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:6.0 2 | //===----------------------------------------------------------------------===// 3 | // 4 | // This source file is part of the SwiftOpenAPIGenerator open source project 5 | // 6 | // Copyright (c) 2023 Apple Inc. and the SwiftOpenAPIGenerator 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 SwiftOpenAPIGenerator project authors 11 | // 12 | // SPDX-License-Identifier: Apache-2.0 13 | // 14 | //===----------------------------------------------------------------------===// 15 | import Foundation 16 | import PackageDescription 17 | 18 | // General Swift-settings for all targets. 19 | let swiftSettings: [SwiftSetting] = [ 20 | // https://github.com/apple/swift-evolution/blob/main/proposals/0335-existential-any.md 21 | // Require `any` for existential types. 22 | .enableUpcomingFeature("ExistentialAny"), 23 | ] 24 | 25 | let package = Package( 26 | name: "swift-openapi-async-http-client", 27 | platforms: [.macOS(.v10_15), .iOS(.v13), .tvOS(.v13), .watchOS(.v6), .visionOS(.v1)], 28 | products: [.library(name: "OpenAPIAsyncHTTPClient", targets: ["OpenAPIAsyncHTTPClient"])], 29 | dependencies: [ 30 | .package(url: "https://github.com/apple/swift-nio", from: "2.58.0"), 31 | .package(url: "https://github.com/swift-server/async-http-client.git", from: "1.23.0"), 32 | .package(url: "https://github.com/apple/swift-openapi-runtime", from: "1.0.0"), 33 | .package(url: "https://github.com/apple/swift-http-types", from: "1.0.0"), 34 | ], 35 | targets: [ 36 | .target( 37 | name: "OpenAPIAsyncHTTPClient", 38 | dependencies: [ 39 | .product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"), 40 | .product(name: "HTTPTypes", package: "swift-http-types"), 41 | .product(name: "AsyncHTTPClient", package: "async-http-client"), 42 | .product(name: "NIOFoundationCompat", package: "swift-nio"), 43 | ], 44 | swiftSettings: swiftSettings 45 | ), 46 | .testTarget( 47 | name: "OpenAPIAsyncHTTPClientTests", 48 | dependencies: ["OpenAPIAsyncHTTPClient"], 49 | swiftSettings: swiftSettings 50 | ), 51 | ] 52 | ) 53 | 54 | // --- STANDARD CROSS-REPO SETTINGS DO NOT EDIT --- // 55 | for target in package.targets { 56 | switch target.type { 57 | case .regular, .test, .executable: 58 | var settings = target.swiftSettings ?? [] 59 | // https://github.com/swiftlang/swift-evolution/blob/main/proposals/0444-member-import-visibility.md 60 | settings.append(.enableUpcomingFeature("MemberImportVisibility")) 61 | target.swiftSettings = settings 62 | case .macro, .plugin, .system, .binary: () // not applicable 63 | @unknown default: () // we don't know what to do here, do nothing 64 | } 65 | } 66 | // --- END: STANDARD CROSS-REPO SETTINGS DO NOT EDIT --- // 67 | -------------------------------------------------------------------------------- /Tests/OpenAPIAsyncHTTPClientTests/Test_AsyncHTTPClientTransport.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftOpenAPIGenerator open source project 4 | // 5 | // Copyright (c) 2023 Apple Inc. and the SwiftOpenAPIGenerator 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 SwiftOpenAPIGenerator project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | import XCTest 15 | import OpenAPIRuntime 16 | import NIOCore 17 | import NIOHTTP1 18 | import NIOPosix 19 | import AsyncHTTPClient 20 | @testable import OpenAPIAsyncHTTPClient 21 | import HTTPTypes 22 | 23 | class Test_AsyncHTTPClientTransport: XCTestCase { 24 | 25 | static var testData: Data { get throws { try XCTUnwrap(#"[{}]"#.data(using: .utf8)) } } 26 | 27 | static var testBuffer: ByteBuffer { ByteBuffer(string: #"[{}]"#) } 28 | 29 | static var testUrl: URL { 30 | get throws { try XCTUnwrap(URL(string: "http://example.com/api/v1/hello/Maria?greeting=Howdy")) } 31 | } 32 | 33 | func testConvertRequest() throws { 34 | let request: HTTPRequest = .init( 35 | method: .post, 36 | scheme: nil, 37 | authority: nil, 38 | path: "/hello%20world/Maria?greeting=Howdy", 39 | headerFields: [.contentType: "application/json"] 40 | ) 41 | let requestBody = try HTTPBody(Self.testData) 42 | let httpRequest = try AsyncHTTPClientTransport.convertRequest( 43 | request, 44 | body: requestBody, 45 | baseURL: try XCTUnwrap(URL(string: "http://example.com/api/v1")) 46 | ) 47 | XCTAssertEqual(httpRequest.url, "http://example.com/api/v1/hello%20world/Maria?greeting=Howdy") 48 | XCTAssertEqual(httpRequest.method, .POST) 49 | XCTAssertEqual(httpRequest.headers, ["content-type": "application/json"]) 50 | // TODO: Not sure how to test that httpRequest.body is what we expect, can't 51 | // find an API for reading it back. 52 | } 53 | 54 | func testConvertResponse() async throws { 55 | let httpResponse = HTTPClientResponse( 56 | status: .ok, 57 | headers: ["content-type": "application/json"], 58 | body: .bytes(Self.testBuffer) 59 | ) 60 | let (response, maybeResponseBody) = try await AsyncHTTPClientTransport.convertResponse( 61 | method: .get, 62 | httpResponse: httpResponse 63 | ) 64 | let responseBody = try XCTUnwrap(maybeResponseBody) 65 | XCTAssertEqual(response.status.code, 200) 66 | XCTAssertEqual(response.headerFields, [.contentType: "application/json"]) 67 | let bufferedResponseBody = try await Data(collecting: responseBody, upTo: .max) 68 | XCTAssertEqual(bufferedResponseBody, try Self.testData) 69 | } 70 | 71 | func testSend() async throws { 72 | let transport = AsyncHTTPClientTransport(configuration: .init(), requestSender: TestSender.test) 73 | let request: HTTPRequest = .init( 74 | method: .get, 75 | scheme: nil, 76 | authority: nil, 77 | path: "/api/v1/hello/Maria", 78 | headerFields: [.init("x-request")!: "yes"] 79 | ) 80 | let (response, maybeResponseBody) = try await transport.send( 81 | request, 82 | body: nil, 83 | baseURL: Self.testUrl, 84 | operationID: "sayHello" 85 | ) 86 | let responseBody = try XCTUnwrap(maybeResponseBody) 87 | let bufferedResponseBody = try await String(collecting: responseBody, upTo: .max) 88 | XCTAssertEqual(bufferedResponseBody, "[{}]") 89 | XCTAssertEqual(response.status.code, 200) 90 | } 91 | } 92 | 93 | struct TestSender: HTTPRequestSending { 94 | var sendClosure: 95 | @Sendable (AsyncHTTPClientTransport.Request, HTTPClient, TimeAmount) async throws -> 96 | AsyncHTTPClientTransport.Response 97 | func send(request: AsyncHTTPClientTransport.Request, with client: HTTPClient, timeout: TimeAmount) async throws 98 | -> AsyncHTTPClientTransport.Response 99 | { try await sendClosure(request, client, timeout) } 100 | 101 | static var test: Self { 102 | TestSender { request, _, _ in 103 | XCTAssertEqual(request.headers.first(name: "x-request"), "yes") 104 | return HTTPClientResponse( 105 | status: .ok, 106 | headers: ["content-type": "application/json"], 107 | body: .bytes(Test_AsyncHTTPClientTransport.testBuffer) 108 | ) 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Sources/OpenAPIAsyncHTTPClient/AsyncHTTPClientTransport.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the SwiftOpenAPIGenerator open source project 4 | // 5 | // Copyright (c) 2023 Apple Inc. and the SwiftOpenAPIGenerator 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 SwiftOpenAPIGenerator project authors 10 | // 11 | // SPDX-License-Identifier: Apache-2.0 12 | // 13 | //===----------------------------------------------------------------------===// 14 | import OpenAPIRuntime 15 | import AsyncHTTPClient 16 | import NIOCore 17 | import NIOHTTP1 18 | import NIOFoundationCompat 19 | import HTTPTypes 20 | #if canImport(Darwin) 21 | import Foundation 22 | #else 23 | @preconcurrency import struct Foundation.URL 24 | import struct Foundation.URLComponents 25 | import struct Foundation.Data 26 | import protocol Foundation.LocalizedError 27 | #endif 28 | 29 | /// A client transport that performs HTTP operations using the HTTPClient type 30 | /// provided by the AsyncHTTPClient library. 31 | /// 32 | /// ### Use the AsyncHTTPClient transport 33 | /// 34 | /// Instantiate the transport: 35 | /// 36 | /// let transport = AsyncHTTPClientTransport() 37 | /// 38 | /// Instantiate the `Client` type generated by the Swift OpenAPI Generator for 39 | /// your provided OpenAPI document. For example: 40 | /// 41 | /// let client = Client( 42 | /// serverURL: URL(string: "https://example.com")!, 43 | /// transport: transport 44 | /// ) 45 | /// 46 | /// Use the client to make HTTP calls defined in your OpenAPI document. For 47 | /// example, if the OpenAPI document contains an HTTP operation with 48 | /// the identifier `checkHealth`, call it from Swift with: 49 | /// 50 | /// let response = try await client.checkHealth() 51 | /// 52 | /// ### Provide a custom Client 53 | /// 54 | /// The ``AsyncHTTPClientTransport/Configuration-swift.struct`` type allows you 55 | /// to provide a custom `HTTPClient` and tweak behaviors such as the default 56 | /// timeout. 57 | public struct AsyncHTTPClientTransport: ClientTransport { 58 | 59 | /// A set of configuration values for the AsyncHTTPClient transport. 60 | public struct Configuration: Sendable { 61 | 62 | /// The HTTP client used for performing HTTP calls. 63 | public var client: HTTPClient 64 | 65 | /// The default request timeout. 66 | public var timeout: TimeAmount 67 | 68 | /// Creates a new configuration with the specified client and timeout. 69 | /// - Parameters: 70 | /// - client: The underlying client used to perform HTTP operations. 71 | /// - timeout: The request timeout, defaults to 1 minute. 72 | public init(client: HTTPClient = .shared, timeout: TimeAmount = .minutes(1)) { 73 | self.client = client 74 | self.timeout = timeout 75 | } 76 | 77 | /// Creates a new configuration with the specified client and timeout. 78 | /// - Parameters: 79 | /// - client: The underlying client used to perform HTTP operations. 80 | /// Provide nil to use the shared client. 81 | /// - timeout: The request timeout, defaults to 1 minute. 82 | @available(*, deprecated, message: "Use the initializer with a non-optional client parameter.") 83 | @_disfavoredOverload public init(client: HTTPClient? = nil, timeout: TimeAmount = .minutes(1)) { 84 | self.init(client: client ?? .shared, timeout: timeout) 85 | } 86 | } 87 | 88 | /// A request to be sent by the transport. 89 | internal typealias Request = HTTPClientRequest 90 | 91 | /// A response returned by the transport. 92 | internal typealias Response = HTTPClientResponse 93 | 94 | /// Specialized error thrown by the transport. 95 | internal enum Error: Swift.Error, CustomStringConvertible, LocalizedError { 96 | 97 | /// Invalid URL composed from base URL and received request. 98 | case invalidRequestURL(request: HTTPRequest, baseURL: URL) 99 | 100 | // MARK: CustomStringConvertible 101 | 102 | var description: String { 103 | switch self { 104 | case let .invalidRequestURL(request: request, baseURL: baseURL): 105 | return 106 | "Invalid request URL from request path: \(request.path ?? "") relative to base URL: \(baseURL.absoluteString)" 107 | } 108 | } 109 | 110 | // MARK: LocalizedError 111 | 112 | var errorDescription: String? { description } 113 | } 114 | 115 | /// A set of configuration values used by the transport. 116 | public var configuration: Configuration 117 | 118 | /// Underlying request sender for the transport. 119 | internal let requestSender: any HTTPRequestSending 120 | 121 | /// Creates a new transport. 122 | /// - Parameters: 123 | /// - configuration: A set of configuration values used by the transport. 124 | /// - requestSender: The underlying request sender. 125 | internal init(configuration: Configuration, requestSender: any HTTPRequestSending) { 126 | self.configuration = configuration 127 | self.requestSender = requestSender 128 | } 129 | 130 | /// Creates a new transport. 131 | /// - Parameter configuration: A set of configuration values used by the transport. 132 | public init(configuration: Configuration = .init()) { 133 | self.init(configuration: configuration, requestSender: AsyncHTTPRequestSender()) 134 | } 135 | 136 | // MARK: ClientTransport 137 | 138 | /// Sends an HTTP request and returns the corresponding HTTP response. 139 | /// 140 | /// - Parameters: 141 | /// - request: The HTTP request to send. 142 | /// - body: The HTTP body to include in the request (optional). 143 | /// - baseURL: The base URL for the request. 144 | /// - operationID: The identifier for the operation. 145 | /// 146 | /// - Returns: A tuple containing the HTTP response and an optional HTTP body in the response. 147 | /// - Throws: An error if the request or response handling encounters any issues. 148 | public func send(_ request: HTTPRequest, body: HTTPBody?, baseURL: URL, operationID: String) async throws -> ( 149 | HTTPResponse, HTTPBody? 150 | ) { 151 | let httpRequest = try Self.convertRequest(request, body: body, baseURL: baseURL) 152 | let httpResponse = try await invokeSession(with: httpRequest) 153 | let response = try await Self.convertResponse(method: request.method, httpResponse: httpResponse) 154 | return response 155 | } 156 | 157 | // MARK: Internal 158 | 159 | /// Converts the shared Request type into URLRequest. 160 | internal static func convertRequest(_ request: HTTPRequest, body: HTTPBody?, baseURL: URL) throws 161 | -> HTTPClientRequest 162 | { 163 | guard var baseUrlComponents = URLComponents(string: baseURL.absoluteString), 164 | let requestUrlComponents = URLComponents(string: request.path ?? "") 165 | else { throw Error.invalidRequestURL(request: request, baseURL: baseURL) } 166 | baseUrlComponents.percentEncodedPath += requestUrlComponents.percentEncodedPath 167 | baseUrlComponents.percentEncodedQuery = requestUrlComponents.percentEncodedQuery 168 | guard let url = baseUrlComponents.url else { throw Error.invalidRequestURL(request: request, baseURL: baseURL) } 169 | var clientRequest = HTTPClientRequest(url: url.absoluteString) 170 | clientRequest.method = request.method.asHTTPMethod 171 | for header in request.headerFields { 172 | clientRequest.headers.add(name: header.name.canonicalName, value: header.value) 173 | } 174 | if let body { 175 | let length: HTTPClientRequest.Body.Length 176 | switch body.length { 177 | case .unknown: length = .unknown 178 | case .known(let count): length = .known(count) 179 | } 180 | clientRequest.body = .stream(body.map { .init(bytes: $0) }, length: length) 181 | } 182 | return clientRequest 183 | } 184 | 185 | /// Converts the received URLResponse into the shared Response. 186 | internal static func convertResponse(method: HTTPRequest.Method, httpResponse: HTTPClientResponse) async throws -> ( 187 | HTTPResponse, HTTPBody? 188 | ) { 189 | 190 | var headerFields: HTTPFields = [:] 191 | for header in httpResponse.headers { headerFields[.init(header.name)!] = header.value } 192 | 193 | let length: HTTPBody.Length 194 | if let lengthHeaderString = headerFields[.contentLength], let lengthHeader = Int64(lengthHeaderString) { 195 | length = .known(lengthHeader) 196 | } else { 197 | length = .unknown 198 | } 199 | 200 | let body: HTTPBody? 201 | switch method { 202 | case .head, .connect, .trace: body = nil 203 | default: 204 | body = HTTPBody(httpResponse.body.map { $0.readableBytesView }, length: length, iterationBehavior: .single) 205 | } 206 | 207 | let response = HTTPResponse(status: .init(code: Int(httpResponse.status.code)), headerFields: headerFields) 208 | return (response, body) 209 | } 210 | 211 | // MARK: Private 212 | 213 | /// Makes the underlying HTTP call. 214 | private func invokeSession(with request: Request) async throws -> Response { 215 | try await requestSender.send(request: request, with: configuration.client, timeout: configuration.timeout) 216 | } 217 | } 218 | 219 | extension HTTPTypes.HTTPRequest.Method { 220 | var asHTTPMethod: NIOHTTP1.HTTPMethod { 221 | switch self { 222 | case .get: return .GET 223 | case .put: return .PUT 224 | case .post: return .POST 225 | case .delete: return .DELETE 226 | case .options: return .OPTIONS 227 | case .head: return .HEAD 228 | case .patch: return .PATCH 229 | case .trace: return .TRACE 230 | default: return .RAW(value: rawValue) 231 | } 232 | } 233 | } 234 | 235 | /// A type that performs HTTP operations using the HTTP client. 236 | internal protocol HTTPRequestSending: Sendable { 237 | func send(request: AsyncHTTPClientTransport.Request, with client: HTTPClient, timeout: TimeAmount) async throws 238 | -> AsyncHTTPClientTransport.Response 239 | } 240 | 241 | /// Performs HTTP calls using AsyncHTTPClient 242 | internal struct AsyncHTTPRequestSender: HTTPRequestSending { 243 | func send(request: AsyncHTTPClientTransport.Request, with client: AsyncHTTPClient.HTTPClient, timeout: TimeAmount) 244 | async throws -> AsyncHTTPClientTransport.Response 245 | { try await client.execute(request, timeout: timeout) } 246 | } 247 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | 204 | --------------------------------------------------------------------------------