[
  {
    "path": ".github/FUNDING.yml",
    "content": "github: seanmonstar\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: \"Bug report 🐛\"\ndescription: Create a report to help us improve\nlabels: [\"C-bug\"]\nbody:\n  - type: input\n    id: version\n    attributes:\n      label: Version\n      description: List the version(s) of `hyper`, and any relevant hyper dependency (such as `h2` if this is related to HTTP/2).\n      placeholder: \"hyper 1.0.0, h2 0.4.0\"\n    validations:\n      required: true\n\n  - type: input\n    id: platform\n    attributes:\n      label: Platform\n      description: The output of `uname -a` (UNIX), or version and 32 or 64-bit (Windows)\n      placeholder: \"Linux 5.15.0 x86_64 / Windows 11 64-bit\"\n    validations:\n      required: true\n\n  - type: textarea\n    id: summary\n    attributes:\n      label: Summary\n      description: A short summary of the bug\n      placeholder: \"Brief description of what went wrong\"\n    validations:\n      required: true\n\n  - type: textarea\n    id: code\n    attributes:\n      label: Code Sample\n      description: Code sample that causes the bug (if applicable)\n      render: rust\n      placeholder: |\n        use hyper::...;\n\n        fn main() {\n            // code that reproduces the bug\n        }\n\n  - type: textarea\n    id: expected\n    attributes:\n      label: Expected Behavior\n      description: What you expected to happen\n    validations:\n      required: true\n\n  - type: textarea\n    id: actual\n    attributes:\n      label: Actual Behavior\n      description: What actually happened instead\n    validations:\n      required: true\n\n  - type: textarea\n    id: additional\n    attributes:\n      label: Additional Context\n      description: Any other context about the problem (stack traces, related issues, etc.)\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: \"Feature request \\U0001F4A1\"\nabout: Suggest an idea for this project\ntitle: ''\nlabels: C-feature\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE",
    "content": ""
  },
  {
    "path": ".github/workflows/CI.yml",
    "content": "name: CI\non:\n  pull_request:\n  push:\n    branches:\n      - master\n\nenv:\n  RUST_BACKTRACE: 1\n\npermissions:\n  contents: read # to fetch code (actions/checkout)\n\njobs:\n  ci-pass:\n    name: CI is green\n    runs-on: ubuntu-latest\n    needs:\n      - style\n      - test\n      - msrv\n      - miri\n      - features\n      - ffi\n      - ffi-header\n      - ffi-cargo-c\n      - doc\n      - check-external-types\n      - udeps\n      - minimal-versions\n      - semver\n    steps:\n      - run: exit 0\n\n  style:\n    name: Check Style\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - name: Install Rust\n        uses: dtolnay/rust-toolchain@stable\n        with:\n          components: rustfmt\n\n      - name: cargo fmt --check\n        run: |\n          if ! rustfmt --check --edition 2021 $(git ls-files '*.rs'); then\n            printf \"Please run \\`rustfmt --edition 2021 \\$(git ls-files '*.rs')\\` to fix rustfmt errors.\\nSee docs/CODE_STYLE.md for more details.\\n\" >&2\n            exit 1\n          fi\n\n  test:\n    name: Test ${{ matrix.rust }} on ${{ matrix.os }}\n    needs: [style]\n    strategy:\n      matrix:\n        rust:\n          - stable\n          - beta\n          - nightly\n\n        os:\n          - ubuntu-latest\n          - windows-latest\n          - macOS-latest\n\n        include:\n          - rust: stable\n            features: \"--features full\"\n          - rust: beta\n            features: \"--features full\"\n          - rust: nightly\n            features: \"--features full,nightly\"\n            benches: true\n\n    runs-on: ${{ matrix.os }}\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - name: Install Rust (${{ matrix.rust }})\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: ${{ matrix.rust }}\n\n      - uses: Swatinem/rust-cache@v2\n\n      - name: Test\n        run: cargo test ${{ matrix.features }}\n\n      - name: Test all benches\n        if: matrix.benches\n        run: cargo test --benches ${{ matrix.features }}\n\n  msrv:\n    name: Check MSRV\n    needs: [style]\n\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - uses: dtolnay/rust-toolchain@stable\n\n      - name: Resolve MSRV aware dependencies\n        run: cargo update\n        env:\n          CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: fallback\n\n      - name: Get MSRV from package metadata\n        id: msrv\n        run: echo \"version=$(yq '.package.rust-version' Cargo.toml)\" >> $GITHUB_OUTPUT\n\n      - name: Install Rust (${{ steps.msrv.outputs.version }})\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: ${{ steps.msrv.outputs.version }}\n\n      - uses: Swatinem/rust-cache@v2\n\n      - name: Check\n        run: cargo check --features full\n\n  miri:\n    name: Test with Miri\n    needs: [style]\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - name: Install Rust\n        uses: dtolnay/rust-toolchain@nightly\n        with:\n          components: miri\n\n      - uses: Swatinem/rust-cache@v2\n\n      - name: Test\n        # Can't enable tcp feature since Miri does not support the tokio runtime\n        run: MIRIFLAGS=\"-Zmiri-disable-isolation\" cargo miri test --features http1,http2,client,server,nightly\n\n  features:\n    name: features\n    needs: [style]\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - name: Install Rust\n        uses: dtolnay/rust-toolchain@stable\n\n      - name: Install cargo-hack\n        uses: taiki-e/install-action@cargo-hack\n\n      - uses: Swatinem/rust-cache@v2\n\n      - name: check --feature-powerset\n        run: cargo hack --no-dev-deps check --feature-powerset --depth 2 --skip ffi,tracing\n        env:\n          RUSTFLAGS: \"-D dead_code -D unused_imports\"\n\n      - name: check --feature-powerset with tracing feature\n        run: cargo hack --no-dev-deps check --feature-powerset --depth 2 --features tracing --skip ffi\n        env:\n          RUSTFLAGS: \"--cfg hyper_unstable_tracing -D dead_code -D unused_imports\"\n\n  ffi:\n    name: Test C API (FFI)\n    needs: [style]\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - name: Install Rust\n        uses: dtolnay/rust-toolchain@stable\n\n      - uses: Swatinem/rust-cache@v2\n\n      - name: Build FFI\n        env:\n          RUSTFLAGS: --cfg hyper_unstable_ffi\n        run: cargo rustc --features client,http1,http2,ffi --crate-type cdylib\n\n      - name: Make Examples\n        run: cd capi/examples && make client\n\n      - name: Run FFI unit tests\n        env:\n          RUSTFLAGS: --cfg hyper_unstable_ffi\n        run: cargo test --features client,http1,http2,ffi --lib\n\n  ffi-header:\n    name: Verify hyper.h is up to date\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - name: Install Rust\n        uses: dtolnay/rust-toolchain@stable\n\n      - name: Install cbindgen\n        uses: taiki-e/cache-cargo-install-action@v2\n        with:\n          tool: cbindgen\n\n      - name: Install cargo-expand\n        uses: taiki-e/cache-cargo-install-action@v2\n        with:\n          tool: cargo-expand\n\n      - uses: Swatinem/rust-cache@v2\n\n      - name: Build FFI\n        env:\n          RUSTFLAGS: --cfg hyper_unstable_ffi\n        run: cargo build --features client,http1,http2,ffi\n\n      - name: Ensure that hyper.h is up to date\n        run: ./capi/gen_header.sh --verify\n\n  ffi-cargo-c:\n    name: Test cargo-c support (FFI)\n    needs: [style]\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - name: Install Rust\n        uses: dtolnay/rust-toolchain@stable\n\n      - uses: Swatinem/rust-cache@v2\n\n      - name: Install cargo-c\n        env:\n          LINK: https://github.com/lu-zero/cargo-c/releases/latest/download\n          CARGO_C_FILE: cargo-c-x86_64-unknown-linux-musl.tar.gz\n        run: |\n          curl -L $LINK/$CARGO_C_FILE | tar xz -C ~/.cargo/bin\n\n      - name: Build with cargo-c\n        env:\n          RUSTFLAGS: --cfg hyper_unstable_ffi\n        run: cargo cbuild --features client,http1,http2,ffi\n\n  doc:\n    name: Build docs\n    needs: [style, test]\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - name: Install Rust\n        uses: dtolnay/rust-toolchain@nightly\n\n      - uses: Swatinem/rust-cache@v2\n\n      - name: cargo doc\n        run: cargo rustdoc --features full,ffi -- --cfg docsrs --cfg hyper_unstable_ffi -D rustdoc::broken-intra-doc-links\n\n  check-external-types:\n    name: Check exposed types\n    needs: [style, test]\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - name: Install Rust\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: nightly-2025-10-18 # Compatible version for cargo-check-external-types\n\n      - name: Install cargo-check-external-types\n        uses: taiki-e/cache-cargo-install-action@v2\n        with:\n          tool: cargo-check-external-types@0.4.0\n\n      - uses: Swatinem/rust-cache@v2\n\n      - name: check-external-types\n        run: cargo check-external-types --config .github/workflows/external-types.toml\n\n  udeps:\n    needs: [style]\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n\n      - name: Install Rust\n        uses: dtolnay/rust-toolchain@nightly\n\n      - name: Install cargo-udeps\n        uses: taiki-e/install-action@cargo-udeps\n\n      - uses: Swatinem/rust-cache@v2\n\n      - name: Check unused dependencies on default features\n        run: cargo udeps\n\n      - name: Check unused dependencies on full features\n        run: cargo udeps --features full\n\n  minimal-versions:\n    runs-on: ubuntu-latest\n    needs: [style]\n    steps:\n      - uses: actions/checkout@v6\n      - uses: dtolnay/rust-toolchain@nightly\n      - uses: dtolnay/rust-toolchain@stable\n      - uses: taiki-e/install-action@cargo-hack\n      - uses: taiki-e/install-action@cargo-minimal-versions\n      - uses: Swatinem/rust-cache@v2\n      - run: cargo minimal-versions check\n      - run: cargo minimal-versions check --features full\n\n  semver:\n    name: semver\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n      - name: Check semver\n        uses: obi1kenobi/cargo-semver-checks-action@v2\n        with:\n          feature-group: only-explicit-features\n          features: full\n          release-type: minor\n"
  },
  {
    "path": ".github/workflows/bench.yml",
    "content": "name: Benchmark\non:\n  push:\n    branches:\n      - master\n\njobs:\n  benchmark:\n    name: Benchmark\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        bench:\n          - end_to_end\n          - pipeline\n    steps:\n      - uses: actions/checkout@v6\n\n      - name: Install Rust\n        uses: dtolnay/rust-toolchain@nightly\n\n      # Run benchmark and stores the output to a file\n      - name: Run benchmark\n        run: cargo bench --features full --bench ${{ matrix.bench }} | tee output.txt\n\n      # Download previous benchmark result from cache (if exists)\n      - name: Download previous benchmark data\n        uses: actions/cache@v3\n        with:\n          path: ./cache\n          key: ${{ runner.os }}-benchmark\n\n      # Run `github-action-benchmark` action\n      - name: Store benchmark result\n        uses: seanmonstar/github-action-benchmark@v1-patch-1\n        with:\n          name: ${{ matrix.bench }}\n          # What benchmark tool the output.txt came from\n          tool: 'cargo'\n          # Where the output from the benchmark tool is stored\n          output-file-path: output.txt\n          # # Where the previous data file is stored\n          # external-data-json-path: ./cache/benchmark-data.json\n          # Workflow will fail when an alert happens\n          fail-on-alert: true\n          # GitHub API token to make a commit comment\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          # Enable alert commit comment\n          comment-on-alert: true\n          #alert-comment-cc-users: '@seanmonstar'\n          auto-push: true\n\n      # Upload the updated cache file for the next job by actions/cache\n"
  },
  {
    "path": ".github/workflows/cargo-audit.yml",
    "content": "name: cargo-audit\non:\n  push:\n    paths:\n      - '**/Cargo.toml'\n      - '**/Cargo.lock'\n  schedule:\n    - cron: '0 16 * * Mon'\n\njobs:\n  security_audit:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n      - name: Generate lockfile\n        run: cargo generate-lockfile --features full\n      - uses: rustsec/audit-check@v2\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/external-types.toml",
    "content": "allowed_external_types = [\n    \"bytes::buf::buf_impl::Buf\",\n    \"bytes::bytes::Bytes\",\n    \"http::header\",\n    \"http::header::map::HeaderMap\",\n    \"http::method::Method\",\n    \"http::request::Request\",\n    \"http::response::Response\",\n    \"http::status::StatusCode\",\n    \"http::uri::Uri\",\n    \"http::version::Version\",\n    \"http_body::Body\",\n    \"http_body::frame::Frame\",\n    \"http_body::size_hint::SizeHint\",\n]\n"
  },
  {
    "path": ".gitignore",
    "content": "target\nCargo.lock\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "### v1.8.1 (2025-11-13)\n\n\n#### Bug Fixes\n\n* **http1:** fix consuming extra CPU from previous change (#3977) ([4492f31e](https://github.com/hyperium/hyper/commit/4492f31e9429c34166da5a069c00b65be20e4a02))\n\n\n## v1.8.0 (2025-11-11)\n\n\n#### Bug Fixes\n\n* **http1:** fix rare missed write wakeup on connections (#3952) ([2377b893](https://github.com/hyperium/hyper/commit/2377b893f6e64ca9878e4f25d1472b96baa7e3ea))\n* **http2:** fix internals of HTTP/2 CONNECT upgrades (#3967) ([58e0e7dc](https://github.com/hyperium/hyper/commit/58e0e7dc70612117ccdc40da395922f791cb273a), closes [#3966](https://github.com/hyperium/hyper/issues/3966))\n\n\n#### Features\n\n* **rt:** add `Timer::now()` method to allow overriding the instant returned (#3965) ([5509ebe6](https://github.com/hyperium/hyper/commit/5509ebe6156e32d4f8986fafa25c2918a30005be))\n\n\n#### Breaking Changes\n\n* The HTTP/2 client connection no longer allows an executor\n  that can not spawn itself.\n\n  This was an oversight originally. The client connection will now include spawning\n  a future that keeps a copy of the executor to spawn other futures. Thus, if it is\n  `!Send`, it needs to spawn `!Send` futures. The likelihood of executors that match\n  the previously allowed behavior should be very remote.\n\n  There is also technically a semver break in here, which is that the\n  `Http2ClientConnExec` trait no longer dyn-compatible, because it now expects to\n  be `Clone`. This should not break usage of the `conn` builder, because it already\n  separately had `E: Clone` bounds. If someone were using `dyn Http2ClientConnExec`,\n  that will break. However, there is no purpose for doing so, and it is not usable\n  otherwise, since the trait only exists to propagate bounds into hyper. Thus, the\n  breakage should not affect anyone.\n ([58e0e7dc](https://github.com/hyperium/hyper/commit/58e0e7dc70612117ccdc40da395922f791cb273a))\n\n\n## v1.7.0 (2025-08-18)\n\n\n#### Bug Fixes\n\n* **server:** improve caching accuracy of Date header (#3887) ([436cadd1](https://github.com/hyperium/hyper/commit/436cadd1ac08a9508a46f550e03281db9f2fee97))\n\n\n#### Features\n\n* **client:**\n  * add a `TrySendError::error()` method (#3885) ([efa0b269](https://github.com/hyperium/hyper/commit/efa0b26958386ffaf646e6d9a3150ca5041162a3))\n  * add a `TrySendError::message()` method (#3884) ([03fd6aff](https://github.com/hyperium/hyper/commit/03fd6aff88c99a0842bb2e578a4993a432c03049))\n* **error:** add `Error::is_shutdown()` (#3863) ([b8affd8a](https://github.com/hyperium/hyper/commit/b8affd8a2ee5d77dec0c32050a7234e4f2f3751b), closes [#2745](https://github.com/hyperium/hyper/issues/2745))\n* **server:** add `allow_multiple_spaces_in_request_line_delimiters` http1 builder method (#3929) ([9749184f](https://github.com/hyperium/hyper/commit/9749184f8a21c387e404d628aceb992f0bf93e49))\n\n\n## v1.6.0 (2025-01-28)\n\n\n#### Bug Fixes\n\n* **server:**\n  * start http1 header read timeout when conn is idle (#3828) ([10b09ffc](https://github.com/hyperium/hyper/commit/10b09ffc04a97bbc96444172b7c5e02665827c67), closes [#3780](https://github.com/hyperium/hyper/issues/3780), [#3781](https://github.com/hyperium/hyper/issues/3781))\n  * change `max_local_error_reset_streams` function to `&mut self` (#3820) ([e981a91e](https://github.com/hyperium/hyper/commit/e981a91e68aa92b0dee771362de771daa31c713e))\n\n\n#### Features\n\n* **ext:** add `ext::on_informational()` callback extension (#3818) ([8ce1fcfa](https://github.com/hyperium/hyper/commit/8ce1fcfae97611ace027b9e26717ae957b323f24), closes [#2565](https://github.com/hyperium/hyper/issues/2565))\n* **server:** add `http1::Builder::ignore_invalid_headers(bool)` option (#3824) ([3817a79b](https://github.com/hyperium/hyper/commit/3817a79b213f840302d7e27fac8508de9caada0f))\n\n\n#### Breaking Changes\n\n* `http2::Builder::max_local_error_reset_streams()` now takes `&mut self` and returns `&mut Self`. In practice, this shouldn't break almost anyone. It was the wrong receiver and return types.\n ([e981a91e](https://github.com/hyperium/hyper/commit/e981a91e68aa92b0dee771362de771daa31c713e))\n\n\n### v1.5.2 (2024-12-16)\n\n\n#### Bug Fixes\n\n* **http1:**\n  * fix intermitent panic parsing partial headers (#3812) ([a131111f](https://github.com/hyperium/hyper/commit/a131111f9c3189bab36fed9f46872c88dc0d601e), closes [#3811](https://github.com/hyperium/hyper/issues/3811))\n  * skip debug assertion of content length for HEAD responses (#3795) ([eaf2267c](https://github.com/hyperium/hyper/commit/eaf2267cdc148604469fb09da22646f31710107a), closes [#3794](https://github.com/hyperium/hyper/issues/3794))\n\n\n#### Features\n\n* **ffi:** add cargo-c support (#3787) ([7f4a6826](https://github.com/hyperium/hyper/commit/7f4a68265cb897d15b04fc772639234554ba79e8), closes [#3786](https://github.com/hyperium/hyper/issues/3786))\n\n\n### v1.5.1 (2024-11-19)\n\n\n#### Bug Fixes\n\n* **http2:**\n  * pass proper value to h2 max_local_error_reset_streams ([4a20147a](https://github.com/hyperium/hyper/commit/4a20147a1b73003860a8391c4b89ccd8a78a832e))\n  * improve graceful shutdown during handshake (#3729) ([13b05943](https://github.com/hyperium/hyper/commit/13b0594348916b901ad7e1c838b9d90298db6af4))\n\n\n## v1.5.0 (2024-10-15)\n\n\n#### Bug Fixes\n\n* **http1:**\n  * improve performance of parsing sequentially partial messages (#3764) ([3900a23](https://github.com/hyperium/hyper/commit/3900a2381b96a7e7f608a5e031b3e90ddcdfcd74))\n  * send 'connection: close' when connection is ending (#3725) ([c86a6bcb](https://github.com/hyperium/hyper/commit/c86a6bcb4acb0f92e731ea2e4c1e4a839248a600), closes [#3720](https://github.com/hyperium/hyper/issues/3720))\n  * make `date_header` effective (#3718) ([7de02373](https://github.com/hyperium/hyper/commit/7de02373f5e4ce392587a4d9d7710c6faf9c6165))\n* **http2:** strip content-length header in response to CONNECT requests (#3748) ([67a4a498](https://github.com/hyperium/hyper/commit/67a4a498d8bbdce4e604bc578da4693fb048f83d))\n\n\n#### Features\n\n* **client:** Add HTTP/2 builder options `header_table_size()` and `max_concurrent_streams()`  ([4c84e8c1](https://github.com/hyperium/hyper/commit/4c84e8c1c26a1464221de96b9f39816ce7251a5f))\n* **rt:** add `ReadBufCursor` methods `remaining()` and `put_slice()` (#3700) ([5a13041e](https://github.com/hyperium/hyper/commit/5a13041ed7033c9dab6e2adafd08b6af20cd33fb))\n\n\n### v1.4.1 (2024-07-09)\n\n\n#### Bug Fixes\n\n* **http1:** reject final chunked if missing 0 ([8e5de1bb](https://github.com/hyperium/hyper/commit/8e5de1bb57e10b5bd9e70ab22489da787517238a))\n\n\n## v1.4.0 (2024-07-01)\n\n\n#### Bug Fixes\n\n* **http2:** stop removing \"Trailer\" header in HTTP/2 responses as per RFC 9110 (#3648) ([a3269f7a](https://github.com/hyperium/hyper/commit/a3269f7ab285dbeb44a3a7dbc163fcadd65087f9))\n* **server:** start header read timeout immediately (#3185) ([0eb1b6cf](https://github.com/hyperium/hyper/commit/0eb1b6cf4d914ce9c3f8e92a8b43754eba27a327))\n\n\n#### Features\n\n* **client:**\n  * add `SendRequest::try_send_request()` method (#3691) ([4ffaad53](https://github.com/hyperium/hyper/commit/4ffaad53c78572c500584e0cb5d76ae6ffc6adb6))\n  * remove `Send +Sync` bounds requirement of `http2::Connection` executor (#3682) ([56c3cd56](https://github.com/hyperium/hyper/commit/56c3cd560bc10671d3d8b638f3f17a304f920c6b))\n  * remove `'static` lifetime bound on http1/2 client IO (#3667) ([9580b357](https://github.com/hyperium/hyper/commit/9580b357635031f3d631303f3afffc2afae77933))\n* **http1:** add support for receiving trailer fields (#3637) ([ac84af6b](https://github.com/hyperium/hyper/commit/ac84af6b32a5d37d9343013ace088aaae47587b6), closes [#2703](https://github.com/hyperium/hyper/issues/2703))\n* **server:** add `Builder::auto_date_header(bool)` to allow disabling Date headers ([721785ef](https://github.com/hyperium/hyper/commit/721785efad8537513e48d900a85c05ce79483018))\n* **service:** implement Service for reference types (#3607) ([eade122d](https://github.com/hyperium/hyper/commit/eade122db25f51619aee5db845de2a61b7ff2f74))\n\n\n### v1.3.1 (2024-04-16)\n\n#### Bug Fixes\n\n* **client:** revert auto content-length header for some requests (#3633)\n\n\n## v1.3.0 (2024-04-15)\n\n\n#### Bug Fixes\n\n* **client:** send content-length even with no body ([172fdfaf](https://github.com/hyperium/hyper/commit/172fdfaf0e0d9222917f271a83339238082e2657))\n* **http2:**\n  * `max_header_list_size(num)` defaults to 16kb ([203d1b09](https://github.com/hyperium/hyper/commit/203d1b090d0d0349c7e373e881ac4ddba72129be))\n  * `initial_max_send_streams` defaults to 100 ([2d1bd708](https://github.com/hyperium/hyper/commit/2d1bd7085e37a55ed6393f0e3f1b9a0b06db4d5d))\n* **server:**\n  * avoid unwrapping for the `Future` impl of HTTP/1 `UpgradeableConnection` (#3627) ([b79be911](https://github.com/hyperium/hyper/commit/b79be911696f6a93e8d408080ebbf558b612ce3c), closes [#3621](https://github.com/hyperium/hyper/issues/3621))\n  * avoid  `graceful_shutdown` panic on upgraded H1 connection (#3616) ([6ecf8521](https://github.com/hyperium/hyper/commit/6ecf85218fb24531184c53d5ed0eb7caf13cdcef))\n\n\n#### Features\n\n* **client:**\n  * add `max_header_list_size(num)` to `http2::Builder`. ([1c5b1b87](https://github.com/hyperium/hyper/commit/1c5b1b87ae1497a702e30ea82a486fb61a3f8133))\n  * add `max_pending_accept_reset_streams` HTTP2 option (#3617) ([330ddf1d](https://github.com/hyperium/hyper/commit/330ddf1de1ca2841469d30d24143902e5ff06365))\n* **ext:** implement From ReasonPhrase for Bytes ([dc27043a](https://github.com/hyperium/hyper/commit/dc27043aa319c0e630b7385a36aca0f3bee70670))\n* **service:** expose Service and HttpService trait unconditionally ([6aee2e6e](https://github.com/hyperium/hyper/commit/6aee2e6e260e7d407256d6b7da6a0d90c1bb9c67))\n* **server:** relax `'static` from connection IO trait bounds  (#3595) ([0013bdda](https://github.com/hyperium/hyper/commit/0013bdda5cd34ed6fca089eceb0133395b7be041))\n\n\n## v1.2.0 (2024-02-21)\n\n\n#### Bug Fixes\n\n* **http2:** typo in trace logging (#3536) ([79862ec2](https://github.com/hyperium/hyper/commit/79862ec2e84c32122c820958ceec06d8b7701ff7))\n* **rt:** `Sleep::downcast_mut_pin()` no longer extend lifetime ([7206fe30](https://github.com/hyperium/hyper/commit/7206fe30302937075c51c16a69d1eb3bbce6a671), closes [#3556](https://github.com/hyperium/hyper/issues/3556))\n\n\n#### Features\n\n* **http1:** support configurable `max_headers(num)` to client and server (#3523) ([b1142448](https://github.com/hyperium/hyper/commit/b114244898828e9fb254bea1f0bbdd24850b2f3f))\n* **http2:**\n  * add config for `max_local_error_reset_streams` in server (#3530) ([d7680e30](https://github.com/hyperium/hyper/commit/d7680e30e48926a5a3f94a0986d39181d5ab2218))\n  * add `initial_max_send_streams` method to HTTP/2 client builder (#3524) ([fdfa60d9](https://github.com/hyperium/hyper/commit/fdfa60d9fafb8a6bfb40acc4042ee54a2b9aad32))\n  * add `max_pending_accept_reset_streams(num)` back to HTTP/2 server builder (#3507 ([a9fa893f](https://github.com/hyperium/hyper/commit/a9fa893f18c6409abae2e1dcbba0f4487df54d4f))\n\n\n#### Breaking Changes\n\n* The returned lifetime from `Sleep::downcast_mut_pin()`\n  is no longer `'static`. This shouldn't affect most usage. This sort of\n  breaking change is needed because it is _wrong_.\n\n ([7206fe30](https://github.com/hyperium/hyper/commit/7206fe30302937075c51c16a69d1eb3bbce6a671))\n\n\n## v1.1.0 (2023-12-18)\n\n\n#### Bug Fixes\n\n* **http1:**\n  * add internal limit for chunked extensions (#3495) ([d71ff962](https://github.com/hyperium/hyper/commit/d71ff962b08aca2f1c9c1724dfdab5bc1ec6ecd2))\n  * reject chunked headers missing a digit (#3494) ([82915386](https://github.com/hyperium/hyper/commit/829153865a4d2bbb52227183c8857e57dc3e231b))\n\n\n#### Features\n\n* **client:** add `http1::Connection` `without_shutdown()` method (#3430) ([210bfaa7](https://github.com/hyperium/hyper/commit/210bfaa711b5da1f6756582a2e4bc3e229924800))\n* **http1:** Add support for sending HTTP/1.1 Chunked Trailer Fields (#3375) ([31b41807](https://github.com/hyperium/hyper/commit/31b41807523370f3efbf47ba16c9e1c193b6335a), closes [#2719](https://github.com/hyperium/hyper/issues/2719))\n* **server:** expose `server::conn::http1::UpgradeableConnection` (#3457) ([6e3042a8](https://github.com/hyperium/hyper/commit/6e3042a86f10359624857d31bc9e876f521aee42))\n\n\n### v1.0.1 (2023-11-16)\r\n\r\nThis release \"fixes\" or adds a few things that should have been in 1.0.0, but were forgotten. Thus, it includes additions that would normally be a semver-minor release, but because it is so close to 1.0.0, it is released as a patch version.\r\n\r\n#### Bug Fixes\r\n\r\n* **rt:** implement Read/Write for Pin<P> (#3413) ([dd6d81ca](https://github.com/hyperium/hyper/commit/dd6d81ca4a180695dc70d6c9b2aececd29606224), closes [#3412](https://github.com/hyperium/hyper/issues/3412))\r\n\r\n\r\n#### Features\r\n\r\n* **rt:** Make ReadBuf::new public ([7161f562](https://github.com/hyperium/hyper/commit/7161f56274a30bfbe4a718bbe21d35beaf86b00b))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* Pin is #[fundamental], so providing a Read/Write impl for it theoretically conflicts\r\n  with existing user Read/Write for Pin<...> impls. However, those impls\r\n  probably don't exist yet.\r\n ([dd6d81ca](https://github.com/hyperium/hyper/commit/dd6d81ca4a180695dc70d6c9b2aececd29606224))\r\n\r\n\r\n## v1.0.0 (2023-11-15)\r\n\r\nBe sure to check out the [upgrading guide](https://hyper.rs/guides/1/upgrading).\r\n\r\n#### Bug Fixes\r\n\r\n* **client:**\r\n  * avoid double-polling a Select future (#3290) ([fece9f7f](https://github.com/hyperium/hyper/commit/fece9f7f50431cf9533cfe7106b53a77b48db699), closes [#3289](https://github.com/hyperium/hyper/issues/3289))\r\n  * early server response shouldn't propagate NO_ERROR (#3275) ([194e6f98](https://github.com/hyperium/hyper/commit/194e6f984763f5dc1c376082170a85cc4db40ce4), closes [#2872](https://github.com/hyperium/hyper/issues/2872))\r\n  * remove Send bounds for request `Body` (#3266) ([4ace340b](https://github.com/hyperium/hyper/commit/4ace340bb00a2ffe8ec93e4955989eb69f29d531), closes [#3184](https://github.com/hyperium/hyper/issues/3184))\r\n* **ffi:** fix deadlock in `hyper_executor::poll_next` (#3370) ([0c7d03ef](https://github.com/hyperium/hyper/commit/0c7d03eff2f2433e4f4a0a768009d97e1a7858fd), closes [#3369](https://github.com/hyperium/hyper/issues/3369))\r\n* **http2:**\r\n  * don't send keep-alive ping when idle (#3381) ([429ad8a3](https://github.com/hyperium/hyper/commit/429ad8a34b20a877b4d17df1f4991a193f4a56f0))\r\n  * change default server max concurrent streams to 200 (#3362) ([dd638b5b](https://github.com/hyperium/hyper/commit/dd638b5b34225d2c5ad0bd01de0ecf738f9a0e12), closes [#3358](https://github.com/hyperium/hyper/issues/3358))\r\n* **server:** Respect Expect header only when http proto > 1.0 (#3294) ([43d2f5c6](https://github.com/hyperium/hyper/commit/43d2f5c6cfd575f7259a5b3684f7e99cedbd0edb))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** allow `!Send` IO with HTTP/1 client (#3371) ([cf87eda8](https://github.com/hyperium/hyper/commit/cf87eda82ca0af1f5f45b0a0710eaae9ec1aed7b), closes [#3363](https://github.com/hyperium/hyper/issues/3363))\r\n* **error:**\r\n  * `Error::source()` is purposefully unspecified (#3318) ([502a6450](https://github.com/hyperium/hyper/commit/502a645053b0d19252d9fdc170b0a2c0a6fe0ba6), closes [#2843](https://github.com/hyperium/hyper/issues/2843))\r\n  * change `Display for Error` to only print top error (#3312) ([50f123af](https://github.com/hyperium/hyper/commit/50f123afc0e6c289030bf8699dbec826dc47572c), closes [#2844](https://github.com/hyperium/hyper/issues/2844))\r\n* **ext:**\r\n  * make `ReasonPhrase::from_static` a const fn ([d4a61e3d](https://github.com/hyperium/hyper/commit/d4a61e3da87a08a25772cd3aa2f503cb4346c81f))\r\n  * remove `ReasonPhrase::from_bytes_unchecked()` method ([4021c57b](https://github.com/hyperium/hyper/commit/4021c57bd9265b9ebc5b88c9bffbb0ac3704bdbe))\r\n* **lib:**\r\n  * update to `http` 1.0 ([899e92a5](https://github.com/hyperium/hyper/commit/899e92a580961c5bd1cc9b49a8fb7c7cd8b53ef8))\r\n  * missing Timer will warn or panic ([f3308c04](https://github.com/hyperium/hyper/commit/f3308c044d402dfad448bbc0497b14c69a8f22f2), closes [#3393](https://github.com/hyperium/hyper/issues/3393))\r\n  * increase MSRV to 1.63 (#3293) ([e68dc961](https://github.com/hyperium/hyper/commit/e68dc961a7dad0a96e16898b0da234927564c079))\r\n* **rt:** rename to `Http2ClientConnExec` and `Http2ServerConnExec` ([52b27faa](https://github.com/hyperium/hyper/commit/52b27faa09715b5835804de7abf6998e028736fc))\r\n* **server:** default `http1` `header_read_timeout` to 30 seconds ([8bf26d1e](https://github.com/hyperium/hyper/commit/8bf26d1e394a8f207debe45445a5fb85cc349238))\r\n* **upgrade:** introduce tracing as an optional unstable feature (#3326) ([da3fc76c](https://github.com/hyperium/hyper/commit/da3fc76c06b6caa60f6abc1da570d56d7c8fa468), closes [#3319](https://github.com/hyperium/hyper/issues/3319))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* Upgrade to `http` 1.0.\r\n\r\n ([899e92a5](https://github.com/hyperium/hyper/commit/899e92a580961c5bd1cc9b49a8fb7c7cd8b53ef8))\r\n* (From previous RCs) `ExecutorClient` is renamed to\r\n  `Http2ClientConnExec`, and `Http2ConnExec` is renamed to\r\n  `Http2ServerConnExec`.\r\n\r\n ([52b27faa](https://github.com/hyperium/hyper/commit/52b27faa09715b5835804de7abf6998e028736fc))\r\n* If you use client HTTP/1 upgrades, you must call\r\n  `Connection::with_upgrades()` to still work the same.\r\n ([cf87eda8](https://github.com/hyperium/hyper/commit/cf87eda82ca0af1f5f45b0a0710eaae9ec1aed7b))\r\n* HTTP/2 server builder now has a default max concurrent streams. This is a\r\n  behavior change. Consider setting your own maximum.\r\n ([dd638b5b](https://github.com/hyperium/hyper/commit/dd638b5b34225d2c5ad0bd01de0ecf738f9a0e12))\r\n* Do not build any logic depending on the exact types of\r\n  an `Error::source()`. They are only for debugging.\r\n ([502a6450](https://github.com/hyperium/hyper/commit/502a645053b0d19252d9fdc170b0a2c0a6fe0ba6))\r\n* The format no longer prints the error chain. Be sure to\r\n  check if you are logging errors directly.\r\n\r\n  The `Error::message()` method is removed, it is no longer needed.\r\n\r\n  The `Error::into_cause()` method is removed.\r\n ([50f123af](https://github.com/hyperium/hyper/commit/50f123afc0e6c289030bf8699dbec826dc47572c))\r\n* The `ReasonPhrase::from_bytes_unchecked()` method is\r\n  gone. Use `from_static()` or `TryFrom` to construct one.\r\n\r\n ([4021c57b](https://github.com/hyperium/hyper/commit/4021c57bd9265b9ebc5b88c9bffbb0ac3704bdbe))\r\n\r\n\r\n### v1.0.0-rc.4 (2023-07-10)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http1:**\r\n  * http1 server graceful shutdown fix (#3261) ([f4b51300](https://github.com/hyperium/hyper/commit/f4b513009d81083081d1c60c1981847bbb17dd5d))\r\n  * send error on Incoming body when connection errors (#3256) ([52f19259](https://github.com/hyperium/hyper/commit/52f192593fb9ebcf6d3894e0c85cbf710da4decd), closes [#3253](https://github.com/hyperium/hyper/issues/3253))\r\n  * properly end chunked bodies when it was known to be empty (#3254) ([fec64cf0](https://github.com/hyperium/hyper/commit/fec64cf0abdc678e30ca5f1b310c5118b2e01999), closes [#3252](https://github.com/hyperium/hyper/issues/3252))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** Make clients able to use non-Send executor (#3184) ([d977f209](https://github.com/hyperium/hyper/commit/d977f209bc6068d8f878b22803fc42d90c887fcc), closes [#3017](https://github.com/hyperium/hyper/issues/3017))\r\n* **rt:**\r\n  * replace IO traits with hyper::rt ones (#3230) ([f9f65b7a](https://github.com/hyperium/hyper/commit/f9f65b7aa67fa3ec0267fe015945973726285bc2), closes [#3110](https://github.com/hyperium/hyper/issues/3110))\r\n  * add downcast on `Sleep` trait (#3125) ([d92d3917](https://github.com/hyperium/hyper/commit/d92d3917d950e4c61c37c2170f3ce273d2a0f7d1), closes [#3027](https://github.com/hyperium/hyper/issues/3027))\r\n* **service:** change Service::call to take &self (#3223) ([d894439e](https://github.com/hyperium/hyper/commit/d894439e009aa75103f6382a7ba98fb17da72f02), closes [#3040](https://github.com/hyperium/hyper/issues/3040))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* Any IO transport type provided must now implement `hyper::rt::{Read, Write}` instead of\r\n  `tokio::io` traits. You can grab a helper type from `hyper-util` to wrap Tokio types, or implement the traits yourself,\r\n  if it's a custom type.\r\n ([f9f65b7a](https://github.com/hyperium/hyper/commit/f9f65b7aa67fa3ec0267fe015945973726285bc2))\r\n* `client::conn::http2` types now use another generic for an `Executor`.\r\n  Code that names `Connection` needs to include the additional generic parameter.\r\n ([d977f209](https://github.com/hyperium/hyper/commit/d977f209bc6068d8f878b22803fc42d90c887fcc))\r\n* The Service::call function no longer takes a mutable reference to self.\r\n  The FnMut trait bound on the service::util::service_fn function and the trait bound\r\n  on the impl for the ServiceFn struct were changed from FnMut to Fn.\r\n\r\n ([d894439e](https://github.com/hyperium/hyper/commit/d894439e009aa75103f6382a7ba98fb17da72f02))\r\n\r\n\r\n\r\n### v1.0.0-rc.3 (2023-02-23)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **server:** prevent sending 100-continue if user drops request body (#3137) ([499fe1f9](https://github.com/hyperium/hyper/commit/499fe1f949895218c4fd2305a0eddaf24f1dd0a9))\r\n\r\n\r\n#### Features\r\n\r\n* **client:**\r\n  * add `is_ready()` and `is_closed()` methods to `SendRequest` (#3148) ([3fb59919](https://github.com/hyperium/hyper/commit/3fb59919941d3145be6d84dab85d222ea0e7664b))\r\n  * `http2` builder now requires an `Executor` (#3135) ([8068aa01](https://github.com/hyperium/hyper/commit/8068aa011f6477a21ad54230c8fef9e26b330503), closes [#3128](https://github.com/hyperium/hyper/issues/3128))\r\n  * remove unneeded HTTP/1 executor (#3108) ([1de9accf](https://github.com/hyperium/hyper/commit/1de9accf1e133d1a23311879f466251b2f6481e5))\r\n* **rt:** make private executor traits public (but sealed) in `rt::bounds` (#3127) ([fc9f3070](https://github.com/hyperium/hyper/commit/fc9f30701a159772d0c014de47d16798502bae2c), closes [#2051](https://github.com/hyperium/hyper/issues/2051), [#3097](https://github.com/hyperium/hyper/issues/3097))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n*  `hyper::client::conn::Http2::Builder::new` now requires an executor argument.\r\n ([8068aa01](https://github.com/hyperium/hyper/commit/8068aa011f6477a21ad54230c8fef9e26b330503))\r\n* The method\r\n  `hyper::client::conn::http1::Builder::executor()` is removed, since it did nothing.\r\n ([1de9accf](https://github.com/hyperium/hyper/commit/1de9accf1e133d1a23311879f466251b2f6481e5))\r\n\r\n\r\n### v1.0.0-rc.2 (2022-12-29)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** send an error back to client when dispatch misbehaves () ([75aac9f4](https://github.com/hyperium/hyper/commit/75aac9f47fe0246016e6133cd3cfa35b63c8904e), closes [#2649](https://github.com/hyperium/hyper/issues/2649))\r\n* **http2:** Fix race condition in client dispatcher (#3041) ([f202230c](https://github.com/hyperium/hyper/commit/f202230c6fa274f6a4e6cbaad57ca59beb0a5125))\r\n\r\n\r\n#### Features\r\n\r\n* **body:** upgrade to http-body 1.0.0-rc.2 (#3106) ([51b45e3f](https://github.com/hyperium/hyper/commit/51b45e3f8580da5667a45395e6622455b10e2ad3))\r\n* **client:**\r\n  * remove http2_ prefixes from `client::conn::http2::Builder` methods ([669df217](https://github.com/hyperium/hyper/commit/669df2173e059544fbaded0d666c5bfc113eaa0e))\r\n  * remove http1_ prefixes from `client::conn::http1::Builder` methods ([4cbaef79](https://github.com/hyperium/hyper/commit/4cbaef79f0ec03643c09e4e6fbbed23bf589e548))\r\n  * implement `Clone` for `http2::SendRequest` (#3042) ([00ea49e4](https://github.com/hyperium/hyper/commit/00ea49e47a565748a4e4657f7047dca5851f8b7a), closes [#3036](https://github.com/hyperium/hyper/issues/3036))\r\n  * allow ignoring HTTP/1 invalid header lines in requests ([81e25fa8](https://github.com/hyperium/hyper/commit/81e25fa868c86e4ea81d5a96fdca497a4b1ab3c1))\r\n* **rt:** Clean up Timer trait (#3037) ([8790fee7](https://github.com/hyperium/hyper/commit/8790fee74937016e6b288493bc62c61f7866c310), closes [#3028](https://github.com/hyperium/hyper/issues/3028))\r\n* **server:**\r\n  * remove http1_ method prefixes from `server::conn::http2::Builder` ([291ed0b4](https://github.com/hyperium/hyper/commit/291ed0b49bc7fd6f43890815cdf93aaefaf59011))\r\n  * remove http1_ method prefixes from `server::conn::http2::Builder` ([48e70c69](https://github.com/hyperium/hyper/commit/48e70c691e44d5e37d4b51fe8980f76d27c989b3))\r\n  * remove `server::conn::http2::Builder::with_executor()` (#3089) ([ab59a6f7](https://github.com/hyperium/hyper/commit/ab59a6f7a1e654b1607744320de5f8477de5d6c8), closes [#3087](https://github.com/hyperium/hyper/issues/3087))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* removes `server::conn::http2::Builder::with_executor()`\r\n ([ab59a6f7](https://github.com/hyperium/hyper/commit/ab59a6f7a1e654b1607744320de5f8477de5d6c8))\r\n* The return types of `Timer` have been changed.\r\n ([8790fee7](https://github.com/hyperium/hyper/commit/8790fee74937016e6b288493bc62c61f7866c310))\r\n* The return types for `Frame::into_data()` and `Frame::into_trailers()` have been changed from `Option<T>` to `Result<T, Self>`.\r\n\r\n### v1.0.0-rc.1 (2022-10-25)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http1:**\r\n  * trim obs-folded headers when unfolding (#2926) ([d4b5bd4e](https://github.com/hyperium/hyper/commit/d4b5bd4ee6af0ae8924cf05ab799cc3e19a3c62d))\r\n\r\n\r\n#### Features\r\n\r\n* **body:**\r\n  * rename `Body` struct to `Incoming` (#3022) ([95a153bb](https://github.com/hyperium/hyper/commit/95a153bbc2717bd4233486e09848622ceb900574), closes [#2971](https://github.com/hyperium/hyper/issues/2971))\r\n  * update `HttpBody` trait to use `Frame`s (#3020) ([0888623d](https://github.com/hyperium/hyper/commit/0888623d3764e887706d4e38f82f0fb57c50bd1a), closes [#3010](https://github.com/hyperium/hyper/issues/3010))\r\n  * make body::Sender and Body::channel private (#2970) ([d963e6a9](https://github.com/hyperium/hyper/commit/d963e6a9504575116f63df2485d8480fdb9b6f0b), closes [#2962](https://github.com/hyperium/hyper/issues/2962))\r\n  * remove \"full\" constructors from `Body` (#2958) ([9e8fc8fc](https://github.com/hyperium/hyper/commit/9e8fc8fca195f470a82be5bfb2fd8019c044b97a))\r\n* **client:**\r\n  * remove `client::conn::{SendRequest, Connection}` (#2987) ([8ae73cac](https://github.com/hyperium/hyper/commit/8ae73cac6a8f6a61944505c121158dc312e7b68f))\r\n  * remove `client::connect` module (#2949) ([5e206883](https://github.com/hyperium/hyper/commit/5e206883984fe6de2812861ec363964d92b89b06))\r\n  * remove higher-level `hyper::Client` (#2941) ([bb3af17c](https://github.com/hyperium/hyper/commit/bb3af17ce1a3841e9170adabcce595c7c8743ea7))\r\n  * remove `hyper::client::server` (#2940) ([889fa2d8](https://github.com/hyperium/hyper/commit/889fa2d87252108eb7668b8bf034ffcc30985117))\r\n  * introduce version-specific client modules (#2906) ([509672aa](https://github.com/hyperium/hyper/commit/509672aada0af68a91d963e69828c6e31c44cb7b))\r\n* **ffi:** add http1_allow_multiline_headers (#2918) ([09e35668](https://github.com/hyperium/hyper/commit/09e35668e5b094d679efb4b98ecde9cb6f9f2f93))\r\n* **lib:** remove `stream` cargo feature (#2896) ([ce72f734](https://github.com/hyperium/hyper/commit/ce72f73464d96fd67b59ceff08fd424733b43ffa), closes [#2855](https://github.com/hyperium/hyper/issues/2855))\r\n* **rt:** add Timer trait (#2974) ([fae97ced](https://github.com/hyperium/hyper/commit/fae97ced3a1f71fc46b6eadd3313e19705cc0006))\r\n* **server:**\r\n  * remove `server::conn::{Http, Connection}` types (#3013) ([0766d3f7](https://github.com/hyperium/hyper/commit/0766d3f78d116ea243222cea134cfe7f418e6a3c), closes [#3012](https://github.com/hyperium/hyper/issues/3012))\r\n  * `server::conn::http1` and `server::conn::http2` modules (#3011) ([fc4d3356](https://github.com/hyperium/hyper/commit/fc4d3356cb7f2fffff5af9c474fa34c5adc5d6f1), closes [#2851](https://github.com/hyperium/hyper/issues/2851))\r\n  * remove the high-level Server API (#2932) ([3c7bef3b](https://github.com/hyperium/hyper/commit/3c7bef3b6f6b6c3ec780e5e2db12c9d5795c1b80))\r\n  * remove `AddrStream` struct (#2869) ([e9cab49e](https://github.com/hyperium/hyper/commit/e9cab49e6e18f712b94137966580f6756e32fabb), closes [#2850](https://github.com/hyperium/hyper/issues/2850))\r\n* **service:** create own `Service` trait (#2920) ([fee7d361](https://github.com/hyperium/hyper/commit/fee7d361c28c7eb42ef6bbfae0db14028d24bfee), closes [#2853](https://github.com/hyperium/hyper/issues/2853))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* The polling functions of the `Body` trait have been\r\n  redesigned.\r\n\r\n  The free functions `hyper::body::to_bytes` and `aggregate` have been\r\n  removed. Similar functionality is on\r\n  `http_body_util::BodyExt::collect`.\r\n ([0888623d](https://github.com/hyperium/hyper/commit/0888623d3764e887706d4e38f82f0fb57c50bd1a))\r\n* Either choose a version-specific `Connection` type, or\r\n  look for the auto-version type in `hyper-util`.\r\n ([0766d3f7](https://github.com/hyperium/hyper/commit/0766d3f78d116ea243222cea134cfe7f418e6a3c))\r\n* Pick a version-specific connection, or use the combined\r\n  one in `hyper-util`.\r\n ([8ae73cac](https://github.com/hyperium/hyper/commit/8ae73cac6a8f6a61944505c121158dc312e7b68f))\r\n* Change any manual `impl tower::Service` to implement `hyper::service::Service` instead. The `poll_ready` method has been removed.\r\n ([fee7d361](https://github.com/hyperium/hyper/commit/fee7d361c28c7eb42ef6bbfae0db14028d24bfee))\r\n* The trait has been renamed.\r\n ([031454e5](https://github.com/hyperium/hyper/commit/031454e5e647dda0648424a944dbef795505e2e4))\r\n* A channel body will be available in `hyper-util`.\r\n ([d963e6a9](https://github.com/hyperium/hyper/commit/d963e6a9504575116f63df2485d8480fdb9b6f0b))\r\n* Use the types from `http-body-util`.\r\n ([9e8fc8fc](https://github.com/hyperium/hyper/commit/9e8fc8fca195f470a82be5bfb2fd8019c044b97a))\r\n* Use `connect` from `hyper-util`.\r\n ([5e206883](https://github.com/hyperium/hyper/commit/5e206883984fe6de2812861ec363964d92b89b06))\r\n* A pooling client is in the hyper-util crate.\r\n ([bb3af17c](https://github.com/hyperium/hyper/commit/bb3af17ce1a3841e9170adabcce595c7c8743ea7))\r\n* Tower `Service` utilities will exist in `hyper-util`.\r\n ([889fa2d8](https://github.com/hyperium/hyper/commit/889fa2d87252108eb7668b8bf034ffcc30985117))\r\n\r\n\r\n### v0.14.19 (2022-05-27)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http1:** fix preserving header case without enabling ffi (#2820) ([6a35c175](https://github.com/hyperium/hyper/commit/6a35c175f2b416851518b5831c2c7827d6dbd822))\r\n* **server:** don't add implicit content-length to HEAD responses (#2836) ([67b73138](https://github.com/hyperium/hyper/commit/67b73138f110979f3c77ef7b56588f018837e592))\r\n\r\n\r\n#### Features\r\n\r\n* **server:**\r\n  * add `Connection::http2_max_header_list_size` option (#2828) ([a32658c1](https://github.com/hyperium/hyper/commit/a32658c1ae7f1261fa234a767df963be4fc63521), closes [#2826](https://github.com/hyperium/hyper/issues/2826))\r\n  * add `AddrStream::local_addr()` (#2816) ([ffbf610b](https://github.com/hyperium/hyper/commit/ffbf610b1631cabfacb20886270e3c137fa93800), closes [#2773](https://github.com/hyperium/hyper/issues/2773))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* **ffi (unstable):**\r\n  * `hyper_clientconn_options_new` no longer sets the `http1_preserve_header_case` connection option by default.\r\n    Users should now call `hyper_clientconn_options_set_preserve_header_case` if they desire that functionality. ([78de8914](https://github.com/hyperium/hyper/commit/78de8914eadeab4b9a2c71a82c77b2ce33fe6c74))\r\n\r\n\r\n### v0.14.18 (2022-03-22)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **ffi:** don't build C libraries by default ([1c663706](https://github.com/hyperium/hyper/commit/1c6637060e36654ddb2fdfccb0d146c7ad527476))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** add `HttpInfo::local_addr()` method ([055b4e7e](https://github.com/hyperium/hyper/commit/055b4e7ea6bd22859c20d60776b0c8f20d27498e), closes [#2767](https://github.com/hyperium/hyper/issues/2767))\r\n\r\n\r\n### v0.14.17 (2022-02-10)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** avoid panics in uses of `Instant` (#2746) ([dcdd6d10](https://github.com/hyperium/hyper/commit/dcdd6d109069949ee68ba70ece4a2b4f21079479))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** implement the HTTP/2 extended CONNECT protocol from RFC 8441 (#2682) ([5ec094ca](https://github.com/hyperium/hyper/commit/5ec094caa5c999e6f919a2bc82f5f3b7d40c2d8a))\r\n* **error:** add `Error::message` (#2737) ([6932896a](https://github.com/hyperium/hyper/commit/6932896a7fca58fe461269461f925da8fd4e8d8a), closes [#2732](https://github.com/hyperium/hyper/issues/2732))\r\n* **http1:** implement obsolete line folding (#2734) ([1f0c177b](https://github.com/hyperium/hyper/commit/1f0c177b35b14054eb1e5108e75f8bd3ff52813e))\r\n\r\n\r\n### v0.14.16 (2021-12-09)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http1:** return 414 when URI contains more than 65534 characters (#2706) ([5f938fff](https://github.com/hyperium/hyper/commit/5f938fffa64df23a2e4af81ed4e6d8bd760e2d05), closes [#2701](https://github.com/hyperium/hyper/issues/2701))\r\n* **http2:** received `Body::size_hint()` now return 0 if implicitly empty (#2715) ([84b78b6c](https://github.com/hyperium/hyper/commit/84b78b6c877ff9aaa28d1e348a5deb63a9282503))\r\n* **server:** use case-insensitive comparison for Expect: 100-continue (#2709) ([7435cc33](https://github.com/hyperium/hyper/commit/7435cc3399895643062f4e399fae6d5b20b049a1), closes [#2708](https://github.com/hyperium/hyper/issues/2708))\r\n\r\n\r\n#### Features\r\n\r\n* **http2:** add `http2_max_send_buf_size` option to client and server ([bff977b7](https://github.com/hyperium/hyper/commit/bff977b73ca8d737f5492c86c09fd64735c45461))\r\n* **server:** add HTTP/1 header read timeout option (#2675) ([842c6553](https://github.com/hyperium/hyper/commit/842c6553a5414a3a4a0fbf973079200612a9c3d2), closes [#2457](https://github.com/hyperium/hyper/issues/2457))\r\n\r\n\r\n### v0.14.15 (2021-11-16)\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** cancel blocking DNS lookup if `GaiFuture` is dropped ([174b553d](https://github.com/hyperium/hyper/commit/174b553d)\r\n\r\n#### Features\r\n\r\n* **http1:** add `http1_writev(bool)` options to Client and Server builders, to allow forcing vectored writes ([80627141](https://github.com/hyperium/hyper/commit/80627141))\r\n* **upgrade:** allow http upgrades with any body type ([ab469eb3](https://github.com/hyperium/hyper/commit/ab469eb3c6cd5e7a035d734f3d21ff4d2d6a21ab))\r\n\r\n\r\n### v0.14.14 (2021-10-22)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:**\r\n  * make ResponseFuture implement Sync ([bd6c35b9](https://github.com/hyperium/hyper/commit/bd6c35b98f9513f14ed9cecad933bc7fdb8635ea))\r\n  * remove ipv6 square brackets before resolving ([910e0268](https://github.com/hyperium/hyper/commit/910e02687df3245aae4bc519fb0bd7eb6a34db7d))\r\n\r\n\r\n#### Features\r\n\r\n* **h2:** always include original h2 error on broken pipe ([6169db25](https://github.com/hyperium/hyper/commit/6169db250c932dd012d391389826cd34833077b4))\r\n* **server:** Remove Send + Sync requirement for Body in with_graceful_shutdown ([1d553e52](https://github.com/hyperium/hyper/commit/1d553e52c6953ea3b039f5c3f89d35cb56e2436a))\r\n\r\n\r\n### v0.14.13 (2021-09-16)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** don't reuse a connection while still flushing ([c88011da](https://github.com/hyperium/hyper/commit/c88011da4ed5b5ca9107c4a2339a7ab054c5f27f))\r\n* **server:** convert panic to error if Connection::without_shutdown called on HTTP/2 conn ([ea3e2282](https://github.com/hyperium/hyper/commit/ea3e228287e714b97aa44c840a487abd3a915e15))\r\n\r\n\r\n#### Features\r\n\r\n* **ffi:** add hyper_request_set_uri_parts ([a54689b9](https://github.com/hyperium/hyper/commit/a54689b921ca16dd0f29b3f4a74feae60218db34))\r\n* **lib:**\r\n  * Export more things with Cargo features (server, !http1, !http2) ([0a4b56ac](https://github.com/hyperium/hyper/commit/0a4b56acb82ef41a3336f482b240c67c784c434f))\r\n  * Export rt module independently of Cargo features ([cf6f62c7](https://github.com/hyperium/hyper/commit/cf6f62c71eda3b3a8732d86387e4ed8711cf9a86))\r\n\r\n\r\n### v0.14.12 (2021-08-24)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **ffi:** on_informational callback had no headers ([39b6d01a](https://github.com/hyperium/hyper/commit/39b6d01aa0e520077bb25e16811f5ece00a224d6))\r\n* **http1:** apply header title case for consecutive dashes (#2613) ([684f2fa7](https://github.com/hyperium/hyper/commit/684f2fa76d44fa2b1b063ad0443a1b0d16dfad0e))\r\n* **http2:** improve errors emitted by HTTP2 `Upgraded` stream shutdown (#2622) ([be08648e](https://github.com/hyperium/hyper/commit/be08648e8298cdb13e9879ee761a73f827268962))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** expose http09 and http1 options on `client::conn::Builder` (#2611) ([73bff4e9](https://github.com/hyperium/hyper/commit/73bff4e98c372ce04b006370c0b0d2af29ea8718), closes [#2461](https://github.com/hyperium/hyper/issues/2461))\r\n\r\n\r\n### v0.14.11 (2021-07-21)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** retry when pool checkout returns closed HTTP2 connection (#2585) ([52214f39](https://github.com/hyperium/hyper/commit/52214f391c0a18dc66d1ccff9c0c004c5da85002))\r\n* **http2:**\r\n  * improve I/O errors emitted by H2Upgraded (#2598) ([f51c677d](https://github.com/hyperium/hyper/commit/f51c677dec9debf60cb336dc938bae103adf17a0))\r\n  * preserve `proxy-authenticate` and `proxy-authorization` headers (#2597) ([52435701](https://github.com/hyperium/hyper/commit/5243570137ae49628cb387fff5611eea0add33bf))\r\n\r\n\r\n#### Features\r\n\r\n* **ffi:** add hyper_request_on_informational ([25d18c0b](https://github.com/hyperium/hyper/commit/25d18c0b74ccf9e51f986daa3b2b98c0109f827a))\r\n\r\n\r\n### v0.14.10 (2021-07-07)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http1:**\r\n  * reject content-lengths that have a plus sign prefix ([06335158](https://github.com/hyperium/hyper/commit/06335158ca48724db9bf074398067d2db08613e7))\r\n  * protect against overflow in chunked decoder ([efd9a982](https://github.com/hyperium/hyper/commit/efd9a9821fd2f1ae04b545094de76a435b62e70f))\r\n\r\n\r\n#### Features\r\n\r\n* **ffi:** add option to get raw headers from response ([8c89a8c1](https://github.com/hyperium/hyper/commit/8c89a8c1665b6fbec3f13b8c0e84c79464179c89))\r\n\r\n\r\n### v0.14.9 (2021-06-07)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http1:** reduce memory used with flatten write strategy ([eb0c6463](https://github.com/hyperium/hyper/commit/eb0c64639503bbd4f6e3b1ce3a02bff8eeea7ee8))\r\n\r\n\r\n### v0.14.8 (2021-05-25)\r\n\r\n\r\n#### Features\r\n\r\n* **client:** allow to config http2 max concurrent reset streams (#2535) ([b9916c41](https://github.com/hyperium/hyper/commit/b9916c410182c6225e857f0cded355ea1b74c865))\r\n* **error:** add `Error::is_parse_too_large` and `Error::is_parse_status` methods (#2538) ([960a69a5](https://github.com/hyperium/hyper/commit/960a69a5878ede82c56f50ac1444a9e75e885a8f))\r\n* **http2:**\r\n  * Implement Client and Server CONNECT support over HTTP/2 (#2523) ([5442b6fa](https://github.com/hyperium/hyper/commit/5442b6faddaff9aeb7c073031a3b7aa4497fda4d), closes [#2508](https://github.com/hyperium/hyper/issues/2508))\r\n  * allow HTTP/2 requests by ALPN when http2_only is unset (#2527) ([be9677a1](https://github.com/hyperium/hyper/commit/be9677a1e782d33c4402772e0fc4ef0a4c49d507))\r\n\r\n\r\n#### Performance\r\n\r\n* **http2:** reduce amount of adaptive window pings as BDP stabilizes (#2550) ([4cd06bf2](https://github.com/hyperium/hyper/commit/4cd06bf2))\r\n\r\n\r\n### v0.14.7 (2021-04-22)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http1:** http1_title_case_headers should move Builder ([a303b3c3](https://github.com/hyperium/hyper/commit/a303b3c329e6b8ecfa1da0b9b9e94736628167e0))\r\n\r\n\r\n#### Features\r\n\r\n* **server:** implement forgotten settings for case preserving ([4fd6c4cb](https://github.com/hyperium/hyper/commit/4fd6c4cb0b58bb0831ae0f876d858aba1588d0e3))\r\n\r\n\r\n### v0.14.6 (2021-04-21)\r\n\r\n\r\n#### Features\r\n\r\n* **client:** add option to allow misplaced spaces in HTTP/1 responses (#2506) ([11345394](https://github.com/hyperium/hyper/commit/11345394d968d4817e1a0ee2550228ac0ae7ce74))\r\n* **http1:** add options to preserve header casing (#2480) ([dbea7716](https://github.com/hyperium/hyper/commit/dbea7716f157896bf7d2d417be7b4e382e7dc34f), closes [#2313](https://github.com/hyperium/hyper/issues/2313))\r\n\r\n\r\n### v0.14.5 (2021-03-26)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** omit default port from automatic Host headers (#2441) ([0b11eee9](https://github.com/hyperium/hyper/commit/0b11eee9bde421cdc1680cadabfd38c5aff8e62f))\r\n* **headers:** Support multiple Content-Length values on same line (#2471) ([48fdaf16](https://github.com/hyperium/hyper/commit/48fdaf160689f333e9bb63388d0b1d0fa29a1391), closes [#2470](https://github.com/hyperium/hyper/issues/2470))\r\n* **server:** skip automatic Content-Length headers when not allowed (#2216) ([8cbf9527](https://github.com/hyperium/hyper/commit/8cbf9527dfb313b3f84fcd83260c5c72ce4a1beb), closes [#2215](https://github.com/hyperium/hyper/issues/2215))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** allow HTTP/0.9 responses behind a flag (#2473) ([68d4e4a3](https://github.com/hyperium/hyper/commit/68d4e4a3db91fb43f41a8c4fce1175ddb56816af), closes [#2468](https://github.com/hyperium/hyper/issues/2468))\r\n* **server:** add `AddrIncoming::from_listener` constructor (#2439) ([4c946af4](https://github.com/hyperium/hyper/commit/4c946af49cc7fbbc6bd4894283a654625c2ea383))\r\n\r\n\r\n### v0.14.4 (2021-02-05)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **build**: Fix compile error when only `http1` feature was enabled.\r\n\r\n\r\n### v0.14.3 (2021-02-05)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** HTTP/1 client \"Transfer-Encoding\" repair code would panic (#2410) ([2c8121f1](https://github.com/hyperium/hyper/commit/2c8121f1735aa8efeb0d5e4ef595363c373ba470), closes [#2409](https://github.com/hyperium/hyper/issues/2409))\r\n* **http1:** fix server misinterpreting multiple Transfer-Encoding headers ([8f93123e](https://github.com/hyperium/hyper/commit/8f93123efef5c1361086688fe4f34c83c89cec02))\r\n\r\n\r\n#### Features\r\n\r\n* **body:**\r\n  * reexport `hyper::body::SizeHint` (#2404) ([9956587f](https://github.com/hyperium/hyper/commit/9956587f83428a5dbe338ba0b55c1dc0bce8c282))\r\n  * add `send_trailers` to Body channel's `Sender` (#2387) ([bf8d74ad](https://github.com/hyperium/hyper/commit/bf8d74ad1cf7d0b33b470b1e61625ebac56f9c4c), closes [#2260](https://github.com/hyperium/hyper/issues/2260))\r\n* **ffi:**\r\n  * add HYPERE_INVALID_PEER_MESSAGE error code for parse errors ([1928682b](https://github.com/hyperium/hyper/commit/1928682b33f98244435ba6d574677546205a15ec))\r\n  * Initial C API for hyper ([3ae1581a](https://github.com/hyperium/hyper/commit/3ae1581a539b67363bd87d9d8fc8635a204eec5d))\r\n\r\n\r\n### v0.14.2 (2020-12-29)\r\n\r\n\r\n#### Features\r\n\r\n* **client:** expose `connect` types without proto feature (#2377) ([73a59e5f](https://github.com/hyperium/hyper/commit/73a59e5fc7ddedcb7cbd91e97b33385fde57aa10))\r\n* **server:** expose `Accept` without httpX features (#2382) ([a6d4fcbe](https://github.com/hyperium/hyper/commit/a6d4fcbee65bebf461291def75f4c512ec62a664))\r\n\r\n\r\n### v0.14.1 (2020-12-23)\r\n\r\n* Fixes building documentation.\r\n\r\n\r\n## v0.14.0 (2020-12-23)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** log socket option errors instead of returning error (#2361) ([dad5c879](https://github.com/hyperium/hyper/commit/dad5c8792fec7b586b41b5237bc161d8f0c09f72), closes [#2359](https://github.com/hyperium/hyper/issues/2359))\r\n* **http1:**\r\n  * ignore chunked trailers (#2357) ([1dd761c8](https://github.com/hyperium/hyper/commit/1dd761c87de226261599ff2518fe9d231ba1c82d), closes [#2171](https://github.com/hyperium/hyper/issues/2171))\r\n  * ending close-delimited body should close (#2322) ([71f34024](https://github.com/hyperium/hyper/commit/71f340242120f1ea52c7446b4bae37b894b83912))\r\n\r\n\r\n#### Features\r\n\r\n* **client:**\r\n  * change DNS Resolver to resolve to SocketAddrs (#2346) ([b4e24332](https://github.com/hyperium/hyper/commit/b4e24332a0cd44068a806081d51686f50c086056), closes [#1937](https://github.com/hyperium/hyper/issues/1937))\r\n  * Make `client` an optional feature ([4e55583d](https://github.com/hyperium/hyper/commit/4e55583d30a597884883f1a51b678f5c57c76765))\r\n* **http1:** Make HTTP/1 support an optional feature ([2a19ab74](https://github.com/hyperium/hyper/commit/2a19ab74ed69bc776da25544e98979c9fb6e1834))\r\n* **http2:** Make HTTP/2 support an optional feature ([b819b428](https://github.com/hyperium/hyper/commit/b819b428d314f2203642a015545967601b8e518a))\r\n* **lib:**\r\n  * Upgrade to Tokio 1.0, Bytes 1.0, http-body 0.4 (#2369) ([fad42acc](https://github.com/hyperium/hyper/commit/fad42acc79b54ce38adf99c58c894f29fa2665ad), closes [#2370](https://github.com/hyperium/hyper/issues/2370))\r\n  * remove dependency on `tracing`'s `log` feature (#2342) ([db32e105](https://github.com/hyperium/hyper/commit/db32e1050cf1eae63af0365c97e920f1295b6bea), closes [#2326](https://github.com/hyperium/hyper/issues/2326))\r\n  * disable all optional features by default (#2336) ([ed2b22a7](https://github.com/hyperium/hyper/commit/ed2b22a7f66899d338691552fbcb6c0f2f4e06b9))\r\n* **server:** Make the `server` code an optional feature (#2334) ([bdb5e5d6](https://github.com/hyperium/hyper/commit/bdb5e5d6946f4e3f8115a6b1683aff6a04df73de))\r\n* **upgrade:** Moved HTTP upgrades off `Body` to a new API (#2337) ([121c3313](https://github.com/hyperium/hyper/commit/121c33132c0950aaa422848cdc43f6691ddf5785), closes [#2086](https://github.com/hyperium/hyper/issues/2086))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* hyper depends on `tokio` v1 and `bytes` v1.\r\n* Custom resolvers used with `HttpConnector` must change\r\n  to resolving to an iterator of `SocketAddr`s instead of `IpAddr`s.\r\n ([b4e24332](https://github.com/hyperium/hyper/commit/b4e24332a0cd44068a806081d51686f50c086056))\r\n* hyper no longer emits `log` records automatically.\r\n  If you need hyper to integrate with a `log` logger (as opposed to `tracing`),\r\n  you can add `tracing = { version = \"0.1\", features = [\"log\"] }` to activate them.\r\n ([db32e105](https://github.com/hyperium/hyper/commit/db32e1050cf1eae63af0365c97e920f1295b6bea))\r\n* Removed `http1_writev` methods from `client::Builder`,\r\n  `client::conn::Builder`, `server::Builder`, and `server::conn::Builder`.\r\n  \r\n  Vectored writes are now enabled based on whether the `AsyncWrite`\r\n  implementation in use supports them, rather than though adaptive\r\n  detection. To explicitly disable vectored writes, users may wrap the IO\r\n  in a newtype that implements `AsyncRead` and `AsyncWrite` and returns\r\n  `false` from its `AsyncWrite::is_write_vectored` method.\r\n ([d6aadb83](https://github.com/hyperium/hyper/commit/d6aadb830072959497f414c01bcdba4c8e681088))\r\n* The method `Body::on_upgrade()` is gone. It is\r\n  essentially replaced with `hyper::upgrade::on(msg)`.\r\n ([121c3313](https://github.com/hyperium/hyper/commit/121c33132c0950aaa422848cdc43f6691ddf5785))\r\n* All optional features have been disabled by default.\r\n ([ed2b22a7](https://github.com/hyperium/hyper/commit/ed2b22a7f66899d338691552fbcb6c0f2f4e06b9))\r\n* The HTTP server code is now an optional feature. To\r\n  enable the server, add `features = [\"server\"]` to the dependency in\r\n  your `Cargo.toml`.\r\n ([bdb5e5d6](https://github.com/hyperium/hyper/commit/bdb5e5d6946f4e3f8115a6b1683aff6a04df73de))\r\n* The HTTP client of hyper is now an optional feature. To\r\n  enable the client, add `features = [\"client\"]` to the dependency in\r\n  your `Cargo.toml`.\r\n ([4e55583d](https://github.com/hyperium/hyper/commit/4e55583d30a597884883f1a51b678f5c57c76765))\r\n* This puts all HTTP/1 methods and support behind an\r\n  `http1` cargo feature, which will not be enabled by default. To use\r\n  HTTP/1, add `features = [\"http1\"]` to the hyper dependency in your\r\n  `Cargo.toml`.\r\n\r\n ([2a19ab74](https://github.com/hyperium/hyper/commit/2a19ab74ed69bc776da25544e98979c9fb6e1834))\r\n* This puts all HTTP/2 methods and support behind an\r\n  `http2` cargo feature, which will not be enabled by default. To use\r\n  HTTP/2, add `features = [\"http2\"]` to the hyper dependency in your\r\n  `Cargo.toml`.\r\n\r\n ([b819b428](https://github.com/hyperium/hyper/commit/b819b428d314f2203642a015545967601b8e518a))\r\n\r\n\r\n### v0.13.9 (2020-11-02)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** fix panic when addrs in ConnectingTcpRemote is empty (#2292) ([01103da5](https://github.com/hyperium/hyper/commit/01103da5d9b15e2a7fdc2f1dfec2c23a890d5c16), closes [#2291](https://github.com/hyperium/hyper/issues/2291))\r\n* **http2:** reschedule keep alive interval timer once a pong is received ([2a938d96](https://github.com/hyperium/hyper/commit/2a938d96aec62603dcb548834676ae2c71ae8be2), closes [#2310](https://github.com/hyperium/hyper/issues/2310))\r\n\r\n\r\n#### Features\r\n\r\n* **client:**\r\n  * add `HttpConnector::set_local_addresses` to set both IPv6 and IPv4 local addrs ( ([fb19f3a8](https://github.com/hyperium/hyper/commit/fb19f3a86997af1c8a31a7d5ce6f2b018c9b5a0d))\r\n  * Add accessors to `Connected` fields (#2290) ([2dc9768d](https://github.com/hyperium/hyper/commit/2dc9768d2d3884afa20c08b7cd8782c870d925d2))\r\n\r\n\r\n### v0.13.8 (2020-09-18)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http1:** return error if user body ends prematurely ([1ecbcbb1](https://github.com/hyperium/hyper/commit/1ecbcbb119e221f60d37b934b81d18493ebded1b), closes [#2263](https://github.com/hyperium/hyper/issues/2263))\r\n\r\n\r\n#### Features\r\n\r\n* **lib:** Setting `http1_writev(true)` will now force writev queue usage ([187c22af](https://github.com/hyperium/hyper/commit/187c22afb5a13d4fa9a3b938a1d71b11b337ac97), closes [#2282](https://github.com/hyperium/hyper/issues/2282))\r\n* **server:** implement `AsRawFd` for `AddrStream` (#2246) ([b5d5e214](https://github.com/hyperium/hyper/commit/b5d5e21449eb613a3c92dcced6f38d227e405594), closes [#2245](https://github.com/hyperium/hyper/issues/2245))\r\n\r\n\r\n### v0.13.7 (2020-07-13)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** don't panic in DNS resolution when task cancelled (#2229) ([0d0d3635](https://github.com/hyperium/hyper/commit/0d0d3635476ba22e5a2b39b0e4b243f57f1f36d2))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** impl tower_service::Service for &Client (#2089) ([77c3b5bc](https://github.com/hyperium/hyper/commit/77c3b5bc0c0d58ecd9f3c004287f65b8a94cc429))\r\n* **http2:** configure HTTP/2 frame size in the high-level builders too (#2214) ([2354a7ee](https://github.com/hyperium/hyper/commit/2354a7eec352b1f72cd8989d29d73dff211403a1))\r\n* **lib:** Move from `log` to `tracing` in a backwards-compatible way (#2204) ([9832aef9](https://github.com/hyperium/hyper/commit/9832aef9eeaeff8979354d5de04b8706ff79a233))\r\n\r\n\r\n### v0.13.6 (2020-05-29)\r\n\r\n\r\n#### Features\r\n\r\n* **body:** remove Sync bound for Body::wrap_stream ([042c7706](https://github.com/hyperium/hyper/commit/042c770603a212f22387807efe4fc672959df40c))\r\n* **http2:** allow configuring the HTTP/2 frame size ([b6446456](https://github.com/hyperium/hyper/commit/b64464562a02a642a3cf16ea072f39621da21980))\r\n\r\n\r\n### v0.13.5 (2020-04-17)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **server:** fix panic in Connection::graceful_shutdown ([fce3ddce](https://github.com/hyperium/hyper/commit/fce3ddce4671e7df439a9d8fdc469b079fc07318))\r\n\r\n\r\n### v0.13.4 (2020-03-20)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http1:** try to drain connection buffer if user drops Body ([d838d54f](https://github.com/hyperium/hyper/commit/d838d54fdf0fc4a613612f68274f3520f333dd8e))\r\n\r\n\r\n#### Features\r\n\r\n* **http2:** add HTTP2 keep-alive support for client and server ([9a8413d9](https://github.com/hyperium/hyper/commit/9a8413d91081ad5a949276f05337e984c455e251))\r\n\r\n\r\n### v0.13.3 (2020-03-03)\r\n\r\n\r\n#### Features\r\n\r\n* **client:** rename `client::Builder` pool options (#2142) ([a82fd6c9](https://github.com/hyperium/hyper/commit/a82fd6c94aa4ce11fe685f9ccfb85c596d596c6e))\r\n* **http2:** add adaptive window size support using BDP (#2138) ([48102d61](https://github.com/hyperium/hyper/commit/48102d61228b592b466af273a81207e729315681))\r\n* **server:** add `poll_peek` to `AddrStream` (#2127) ([24d53d3f](https://github.com/hyperium/hyper/commit/24d53d3f66f843a6c19204cc7c52cd80e327d41a))\r\n\r\n\r\n### v0.13.2 (2020-01-29)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **body:** return exactly 0 SizeHint for empty body (#2122) ([dc882047](https://github.com/hyperium/hyper/commit/dc88204716664d12e20598c78cb87cd44c6f23af))\r\n* **client:** strip path from Uri before calling Connector (#2109) ([ba2a144f](https://github.com/hyperium/hyper/commit/ba2a144f8b81042247088215425f91760d8694a1))\r\n* **http1:**\r\n  * only send `100 Continue` if request body is polled ([c4bb4db5](https://github.com/hyperium/hyper/commit/c4bb4db5c219459b37d796f9aa2b3cdc93325621))\r\n  * remove panic for HTTP upgrades that have been ignored (#2115) ([1881db63](https://github.com/hyperium/hyper/commit/1881db6391acc949384f8ddfcac8c82a2b133c8d), closes [#2114](https://github.com/hyperium/hyper/issues/2114))\r\n* **http2:** don't add client content-length if method doesn't require it ([fb90d30c](https://github.com/hyperium/hyper/commit/fb90d30c02d8f7cdc9a643597d5c4ca7a123f3dd))\r\n\r\n\r\n#### Features\r\n\r\n* **service:** Implement Clone/Copy on ServiceFn and MakeServiceFn (#2104) ([a5720fab](https://github.com/hyperium/hyper/commit/a5720fab4ced447b8ade43cc1ce8b35442ebf234))\r\n\r\n\r\n### v0.13.1 (2019-12-13)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http1:** fix response with non-chunked transfer-encoding to be close-delimited ([cb71d2cd](https://github.com/hyperium/hyper/commit/cb71d2cdbd22e538663e724916dc343430efcf29), closes [#2058](https://github.com/hyperium/hyper/issues/2058))\r\n\r\n\r\n#### Features\r\n\r\n* **body:** implement `HttpBody` for `Request` and `Response` ([4b6099c7](https://github.com/hyperium/hyper/commit/4b6099c7aa558e6b1fda146ce6179cb0c67858d7), closes [#2067](https://github.com/hyperium/hyper/issues/2067))\r\n* **client:** expose `hyper::client::connect::Connect` trait alias ([2553ea1a](https://github.com/hyperium/hyper/commit/2553ea1a7ae3d11f0232a5818949146fa3f68a29))\r\n\r\n\r\n## v0.13.0 (2019-12-10)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:**\r\n  * fix polling dispatch channel after it has closed ([039281b8](https://github.com/hyperium/hyper/commit/039281b89cf1ab54a0ecc10c5e7fee56d4da0cf4))\r\n  * fix panic from unreachable code ([e6027bc0](https://github.com/hyperium/hyper/commit/e6027bc02db92d1137c54a26eef2e1cb4d810e25))\r\n* **dependencies:** require correct bytes minimum version (#1975) ([536b1e18](https://github.com/hyperium/hyper/commit/536b1e184e9704f50716cf10bf9d4e11a79337da))\r\n* **server:**\r\n  * change `Builder` window size methods to be by-value ([a22dabd0](https://github.com/hyperium/hyper/commit/a22dabd0935e5471fb6b7e511fc9c585ced0a53a), closes [#1814](https://github.com/hyperium/hyper/issues/1814))\r\n  * ignore expect-continue with no body in debug mode ([ca5836f1](https://github.com/hyperium/hyper/commit/ca5836f1ece7c4a67172bcbe72745cb49e8951b0), closes [#1843](https://github.com/hyperium/hyper/issues/1843))\r\n  * Remove unneeded `'static` bound of `Service` on `Connection` (#1971) ([4d147126](https://github.com/hyperium/hyper/commit/4d14712643e4c2ba235a569bb5d9e3099101c1a1))\r\n\r\n\r\n#### Features\r\n\r\n* **body:**\r\n  * change `Sender::send_data` to an `async fn`. ([62a96c07](https://github.com/hyperium/hyper/commit/62a96c077b85792fbf6eb080ec8fec646c47e385))\r\n  * require `Sync` when wrapping a dynamic `Stream` ([44413721](https://github.com/hyperium/hyper/commit/4441372121e8b278ac773ddd4e408a642dadf2d8))\r\n  * add `body::aggregate` and `body::to_bytes` functions ([8ba9a8d2](https://github.com/hyperium/hyper/commit/8ba9a8d2c4bab0f44b3f94a326b3b91c82d7877e))\r\n  * replace `Chunk` type with `Bytes` ([5a598757](https://github.com/hyperium/hyper/commit/5a59875742500672f253719c1e1a16b4eddfacc7), closes [#1931](https://github.com/hyperium/hyper/issues/1931))\r\n  * replace the `Payload` trait with `HttpBody` ([c63728eb](https://github.com/hyperium/hyper/commit/c63728eb38182ad2f93edd729dbf50f3d5c40479))\r\n* **client:**\r\n  * impl tower_service::Service for Client ([edbd10ac](https://github.com/hyperium/hyper/commit/edbd10ac96c5cc6dbeca80ada80f143dbd13d118))\r\n  * provide tower::Service support for clients (#1915) ([eee2a728](https://github.com/hyperium/hyper/commit/eee2a728797346f8c96c15c5958a05432a4e4453))\r\n  * change connectors to return an `impl Connection` ([4d7a2266](https://github.com/hyperium/hyper/commit/4d7a2266b88b2c5c92231bcd2bd75d5842198add))\r\n  * remove `Destination` for `http::Uri` in connectors ([319e8aee](https://github.com/hyperium/hyper/commit/319e8aee1571d8d3639b3259e7a1edb964e6a26c))\r\n  * filter remote IP addresses by family of given local IP address ([131962c8](https://github.com/hyperium/hyper/commit/131962c86ab0a31c2413261cf4532eca88d67dcb))\r\n  * change `Resolve` to be `Service<Name>` ([9d9233ce](https://github.com/hyperium/hyper/commit/9d9233ce7ceddb0fa6f5e725b0a781929add3c58), closes [#1903](https://github.com/hyperium/hyper/issues/1903))\r\n  * change `Connect` trait into an alias for `Service` ([d67e49f1](https://github.com/hyperium/hyper/commit/d67e49f1491327a78f804bab32804dc6c73d2974), closes [#1902](https://github.com/hyperium/hyper/issues/1902))\r\n  * change `GaiResolver` to use a global blocking threadpool ([049b5132](https://github.com/hyperium/hyper/commit/049b5132dbb6199a32e1795d005003f99d0e0b74))\r\n  * Add connect timeout to HttpConnector (#1972) ([4179297a](https://github.com/hyperium/hyper/commit/4179297ac9805af8f84d54525e089ff3f19008ab))\r\n* **lib:**\r\n  * update to `std::future::Future` ([8f4b05ae](https://github.com/hyperium/hyper/commit/8f4b05ae78567dfc52236bc83d7be7b7fc3eebb0))\r\n  * add optional `tcp` feature, split from `runtime` ([5b348b82](https://github.com/hyperium/hyper/commit/5b348b821c3f43d8dd71179862190932fcca6a1c))\r\n  * make `Stream` trait usage optional behind the `stream` feature, enabled by default ([0b03b730](https://github.com/hyperium/hyper/commit/0b03b730531654b1b5f632099386ab27c94eb9f4), closes [#2034](https://github.com/hyperium/hyper/issues/2034))\r\n  * update Tokio, bytes, http, h2, and http-body ([cb3f39c2](https://github.com/hyperium/hyper/commit/cb3f39c2dc6340060f6b17f354f04c872a947574))\r\n* **rt:** introduce `rt::Executor` trait ([6ae5889f](https://github.com/hyperium/hyper/commit/6ae5889f8378b6454d4dc620f33bd1678d0e00e4), closes [#1944](https://github.com/hyperium/hyper/issues/1944))\r\n* **server:**\r\n  * introduce `Accept` trait ([b3e55062](https://github.com/hyperium/hyper/commit/b3e5506261c33dcaca39a126e891a0b9d5df5eea))\r\n  * give `Server::local_addr` a more general type ([3cc93e79](https://github.com/hyperium/hyper/commit/3cc93e796aad59b3996fc26b8839a783e0307925))\r\n  * change `http1_half_close` option default to disabled ([7e31fd88](https://github.com/hyperium/hyper/commit/7e31fd88a86ac032d05670ba4e293e3e5fcccbaf))\r\n* **service:**\r\n    * use tower_service::Service for hyper::service ([ec520d56](https://github.com/hyperium/hyper/commit/ec520d5602d819fd92f497cc230df436c1a39eb0))\r\n  * rename `Service` to `HttpService`, re-export `tower::Service` ([4f274399](https://github.com/hyperium/hyper/commit/4f2743991c227836c3886778512afe1297df3e5b), closes [#1959](https://github.com/hyperium/hyper/issues/1959))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* All usage of async traits (`Future`, `Stream`,\r\n`AsyncRead`, `AsyncWrite`, etc) are updated to newer versions.\r\n\r\n ([8f4b05ae](https://github.com/hyperium/hyper/commit/8f4b05ae78567dfc52236bc83d7be7b7fc3eebb0))\r\n* All usage of `hyper::Chunk` should be replaced with\r\n  `bytes::Bytes` (or `hyper::body::Bytes`).\r\n\r\n ([5a598757](https://github.com/hyperium/hyper/commit/5a59875742500672f253719c1e1a16b4eddfacc7))\r\n* Using a `Body` as a `Stream`, and constructing one via\r\n  `Body::wrap_stream`, require enabling the `stream` feature.\r\n\r\n ([511ea388](https://github.com/hyperium/hyper/commit/511ea3889b5cceccb3a42aa72465fe38adef71a4))\r\n* Calls to `GaiResolver::new` and `HttpConnector::new` no\r\n  longer should pass an integer argument for the number of threads.\r\n\r\n ([049b5132](https://github.com/hyperium/hyper/commit/049b5132dbb6199a32e1795d005003f99d0e0b74))\r\n* Connectors no longer return a tuple of\r\n  `(T, Connected)`, but a single `T: Connection`.\r\n\r\n ([4d7a2266](https://github.com/hyperium/hyper/commit/4d7a2266b88b2c5c92231bcd2bd75d5842198add))\r\n* All usage of `hyper::client::connect::Destination`\r\n  should be replaced with `http::Uri`.\r\n\r\n ([319e8aee](https://github.com/hyperium/hyper/commit/319e8aee1571d8d3639b3259e7a1edb964e6a26c))\r\n* All usage of `hyper::body::Payload` should be replaced\r\n  with `hyper::body::HttpBody`.\r\n\r\n ([c63728eb](https://github.com/hyperium/hyper/commit/c63728eb38182ad2f93edd729dbf50f3d5c40479))\r\n* Any type passed to the `executor` builder methods must\r\n  now implement `hyper::rt::Executor`.\r\n\r\n  `hyper::rt::spawn` usage should be replaced with `tokio::task::spawn`.\r\n\r\n  `hyper::rt::run` usage should be replaced with `#[tokio::main]` or\r\n  managing a `tokio::runtime::Runtime` manually.\r\n\r\n ([6ae5889f](https://github.com/hyperium/hyper/commit/6ae5889f8378b6454d4dc620f33bd1678d0e00e4))\r\n* The `Resolve` trait is gone. All custom resolvers should\r\n  implement `tower::Service` instead.\r\n\r\n  The error type of `HttpConnector` has been changed away from\r\n  `std::io::Error`.\r\n\r\n ([9d9233ce](https://github.com/hyperium/hyper/commit/9d9233ce7ceddb0fa6f5e725b0a781929add3c58))\r\n* Any manual implementations of `Connect` must instead\r\n  implement `tower::Service<Uri>`.\r\n\r\n ([d67e49f1](https://github.com/hyperium/hyper/commit/d67e49f1491327a78f804bab32804dc6c73d2974))\r\n* The server's behavior will now by default close\r\n  connections when receiving a read EOF. To allow for clients to close\r\n  the read half, call `http1_half_close(true)` when configuring a\r\n  server.\r\n\r\n ([7e31fd88](https://github.com/hyperium/hyper/commit/7e31fd88a86ac032d05670ba4e293e3e5fcccbaf))\r\n* Passing a `Stream` to `Server::builder` or\r\n  `Http::serve_incoming` must be changed to pass an `Accept` instead. The\r\n  `stream` optional feature can be enabled, and then a stream can be\r\n  converted using `hyper::server::accept::from_stream`.\r\n\r\n ([b3e55062](https://github.com/hyperium/hyper/commit/b3e5506261c33dcaca39a126e891a0b9d5df5eea))\r\n* Usage of `send_data` should either be changed to\r\n  async/await or use `try_send_data`.\r\n\r\n ([62a96c07](https://github.com/hyperium/hyper/commit/62a96c077b85792fbf6eb080ec8fec646c47e385))\r\n\r\n\r\n### v0.12.35 (2019-09-13)\r\n\r\n\r\n#### Features\r\n\r\n* **body:** identify aborted body write errors ([32869224](https://github.com/hyperium/hyper/commit/3286922460ab63d0a804d8170d862ff4ba5951dd))\r\n\r\n\r\n### v0.12.34 (2019-09-04)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** allow client GET requests with explicit body headers ([23fc8b08](https://github.com/hyperium/hyper/commit/23fc8b0806e7fde435ca00479cd5e3c8c5bdeee7), closes [#1925](https://github.com/hyperium/hyper/issues/1925))\r\n\r\n\r\n### v0.12.33 (2019-09-04)\r\n\r\n\r\n### v0.12.32 (2019-07-08)\r\n\r\n\r\n#### Features\r\n\r\n* **client:** `HttpConnector`: allow to set socket buffer sizes ([386109c4](https://github.com/hyperium/hyper/commit/386109c421c21e6e2d70e76d7dd072ef3bb62c58))\r\n\r\n\r\n### v0.12.31 (2019-06-25)\r\n\r\n\r\n### v0.12.30 (2019-06-14)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http1:** force always-ready connections to yield after a few spins ([8316f96d](https://github.com/hyperium/hyper/commit/8316f96d807454b76cde3cc6a7be552c02000529))\r\n* **http2:** correctly propagate HTTP2 request cancellation ([50198851](https://github.com/hyperium/hyper/commit/50198851a2b1e47c5ad60565eacb712fb3df1ad6))\r\n\r\n\r\n### v0.12.29 (2019-05-16)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **server:** skip automatic Content-Length header for HTTP 304 responses ([b342c38f](https://github.com/hyperium/hyper/commit/b342c38f08972fe8be4ef9844e30f1e7a121bbc4), closes [#1797](https://github.com/hyperium/hyper/issues/1797))\r\n\r\n\r\n#### Features\r\n\r\n* **body:** implement `http_body::Body` for `hyper::Body` ([2d9f3490](https://github.com/hyperium/hyper/commit/2d9f3490aa04393a12854680aa3e6d6117ba2407))\r\n* **client:** Implement `TryFrom` for `Destination` (#1810) ([d1183a80](https://github.com/hyperium/hyper/commit/d1183a80278decf3955874629e9cff427edecb05), closes [#1808](https://github.com/hyperium/hyper/issues/1808))\r\n* **server:** add initial window builder methods that take self by-val (#1817) ([8b45af7f](https://github.com/hyperium/hyper/commit/8b45af7f314cea7d1db5cb6990088dd8442aa87b))\r\n\r\n\r\n### v0.12.28 (2019-04-29)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:**\r\n  * detect HTTP2 connection closures sooner ([e0ec5cad](https://github.com/hyperium/hyper/commit/e0ec5cad9ae3eaa5d9fffeeb636b1363029fcb9c))\r\n  * fix a rare connection pool race condition ([4133181b](https://github.com/hyperium/hyper/commit/4133181bb20f8d7e990994b2119c590f832a95f1))\r\n\r\n\r\n#### Features\r\n\r\n* **server:** impl Sink for Body::Sender ([8d70baca](https://github.com/hyperium/hyper/commit/8d70baca611869c1997571e8513717396b13328b), closes [#1781](https://github.com/hyperium/hyper/issues/1781))\r\n\r\n\r\n### v0.12.27 (2019-04-10)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http2:** fix import of h2::Reason to work on 1.26 ([5680d944](https://github.com/hyperium/hyper/commit/5680d9441903d6c8d17c19b3ea1e054af76bb08d))\r\n\r\n\r\n### v0.12.26 (2019-04-09)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http2:** send a GOAWAY when the user's Service::poll_ready errors ([42c5efc0](https://github.com/hyperium/hyper/commit/42c5efc085ac71223e4b57d0e1b866e64d41f4e5))\r\n* **server:** prohibit the length headers on successful CONNECT ([d1501a0f](https://github.com/hyperium/hyper/commit/d1501a0fd3b616d3e42459fc83bdd7ebd01d217e), closes [#1783](https://github.com/hyperium/hyper/issues/1783))\r\n\r\n\r\n#### Features\r\n\r\n* **http2:** check `Error::source()` for an HTTP2 error code to send in reset ([fc18b680](https://github.com/hyperium/hyper/commit/fc18b680a5656a0c31bc09c1c70571956a1fd013))\r\n\r\n\r\n### v0.12.25 (2019-03-01)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** coerce HTTP_2 requests to HTTP_11 ([3a6080b1](https://github.com/hyperium/hyper/commit/3a6080b14abecc29c9aed77be6d60d34a12b368c), closes [#1770](https://github.com/hyperium/hyper/issues/1770))\r\n* **http2:** send INTERNAL_ERROR when user's Service errors ([8f926a0d](https://github.com/hyperium/hyper/commit/8f926a0daeaf4716cfb2e6db143c524da34421de))\r\n\r\n\r\n#### Features\r\n\r\n* **error:** implement `Error::source` when available ([4cf22dfa](https://github.com/hyperium/hyper/commit/4cf22dfa2139f072e0ee937de343a0b0b0a77a22), closes [#1768](https://github.com/hyperium/hyper/issues/1768))\r\n* **http2:** Add window size config options for Client and Server ([7dcd4618](https://github.com/hyperium/hyper/commit/7dcd4618c059cc76987a32d3acb75e2aaed4419e), closes [#1771](https://github.com/hyperium/hyper/issues/1771))\r\n* **server:** add `http2_max_concurrent_streams` builder option ([cbae4294](https://github.com/hyperium/hyper/commit/cbae4294c416a64b56f30be7b6494f9934016d1e), closes [#1772](https://github.com/hyperium/hyper/issues/1772))\r\n* **service:**\r\n  * add `poll_ready` to `Service` and `MakeService` (#1767) ([0bf30ccc](https://github.com/hyperium/hyper/commit/0bf30ccc68feefb0196d2db9536232e5913598da))\r\n  * allow `FnMut` with `service_fn` ([877606d5](https://github.com/hyperium/hyper/commit/877606d5c81195374259561aa98b973a00fa6056))\r\n\r\n\r\n### v0.12.24 (2019-02-11)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** fix panic when CONNECT request doesn't have a port ([d16b2c30](https://github.com/hyperium/hyper/commit/d16b2c30810a2d96ab226997930d953b2fc2626b))\r\n\r\n\r\n#### Features\r\n\r\n* **server:**\r\n  * add `http1_max_buf_size` in the `server::Builder` (#1761) ([3e9782c2](https://github.com/hyperium/hyper/commit/3e9782c2a9501a3122df8a54775a1fa7f2386fea))\r\n  * add `into_inner` to `AddrStream` (#1762) ([e52f80df](https://github.com/hyperium/hyper/commit/e52f80df5a114844d239561218112a650067f006))\r\n\r\n\r\n### v0.12.23 (2019-01-24)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http2:** revert http2 refactor causing a client hang ([9aa7e990](https://github.com/hyperium/hyper/commit/9aa7e99010a1a0f086ade27f99cf4b8da00ae750))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** add `conn::Builder::max_buf_size()` ([078ed82d](https://github.com/hyperium/hyper/commit/078ed82dd5fed2f6c4399ff041ef116c712eaaf8), closes [#1748](https://github.com/hyperium/hyper/issues/1748))\r\n\r\n\r\n### v0.12.22 (2019-01-23)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** parse IPv6 hosts correctly in HttpConnector ([c328c62e](https://github.com/hyperium/hyper/commit/c328c62ec29cd328c1c7331bb316fe4a548f11d7))\r\n\r\n\r\n### v0.12.21 (2019-01-15)\r\n\r\n\r\n#### Features\r\n\r\n* **client:**\r\n  * add `Destination::try_from_uri` constructor ([c809542c](https://github.com/hyperium/hyper/commit/c809542c830c8d542877a22dd54b1c5c679ae433))\r\n  * Add useful trait impls to Name ([be5ec455](https://github.com/hyperium/hyper/commit/be5ec45571e0b1c6c2b20fe4ab49ef1b0226a004))\r\n  * add FromStr impl for Name ([607c4da0](https://github.com/hyperium/hyper/commit/607c4da0b96ca430593599c928c882a17a7914d5))\r\n\r\n\r\n### v0.12.20 (2019-01-07)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **dependencies:** disable unneeded optional tokio features ([e5135dd6](https://github.com/hyperium/hyper/commit/e5135dd6f619b5817e31572c98b45d7c4b34f43a), closes [#1739](https://github.com/hyperium/hyper/issues/1739))\r\n* **http2:** don't consider an h2 send request error as canceled ([cf034e99](https://github.com/hyperium/hyper/commit/cf034e99fa895fdf4b66edf392f8c7ca366448fd))\r\n\r\n\r\n### v0.12.19 (2018-12-18)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **rt:** prevent fallback reactor thread from being created accidentally ([1d253b4d](https://github.com/hyperium/hyper/commit/1d253b4d4759e045409fcf140adda7d327a05c8a))\r\n\r\n\r\n### v0.12.18 (2018-12-11)\r\n\r\n\r\n#### Features\r\n\r\n* **server:** add `server::conn::AddrIncoming::bind` constructor ([2d5eabde](https://github.com/hyperium/hyper/commit/2d5eabdeed06ea1c88d88dff464929616710ee9a))\r\n\r\n\r\n### v0.12.17 (2018-12-05)\r\n\r\n\r\n#### Features\r\n\r\n* **error:** add `Error::is_connect` method ([01f64983](https://github.com/hyperium/hyper/commit/01f64983559602b9ebaaeecf6d33e97a88185676))\r\n* **server:**\r\n  * add `tcp_sleep_on_accept_errors` builder method ([a6fff13a](https://github.com/hyperium/hyper/commit/a6fff13a392d3394cacb1215f83bd8ec87671566), closes [#1713](https://github.com/hyperium/hyper/issues/1713))\r\n  * add `http1_half_close(bool)` option ([73345be6](https://github.com/hyperium/hyper/commit/73345be65f895660492e28e718786b66034a4d03), closes [#1716](https://github.com/hyperium/hyper/issues/1716))\r\n* **service:** export `hyper::service::MakeServiceRef` ([a522c315](https://github.com/hyperium/hyper/commit/a522c3151abd11795d3263f6607a7caf7c19a585))\r\n\r\n#### Performance\r\n\r\n* **http1:** implement an adaptive read buffer strategy which helps with throughput and memory management ([fd25129d](https://github.com/hyperium/hyper/commit/fd25129dc0e543538ccbd1794d22014bc187e050), closes [#1708](https://github.com/hyperium/hyper/issues/1708))\r\n\r\n### v0.12.16 (2018-11-21)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** fix connection leak when Response finishes before Request body ([e455fa24](https://github.com/hyperium/hyper/commit/e455fa2452cf45d66de6b4c3dc567e2b5d2368a4), closes [#1717](https://github.com/hyperium/hyper/issues/1717))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** add `http1_read_buf_exact_size` Builder option ([2e7250b6](https://github.com/hyperium/hyper/commit/2e7250b6698407b97961b8fcae78696e94d6ea57))\r\n\r\n\r\n### v0.12.15 (2018-11-20)\r\n\r\n\r\n#### Features\r\n\r\n* **client:** add client::conn::Builder::executor method ([95446cc3](https://github.com/hyperium/hyper/commit/95446cc338f8055539dd3503c482d649f42a531c))\r\n* **server:** change `NewService` to `MakeService` with connection context ([30870029](https://github.com/hyperium/hyper/commit/30870029b9eb162f566d8dddd007fb6df9cd69af), closes [#1650](https://github.com/hyperium/hyper/issues/1650))\r\n\r\n\r\n### v0.12.14 (2018-11-07)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **header:** fix panic when parsing header names larger than 64kb ([9245e940](https://github.com/hyperium/hyper/commit/9245e9409aeb5bb3e31b7f7c0e125583d1318465))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** add ALPN h2 support for client connectors ([976a77a6](https://github.com/hyperium/hyper/commit/976a77a67360a2590699c0b2bb3a4c3ccc0ff1ba))\r\n\r\n\r\n### v0.12.13 (2018-10-26)\r\n\r\n\r\n#### Features\r\n\r\n* **client:**\r\n  * add `Resolve`, used by `HttpConnector` ([2d5af177](https://github.com/hyperium/hyper/commit/2d5af177c1f0cfa3f592eec56f3a971fd9770f72), closes [#1517](https://github.com/hyperium/hyper/issues/1517))\r\n  * adds `HttpInfo` to responses when `HttpConnector` is used ([13d53e1d](https://github.com/hyperium/hyper/commit/13d53e1d0c095a61f64ff1712042aa615122d33d), closes [#1402](https://github.com/hyperium/hyper/issues/1402))\r\n* **dns:**\r\n  * export `client::connect::dns` module, and `TokioThreadpoolGaiResolver` type. ([34d780ac](https://github.com/hyperium/hyper/commit/34d780acd0fd7fe6a41b3eca1641791c7a33b366))\r\n  * tokio_threadpool::blocking resolver ([1e8d6439](https://github.com/hyperium/hyper/commit/1e8d6439cf4f9c7224fe80f0aeee32e2af1adbb0), closes [#1676](https://github.com/hyperium/hyper/issues/1676))\r\n* **http:** reexport `http` crate ([d55b5efb](https://github.com/hyperium/hyper/commit/d55b5efb890ef04e37825221deae9c57e9e602fa))\r\n* **server:** allow `!Send` Servers ([ced949cb](https://github.com/hyperium/hyper/commit/ced949cb6b798f25c2ffbdb3ebda6858c18393a7))\r\n\r\n\r\n### v0.12.12 (2018-10-16)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **armv7:** split record_header_indices loop to work around rustc/LLVM bug ([30a4f237](https://github.com/hyperium/hyper/commit/30a4f2376a392e50ade48685f92e930385ebb68f))\r\n* **http2:** add Date header if not present for HTTP2 server responses ([37ec724f](https://github.com/hyperium/hyper/commit/37ec724fd6405dd97c5873dddc956df1711b29ab))\r\n* **server:** log and ignore connection errors on newly accepted sockets ([66a857d8](https://github.com/hyperium/hyper/commit/66a857d801c1fc82d35b6da2d27441aa046aae47))\r\n\r\n\r\n### v0.12.11 (2018-09-28)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** allow calling `Destination::set_host` with IPv6 addresses ([af5e4f3e](https://github.com/hyperium/hyper/commit/af5e4f3ec24a490e209e3e73f86207b63ce7191a), closes [#1661](https://github.com/hyperium/hyper/issues/1661))\r\n* **server:** use provided executor if fallback to HTTP2 ([1370a6f8](https://github.com/hyperium/hyper/commit/1370a6f8f06f9906ff75dec904ab9c6d763e37f0))\r\n\r\n\r\n### v0.12.10 (2018-09-14)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http1:** fix title-case option when header names have symbols ([ca5e520e](https://github.com/hyperium/hyper/commit/ca5e520e7aa6d0a211e3c152c09095d35326ca12))\r\n\r\n\r\n### v0.12.9 (2018-08-28)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http2:** allow TE \"trailers\" request headers ([24f11a42](https://github.com/hyperium/hyper/commit/24f11a421d8422714bf023a602d7718b885a39a0), closes [#1642](https://github.com/hyperium/hyper/issues/1642))\r\n* **server:** properly handle keep-alive for HTTP/1.0 ([1448e406](https://github.com/hyperium/hyper/commit/1448e4067b10da6fe4584921314afc1f5f4e3c8d), closes [#1614](https://github.com/hyperium/hyper/issues/1614))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** add `max_idle_per_host` configuration option ([a3c44ded](https://github.com/hyperium/hyper/commit/a3c44ded556b7ef9487ec48cf42fa948d64f5a83))\r\n* **server:** add `Server::with_graceful_shutdown` method ([168c7d21](https://github.com/hyperium/hyper/commit/168c7d2155952ba09f781c331fd67593b820af20), closes [#1575](https://github.com/hyperium/hyper/issues/1575))\r\n\r\n\r\n### v0.12.8 (2018-08-10)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **server:** coerce responses with HTTP2 version to HTTP/1.1 when protocol is 1.x ([195fbb2a](https://github.com/hyperium/hyper/commit/195fbb2a3728460e7f7eca2035461ce055db6cd0))\r\n\r\n\r\n#### Features\r\n\r\n* **server:**\r\n  * add Builder::http1_keepalive method ([b459adb4](https://github.com/hyperium/hyper/commit/b459adb43a753ba082f1fc03c90ff4e76625666f))\r\n  * add `Server::from_tcp` constructor ([bb4c5e24](https://github.com/hyperium/hyper/commit/bb4c5e24c846995b66e361d1c2446cb81984bbbd), closes [#1602](https://github.com/hyperium/hyper/issues/1602))\r\n  * add remote_addr method to AddrStream ([26f3a5ed](https://github.com/hyperium/hyper/commit/26f3a5ed317330db39dd33f49bafd859bc867d8a))\r\n\r\n\r\n### v0.12.7 (2018-07-23)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http1:** reduce closed connections when body is dropped ([6530a00a](https://github.com/hyperium/hyper/commit/6530a00a8e3449a8fd7e4ed6ad1231b6b1579c38))\r\n\r\n\r\n### v0.12.6 (2018-07-11)\r\n\r\n\r\n#### Features\r\n\r\n* **client:**\r\n  * add ability to include `SO_REUSEADDR` option on sockets ([13862d11](https://github.com/hyperium/hyper/commit/13862d11ad329e5198622ad3e924e1aa05ab2c8a), closes [#1599](https://github.com/hyperium/hyper/issues/1599))\r\n  * implement rfc 6555 (happy eyeballs) ([02a9c29e](https://github.com/hyperium/hyper/commit/02a9c29e2e816c8a583f65b372fcf7b8503e6bad))\r\n* **server:** add `Builder::http1_pipeline_flush` configuration ([5b5e3090](https://github.com/hyperium/hyper/commit/5b5e3090955c1b6c1e7a8cb97b43de8d099f5303))\r\n\r\n\r\n### v0.12.5 (2018-06-28)\r\n\r\n\r\n### v0.12.4 (2018-06-28)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:**\r\n  * fix keep-alive header detection when parsing responses ([c03c39e0](https://github.com/hyperium/hyper/commit/c03c39e0ffca94bce265db92281a50b2abae6f2b))\r\n  * try to reuse connections when pool checkout wins ([f2d464ac](https://github.com/hyperium/hyper/commit/f2d464ac79b47f988bffc826b80cf7d107f80694))\r\n\r\n\r\n### v0.12.3 (2018-06-25)\r\n\r\n\r\n#### Features\r\n\r\n* **client:** enable CONNECT requests through the `Client` ([2a3844ac](https://github.com/hyperium/hyper/commit/2a3844acc393d42ff1b75f798dcc321a20956bea))\r\n* **http2:** quickly cancel when receiving RST_STREAM ([ffdb4788](https://github.com/hyperium/hyper/commit/ffdb47883190a8889cf30b716294383392a763c5))\r\n\r\n\r\n### v0.12.2 (2018-06-19)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http2:**\r\n  * implement `graceful_shutdown` for HTTP2 server connections ([b7a0c2d5](https://github.com/hyperium/hyper/commit/b7a0c2d5967d9ca22bd5e031166876c81ae80606), closes [#1550](https://github.com/hyperium/hyper/issues/1550))\r\n  * send trailers if Payload includes them ([3affe2a0](https://github.com/hyperium/hyper/commit/3affe2a0af445a01acb75181b16e71eb9fef4ae2))\r\n* **lib:** return an error instead of panic if execute fails ([482a5f58](https://github.com/hyperium/hyper/commit/482a5f589ea2bdb798f01645653975089f40ef44), closes [#1566](https://github.com/hyperium/hyper/issues/1566))\r\n* **server:**\r\n  * fix debug assert failure when kept-alive connections see a parse error ([396fe80e](https://github.com/hyperium/hyper/commit/396fe80e76840dea9373ca448b20cf7a9babd2f8))\r\n  * correctly handle CONNECT requests ([d7ab0166](https://github.com/hyperium/hyper/commit/d7ab01667659290784bfe685951c83a6f69e415e))\r\n\r\n\r\n#### Features\r\n\r\n* **body:**\r\n  * make `Body` know about incoming `Content-Length` ([a0a0fcdd](https://github.com/hyperium/hyper/commit/a0a0fcdd9b126ee2c0810b2839c7ab847f5788ad), closes [#1545](https://github.com/hyperium/hyper/issues/1545))\r\n  * add `Sender::abort` ([a096799c](https://github.com/hyperium/hyper/commit/a096799c1b4581ce1a47ed0817069997a9031828))\r\n* **client:** add `set_scheme`, `set_host`, and `set_port` for `Destination` ([27db8b00](https://github.com/hyperium/hyper/commit/27db8b0061f85d89ec94e07295463e8d1030d94f), closes [#1564](https://github.com/hyperium/hyper/issues/1564))\r\n* **error:** add `Error::cause2` and `Error::into_cause` ([bc5e22f5](https://github.com/hyperium/hyper/commit/bc5e22f58095f294333f49f12eeb7e504cda666c), closes [#1542](https://github.com/hyperium/hyper/issues/1542))\r\n* **http1:** Add higher-level HTTP upgrade support to Client and Server (#1563) ([fea29b29](https://github.com/hyperium/hyper/commit/fea29b29e2bbbba10760917a234a8cf4a6133be4), closes [#1395](https://github.com/hyperium/hyper/issues/1395))\r\n* **http2:**\r\n  * implement flow control for h2 bodies ([1c3fbfd6](https://github.com/hyperium/hyper/commit/1c3fbfd6bf6b627f75ef694e69c8074745276e9b), closes [#1548](https://github.com/hyperium/hyper/issues/1548))\r\n  * Add `content_length()` value to incoming h2 `Body` ([9a28268b](https://github.com/hyperium/hyper/commit/9a28268b98f30fd25e862b4a182a853a9a6e1841), closes [#1546](https://github.com/hyperium/hyper/issues/1546))\r\n  * set Content-Length header on outgoing messages ([386fc0d7](https://github.com/hyperium/hyper/commit/386fc0d70b70d36ac44ec5562cd26babdfd46fc9), closes [#1547](https://github.com/hyperium/hyper/issues/1547))\r\n  * Strip connection headers before sending ([f20afba5](https://github.com/hyperium/hyper/commit/f20afba57d6fabb04085968342e5fd62b45bc8df))\r\n\r\n\r\n### v0.12.1 (2018-06-04)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **server:** add upgrading process to `poll_without_shutdown()` (#1530) ([c6e90b7b](https://github.com/hyperium/hyper/commit/c6e90b7b6509276c744b531f8b1f7b043059c4ec))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** implement `Clone` for `Destination` ([15188b7c](https://github.com/hyperium/hyper/commit/15188b7c7fc6774301a16923127df596486cc913))\r\n* **server:**\r\n  * add `http1_writev` config option for servers ([810435f1](https://github.com/hyperium/hyper/commit/810435f1469eb028c6a819368d63edb54d6c341c), closes [#1527](https://github.com/hyperium/hyper/issues/1527))\r\n  * add `http1_only` configuration ([14d9246d](https://github.com/hyperium/hyper/commit/14d9246de2e97908c915caf254a37fd62edb25d3), closes [#1512](https://github.com/hyperium/hyper/issues/1512))\r\n  * add `try_into_parts()` to `conn::Connection` (#1531) ([c615a324](https://github.com/hyperium/hyper/commit/c615a3242f2518bc8acf05116ebe87ea98773c28))\r\n\r\n\r\n## v0.12.0 (2018-06-01)\r\n\r\n#### Features\r\n\r\n* **lib:**\r\n  * add HTTP/2 support for Client and Server ([c119097f](https://github.com/hyperium/hyper/commit/c119097fd072db51751b100fa186b6f64785954d))\r\n  * convert to use tokio 0.1 ([27b8db3a](https://github.com/hyperium/hyper/commit/27b8db3af8852ba8280a2868f703d3230a1db85e))\r\n  * replace types with those from `http` crate ([3cd48b45](https://github.com/hyperium/hyper/commit/3cd48b45fb622fb9e69ba773e7f92b9d3e9ac018))\r\n* **body:**\r\n  * remove `Body::is_empty()` ([19f90242](https://github.com/hyperium/hyper/commit/19f90242f8a3768b2d8d4bff4044a2d6c77d40aa))\r\n  * change `Payload::Data` to be a `Buf` ([a3be110a](https://github.com/hyperium/hyper/commit/a3be110a55571a1ee9a31b2335d7aec27c04e96a), closes [#1508](https://github.com/hyperium/hyper/issues/1508))\r\n  * add `From<Box<Stream>>` impl for `Body` ([45efba27](https://github.com/hyperium/hyper/commit/45efba27df90650bf4669738102ad6e432ddc75d))\r\n  * introduce a `Payload` trait to represent bodies ([fbc449e4](https://github.com/hyperium/hyper/commit/fbc449e49cc4a4f8319647dccfb288d3d83df2bd), closes [#1438](https://github.com/hyperium/hyper/issues/1438))\r\n* **client:**\r\n  * rename `FutureResponse` to `ResponseFuture` ([04c74ef5](https://github.com/hyperium/hyper/commit/04c74ef596eb313b785ecad6c42c0375ddbb1e96))\r\n  * support local bind for `HttpConnector` ([b6a3c85d](https://github.com/hyperium/hyper/commit/b6a3c85d0f9ede10759dc2309502e88ea3e513f7), closes [#1498](https://github.com/hyperium/hyper/issues/1498))\r\n  * add support for title case header names (#1497) ([a02fec8c](https://github.com/hyperium/hyper/commit/a02fec8c7898792cbeadde7e0f5bf111d55dd335), closes [#1492](https://github.com/hyperium/hyper/issues/1492))\r\n  * add support to set `SO_NODELAY` on client HTTP sockets ([016d79ed](https://github.com/hyperium/hyper/commit/016d79ed2633e3f939a2cd10454cbfc5882effb4), closes [#1473](https://github.com/hyperium/hyper/issues/1473))\r\n  * improve construction of `Client`s ([fe1578ac](https://github.com/hyperium/hyper/commit/fe1578acf628844d7cccb3e896c5e0bb2a0be729))\r\n  * redesign the `Connect` trait ([8c52c2df](https://github.com/hyperium/hyper/commit/8c52c2dfd342e798420a0b83cde7d54f3af5e351), closes [#1428](https://github.com/hyperium/hyper/issues/1428))\r\n* **error:** revamp `hyper::Error` type ([5d3c4722](https://github.com/hyperium/hyper/commit/5d3c472228d40b57e47ea26004b3710cfdd451f3), closes [#1128](https://github.com/hyperium/hyper/issues/1128), [#1130](https://github.com/hyperium/hyper/issues/1130), [#1431](https://github.com/hyperium/hyper/issues/1431), [#1338](https://github.com/hyperium/hyper/issues/1338))\r\n* **rt:** make tokio runtime optional ([d127201e](https://github.com/hyperium/hyper/commit/d127201ef22b10ab1d84b3f2215863eb2d03bfcb))\r\n* **server:**\r\n  * support HTTP1 and HTTP2 automatically ([bc6af88a](https://github.com/hyperium/hyper/commit/bc6af88a32e29e5a4f3719d8abc664f9ab10dddd), closes [#1486](https://github.com/hyperium/hyper/issues/1486))\r\n  * re-design `Server` as higher-level API ([c4974500](https://github.com/hyperium/hyper/commit/c4974500abee45b95b0b54109cad15978ef8ced9), closes [#1322](https://github.com/hyperium/hyper/issues/1322), [#1263](https://github.com/hyperium/hyper/issues/1263))\r\n* **service:** introduce hyper-specific `Service` ([2dc6202f](https://github.com/hyperium/hyper/commit/2dc6202fe7294fa74cf1ba58a45e48b8a927934f), closes [#1461](https://github.com/hyperium/hyper/issues/1461))\r\n\r\n#### Bug Fixes\r\n\r\n* **lib:** remove deprecated tokio-proto APIs ([a37e6b59](https://github.com/hyperium/hyper/commit/a37e6b59e6d6936ee31c6d52939869933c709c78))\r\n* **server:** panic on max_buf_size too small ([aac250f2](https://github.com/hyperium/hyper/commit/aac250f29d3b05d8c07681a407825811ec6a0b56))\r\n\r\n#### Breaking Changes\r\n\r\n* `Body::is_empty()` is gone. Replace with\r\n  `Body::is_end_stream()`, from the `Payload` trait.\r\n\r\n  ([19f90242](https://github.com/hyperium/hyper/commit/19f90242f8a3768b2d8d4bff4044a2d6c77d40aa))\r\n* Each payload chunk must implement `Buf`, instead of\r\n  just `AsRef<[u8]>`.\r\n\r\n  ([a3be110a](https://github.com/hyperium/hyper/commit/a3be110a55571a1ee9a31b2335d7aec27c04e96a))\r\n* Replace any references of\r\n  `hyper::client::FutureResponse` to `hyper::client::ResponseFuture`.\r\n\r\n  ([04c74ef5](https://github.com/hyperium/hyper/commit/04c74ef596eb313b785ecad6c42c0375ddbb1e96))\r\n* The `Service` trait has changed: it has some changed\r\n  associated types, and `call` is now bound to `&mut self`.\r\n\r\n  The `NewService` trait has changed: it has some changed associated\r\n  types, and `new_service` now returns a `Future`.\r\n\r\n  `Client` no longer implements `Service` for now.\r\n\r\n  `hyper::server::conn::Serve` now returns `Connecting` instead of\r\n  `Connection`s, since `new_service` can now return a `Future`. The\r\n  `Connecting` is a future wrapping the new service future, returning\r\n  a `Connection` afterwards. In many cases, `Future::flatten` can be\r\n  used.\r\n\r\n  ([2dc6202f](https://github.com/hyperium/hyper/commit/2dc6202fe7294fa74cf1ba58a45e48b8a927934f))\r\n* The `Server` is no longer created from `Http::bind`,\r\n  nor is it `run`. It is a `Future` that must be polled by an\r\n  `Executor`.\r\n\r\n  The `hyper::server::Http` type has move to\r\n  `hyper::server::conn::Http`.\r\n\r\n  ([c4974500](https://github.com/hyperium/hyper/commit/c4974500abee45b95b0b54109cad15978ef8ced9))\r\n* `Client:new(&handle)` and `Client::configure()` are now\r\n  `Client::new()` and `Client::builder()`.\r\n\r\n  ([fe1578ac](https://github.com/hyperium/hyper/commit/fe1578acf628844d7cccb3e896c5e0bb2a0be729))\r\n* `Error` is no longer an enum to pattern match over, or\r\n  to construct. Code will need to be updated accordingly.\r\n\r\n  For body streams or `Service`s, inference might be unable to determine\r\n  what error type you mean to return.\r\n\r\n  ([5d3c4722](https://github.com/hyperium/hyper/commit/5d3c472228d40b57e47ea26004b3710cfdd451f3))\r\n* All uses of `Handle` now need to be new-tokio `Handle`.\r\n\r\n  ([27b8db3a](https://github.com/hyperium/hyper/commit/27b8db3af8852ba8280a2868f703d3230a1db85e))\r\n* Custom connectors should now implement `Connect`\r\n  directly, instead of `Service`.\r\n\r\n  Calls to `connect` no longer take `Uri`s, but `Destination`. There\r\n  are `scheme`, `host`, and `port` methods to query relevant\r\n  information.\r\n\r\n  The returned future must be a tuple of the transport and `Connected`.\r\n  If no relevant extra information is needed, simply return\r\n  `Connected::new()`.\r\n\r\n  ([8c52c2df](https://github.com/hyperium/hyper/commit/8c52c2dfd342e798420a0b83cde7d54f3af5e351))\r\n* All code that was generic over the body as `Stream` must\r\n  be adjusted to use a `Payload` instead.\r\n\r\n  `hyper::Body` can still be used as a `Stream`.\r\n\r\n  Passing a custom `impl Stream` will need to either implement\r\n  `Payload`, or as an easier option, switch to `Body::wrap_stream`.\r\n\r\n  `Body::pair` has been replaced with `Body::channel`, which returns a\r\n  `hyper::body::Sender` instead of a `futures::sync::mpsc::Sender`.\r\n\r\n  ([fbc449e4](https://github.com/hyperium/hyper/commit/fbc449e49cc4a4f8319647dccfb288d3d83df2bd))\r\n* `Method`, `Request`, `Response`, `StatusCode`,\r\n  `Version`, and `Uri` have been replaced with types from the `http`\r\n  crate.\r\n\r\n  ([3cd48b45](https://github.com/hyperium/hyper/commit/3cd48b45fb622fb9e69ba773e7f92b9d3e9ac018))\r\n  * The variants of `Method` are now uppercase, for instance, `Method::Get` is now `Method::GET`.\r\n  * The variants of `StatusCode` are now uppercase, for instance, `StatusCode::Ok` is now `StatusCode::OK`.\r\n  * The variants of `Version` are now uppercase, for instance, `HttpVersion::Http11` is now `Version::HTTP_11`.\r\n*  The typed headers from `hyper::header` are gone for now.\r\n\r\n  The `http::header` module is re-exported as `hyper::header`.\r\n\r\n  For example, a before setting the content-length:\r\n\r\n  ```rust\r\n  use hyper::header::ContentLength;\r\n  res.headers_mut().set(ContentLength(15));\r\n  ```\r\n\r\n  And now **after**, with the `http` types:\r\n\r\n  ```rust\r\n  use hyper::header::{CONTENT_LENGTH, HeaderValue};\r\n  res.headers_mut().insert(CONTENT_LENGTH, HeaderValue::from_static(\"15\"));\r\n  ```\r\n\r\n  ([3cd48b45](https://github.com/hyperium/hyper/commit/3cd48b45fb622fb9e69ba773e7f92b9d3e9ac018))\r\n* The `mime` crate is no longer re-exported as `hyper::mime`.\r\n\r\n  The typed headers don't exist, and so they do not need the `mime` crate.\r\n\r\n  To continue using `mime` for other purposes, add it directly to your `Cargo.toml`\r\n  as a dependency.\r\n\r\n  ([3cd48b45](https://github.com/hyperium/hyper/commit/3cd48b45fb622fb9e69ba773e7f92b9d3e9ac018))\r\n* Removed `compat` cargo feature, and `compat` related API. This was the conversion methods for hyper's\r\n  types to and from `http` crate's types.\r\n\r\n  ([3cd48b45](https://github.com/hyperium/hyper/commit/3cd48b45fb622fb9e69ba773e7f92b9d3e9ac018))\r\n* Removed deprecated APIs:\r\n  ([a37e6b59](https://github.com/hyperium/hyper/commit/a37e6b59e6d6936ee31c6d52939869933c709c78))\r\n  * The `server-proto` cargo feature, which included `impl ServerProto for Http`, and related associated types.\r\n  * `client::Config::no_proto()`\r\n  * `tokio_proto::streaming::Body::from(hyper::Body)`\r\n  * `hyper::Body::from(tokio_proto::streaming::Body)`\r\n  * `hyper::Body::from(futures::sync::mpsc::Receiver)`\r\n  * `Http::no_proto()`\r\n\r\n\r\n### v0.11.27 (2018-05-16)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** prevent pool checkout looping on not-ready connections ([ccec79da](https://github.com/hyperium/hyper/commit/ccec79dadc84f1e9fced9159189d9f8caa6e17a4), closes [#1519](https://github.com/hyperium/hyper/issues/1519))\r\n* **server:** skip SO_REUSEPORT errors ([2c48101a](https://github.com/hyperium/hyper/commit/2c48101a6ee1269d7c94a0c3e606b2d635b20615), closes [#1509](https://github.com/hyperium/hyper/issues/1509))\r\n\r\n\r\n### v0.11.26 (2018-05-05)\r\n\r\n\r\n#### Features\r\n\r\n* **server:** add Server::run_threads to run on multiple threads ([8b644c1a](https://github.com/hyperium/hyper/commit/8b644c1a2a1a629be9b263d8fae5963a61af91cd))\r\n\r\n\r\n### v0.11.25 (2018-04-04)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** ensure idle connection is pooled before response body finishes ([7fe9710a](https://github.com/hyperium/hyper/commit/7fe9710a98650efc37f35bb21b19926c015f0631))\r\n\r\n\r\n### v0.11.24 (2018-03-22)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **header:** remove charset=utf8 from `ContentType::text()` ([ba789e65](https://github.com/hyperium/hyper/commit/ba789e6552eb74afb98f4d462d5c06c6643535d3))\r\n\r\n\r\n### v0.11.23 (2018-03-22)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **server:** prevent to output Transfer-encoding when server upgrade (#1465) ([eb105679](https://github.com/hyperium/hyper/commit/eb105679271a6e0ccc09f37978314a1a8d686217))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** introduce lower-level Connection API ([1207c2b6](https://github.com/hyperium/hyper/commit/1207c2b62456fc729c3a29c56c3966b319b474a9), closes [#1449](https://github.com/hyperium/hyper/issues/1449))\r\n* **header:** add `text()` and `text_utf8()` constructors to `ContentType` ([45cf8c57](https://github.com/hyperium/hyper/commit/45cf8c57c932a2756365748dc1e598ad3ee4b8ef))\r\n* **server:**\r\n  * add `service` property to `server::conn::Parts` ([bf7c0bbf](https://github.com/hyperium/hyper/commit/bf7c0bbf4f55fdf465407874b0b2d4bd748e6783), closes [#1471](https://github.com/hyperium/hyper/issues/1471))\r\n    * add upgrade support to lower-level Connection API (#1459) ([d58aa732](https://github.com/hyperium/hyper/commit/d58aa73246112f69410cc3fe912622f284427067), closes [#1323](https://github.com/hyperium/hyper/issues/1323))\r\n\r\n\r\n### v0.11.22 (2018-03-07)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** return error if Request has `CONNECT` method ([bfcdbd9f](https://github.com/hyperium/hyper/commit/bfcdbd9f86480cf6531544ecca247562a18172af))\r\n* **dependencies:** require tokio-core 0.1.11 ([49fcb066](https://github.com/hyperium/hyper/commit/49fcb0663cc30bbfc82cfc3c8e42d539211a3f3f))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** add `Config::set_host` option ([33a385c6](https://github.com/hyperium/hyper/commit/33a385c6b677cce4ece2843c11ac78711fd5b898))\r\n\r\n\r\n### v0.11.21 (2018-02-28)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:**\r\n  * check conn is closed in expire interval ([2fa0c845](https://github.com/hyperium/hyper/commit/2fa0c845b5f3f07e039522a9112a14593e02fe1b))\r\n  * schedule interval to clear expired idle connections ([727b7479](https://github.com/hyperium/hyper/commit/727b74797e5754af8abba8812a876c3c8fda6d94))\r\n  * never call connect if idle connection is available ([13741f51](https://github.com/hyperium/hyper/commit/13741f5145eb3dc894d2bc8d8486fc51c29e2e41))\r\n\r\n\r\n### v0.11.20 (2018-02-26)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **server:**\r\n  * Make sleep_on_errors configurable and use it in example ([3a36eb55](https://github.com/hyperium/hyper/commit/3a36eb559676349d8a321c3159684503014f7fbe))\r\n  * Sleep on socket IO errors ([68458cde](https://github.com/hyperium/hyper/commit/68458cde57a20f4b3c9c306eaf9801189262e0a6))\r\n\r\n\r\n#### Features\r\n\r\n* **body:** add `Body::is_empty()` method ([2f45d539](https://github.com/hyperium/hyper/commit/2f45d5394a2f8a49442ff4798a4b1651c079f0ff))\r\n* **request:** add `Request::body_mut()` method ([3fa191a2](https://github.com/hyperium/hyper/commit/3fa191a2676feb86c91abf8dfcc8e63477980297))\r\n\r\n\r\n### v0.11.19 (2018-02-21)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:**\r\n  * prevent empty bodies sending transfer-encoding for GET, HEAD ([77adab4e](https://github.com/hyperium/hyper/commit/77adab4ebf0fadd9ccd014d24ff0bcec1bce1e8b))\r\n  * detect connection closes as pool tries to use ([dc619a8f](https://github.com/hyperium/hyper/commit/dc619a8fa01616b260ef32a35b35963460987206), closes [#1439](https://github.com/hyperium/hyper/issues/1439))\r\n* **uri:** make absolute-form uris always have a path ([a9413d73](https://github.com/hyperium/hyper/commit/a9413d7367e8b9f0245fc8a90a22ece7d55e7e04))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** Client will retry requests on fresh connections ([ee61ea9a](https://github.com/hyperium/hyper/commit/ee61ea9adf86b309490a68d044e40bd1090338e8))\r\n\r\n\r\n### v0.11.18 (2018-02-07)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** send an `Error::Cancel` if a queued request is dropped ([88f01793](https://github.com/hyperium/hyper/commit/88f01793bec5830370cb88f74a64a2e20a440c17))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** add `http1_writev` configuration option ([b0aa6497](https://github.com/hyperium/hyper/commit/b0aa6497258c20354ae0fe36d668e0c2361b3151))\r\n\r\n\r\n### v0.11.17 (2018-02-05)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** more reliably detect closed pooled connections (#1434) ([265ad67c](https://github.com/hyperium/hyper/commit/265ad67c86379841a5aa821543a01648ccc8c26c))\r\n* **h1:** fix hung streaming bodies over HTTPS ([73109694](https://github.com/hyperium/hyper/commit/731096947d0704de58b75d17e05af956bcb21bd9))\r\n\r\n\r\n### v0.11.16 (2018-01-30)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:**\r\n  * check for dead connections in Pool ([44af2738](https://github.com/hyperium/hyper/commit/44af273853f82b81591b813d13627e143a14a6b7), closes [#1429](https://github.com/hyperium/hyper/issues/1429))\r\n  * error on unsupported 101 responses, ignore other 1xx codes ([22774222](https://github.com/hyperium/hyper/commit/227742221fa7830a14c18becbbc6137d97b57729))\r\n* **server:**\r\n  * send 400 responses on parse errors before closing connection ([7cb72d20](https://github.com/hyperium/hyper/commit/7cb72d2019bffbc667b9ad2d8cbc19c1a513fcf7))\r\n  * error if Response code is 1xx ([44c34ce9](https://github.com/hyperium/hyper/commit/44c34ce9adc888916bd67656cc54c35f7908f536))\r\n\r\n\r\n#### Features\r\n\r\n* **server:** add `Http::max_buf_size()` option ([d22deb65](https://github.com/hyperium/hyper/commit/d22deb6572c279e11773b6bcb862415c08f19c2e), closes [#1368](https://github.com/hyperium/hyper/issues/1368))\r\n* **uri:** Add a `PartialEq<str>` impl for `Uri` ([11b49c2c](https://github.com/hyperium/hyper/commit/11b49c2cc84695e966e9d9a0b05781853b28d7a8))\r\n\r\n#### Performance\r\n\r\n- **h1:** utilize `writev` when possible, reducing copies ([68377ede](https://github.com/hyperium/hyper/commit/68377ede))\r\n\r\n### v0.11.15 (2018-01-22)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **lib:** properly handle HTTP/1.0 remotes ([36e66a50](https://github.com/hyperium/hyper/commit/36e66a50546347c6f9b74c6d3c26e8b910483a4b), closes [#1304](https://github.com/hyperium/hyper/issues/1304))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** add `executor` method when configuring a `Client` ([c89019eb](https://github.com/hyperium/hyper/commit/c89019eb100d00b5235d3b9a0d0b672ab0ef8ddc))\r\n\r\n\r\n### v0.11.14 (2018-01-16)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **tokio-proto:** return end-of-body frame correctly for tokio-proto ([14e4c741](https://github.com/hyperium/hyper/commit/14e4c741dc48a386d7bdc6f8e9e279e60f172722), closes [#1414](https://github.com/hyperium/hyper/issues/1414))\r\n\r\n\r\n### v0.11.13 (2018-01-12)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:**\r\n  * change connection errors to debug log level ([2fe90f25](https://github.com/hyperium/hyper/commit/2fe90f256420ff668966290ac96686ce061453e4), closes [#1412](https://github.com/hyperium/hyper/issues/1412))\r\n  * don't error on read before writing request ([7976023b](https://github.com/hyperium/hyper/commit/7976023b594ec6784e40a147d3baec99a947b118))\r\n* **lib:** properly handle body streaming errors ([7a48d0e8](https://github.com/hyperium/hyper/commit/7a48d0e8b4ad465c0205ddfb116b6bd60dbdec71))\r\n\r\n\r\n### v0.11.12 (2018-01-08)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **server:** add remote_addr back to Request when using Http::bind ([fa7f4377](https://github.com/hyperium/hyper/commit/fa7f4377c1d783ca860820aefc41d0eab73be14c), closes [#1410](https://github.com/hyperium/hyper/issues/1410))\r\n\r\n\r\n### v0.11.11 (2018-01-05)\r\n\r\n\r\n#### Features\r\n\r\n* **client:** replace default dispatcher ([0892cb27](https://github.com/hyperium/hyper/commit/0892cb27777858737449a012bc6ea08ee080e5b7))\r\n* **server:** change default dispatcher ([6ade21aa](https://github.com/hyperium/hyper/commit/6ade21aa7f16dfeb6c0c53fe39c3f168f5f8aec1))\r\n\r\n\r\n### v0.11.10 (2017-12-26)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:**\r\n  * fix panic when request body is empty string ([bfb0f84d](https://github.com/hyperium/hyper/commit/bfb0f84d372ec4251a20d16a1ac514a4177e2a3b))\r\n  * close connections when Response Future or Body is dropped ([ef400812](https://github.com/hyperium/hyper/commit/ef4008121e4faa9383fe4661ebd05de5efe7ee9c), closes [#1397](https://github.com/hyperium/hyper/issues/1397))\r\n  * properly close idle connections after timeout ([139dc7ab](https://github.com/hyperium/hyper/commit/139dc7ab2be271cd58b909db16c6ddbe5109f133), closes [#1397](https://github.com/hyperium/hyper/issues/1397))\r\n* **conn:** don't double shutdown in some cases ([7d3abfbc](https://github.com/hyperium/hyper/commit/7d3abfbcf33946cb8831103c3b55f9966fa9469d))\r\n\r\n\r\n### v0.11.9 (2017-12-09)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** detect valid eof after reading a body ([15fdd53d](https://github.com/hyperium/hyper/commit/15fdd53d4cb1cd0fef41c4bed509020f44512a00), closes [#1396](https://github.com/hyperium/hyper/issues/1396))\r\n\r\n\r\n#### Features\r\n\r\n* **log:** improve quality of debug level logs ([7b593112](https://github.com/hyperium/hyper/commit/7b5931122a07f2a766d3e103001bcb5ee1f983f3))\r\n\r\n\r\n### v0.11.8 (2017-12-06)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:**\r\n  * return error instead of unmatched response when idle ([95e0164e](https://github.com/hyperium/hyper/commit/95e0164e8f0f03742f71868cb2828bcd4bfa5cfc))\r\n  * remove idle connections when read eof is found ([cecef9d4](https://github.com/hyperium/hyper/commit/cecef9d402b76af12e6415519deb2b604f77b195))\r\n  * always wait on reads for pooled connections ([9f212410](https://github.com/hyperium/hyper/commit/9f212410026c780ea2a76ba81705ed137022260d))\r\n  * don't leak connections with no keep-alive ([d2aa5d86](https://github.com/hyperium/hyper/commit/d2aa5d862c95168f4e71cc65155c2dc41f306f36), closes [#1383](https://github.com/hyperium/hyper/issues/1383))\r\n* **conn:** handle when pre-emptive flushing closes the write state ([8f938d97](https://github.com/hyperium/hyper/commit/8f938d97e7f25ca9e8c9ae65f756f952753d9bf7), closes [#1391](https://github.com/hyperium/hyper/issues/1391))\r\n* **lib:** fix `no_proto` dispatcher to flush queue before polling more body ([121b5eef](https://github.com/hyperium/hyper/commit/121b5eef19e65acfecb8261d865554e173f2fc78))\r\n* **server:** allow TLS shutdown before dropping connections with `no_proto` ([60d0eaf8](https://github.com/hyperium/hyper/commit/60d0eaf8916f7cb5073105778f25dff21bd504bb), closes [#1380](https://github.com/hyperium/hyper/issues/1380))\r\n\r\n\r\n#### Features\r\n\r\n* **headers:** Implement `ProxyAuthorization` (#1394) ([c93cdb29](https://github.com/hyperium/hyper/commit/c93cdb290875cb86900e84c333725aefa4d7fad5))\r\n* **server:**\r\n  * Allow keep alive to be turned off for a connection (#1390) ([eb9590e3](https://github.com/hyperium/hyper/commit/eb9590e3da65299928938ae8bb830dfb008fdadd), closes [#1365](https://github.com/hyperium/hyper/issues/1365))\r\n  * add `Http.serve_incoming` to wrap generic accept steams ([e4864a2b](https://github.com/hyperium/hyper/commit/e4864a2bea59b40fb07e6d18329f75817803a3f3))\r\n\r\n\r\n### v0.11.7 (2017-11-14)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:**\r\n  * drop in-use connections when they finish if Client is dropped ([b1765dd1](https://github.com/hyperium/hyper/commit/b1765dd168b24912fbd36682f1f6df70eeb1acd5))\r\n  * don't read extra bytes on idle connections ([7c4b814e](https://github.com/hyperium/hyper/commit/7c4b814e6b95bdb22b11e027b2da16c5abb8399f))\r\n* **server:** GET requests with no body have None instead of Empty ([8bf79648](https://github.com/hyperium/hyper/commit/8bf7964875205155e3018902a6e8facee6c145b6), closes [#1373](https://github.com/hyperium/hyper/issues/1373))\r\n\r\n\r\n#### Features\r\n\r\n* **client:**\r\n  * skip dns resolution when host is a valid ip addr ([b1785c66](https://github.com/hyperium/hyper/commit/b1785c662bc75f7bbd36a242c379d120ff7c6cd2))\r\n  * allow custom executors for HttpConnector ([ed497bf5](https://github.com/hyperium/hyper/commit/ed497bf5e6f1d651e3b30fd42c10245c560aff5b))\r\n  * add names to DNS threads ([e0de55da](https://github.com/hyperium/hyper/commit/e0de55daa2ec241f97fc5ed14f5ec933bde110d7))\r\n* **header:** implement `ByteRangeSpec::to_satisfiable_range` ([bb54e36c](https://github.com/hyperium/hyper/commit/bb54e36c90dc9c2ca876cd7f2c7dc7250d217552))\r\n* **lib:** add support to disable tokio-proto internals ([f7532b71](https://github.com/hyperium/hyper/commit/f7532b71d141ebe41172dbb863d58d519e387a4e))\r\n* **server:**\r\n  * add `const_service` and `service_fn` helpers ([fe38aa4b](https://github.com/hyperium/hyper/commit/fe38aa4bc1c8fdcaefb0d839239c14620a7b8f0a))\r\n  * add `server::Serve` that can use a shared Handle ([39cf6ef7](https://github.com/hyperium/hyper/commit/39cf6ef7d26b3d829ec19fb1db176e8221170cb3))\r\n  * allow creating Server with shared Handle ([0844dede](https://github.com/hyperium/hyper/commit/0844dede191d720e0336ee4aca63af2255abe458))\r\n\r\n\r\n### v0.11.6 (2017-10-02)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **server:** fix experimental pipeline flushing ([6b4635fd](https://github.com/hyperium/hyper/commit/6b4635fd13f5fe91ad6d388c5e66394627ad7ba2))\r\n\r\n\r\n### v0.11.5 (2017-10-02)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http:** avoid infinite recursion when Body::from is called with Cow::Owned. (#1343) ([e8d61737](https://github.com/hyperium/hyper/commit/e8d6173734b0fb43bf7401fdbe43258d913a6284))\r\n\r\n\r\n### v0.11.4 (2017-09-28)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:**  fix panic in Pool ([0fbc215f](https://github.com/hyperium/hyper/commit/0fbc215f), closes [#1339](https://github.com/hyperium/hyper/issues/1339))\r\n\r\n\r\n### v0.11.3 (2017-09-28)\r\n\r\n\r\n#### Features\r\n\r\n* **header:**  add ContentType::xml() constructor ([92595e84](https://github.com/hyperium/hyper/commit/92595e84))\r\n* **http:**  add Body::from(cow) for bytes and strings ([425ff71d](https://github.com/hyperium/hyper/commit/425ff71d))\r\n* **lib:**  implement compatibility with http crate ([0c7d375b](https://github.com/hyperium/hyper/commit/0c7d375b))\r\n* **server:**\r\n  *  add experimental pipeline flush aggregation option to Http ([dd54f20b](https://github.com/hyperium/hyper/commit/dd54f20b))\r\n  *  remove unneeded Send + Sync from Server ([16e834d3](https://github.com/hyperium/hyper/commit/16e834d3))\r\n\r\n#### Bug Fixes\r\n\r\n* **client:**\r\n  *  cleanup dropped pending Checkouts from Pool ([3b91fc65](https://github.com/hyperium/hyper/commit/3b91fc65), closes [#1315](https://github.com/hyperium/hyper/issues/1315))\r\n  *  return Version errors if unsupported ([41c47241](https://github.com/hyperium/hyper/commit/41c47241), closes [#1283](https://github.com/hyperium/hyper/issues/1283))\r\n* **http:**  log errors passed to tokio at debug level ([971864c4](https://github.com/hyperium/hyper/commit/971864c4), closes [#1278](https://github.com/hyperium/hyper/issues/1278))\r\n* **lib:**\r\n  *  Export hyper::RawStatus if the raw_status feature is enabled ([627c4e3d](https://github.com/hyperium/hyper/commit/627c4e3d))\r\n  *  remove logs that contain request and response data ([207fca63](https://github.com/hyperium/hyper/commit/207fca63), closes [#1281](https://github.com/hyperium/hyper/issues/1281))\r\n\r\n#### Performance\r\n\r\n* **server:**  try to read from socket at keep-alive ([1a9f2648](https://github.com/hyperium/hyper/commit/1a9f2648))\r\n\r\n\r\n### v0.11.2 (2017-07-27)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** don't assume bodies on 204 and 304 Responses ([81c0d185](https://github.com/hyperium/hyper/commit/81c0d185bdb2cb11e0fba231e3259097f492dd7d), closes [#1242](https://github.com/hyperium/hyper/issues/1242))\r\n* **header:** fix panic from headers.remove when typed doesn't match ([4bd9746a](https://github.com/hyperium/hyper/commit/4bd9746a0fa56ddc578ec5a8044e6c37390f3770))\r\n* **http:**\r\n  * allow zero-length chunks when no body is allowed ([9b47e186](https://github.com/hyperium/hyper/commit/9b47e1861a6bd766f21c88b95ecfc9b45fad874d))\r\n  * fix encoding when buffer is full ([fc5b9cce](https://github.com/hyperium/hyper/commit/fc5b9cce3176776e4c916cd1b907b1649a538f00))\r\n  * skip zero length chunks when encoding ([d6da3f7b](https://github.com/hyperium/hyper/commit/d6da3f7b40550b425f760d0d331807feff9114fd))\r\n* **server:**\r\n  * improve detection of when a Response can have a body ([673e5cb1](https://github.com/hyperium/hyper/commit/673e5cb1a3dadea178e51677fa660a1258610ae8), closes [#1257](https://github.com/hyperium/hyper/issues/1257))\r\n  * reject Requests with invalid body lengths ([14cbd400](https://github.com/hyperium/hyper/commit/14cbd40071816ec04dd1921e599c1d5cca883898))\r\n  * do not automatically set ContentLength for 204 and 304 Responses ([c4c89a22](https://github.com/hyperium/hyper/commit/c4c89a22f8f1ebc74a13a6ee75a8209081dcb535))\r\n* **uri:** fix Uri parsing of IPv6 and userinfo ([7081c449](https://github.com/hyperium/hyper/commit/7081c4498e707c1240c7e672d39ba4948fffb558), closes [#1269](https://github.com/hyperium/hyper/issues/1269))\r\n\r\n\r\n#### Features\r\n\r\n* **headers:** export missing header types ([c9f4ff33](https://github.com/hyperium/hyper/commit/c9f4ff33821df1bff557dfddac1ba3fc6255ee62))\r\n* **server:** Provide reference to Response body ([a79fc98e](https://github.com/hyperium/hyper/commit/a79fc98e36eac485803b1ab97f35c60198fd72cb), closes [#1216](https://github.com/hyperium/hyper/issues/1216))\r\n* **status:** add `as_u16()` method to `StatusCode` ([5f6f252c](https://github.com/hyperium/hyper/commit/5f6f252c603c642be8037682c1bf7e7ed2392a53))\r\n\r\n\r\n### v0.11.1 (2017-07-03)\r\n\r\n\r\n#### Features\r\n\r\n* **server:** Handle 100-continue ([6164e764](https://github.com/hyperium/hyper/commit/6164e76405935065aeb912f94ba94230e0bac60f))\r\n\r\n\r\n## v0.11.0 (2017-06-13)\r\n\r\n#### Bug Fixes\r\n\r\n* **header:**\r\n  * add length checks to `ETag` parsing ([643fac1e](https://github.com/hyperium/hyper/commit/643fac1e01102524e44ead188e865830ebdfb1f4))\r\n  * prevent 2 panics in `QualityItem` parsing ([d80aae55](https://github.com/hyperium/hyper/commit/d80aae55b1af0420bfcdecb2c8515b48e3e0e641))\r\n  * Allow IPv6 Addresses in `Host` header ([8541ac72](https://github.com/hyperium/hyper/commit/8541ac72d7ec80a36171115501e49dd47bcb1d0d))\r\n  * Remove raw part when getting mutable reference to typed header ([f38717e4](https://github.com/hyperium/hyper/commit/f38717e422a80e04ca95fcd5e5c5d54b7197bed2), closes [#821](https://github.com/hyperium/hyper/issues/821))\r\n  * only add chunked to `TransferEncoding` if not present ([1b4f8579](https://github.com/hyperium/hyper/commit/1b4f85799737a537d8ebfb6afd0423b97238ab8b))\r\n  * ignore invalid cookies ([310d98d5](https://github.com/hyperium/hyper/commit/310d98d50b929b8bde898cbb1137df95da5e0840))\r\n* **http:**\r\n  * Chunked decoder reads last `\\r\\n` ([bffde8c8](https://github.com/hyperium/hyper/commit/bffde8c841353e05e9aea267ca94848ccdeeb394))\r\n  * make Chunked decoder resilient in an async world ([8672ec5a](https://github.com/hyperium/hyper/commit/8672ec5a366e698bd32679d64dce925b3fa11fc6))\r\n* **server:**\r\n  * support HTTP/1.1 pipelining ([523b890a](https://github.com/hyperium/hyper/commit/523b890a19e9325938adf42456eea6191fcb8029))\r\n\r\n#### Features\r\n\r\n* **body:**\r\n  * implement Extend and IntoIterator for Chunk ([78512bdb](https://github.com/hyperium/hyper/commit/78512bdb184903061ea02f1101c99a097483cb69))\r\n  * add Default trait to Body ([f61708ba](https://github.com/hyperium/hyper/commit/f61708ba81fc03a4797688afd5bcec87e8f98eef))\r\n  * implement `Default` for `Body` ([6faa653f](https://github.com/hyperium/hyper/commit/6faa653f0dfaa5220e76a60fcd264511686dfd08))\r\n  * implement `Default` for `Chunk` ([f5567db4](https://github.com/hyperium/hyper/commit/f5567db4dcc04a769725d0b9ccb6a81bc3026acc))\r\n* **client:**\r\n  * add `HttpConnector.enforce_http` ([1c34a05a](https://github.com/hyperium/hyper/commit/1c34a05a85078421078f2cb266dccc5dfce8a9f0))\r\n  * add an accessor for the request body ([4e26646a](https://github.com/hyperium/hyper/commit/4e26646aa7b46d5739d3978126bb70e8c47cde1d))\r\n  * Response.status() now returns a `StatusCode` by value ([d63b7de4](https://github.com/hyperium/hyper/commit/d63b7de44f813696f8ec595d2f8f901526c1720e))\r\n  * add Client::handle ([9101817b](https://github.com/hyperium/hyper/commit/9101817b0fd61d7bcccfaa8933e64d6e3787395d))\r\n  * add Request.set_proxy for HTTP proxy requests ([e8714116](https://github.com/hyperium/hyper/commit/e871411627cab5caf00d8ee65328da9ff05fc53d), closes [#1056](https://github.com/hyperium/hyper/issues/1056))\r\n  * DNS worker count is configurable ([138e1643](https://github.com/hyperium/hyper/commit/138e1643e81669cae9dbe215197abd0e07f0c1e7))\r\n  * add keep_alive_timeout to Client ([976218ba](https://github.com/hyperium/hyper/commit/976218badc4a067e45a9d15af7e4eb5f2a4adc09))\r\n* **error:** Display for Error shows better info ([49e196db](https://github.com/hyperium/hyper/commit/49e196db1c91b2fb5f7ab05d99b9c7bc997195f2), closes [#694](https://github.com/hyperium/hyper/issues/694))\r\n* **header:**\r\n  * add ContentType::octet_stream() constructor ([1a353102](https://github.com/hyperium/hyper/commit/1a35310273732acbf8e8498ebb5dbad3d61386cb))\r\n  * change `Cookie` to be map-like ([dd03e723](https://github.com/hyperium/hyper/commit/dd03e7239238e6c0753cf2502a0534e2c9770d9e), closes [#1145](https://github.com/hyperium/hyper/issues/1145))\r\n  * add `Cookie::iter()` ([edc1c0dd](https://github.com/hyperium/hyper/commit/edc1c0dd01b24ee32250dff51268ad60fff9293d))\r\n  * implement fmt::Display for several headers ([e9e7381e](https://github.com/hyperium/hyper/commit/e9e7381ece21588076bb712d5c508f50cd740591))\r\n  * add `Headers::append_raw` ([b4b2fb78](https://github.com/hyperium/hyper/commit/b4b2fb782e51b2b932e52fab6add7c23a369f1fb))\r\n  * Add support for Retry-After header ([1037bc77](https://github.com/hyperium/hyper/commit/1037bc773256ca05c4311a781e96fbdcaac877fe))\r\n  * add `Encoding::Brotli` variant ([f0ab2b6a](https://github.com/hyperium/hyper/commit/f0ab2b6aedb909d37698365d1fcc34ce749304b5))\r\n  * introduce `header::Raw` (#869) ([50ccdaa7](https://github.com/hyperium/hyper/commit/50ccdaa7e7db574ec9890c220765ffd2da5e493b))\r\n  * add `TE` header struct (#1150) ([f1859dfd](https://github.com/hyperium/hyper/commit/f1859dfd7abfc124dd986edc413f754f76c76e8b), closes [#1109](https://github.com/hyperium/hyper/issues/1109))\r\n  * support Opaque origin headers (#1147) ([41485997](https://github.com/hyperium/hyper/commit/414859978b47dc8ebd0df264afc4e113b8a1909e), closes [#1065](https://github.com/hyperium/hyper/issues/1065))\r\n  * add `HeaderView.raw()` ([8143c33b](https://github.com/hyperium/hyper/commit/8143c33bad9146414f14197c39f6d5326d0f0212))\r\n  * `impl Eq for ContentType` ([bba761ac](https://github.com/hyperium/hyper/commit/bba761ac547b59c885aceea5b9e52bf52e8747b5))\r\n  * add `Link` header implementation ([592c1e21](https://github.com/hyperium/hyper/commit/592c1e21256d3ba2aeba6cdc2b62d8c1ebfa1dbf), closes [#650](https://github.com/hyperium/hyper/issues/650))\r\n  * add `star`, `json`, `text`, `image` constructors to `Accept` ([bdc19d52](https://github.com/hyperium/hyper/commit/bdc19d52bf5ec2e63b785de31bfe0ad3ba4d2550))\r\n  * Add strict-origin and strict-origin-when-cross-origin referer policy ([3593d798](https://github.com/hyperium/hyper/commit/3593d7987a92518736e130586499d97afa3e5b04))\r\n  * support multiple values for Referrer-Policy header ([7b558ae8](https://github.com/hyperium/hyper/commit/7b558ae87a826ca7383c0034d4ca95fc61aeac4c), closes [#882](https://github.com/hyperium/hyper/issues/882))\r\n  * add `Warning` header ([69894d19](https://github.com/hyperium/hyper/commit/69894d19947f01ad4ff54ce0283429758acba9ff), closes [#883](https://github.com/hyperium/hyper/issues/883))\r\n  * `Headers::remove` returns the Header ([9375addb](https://github.com/hyperium/hyper/commit/9375addba03505f2515d493364f9b1beb8b9b99a), closes [#891](https://github.com/hyperium/hyper/issues/891))\r\n  * add `ContentLocation` header ([13c5bf66](https://github.com/hyperium/hyper/commit/13c5bf66c305c08a2a1af26e48115b667d141b18), closes [#870](https://github.com/hyperium/hyper/issues/870))\r\n  * add `LastEventId` header ([e1542a60](https://github.com/hyperium/hyper/commit/e1542a609f99da770a65500333d922c58e39d179))\r\n  * add `Origin header ([01843f88](https://github.com/hyperium/hyper/commit/01843f882265a894c7051dc2ecf5cf09f2c2e8e7), closes [#651](https://github.com/hyperium/hyper/issues/651))\r\n  * Add `ReferrerPolicy` header ([3a86b3a2](https://github.com/hyperium/hyper/commit/3a86b3a2b25be1c088cf7d39bb431b2e624d4191))\r\n* **http:**\r\n  * add Into<Bytes> for Chunk ([fac3d70c](https://github.com/hyperium/hyper/commit/fac3d70c0b716157ba689ae2b8a0089b6afc9bdc))\r\n  * use the bytes crate for Chunk and internally ([65b3e08f](https://github.com/hyperium/hyper/commit/65b3e08f6904634294ff2d105f2551cafe7e754d))\r\n  * allow specifying custom body streams ([1b1311a7](https://github.com/hyperium/hyper/commit/1b1311a7d36b000c9c2c509971ee759da8765711))\r\n* **lib:**\r\n  * add `raw_status` feature in Cargo.toml ([acd62cda](https://github.com/hyperium/hyper/commit/acd62cda446e4c647716a2d595342360dc24a080))\r\n  * remove extern Url type usage ([4fb7e6eb](https://github.com/hyperium/hyper/commit/4fb7e6ebc6b1d429dcce4bc18139bd443fffa6ee))\r\n  * export Method::Put at top level ([5c890321](https://github.com/hyperium/hyper/commit/5c890321ee2da727a814c18d4ee2df5eddd6720e))\r\n  * redesign API to use Futures and Tokio ([2d2d5574](https://github.com/hyperium/hyper/commit/2d2d5574a698e74e5102d39b9a9ab750860d92d1))\r\n  * switch to non-blocking (asynchronous) IO ([d35992d0](https://github.com/hyperium/hyper/commit/d35992d0198d733c251e133ecc35f2bca8540d96))\r\n* **mime:** upgrade to mime v0.3 ([f273224f](https://github.com/hyperium/hyper/commit/f273224f21eedd2f466f12fe30fd24e83c35922c), closes [#738](https://github.com/hyperium/hyper/issues/738))\r\n* **server:**\r\n  * make Http default its body type to hyper::Chunk ([dc97dd77](https://github.com/hyperium/hyper/commit/dc97dd77f45486d9cb9a22a1859809c5af5579e2))\r\n  * make Http compatible with TcpServer ([e04bcc12](https://github.com/hyperium/hyper/commit/e04bcc12a7e081f75482cdca1e4f4c4f597ad2ce), closes [#1036](https://github.com/hyperium/hyper/issues/1036))\r\n  * add path() and query() to Request ([8b3c1206](https://github.com/hyperium/hyper/commit/8b3c1206846cb96be780923952eafe0dde7850bf), closes [#896](https://github.com/hyperium/hyper/issues/896), [#897](https://github.com/hyperium/hyper/issues/897))\r\n* **status:**\r\n  * add `StatusCode::try_from(u16)`. ([f953cafe](https://github.com/hyperium/hyper/commit/f953cafe27d1c5de0c8b859e485225cfc2c18629))\r\n  * remove deprecated `StatusClass` ([94ee6204](https://github.com/hyperium/hyper/commit/94ee6204ae32b8c431c00fdc03dc75eee573c69c))\r\n  * impl Into<u16> for StatusCode ([c42f18db](https://github.com/hyperium/hyper/commit/c42f18db05e47fc24e8a8ece76cbc782b7558e8b))\r\n* **uri:**\r\n  * redesign `RequestUri` type into `Uri` ([9036443e](https://github.com/hyperium/hyper/commit/9036443e6bd61b948ebe622588d2765e22e2b179), closes [#1000](https://github.com/hyperium/hyper/issues/1000))\r\n  * add `is_absolute` method to `Uri` ([154ab29c](https://github.com/hyperium/hyper/commit/154ab29c0d2b50d7bcac0f7918abf2f7a1628112))\r\n* **version:** impl `FromStr` for `HttpVersion` ([47f3aa62](https://github.com/hyperium/hyper/commit/47f3aa6247a3211ae499b30584dca6acb43d2204))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* The `Cookie` header is no longer a wrapper over a\r\n  `Vec<String>`. It must be accessed via its `get` and `set` methods.\r\n\r\n ([dd03e723](https://github.com/hyperium/hyper/commit/dd03e7239238e6c0753cf2502a0534e2c9770d9e))\r\n* Any use of `Quality(num)` should change to `q(num)`.\r\n\r\n ([a4644959](https://github.com/hyperium/hyper/commit/a4644959b0f980d94898d6c2e3cb1763aac73a5e))\r\n* `HttpDate` no longer has public fields. Convert between\r\n  `HttpDate` and `SystemTime` as needed.\r\n\r\n ([316c6fad](https://github.com/hyperium/hyper/commit/316c6fad3026ba5ff5f6b9f31aca4d4f74b144e0))\r\n* The `link_extensions` methods of the `Link` header are\r\n  removed until fixed.\r\n\r\n ([011f28cb](https://github.com/hyperium/hyper/commit/011f28cb18d285401bc8bea2b0f0dbdf80089d97))\r\n* The `fmt_header` method has changed to take a different\r\n  formatter. In most cases, if your header also implements\r\n  `fmt::Display`, you can just call `f.fmt_line(self)`.\r\n\r\n ([6f02d43a](https://github.com/hyperium/hyper/commit/6f02d43ae0d80971a32617e316498b81acf38ca2))\r\n* The `Encoding` enum has an additional variant, `Trailers`.\r\n\r\n ([f1859dfd](https://github.com/hyperium/hyper/commit/f1859dfd7abfc124dd986edc413f754f76c76e8b))\r\n* `Origin.scheme` and `Origin.host` now return `Option`s, since the `Origin` could be `null`.\r\n\r\n ([41485997](https://github.com/hyperium/hyper/commit/414859978b47dc8ebd0df264afc4e113b8a1909e))\r\n* If you were explicitly checking the `StatusCode`, such as\r\n  with an equality comparison, you will need to use the value instead of a\r\n  reference.\r\n\r\n ([d63b7de4](https://github.com/hyperium/hyper/commit/d63b7de44f813696f8ec595d2f8f901526c1720e))\r\n* This removes several deprecated methods for converting\r\n  Headers into strings. Use more specialized methods instead.\r\n\r\n ([ec91bf41](https://github.com/hyperium/hyper/commit/ec91bf418b1f285bac9231d4bee0dd96742e565a))\r\n* The `Url` type is no longer used. Any instance in the\r\n  `Client` API has had it replaced with `hyper::Uri`.\r\n\r\n  This also means `Error::Uri` has changed types to\r\n  `hyper::error::UriError`.\r\n\r\n  The type `hyper::header::parsing::HTTP_VALUE` has been made private,\r\n  as an implementation detail. The function `http_percent_encoding`\r\n  should be used instead.\r\n\r\n ([4fb7e6eb](https://github.com/hyperium/hyper/commit/4fb7e6ebc6b1d429dcce4bc18139bd443fffa6ee))\r\n* This makes `Request.remote_addr` an\r\n  `Option<SocketAddr>`, instead of `SocketAddr`.\r\n\r\n ([e04bcc12](https://github.com/hyperium/hyper/commit/e04bcc12a7e081f75482cdca1e4f4c4f597ad2ce))\r\n* The `Preference` header had a typo in a variant and it's string representation,\r\n  change `Preference::HandlingLeniant` to `Preference::HandlingLenient`.\r\n ([2fa414fb](https://github.com/hyperium/hyper/commit/2fa414fb5fe6dbc922da25cca9960652edf32591))\r\n* `Server` is no longer the primary entry point. Instead,\r\n  an `Http` type is created  and then either `bind` to receive a `Server`,\r\n  or it can be passed to other Tokio things.\r\n ([f45e9c8e](https://github.com/hyperium/hyper/commit/f45e9c8e4fcacc2bd7fed84ef0df6d2fcf8c1134))\r\n* The name of `RequestUri` has changed to `Uri`. It is no\r\n  longer an `enum`, but an opaque struct with getter methods.\r\n\r\n ([9036443e](https://github.com/hyperium/hyper/commit/9036443e6bd61b948ebe622588d2765e22e2b179))\r\n* This adds a new variant to the `Encoding` enum, which\r\n  can break exhaustive matches.\r\n\r\n ([f0ab2b6a](https://github.com/hyperium/hyper/commit/f0ab2b6aedb909d37698365d1fcc34ce749304b5))\r\n* The fields of the `Host` header are no longer\r\n  available. Use the getter methods instead.\r\n\r\n ([cd9fd522](https://github.com/hyperium/hyper/commit/cd9fd522074bfe530c30c878e49e6ac1bd881f1f))\r\n* A big sweeping set of breaking changes.\r\n\r\n ([2d2d5574](https://github.com/hyperium/hyper/commit/2d2d5574a698e74e5102d39b9a9ab750860d92d1))\r\n* `Headers.remove()` used to return a `bool`,\r\n  it now returns `Option<H>`. To determine if a a header exists,\r\n  switch to `Headers.has()`.\r\n ([9375addb](https://github.com/hyperium/hyper/commit/9375addba03505f2515d493364f9b1beb8b9b99a))\r\n* `Header::parse_header` now receives `&Raw`, instead of\r\n  a `&[Vec<u8>]`. `Raw` provides several methods to ease using it, but\r\n  may require some changes to existing code.\r\n ([50ccdaa7](https://github.com/hyperium/hyper/commit/50ccdaa7e7db574ec9890c220765ffd2da5e493b))\r\n* LanguageTag used to be at the crate root, but it is now\r\n  in the `hyper::header` module.\r\n\r\n ([40745c56](https://github.com/hyperium/hyper/commit/40745c5671daf8ac7eb342ff0e1e7c801a7171c4))\r\n* Removes the undocumented `from_u16` function. Use\r\n  `StatusCode::try_from` instead.\r\n\r\n  Also makes the `status` module private. All imports of\r\n  `hyper::status::StatusCode` should be `hyper::StatusCode`.\r\n\r\n ([f953cafe](https://github.com/hyperium/hyper/commit/f953cafe27d1c5de0c8b859e485225cfc2c18629))\r\n* All usage of `status.class()` should change to\r\n  equivalent `status.is_*()` methods.\r\n\r\n ([94ee6204](https://github.com/hyperium/hyper/commit/94ee6204ae32b8c431c00fdc03dc75eee573c69c))\r\n* Most uses of `mime` will likely break. There is no more\r\n  `mime!` macro, nor a `Mime` constructor, nor `TopLevel` and `SubLevel`\r\n  enums.\r\n\r\n  Instead, in most cases, a constant exists that can now be used.\r\n\r\n  For less common mime types, they can be created by parsing a string.\r\n\r\n ([f273224f](https://github.com/hyperium/hyper/commit/f273224f21eedd2f466f12fe30fd24e83c35922c))\r\n* To use `RawStatus`, you must enable the `raw_status`\r\n  crate feature.\r\n\r\n ([acd62cda](https://github.com/hyperium/hyper/commit/acd62cda446e4c647716a2d595342360dc24a080))\r\n* Some headers used `UniCase`, but now use\r\n  `unicase::Ascii`. Upgrade code to `Ascii::new(s)`.\r\n\r\n ([c81edd41](https://github.com/hyperium/hyper/commit/c81edd41d783f67eca7a50d83b40c8a7cedf333c))\r\n* This breaks a lot of the Client and Server APIs.\r\n  Check the documentation for how Handlers can be used for asynchronous\r\n  events.\r\n\r\n ([d35992d0](https://github.com/hyperium/hyper/commit/d35992d0198d733c251e133ecc35f2bca8540d96))\r\n\r\n\r\n### v0.10.9 (2017-04-19)\r\n\r\n\r\n#### Features\r\n\r\n* **server:** add local_addr to retrieve resolved address ([71f250ad](https://github.com/hyperium/hyper/commit/71f250ad46e9ae0cac108e1de6dc15289da26a56))\r\n\r\n\r\n### v0.10.8 (2017-04-11)\r\n\r\n\r\n#### Features\r\n\r\n* **client:**\r\n  * introduce `PooledStream::<S>::get_ref` ([a54ce30f](https://github.com/hyperium/hyper/commit/a54ce30f902772168bbd8dc90f26bb08cecde6ec))\r\n  * introduce Response::get_ref ([5ef0ec2c](https://github.com/hyperium/hyper/commit/5ef0ec2cd2841e78508a61949a207187be914265))\r\n\r\n\r\n### v0.10.7 (2017-04-08)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **server:** don't dup the listener TCP socket. ([d2362331](https://github.com/hyperium/hyper/commit/d23623317820696c910ce43262d5276e8e24c066))\r\n\r\n\r\n### v0.10.6 (2017-04-05)\r\n\r\n\r\n#### Features\r\n\r\n* **buffer:** add from_parts and into_parts functions ([78551dd0](https://github.com/hyperium/hyper/commit/78551dd040e2ab46e833af355c92fe87aa026244))\r\n\r\n\r\n### v0.10.5 (2017-03-01)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http:**\r\n  * Consume entire chunked encoding message ([4147fcd0](https://github.com/hyperium/hyper/commit/4147fcd0d688b6d5b8d6b32f26c147819321a390))\r\n  * fix returning EarlyEof if supplied buffer is zero-len ([1e740fbc](https://github.com/hyperium/hyper/commit/1e740fbcc3fb60af2fe8d2227457fa29582151c3))\r\n\r\n\r\n### v0.10.4 (2017-01-31)\r\n\r\n\r\n#### Features\r\n\r\n* **header:** implement fmt::Display for several headers ([d5075770](https://github.com/hyperium/hyper/commit/d50757707b1c628f398fb0583aa3dd02111ae658))\r\n\r\n\r\n### v0.10.3 (2017-01-30)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **header:**\r\n  * deprecate HeaderFormatter ([282466e1](https://github.com/hyperium/hyper/commit/282466e1c00879cf9dde1ed62c3d436e99bfba85))\r\n  * enable SetCookie.fmt_header when only 1 cookie ([7611c307](https://github.com/hyperium/hyper/commit/7611c3071475afa2b0b80bbba2a0a7223a3d5920))\r\n\r\n\r\n#### Features\r\n\r\n* **header:** add Headers::append_raw ([6babbc40](https://github.com/hyperium/hyper/commit/6babbc40fb86a29ad76083a2a386182c40c0f335))\r\n\r\n\r\n### v0.10.2 (2017-01-23)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **header:** security fix for header values that include newlines ([2603d78f](https://github.com/hyperium/hyper/commit/2603d78f59d284953553b7ef48c3ea4baa085cd1))\r\n* **net:** set timeouts directly in `accept` ([f5d4d653](https://github.com/hyperium/hyper/commit/f5d4d653e35ed20bbbb0b13847b3b9f1cfe9575f))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* This technically will cause code that a calls\r\n  `SetCookie.fmt_header` to panic, as it is no longer to properly write\r\n  that method. Most people should not be doing this at all, and all\r\n  other ways of printing headers should work just fine.\r\n\r\n  The breaking change must occur in a patch version because of the\r\n  security nature of the fix.\r\n\r\n ([2603d78f](https://github.com/hyperium/hyper/commit/2603d78f59d284953553b7ef48c3ea4baa085cd1))\r\n\r\n\r\n### v0.10.1 (2017-01-19)\r\n\r\n\r\n## v0.10.0 (2017-01-10)\r\n\r\n#### Features\r\n\r\n* **client:**\r\n  * change ProxyConfig to allow HTTPS proxies ([14a4f1c2](https://github.com/hyperium/hyper/commit/14a4f1c2f735efe7b638e9078710ca32dc1e360a))\r\n  * remove experimental HTTP2 support ([d301c6a1](https://github.com/hyperium/hyper/commit/d301c6a1708c7d408b7f03ac46674a5f0edd3253))\r\n* **header:** remove `cookie` dependency ([f22701f7](https://github.com/hyperium/hyper/commit/f22701f7e7258ad4a26645eba47a3d374e452e86))\r\n* **lib:**\r\n  * remove SSL dependencies ([2f48612c](https://github.com/hyperium/hyper/commit/2f48612c7e141a9d612d7cb9d524b2f460561f56))\r\n  * remove `serde-serialization` feature ([7b9817ed](https://github.com/hyperium/hyper/commit/7b9817edcf4451bd033e55467c75577031bfe740))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* There is no more `hyper::http::h2`.\r\n\r\n  ([d301c6a1](https://github.com/hyperium/hyper/commit/d301c6a1708c7d408b7f03ac46674a5f0edd3253))\r\n* The `Cookie` and `SetCookie` headers no longer use the\r\n  cookie crate. New headers can be written for any header, or the ones\r\n  provided in hyper can be accessed as strings.\r\n\r\n  ([f22701f7](https://github.com/hyperium/hyper/commit/f22701f7e7258ad4a26645eba47a3d374e452e86))\r\n* There is no longer a `serde-serialization` feature.\r\n  Look at external crates, like `hyper-serde`, to fulfill this feature.\r\n\r\n  ([7b9817ed](https://github.com/hyperium/hyper/commit/7b9817edcf4451bd033e55467c75577031bfe740))\r\n* hyper will no longer provide OpenSSL support out of the\r\n  box. The `hyper::net::Openssl` and related types are gone. The `Client`\r\n  now uses an `HttpConnector` by default, which will error trying to\r\n  access HTTPS URLs.\r\n\r\n  TLS support should be added in from other crates, such as\r\n  hyper-openssl, or similar using different TLS implementations.\r\n\r\n  ([2f48612c](https://github.com/hyperium/hyper/commit/2f48612c7e141a9d612d7cb9d524b2f460561f56))\r\n* Usage of `with_proxy_config` will need to change to\r\n  provide a network connector. For the same functionality, a\r\n  `hyper::net::HttpConnector` can be easily created and passed.\r\n\r\n  ([14a4f1c2](https://github.com/hyperium/hyper/commit/14a4f1c2f735efe7b638e9078710ca32dc1e360a))\r\n\r\n\r\n### v0.9.14 (2016-12-12)\r\n\r\n\r\n#### Features\r\n\r\n* **headers:** add star, json, text, image constructors to Accept ([a9fbbd7f](https://github.com/hyperium/hyper/commit/a9fbbd7fdbcbec51ef560e9882a8fefa64a93b54))\r\n* **server:** add 'take_buf' method to BufReader ([bbbce5fc](https://github.com/hyperium/hyper/commit/bbbce5fc8bca0bcc34df4a4a9223432085fba2ff))\r\n\r\n\r\n### v0.9.13 (2016-11-27)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** close Pooled streams on sockopt error ([d5ffee2e](https://github.com/hyperium/hyper/commit/d5ffee2ec801274ac271273289084b7251b4ce89))\r\n\r\n\r\n### v0.9.12 (2016-11-09)\r\n\r\n\r\n#### Features\r\n\r\n* **error:** re-export url::ParseError ([30e78ac2](https://github.com/hyperium/hyper/commit/30e78ac212ed3085a5217e8d7f641c2f161ddc87))\r\n\r\n\r\n### v0.9.11 (2016-10-31)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **headers:** Allow IPv6 Addresses in Host header ([20f177ab](https://github.com/hyperium/hyper/commit/20f177abec12397f23adf43f6b726daee1a731cf))\r\n\r\n\r\n#### Features\r\n\r\n* **headers:**\r\n  * Add strict-origin and strict-origin-when-cross-origin referer policy ([1be4e769](https://github.com/hyperium/hyper/commit/1be4e7693f7d27c049f35fefb9fffead2581b1f4))\r\n  * support multiple values for Referrer-Policy header ([dc476657](https://github.com/hyperium/hyper/commit/dc4766573af9bd31d57fede5b9ef0ffa56fe44ab), closes [#882](https://github.com/hyperium/hyper/issues/882))\r\n  * add last-event-id header ([2277987f](https://github.com/hyperium/hyper/commit/2277987f3c25380353db606ca7baaf0c854095cd))\r\n* **server:** accept combined certificate files ([eeb1f48e](https://github.com/hyperium/hyper/commit/eeb1f48e17f4c71162ce90f88bda3dc37b489cc7))\r\n\r\n\r\n### v0.9.10 (2016-07-11)\r\n\r\n\r\n#### Features\r\n\r\n* **headers:**\r\n  * add origin header ([64881ae0](https://github.com/hyperium/hyper/commit/64881ae05458f06261b2e7d0f790184678cc42b9))\r\n  * Add Referrer-Policy header ([b76a02cc](https://github.com/hyperium/hyper/commit/b76a02cc446f2a3935006035fd73f5f7a47ec428))\r\n\r\n\r\n### v0.9.9 (2016-06-21)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **headers:** Remove raw part when getting mutable reference to typed header ([63b61524](https://github.com/hyperium/hyper/commit/63b615249443b8f897018f21473c2f1f8e43663c), closes [#821](https://github.com/hyperium/hyper/issues/821))\r\n\r\n\r\n#### Features\r\n\r\n* **error:** Display for Error shows better info ([5620fbf9](https://github.com/hyperium/hyper/commit/5620fbf98f1fd43482a9ffa3c98f2f38b42fd4b0), closes [#694](https://github.com/hyperium/hyper/issues/694))\r\n\r\n\r\n### v0.9.8 (2016-06-14)\r\n\r\n\r\n#### Features\r\n\r\n* **client:** enable use of custom TLS wrapper for proxied connections ([0476196c](https://github.com/hyperium/hyper/commit/0476196c320765a66f730c56048998980b173caf), closes [#824](https://github.com/hyperium/hyper/issues/824))\r\n\r\n\r\n### v0.9.7 (2016-06-09)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **proxy:** fix the 0.9.x build with `--no-default-features --features=security-framework` ([6caffe9f](https://github.com/hyperium/hyper/commit/6caffe9fb302da99ce8cf0c8027c06b8c6de782d), closes [#819](https://github.com/hyperium/hyper/issues/819))\r\n* **server:** Request.ssl() works ([ce0b62ea](https://github.com/hyperium/hyper/commit/ce0b62eae7688987b722599be8e8b2ff6764b224))\r\n\r\n\r\n### v0.9.6 (2016-05-23)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** Manually impl Debug for PooledStream ([aa692236](https://github.com/hyperium/hyper/commit/aa692236a851d29abec63b6a0d61d957cea5fd26))\r\n* **server:** Switch Ssl to SslServer in bounds ([470bc8ec](https://github.com/hyperium/hyper/commit/470bc8ec396bfc9ead6782f72e6de58268767a5a))\r\n\r\n\r\n### v0.9.5 (2016-05-18)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **windows:** disable openssl cert validation for Windows ([c89aca81](https://github.com/hyperium/hyper/commit/c89aca812bf863aadb52326f534a65c1d3cf31d6), closes [#794](https://github.com/hyperium/hyper/issues/794))\r\n\r\n\r\n#### Features\r\n\r\n* **net:** Add OpensslClient constructor ([3c0e1050](https://github.com/hyperium/hyper/commit/3c0e105011fc8a4fc639370836aa6a2e576b6f0e))\r\n\r\n\r\n### v0.9.4 (2016-05-09)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **warnings:** remove unused_code warnings from newest nightlies ([e7229480](https://github.com/hyperium/hyper/commit/e7229480ea669bbe62fe644e312ba06cdca45b1c))\r\n\r\n\r\n#### Features\r\n\r\n* **ssl:**\r\n  * enable hostname verification by default for OpenSSL ([01160abd](https://github.com/hyperium/hyper/commit/01160abd92956e5f995cc45790df7a2b86c8989f), closes [#472](https://github.com/hyperium/hyper/issues/472))\r\n  * use secure ciphers by default in openssl ([54bf6ade](https://github.com/hyperium/hyper/commit/54bf6adeee1c3a231925f3efa7e38f875bc2d4d5))\r\n\r\n### v0.9.3 (2016-05-09)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** fix panic in Pool::connect ([e51bafe2](https://github.com/hyperium/hyper/commit/e51bafe2e4f2a1efc36790232bef488c91131d0b), closes [#780](https://github.com/hyperium/hyper/issues/780))\r\n\r\n\r\n### v0.9.2 (2016-05-04)\r\n\r\n\r\n#### Features\r\n\r\n* **client:**\r\n  *  proper proxy and tunneling in Client ([f36c6b25](https://github.com/hyperium/hyper/commit/f36c6b25), closes [#774](https://github.com/hyperium/hyper/issues/774))\r\n  *  add Proxy support ([25010fc1](https://github.com/hyperium/hyper/commit/25010fc1), closes [#531](https://github.com/hyperium/hyper/issues/531))\r\n\r\n#### Performance\r\n\r\n* **client:**  don't keep Pool mutex locked during getaddrinfo ([5fcc04a6](https://github.com/hyperium/hyper/commit/5fcc04a6))\r\n\r\n\r\n### v0.9.1 (2016-04-21)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **Cargo.toml:** update documentation link ([b783ddf4](https://github.com/hyperium/hyper/commit/b783ddf455ee93cc38510f3179ffe18733c797c1))\r\n\r\n\r\n## v0.9.0 (2016-04-21)\r\n\r\n\r\n#### Features\r\n\r\n* **net:** Add Ssl impls for security-framework ([f37315b2](https://github.com/hyperium/hyper/commit/f37315b2708e092eaf5177a6960df9f7bf11eb5c))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* The re-exported Url type has breaking changes.\r\n ([8fa7a989](https://github.com/hyperium/hyper/commit/8fa7a9896809ef2a24994993b91981105a520f26))\r\n\r\n\r\n### v0.8.1 (2016-04-13)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **headers:** correctly handle repeated headers ([70c69142](https://github.com/hyperium/hyper/commit/70c6914217a9b48880e61b7fb59acd15c6e1421e), closes [#683](https://github.com/hyperium/hyper/issues/683))\r\n\r\n\r\n#### Features\r\n\r\n* **header:** add prefer and preference applied headers ([6f649301](https://github.com/hyperium/hyper/commit/6f6493010a9c190b29aceb3c10c65785923a85f5), closes [#747](https://github.com/hyperium/hyper/issues/747))\r\n* **net:** Split Ssl into SslClient and SslServer ([2c86e807](https://github.com/hyperium/hyper/commit/2c86e8078ec01db2283e1fee1461db4c7bf76d3f), closes [#756](https://github.com/hyperium/hyper/issues/756))\r\n\r\n\r\n## v0.8.0 (2016-03-14)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **headers:** remove charset from `ContentType::json()` convenience method ([ec568e9a](https://github.com/hyperium/hyper/commit/ec568e9a551018b3353b6754eb2fcd729c7ea3c6))\r\n* **net:** fix the typo in `set_write_timeout` ([7c76fff3](https://github.com/hyperium/hyper/commit/7c76fff3aaf0f0a300e76622acb56eaf1e2cb474))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** Implement Debug for Client ([8c7ef7fd](https://github.com/hyperium/hyper/commit/8c7ef7fd937616798780d43f80a6b46507bc3433))\r\n* **status:** add HTTP statuses 421 and 451 ([93fd5a87](https://github.com/hyperium/hyper/commit/93fd5a87bddc5bfe29f35f86d44d3f46c81ff5fa))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* mime 0.2 depends on serde 0.7, so any instances of\r\n  using older versions of serde will need to upgrade.\r\n\r\n ([146df53c](https://github.com/hyperium/hyper/commit/146df53caf2a70cd15f97710738ba8d350040c12))\r\n\r\n\r\n### v0.7.2 (2016-01-04)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **buffer:** fix incorrect resizing of BufReader ([3a18e72b](https://github.com/hyperium/hyper/commit/3a18e72be67152834f6967c6d208f214288178ee), closes [#715](https://github.com/hyperium/hyper/issues/715))\r\n\r\n\r\n#### Features\r\n\r\n* **headers:** allow ExtendedValue structs to be formatted and used as struct members ([da0abe89](https://github.com/hyperium/hyper/commit/da0abe8988a61281b447a554b65ea8fd5d54f81b))\r\n\r\n\r\n### v0.7.1 (2015-12-19)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **cargo:** remove * dependencies for serde and env_logger ([4a05bee9](https://github.com/hyperium/hyper/commit/4a05bee9abdc426bbd904fe356b771e492dc8f43))\r\n* **server:**\r\n  * Flush 100-continue messages ([92ff50f2](https://github.com/hyperium/hyper/commit/92ff50f2e57fa2cb8a55b3d6d9fa43ef9a1b5526), closes [#704](https://github.com/hyperium/hyper/issues/704))\r\n  * Removed check for GET/HEAD request when parsing body ([0b05c590](https://github.com/hyperium/hyper/commit/0b05c5903e86327cc9cb4cac39217e496851fce3), closes [#698](https://github.com/hyperium/hyper/issues/698))\r\n\r\n\r\n#### Features\r\n\r\n* **headers:** add extended parameter parser to the public API ([402fb76b](https://github.com/hyperium/hyper/commit/402fb76bb2f3dab101509e4703743ab075ae41be))\r\n\r\n\r\n## v0.7.0 (2015-11-24)\r\n\r\n\r\n#### Features\r\n\r\n* **all:** add socket timeouts ([fec6e3e8](https://github.com/hyperium/hyper/commit/fec6e3e873eb79bd17d1c072d2ca3c7b91624f9c))\r\n* **headers:**\r\n  * Add Content-Disposition header ([7623ecc2](https://github.com/hyperium/hyper/commit/7623ecc26466e2e072eb2b03afc5e6c16d8e9bc9), closes [#561](https://github.com/hyperium/hyper/issues/561))\r\n  * Add Access-Control-Allow-Credentials header ([19348b89](https://github.com/hyperium/hyper/commit/19348b892be4687e2c0e48b3d01562562340aa1f), closes [#655](https://github.com/hyperium/hyper/issues/655))\r\n  * re-export CookiePair and CookieJar ([799698ca](https://github.com/hyperium/hyper/commit/799698ca87bc8f2f5446e9cb1301e5976657db6b))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* This adds 2 required methods to the `NetworkStream`\r\n  trait, `set_read_timeout` and `set_write_timeout`. Any local\r\n  implementations will need to add them.\r\n\r\n ([fec6e3e8](https://github.com/hyperium/hyper/commit/fec6e3e873eb79bd17d1c072d2ca3c7b91624f9c))\r\n* LanguageTags api is changed.\r\n\r\n ([c747f99d](https://github.com/hyperium/hyper/commit/c747f99d2137e03b5f4393ee3731f6ebeab9ee6e))\r\n\r\n\r\n### v0.6.16 (2015-11-16)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **response:** respond with a 500 if a handler panics ([63c6762c](https://github.com/hyperium/hyper/commit/63c6762c15ec790f54391a71794315599ae0ced8))\r\n\r\n\r\n#### Features\r\n\r\n* **headers:** Add Access-Control-Expose-Headers ([f783e991](https://github.com/hyperium/hyper/commit/f783e9913b988f3d5c28707e2291145999756dbe))\r\n* **server:** Add hooks for HttpListener and HttpsListener to be started from existing listener ([fa0848d4](https://github.com/hyperium/hyper/commit/fa0848d4216aa81e7b7619b7ce0a650356ee7ab7))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* `RequestBuilder<U>` should be replaced by `RequestBuilder`.\r\n\r\n ([ff4a6070](https://github.com/hyperium/hyper/commit/ff4a6070573955d1623d51a3d5302a17eed8f8d6))\r\n\r\n\r\n### v0.6.15 (2015-10-09)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **server:** use a timeout for Server keep-alive ([cdaa2547](https://github.com/hyperium/hyper/commit/cdaa2547ed18dfb0e3b8ed2ca15cfda1f98fa9fc), closes [#368](https://github.com/hyperium/hyper/issues/368))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** add patch method to Client builder interface ([03827c31](https://github.com/hyperium/hyper/commit/03827c3156b5c0a7c865c5846aca2c1ce7a9f4ce))\r\n\r\n\r\n### v0.6.14 (2015-09-21)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http:**\r\n  * Add a stream enum that makes it impossible to lose a stream ([be4e7181](https://github.com/hyperium/hyper/commit/be4e7181456844180963d0e5234656c319ce92a6))\r\n  * Make sure not to lose the stream when CL is invalid ([a36e44af](https://github.com/hyperium/hyper/commit/a36e44af7d4e665a122c1498011ff10035f7376f))\r\n* **server:** use EmptyWriter for status codes that have no body ([9b2998bd](https://github.com/hyperium/hyper/commit/9b2998bddc3c033e4fc4e6a9b7d18504339ded3f))\r\n* **timeouts:** remove rust #![feature] for socket timeouts ([b8729698](https://github.com/hyperium/hyper/commit/b872969880be502b681def26d6b9780cc90ac74b))\r\n\r\n\r\n#### Features\r\n\r\n* **headers:** add PartialEq impl for Headers struct ([76cbf384](https://github.com/hyperium/hyper/commit/76cbf384231e602d888e49932bf9c4fafdd88051))\r\n\r\n\r\n### v0.6.13 (2015-09-02)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** EofReader by nature means the connection is closed ([32e09a04](https://github.com/hyperium/hyper/commit/32e09a04292b0247456a8fb9003a75a6abaa998e))\r\n\r\n\r\n### v0.6.12 (2015-09-01)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** be resilient to invalid response bodies ([75c71170](https://github.com/hyperium/hyper/commit/75c71170206db3119d9b298ea5cf3ee860803124), closes [#640](https://github.com/hyperium/hyper/issues/640))\r\n* **examples:** \"cargo test --features serde-serialization\" ([63608c49](https://github.com/hyperium/hyper/commit/63608c49c0168634238a119eb64ea1074df1b7e6))\r\n* **http:** fix several cases in HttpReader ([5c7195ab](https://github.com/hyperium/hyper/commit/5c7195ab4a213bf0016f2185a63a6341e4cef4de))\r\n\r\n\r\n#### Features\r\n\r\n* **server:** Add Handler per-connection hooks ([6b6182e8](https://github.com/hyperium/hyper/commit/6b6182e8c4c81f634becebe7b45dc21bff59a286))\r\n\r\n\r\n### v0.6.11 (2015-08-27)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** fix panics when some errors occurred inside HttpMessage ([ef15257b](https://github.com/hyperium/hyper/commit/ef15257b733d40bc3a7c598f61918f91385585f9))\r\n* **headers:** case insensitive values for Connection header ([341f8eae](https://github.com/hyperium/hyper/commit/341f8eae6eb33e2242be09541807cdad9afc732e), closes [#635](https://github.com/hyperium/hyper/issues/635))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* This changes the signature of HttpWriter.end(),\r\n  returning a `EndError` that is similar to std::io::IntoInnerError,\r\n  allowing HttpMessage to retrieve the broken connections and not panic.\r\n\r\n  The breaking change isn't exposed in any usage of the `Client` API,\r\n  but for anyone using `HttpWriter` directly, since this was technically\r\n  a public method, that change is breaking.\r\n\r\n ([ef15257b](https://github.com/hyperium/hyper/commit/ef15257b733d40bc3a7c598f61918f91385585f9))\r\n\r\n\r\n### v0.6.10 (2015-08-19)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** close connection when there is an Error ([d32d35bb](https://github.com/hyperium/hyper/commit/d32d35bbea947172224082e1f9b711022ce75e30))\r\n\r\n\r\n#### Features\r\n\r\n* **uri:** implement fmt::Display for RequestUri () ([80931cf4](https://github.com/hyperium/hyper/commit/80931cf4c31d291125700ed3f9be5b3cb015d797), closes [#629](https://github.com/hyperium/hyper/issues/629))\r\n\r\n\r\n### v0.6.9 (2015-08-13)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:**\r\n  * improve keep-alive of bodyless Responses ([67c284a9](https://github.com/hyperium/hyper/commit/67c284a96a006f888f43d8af929516465de76dea))\r\n  * improve HttpReader selection for client Responses ([31f117ea](https://github.com/hyperium/hyper/commit/31f117ea08c01889016fd45e7084e9a049c53f7a), closes [#436](https://github.com/hyperium/hyper/issues/436))\r\n* **nightly:** remove feature flag for duration ([0455663a](https://github.com/hyperium/hyper/commit/0455663a98d7969c23d64d0b775799342507ef8e))\r\n\r\n\r\n#### Features\r\n\r\n* **headers:** Content-Range header ([af062ac9](https://github.com/hyperium/hyper/commit/af062ac954d5b90275138880ce2f5013d6664b5a))\r\n* **net:** impl downcast methods for NetworkStream (without + Send) ([1a91835a](https://github.com/hyperium/hyper/commit/1a91835abaa804aabf2e9bb45e9ab087274b8a18), closes [#521](https://github.com/hyperium/hyper/issues/521))\r\n* **server:** add Request.ssl() to get underlying ssl stream ([7909829f](https://github.com/hyperium/hyper/commit/7909829f98bd9a2f454430f89b6143b977aedb35), closes [#627](https://github.com/hyperium/hyper/issues/627))\r\n\r\n\r\n### v0.6.8 (2015-08-03)\r\n\r\n\r\n#### Features\r\n\r\n* **raw-fd:** implement FromRawFd/FromRawSocket ([664bde58](https://github.com/hyperium/hyper/commit/664bde58d8a6b2d6ce5624ed96b8d6d68214a782))\r\n\r\n\r\n### v0.6.7 (2015-08-03)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **headers:** fix broken deserialization of headers ([f5f5e1cb](https://github.com/hyperium/hyper/commit/f5f5e1cb2d01a22f170432e73b9c5757380cc18b))\r\n\r\n\r\n#### Features\r\n\r\n* **net:**\r\n  * Implement NetworkConnector for closure to be more flexible ([abdd4c5d](https://github.com/hyperium/hyper/commit/abdd4c5d632059ebef9bbee95032c9500620212e))\r\n  * add socket timeouts to Server and Client ([7d1f154c](https://github.com/hyperium/hyper/commit/7d1f154cb7b4db4a029b52857c377000a3f23419), closes [#315](https://github.com/hyperium/hyper/issues/315))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* Any custom implementation of NetworkStream must now\r\n  implement `set_read_timeout` and `set_write_timeout`, so those will\r\n  break. Most users who only use the provided streams should work with\r\n  no changes needed.\r\n\r\nCloses #315\r\n\r\n ([7d1f154c](https://github.com/hyperium/hyper/commit/7d1f154cb7b4db4a029b52857c377000a3f23419))\r\n\r\n\r\n### v0.6.5 (2015-07-23)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **tests:** iter.connect() is now iter.join() ([d2e8b5dc](https://github.com/hyperium/hyper/commit/d2e8b5dc3d2e6f0386656f4a5926acb848d4a61d))\r\n\r\n\r\n#### Features\r\n\r\n* **status:**\r\n  * implement `Hash` for `StatusCode` ([d84f291a](https://github.com/hyperium/hyper/commit/d84f291abc0a64e270143eee943a76a7aebec029))\r\n  * implement `Hash` for `StatusCode` ([aa85f609](https://github.com/hyperium/hyper/commit/aa85f609b5136cb2a9b23408a2b125c6a8a20f37))\r\n\r\n\r\n### v0.6.4 (2015-07-23)\r\n\r\n\r\n#### Features\r\n\r\n* **http:** add optional serialization of common types via `serde` ([87de1b77](https://github.com/hyperium/hyper/commit/87de1b77bcd5533c70a6ab9379121001acc5d366))\r\n\r\n\r\n### v0.6.3 (2015-07-08)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **lint:** change deny(missing_docs) to only apply for tests ([5994a6f8](https://github.com/hyperium/hyper/commit/5994a6f8b4e48c9ab766e425dba210bdac59b00b), closes [#600](https://github.com/hyperium/hyper/issues/600))\r\n\r\n\r\n### v0.6.2 (2015-07-06)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http:** no longer keep alive for Http1.0 if no Connection header ([ddecb262](https://github.com/hyperium/hyper/commit/ddecb262b39b90e594a95ba16c4dc8085930677e), closes [#596](https://github.com/hyperium/hyper/issues/596))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** add url property Response ([82ed9092](https://github.com/hyperium/hyper/commit/82ed9092e30385de004912582a7838e037497c82))\r\n* **headers:** add strict-transport-security header ([7c2e5124](https://github.com/hyperium/hyper/commit/7c2e5124e6678a5806f980902031e6f01652d218), closes [#589](https://github.com/hyperium/hyper/issues/589))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* Access-Control-Allow-Origin does no longer use Url\r\n\r\n ([ed458628](https://github.com/hyperium/hyper/commit/ed458628e54bd241b45f50fb0cf55a84ffb12205))\r\n* Technically a break, since `Response::new()` takes an\r\n  additional argument. In practice, the only place that should have been\r\n  creating Responses directly is inside the Client, so it shouldn't\r\n  break anyone. If you were creating Responses manually, you'll need to\r\n  pass a Url argument.\r\n\r\n ([82ed9092](https://github.com/hyperium/hyper/commit/82ed9092e30385de004912582a7838e037497c82))\r\n\r\n\r\n### v0.6.1 (2015-06-26)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **benches:** adjust to missing `set_ssl_verifier` ([eb38a11b](https://github.com/hyperium/hyper/commit/eb38a11b9ab401d6b909077f92507fa872349d13))\r\n* **cargo:** fix linking on OSX 10.10 ([9af2b66f](https://github.com/hyperium/hyper/commit/9af2b66fe4003706517d95ed94013af9cd365b24))\r\n* **client:** use Ssl instance in creation of SslStream ([1a490e25](https://github.com/hyperium/hyper/commit/1a490e25c321bdd173d47ed7a7a704039746fb29))\r\n\r\n\r\n## v0.6.0 (2015-06-24)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** check for drained stream in Response::drop ([e689f203](https://github.com/hyperium/hyper/commit/e689f20376d3e078f5d380902d39f8ae9c043486))\r\n\r\n\r\n#### Features\r\n\r\n* **client:**\r\n  * impl Sync for Client ([64e47b4b](https://github.com/hyperium/hyper/commit/64e47b4bbd0433065a059804adeb2b4a2d72f327), closes [#254](https://github.com/hyperium/hyper/issues/254))\r\n  * implement Protocol trait for HTTP/1.1 ([dccdf8d6](https://github.com/hyperium/hyper/commit/dccdf8d65a9b900daec34555d3b97c2c3c678067))\r\n  * add `Protocol` trait ([3417303a](https://github.com/hyperium/hyper/commit/3417303a4a9aa4809729d53f0d018338e876da51))\r\n  * implement HttpMessage for HTTP/1.1 ([ecb713f8](https://github.com/hyperium/hyper/commit/ecb713f8494b13bdba91258b1507e8f7ce62b8d9))\r\n  * add `HttpMessage` trait ([289fd02b](https://github.com/hyperium/hyper/commit/289fd02b55a42748cbce8de428939208713a765d))\r\n* **error:** add private `__Nonexhaustive` variant to Error ([7c0421e3](https://github.com/hyperium/hyper/commit/7c0421e3fc1d5a8b4868b57acca87abd685f3430))\r\n* **headers:**\r\n  * add bearer token support ([edf6ac20](https://github.com/hyperium/hyper/commit/edf6ac2074d11694ded275807a66df3a8a8e33a6))\r\n  * add `Range` header ([05c31998](https://github.com/hyperium/hyper/commit/05c319984630b31d18dfbfa9b7567f6c7613d7f8))\r\n* **http2:**\r\n  * implement message API for HTTP/2 ([f0fe2c5a](https://github.com/hyperium/hyper/commit/f0fe2c5a83bd4e654a4ff684f75a1b602f8f38fc))\r\n  * add new error variant for HTTP/2 ([48e9ca2f](https://github.com/hyperium/hyper/commit/48e9ca2f70f6c6475f1579ae9212af7b4ca87e88))\r\n  * add dependency on `solicit` ([3122ffef](https://github.com/hyperium/hyper/commit/3122ffefc2d56ffc03a6fcc264086df0c9d74083))\r\n* **langtags:** use true language tags in headers ([99ff7e62](https://github.com/hyperium/hyper/commit/99ff7e62573865a1fc431db26b6a18c43b9127de))\r\n* **ssl:** redesign SSL usage ([53bba6eb](https://github.com/hyperium/hyper/commit/53bba6eb7f34e61e5c8a835281d625436532de8f))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* AcceptLanguage and ContentLanguage use LanguageTag now,\r\nLanguage removed from Hyper.\r\n\r\n ([99ff7e62](https://github.com/hyperium/hyper/commit/99ff7e62573865a1fc431db26b6a18c43b9127de))\r\n* Server::https was changed to allow any implementation\r\n  of Ssl. Server in general was also changed. HttpConnector no longer\r\n  uses SSL; using HttpsConnector instead.\r\n\r\n ([53bba6eb](https://github.com/hyperium/hyper/commit/53bba6eb7f34e61e5c8a835281d625436532de8f))\r\n* Connectors and Protocols passed to the `Client` must\r\n  now also have a `Sync` bounds, but this shouldn't break default usage.\r\n\r\n ([64e47b4b](https://github.com/hyperium/hyper/commit/64e47b4bbd0433065a059804adeb2b4a2d72f327))\r\n* parse_header returns Result instead of Option, related\r\ncode did also change\r\n\r\n ([195a89fa](https://github.com/hyperium/hyper/commit/195a89fa918a83c9dcab47a4b09edb464d4e8006))\r\n* Adds a new variant to public Error enum. The proper fix\r\n  is to stop matching exhaustively on `hyper::Error`.\r\n\r\n ([7c0421e3](https://github.com/hyperium/hyper/commit/7c0421e3fc1d5a8b4868b57acca87abd685f3430))\r\n* A new variant `Http2` added to a public enum\r\n`hyper::Error`.\r\n\r\n ([48e9ca2f](https://github.com/hyperium/hyper/commit/48e9ca2f70f6c6475f1579ae9212af7b4ca87e88))\r\n* `hyper::client::request::Response` is no longer generic\r\nover `NetworkStream` types. It no longer requires a generic type\r\nparameter at all.\r\n\r\n ([aa297f45](https://github.com/hyperium/hyper/commit/aa297f45322d66980bb2b51c413b15dfd51533ea))\r\n\r\n\r\n### v0.5.2 (2015-06-01)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **buffer:** check capacity before resizing ([b1686d1b](https://github.com/hyperium/hyper/commit/b1686d1b22aa95a17088f99054d577bbb2aef9dc))\r\n\r\n\r\n### v0.5.1 (2015-05-25)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:** don't close stream until EOF ([a5e6174e](https://github.com/hyperium/hyper/commit/a5e6174efd57afb1df7113c64f4e7718a3a94187), closes [#543](https://github.com/hyperium/hyper/issues/543))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** implement Default trait for client ([be041d91](https://github.com/hyperium/hyper/commit/be041d915a55fa1b5088e112b81727b864949976))\r\n* **header:** add ContentType::form_url_encoded() constructor ([2c99d4e9](https://github.com/hyperium/hyper/commit/2c99d4e9068b30ecb6d4eac4d364924fb253fdcd))\r\n* **headers:** return hyper::Error instead of () from header components ([5d669399](https://github.com/hyperium/hyper/commit/5d669399b6ca5ec7d0f01b9d30513cd1cc4cc47b))\r\n* **http:** add get_mut method to HttpReader ([e64ce8c0](https://github.com/hyperium/hyper/commit/e64ce8c05e847b2396e4b7e2bb656240e9806ed8))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* Error enum extended. Return type of header/shared/\r\ntypes changed.\r\n\r\n ([5d669399](https://github.com/hyperium/hyper/commit/5d669399b6ca5ec7d0f01b9d30513cd1cc4cc47b))\r\n\r\n\r\n## v0.5.0 (2015-05-12)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **client:**\r\n  * don't call close() inside Request ([3334fca2](https://github.com/hyperium/hyper/commit/3334fca278e662b2755e41045ce641238514bea9), closes [#519](https://github.com/hyperium/hyper/issues/519))\r\n  * keep the underlying connector when setting an SSL verifier ([f4556d55](https://github.com/hyperium/hyper/commit/f4556d554faa2a1170fec0af5b4076c31e7c3600), closes [#495](https://github.com/hyperium/hyper/issues/495))\r\n* **mock:** adjust ChannelMockConnector connect method to compile ([085d7b07](https://github.com/hyperium/hyper/commit/085d7b0752d7fc0134e99e9eec2a67cc66b319b3))\r\n\r\n\r\n#### Features\r\n\r\n* **header:**\r\n  * add ContentType::json(), plaintext(), html(), jpeg(), and png() constructors ([b6114ecd](https://github.com/hyperium/hyper/commit/b6114ecd2e65bd59e79a67a45913adaf0f1552f0))\r\n  * add Connection::close() and ::keep_alive() constructors ([c2938fb4](https://github.com/hyperium/hyper/commit/c2938fb45f9c1fff2a1235d82b7741531de21445))\r\n  * export __hyper__tm! macro so test modules work with header! ([f64fb10b](https://github.com/hyperium/hyper/commit/f64fb10bc87bb4b5a5291d09364ad6c725a842d8))\r\n* **net:**\r\n  * remove mut requirement for NetworkConnector.connect() ([1b318724](https://github.com/hyperium/hyper/commit/1b318724a5fd425366daddf15c5964d7c3cbc240))\r\n  * add `set_ssl_verifier` method to `NetworkConnector` trait ([a5d632b6](https://github.com/hyperium/hyper/commit/a5d632b6ea53d0988d6383dd734d0b5e6245ba2b))\r\n* **server:** check Response headers for Connection: close in keep_alive loop ([49b5b8fd](https://github.com/hyperium/hyper/commit/49b5b8fdfe256ead8f3aa3d489bc4b299c190a9a))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* Usage of Response.deconstruct() and construct() now use\r\n  a &mut Headers, instead of the struct proper.\r\n\r\n ([49b5b8fd](https://github.com/hyperium/hyper/commit/49b5b8fdfe256ead8f3aa3d489bc4b299c190a9a))\r\n* If you use deref! from the header module, you'll need\r\n  to switch to using __hyper__deref!.\r\n\r\n ([62d96adc](https://github.com/hyperium/hyper/commit/62d96adc6b852b3836b47fc2e154bbdbab9ad7f6))\r\n* Any custom Connectors will need to change to &self in\r\n  the connect method. Any Connectors that needed the mutability need to\r\n  figure out a synchronization strategy.\r\n\r\n  Request::with_connector() takes a &NetworkConnector instead of &mut.\r\n  Any uses of with_connector will need to change to passing &C.\r\n\r\n ([1b318724](https://github.com/hyperium/hyper/commit/1b318724a5fd425366daddf15c5964d7c3cbc240))\r\n* Adding a new required method to a public trait is a\r\nbreaking change.\r\n\r\n ([a5d632b6](https://github.com/hyperium/hyper/commit/a5d632b6ea53d0988d6383dd734d0b5e6245ba2b))\r\n\r\n\r\n## v0.4.0 (2015-05-07)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **net:** ignore NotConnected error in NetworkStream.close ([6be60052](https://github.com/hyperium/hyper/commit/6be60052c627b7e498d973465b4a3ee7efc40665), closes [#508](https://github.com/hyperium/hyper/issues/508))\r\n\r\n\r\n#### Features\r\n\r\n* **error:** add Ssl variant to hyper::Error ([972b3a38](https://github.com/hyperium/hyper/commit/972b3a388ac3af98ba038927c551b92be3a68d62), closes [#483](https://github.com/hyperium/hyper/issues/483))\r\n* **headers:**\r\n  * Allow `null` value in Access-Control-Allow-Origin ([5e341714](https://github.com/hyperium/hyper/commit/5e3417145ced116147ef1e890b4f1e7c775ad173))\r\n  * Parse Upgrade header protocols further ([f47d11b9](https://github.com/hyperium/hyper/commit/f47d11b97bb4a4bf67c3f9aa47c203babf4a9c72), closes [#480](https://github.com/hyperium/hyper/issues/480))\r\n  * Add From header field ([ce9c4af1](https://github.com/hyperium/hyper/commit/ce9c4af1e0a46abc9f7908c2cb0659a2ecab137c))\r\n  * Add Accept-Ranges header field ([2dbe3f9b](https://github.com/hyperium/hyper/commit/2dbe3f9b9a3fc9f04346712e55f40dabaf72d9a8))\r\n* **method:** implement `AsRef<str>` for `Method` ([c29af729](https://github.com/hyperium/hyper/commit/c29af729726ae782bece5e790bce02b0d3ab9ef9))\r\n* **server:**\r\n  * add Response.send to write a sized body ([d5558b68](https://github.com/hyperium/hyper/commit/d5558b687d32d0affb9aaa7185227a4e294f5454), closes [#446](https://github.com/hyperium/hyper/issues/446))\r\n  * dropping a Response will write out to the underlying stream ([a9dcc59c](https://github.com/hyperium/hyper/commit/a9dcc59cd9846609a5733678f66353655c075279))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* Adds a variant to `hyper::Error`, which may break any\r\nexhaustive matches.\r\n\r\n ([972b3a38](https://github.com/hyperium/hyper/commit/972b3a388ac3af98ba038927c551b92be3a68d62))\r\n* The terms `Http` and `Error` have been removed from the Error\r\n  type and its variants. `HttpError` should now be accessed as `hyper::Error`,\r\n  and variants like `HttpIoError` should be accessed as `Error::Io`.\r\n\r\n ([9ba074d1](https://github.com/hyperium/hyper/commit/9ba074d150a55a749161317405fe8b28253c5a9d))\r\n* Add variant to Access-Control-Allow-Origin enum\r\n\r\n ([5e341714](https://github.com/hyperium/hyper/commit/5e3417145ced116147ef1e890b4f1e7c775ad173))\r\n* Upgrade header Protocol changed.\r\n\r\n ([f47d11b9](https://github.com/hyperium/hyper/commit/f47d11b97bb4a4bf67c3f9aa47c203babf4a9c72))\r\n* `from_one_raw_str()` returns `None` on empty values.\r\n\r\n ([a6974c99](https://github.com/hyperium/hyper/commit/a6974c99d39fcbaf3fb9ed38428b21e0301f3602))\r\n\r\n\r\n### v0.3.16 (2015-05-01)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **header:**\r\n  * make test_module of header! optional ([a5ce9c59](https://github.com/hyperium/hyper/commit/a5ce9c59fa61410551b07252364564a2bb13bb86), closes [#490](https://github.com/hyperium/hyper/issues/490))\r\n  * exporting test_header! macro ([2bc5a779](https://github.com/hyperium/hyper/commit/2bc5a779bdc3fce67e06c398ac8702fcbea93dab))\r\n* **http:** keep raw reason phrase in RawStatus ([8cdb9d5d](https://github.com/hyperium/hyper/commit/8cdb9d5d3b0972629e8843d3c1db58dbbbaf49cf), closes [#497](https://github.com/hyperium/hyper/issues/497))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** add a Connection Pool ([1e72a8ab](https://github.com/hyperium/hyper/commit/1e72a8ab3a0092bb863686ad2e65646710706c1b), closes [#363](https://github.com/hyperium/hyper/issues/363), [#41](https://github.com/hyperium/hyper/issues/41))\r\n* **headers:** Add If-Range header ([a39735f1](https://github.com/hyperium/hyper/commit/a39735f1d3d1a314969b5b0085e8f77f0c10c863), closes [#388](https://github.com/hyperium/hyper/issues/388))\r\n\r\n\r\n### v0.3.15 (2015-04-29)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **headers:**\r\n  * Do not parse empty values in list headers. ([093a29ba](https://github.com/hyperium/hyper/commit/093a29bab7eb27e78bb10506478ac486e8d61671))\r\n  * Fix formatting of 0 qualites and formatting of empty list header fields. ([621ef521](https://github.com/hyperium/hyper/commit/621ef521f6723ba2d59beff05ff39ae8fd6df2c3))\r\n\r\n\r\n#### Features\r\n\r\n* **client:**\r\n  * remove Clone requirement for NetworkStream in Client ([60d92c29](https://github.com/hyperium/hyper/commit/60d92c296a445b352679919c03c5ed2a2a297e16))\r\n  * accept &String as Body in RequestBuilder ([a2aefd9a](https://github.com/hyperium/hyper/commit/a2aefd9a5689d4816f7c054bd6c32aa5c6fe3087))\r\n  * accept &String for a Url in RequestBuilder ([8bc179fb](https://github.com/hyperium/hyper/commit/8bc179fb517735a7c1d5cd1d7f5598bb82914dc6))\r\n* **headers:** Implement Content-Language header field ([308880b4](https://github.com/hyperium/hyper/commit/308880b455df4dbb5d32817b5c0320c2a88139e3), closes [#475](https://github.com/hyperium/hyper/issues/475))\r\n* **net:** add https_using_context for user-supplied SslContext ([1a076d1b](https://github.com/hyperium/hyper/commit/1a076d1bc7e8fb9c58904b0cec879dcf0fbce97b))\r\n* **server:** allow consumer to supply an SslContext ([3a1a2427](https://github.com/hyperium/hyper/commit/3a1a24270dd13e22ef59120d66d327528949d5e0), closes [#471](https://github.com/hyperium/hyper/issues/471))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* This removes the trait `IntoBody`, and instead using\r\n  `Into<Body>`, as it's more idiomatic. This will only have broken code\r\n  that had custom implementations of `IntoBody`, and can be fixed by\r\n  changing them to `Into<Body>`.\r\n\r\n ([a2aefd9a](https://github.com/hyperium/hyper/commit/a2aefd9a5689d4816f7c054bd6c32aa5c6fe3087))\r\n\r\n\r\n### v0.3.14 (2015-04-18)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http:** Adjust httparse Request and Response lifetimes. ([76550fdb](https://github.com/hyperium/hyper/commit/76550fdb20bb812e92a1fc3f3a7eaaf4a689348b))\r\n\r\n\r\n### v0.3.13 (2015-04-17)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **server:** JoinHandle type parameter ([c694b138](https://github.com/hyperium/hyper/commit/c694b1385bd294e7c8e0398ee75e3a054ced5006))\r\n\r\n\r\n#### Features\r\n\r\n* **debug:** add Debug impls for StatusClass, Server, and Listening ([0fb92ee7](https://github.com/hyperium/hyper/commit/0fb92ee735136a07c832124df521b96a6779bd39))\r\n\r\n\r\n### v0.3.12 (2015-04-15)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **server:**\r\n  * handle keep-alive closing ([d9187713](https://github.com/hyperium/hyper/commit/d9187713b2eaa628eb34f68c8a7201a6cf8e010d), closes [#437](https://github.com/hyperium/hyper/issues/437))\r\n  * join on thread when Listening drops ([68d4d63c](https://github.com/hyperium/hyper/commit/68d4d63c2a0289b72ec1442d13e1212a0479c50b), closes [#447](https://github.com/hyperium/hyper/issues/447))\r\n  * Use thread::spawn instead of thread::scoped. ([e8649567](https://github.com/hyperium/hyper/commit/e864956734af72bab07a3e01c9665bc1b7c96e5e))\r\n\r\n\r\n#### Features\r\n\r\n* **http:** Implement Debug for HttpReader/Writer. ([2f606c88](https://github.com/hyperium/hyper/commit/2f606c88bd91e5e36dee4c6db00c3117b1adf067))\r\n* **log:** clean up logging ([4f09b002](https://github.com/hyperium/hyper/commit/4f09b002ffb2d076fc8fb01d9b9e0464216b2b41))\r\n* **net:** make HttpStream implement Debug ([7b7f9c25](https://github.com/hyperium/hyper/commit/7b7f9c257d0e2d515bf336c567f12a625471e477))\r\n\r\n\r\n### v0.3.11 (2015-04-15)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **headers:** Content-Encoding needs a hyphen. ([ca2815ef](https://github.com/hyperium/hyper/commit/ca2815effda2a5b27f781b7bc35105aa81121bae))\r\n\r\n\r\n#### Features\r\n\r\n* **client:** remove generic parameter for Connector ([139a51f1](https://github.com/hyperium/hyper/commit/139a51f1c31b80cdddf643e984bbbfbb3d3e8c96), closes [#379](https://github.com/hyperium/hyper/issues/379))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* `AccessControlAllowHeaders` and `AccessControlRequestHeaders` values\r\nare case insensitive now. `AccessControlAllowOrigin` variants are now `Any` and\r\n`Value` to match the other headers.\r\n\r\n ([94f38950](https://github.com/hyperium/hyper/commit/94f38950ddf9a97fdc4f44e42aada4ed8f4d9b43))\r\n* `If-Match`, `If-None-Match` and `Vary` item variant name changed to `Items`\r\n\r\n ([38d297b1](https://github.com/hyperium/hyper/commit/38d297b16e5d14d533947988f770f03b49d47a17))\r\n* `Etag` header field is now `ETag` header field\r\n\r\n ([4434ea6a](https://github.com/hyperium/hyper/commit/4434ea6a7d57d367c0a541c82f6289ffbda5fb6c))\r\n* For people using the default HttpConnector and Client,\r\n    everything should continue to just work. If the Client has been\r\n    used with a generic parameter, it should be removed.\r\n\r\n    However, there were some breaking changes to the internals of\r\n    NetworkConnectors. Specifically, they no longer return a\r\n    NetworkStream, but instead a Into<Box<NetworkStream + Send>>. All\r\n    implementations of NetworkStream should continue to just work,\r\n    however.\r\n\r\n    Possible breakages could come from the stricter usage of Send\r\n    throughout the Client API.\r\n\r\n ([139a51f1](https://github.com/hyperium/hyper/commit/139a51f1c31b80cdddf643e984bbbfbb3d3e8c96))\r\n\r\n\r\n### v0.3.10 (2015-04-06)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **README:** Update to compile example against Rust beta ([341f19d3](https://github.com/hyperium/hyper/commit/341f19d3266c6de9a9a90c94f718124792766630))\r\n\r\n\r\n### v0.3.9 (2015-04-03)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **headers:** Add CowStr as a temporary hack to build on beta. ([8e065563](https://github.com/hyperium/hyper/commit/8e0655637e80c5377c01da4dbca6fb627e6d4225))\r\n\r\n\r\n### v0.3.8 (2015-04-02)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **rustup:** update to rust beta ([0f5858f3](https://github.com/hyperium/hyper/commit/0f5858f37974731243d47710364776fdd73376fe))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* Removed impl_header!() and impl_list_header!() macros,\r\nuse new header!() macro.\r\n\r\n ([262c450f](https://github.com/hyperium/hyper/commit/262c450f908dbf27754daff0784f0f20145036dd))\r\n\r\n\r\n### v0.3.7 (2015-03-31)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **buffer:** zero out new capacity when buffer grows ([cfdabd70](https://github.com/hyperium/hyper/commit/cfdabd70ecc3f5290ae1e6f7e5dfd50310d8658d))\r\n\r\n\r\n#### Features\r\n\r\n* **entitytag:** Add EntityTag comparison, make EntityTag safe to use ([9c21f7f9](https://github.com/hyperium/hyper/commit/9c21f7f953a5163792e71fb186cab391c45d1bb4))\r\n\r\n\r\n### v0.3.6 (2015-03-30)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **buffer:** get_buf to not return consumed part of buffer ([04e3b565](https://github.com/hyperium/hyper/commit/04e3b5651561f087fee7c0345fe77d217d3ad35a), closes [#406](https://github.com/hyperium/hyper/issues/406))\r\n* **rustup:** get rid of slice pattern, add `Reflect` bounds ([c9f2c841](https://github.com/hyperium/hyper/commit/c9f2c841ff0e68dead38e762ed5f8c0f42255bc4))\r\n\r\n\r\n### v0.3.5 (2015-03-28)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **http:** read more before triggering TooLargeError ([cb59f609](https://github.com/hyperium/hyper/commit/cb59f609c61a097d5d9fa728b9df33d79922573b), closes [#389](https://github.com/hyperium/hyper/issues/389))\r\n\r\n\r\n### v0.3.4 (2015-03-26)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **rustup:** static bounds required on Type definition, trivial_casts ([eee7a85d](https://github.com/hyperium/hyper/commit/eee7a85d3c3a3f51a1c3c12496c0e45ea312524e))\r\n\r\n\r\n### v0.3.3 (2015-03-25)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **rustup:**\r\n  * rustc 1.0.0-nightly (123a754cb 2015-03-24) ([3e456f00](https://github.com/hyperium/hyper/commit/3e456f00f9991b1c723a232fc9c76fe8c0539858))\r\n  * 1.0.0-nightly (e2fa53e59 2015-03-20) ([f547080d](https://github.com/hyperium/hyper/commit/f547080df53076711b52a016b990c5be56f42ede))\r\n\r\n\r\n#### Features\r\n\r\n* **headers:** Implementing content-encoding header ([2983e8de](https://github.com/hyperium/hyper/commit/2983e8dea21f02a31012a25b0a302a128768030a), closes [#391](https://github.com/hyperium/hyper/issues/391))\r\n\r\n\r\n### v0.3.2 (2015-03-20)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **benches:** removed unused features ([104d4903](https://github.com/hyperium/hyper/commit/104d49036ff40c730ec8bef8012f19ccbee4aaae))\r\n* **rustup:**\r\n  * rustc 1.0.0-nightly (ea8b82e90) ([8181de25](https://github.com/hyperium/hyper/commit/8181de253aecfe81123e166a141ebfc8430ec4a4))\r\n  * adapt to current rustc ([1f0bc951](https://github.com/hyperium/hyper/commit/1f0bc951c9ee40cab622a72d614d4c45d889ccd3), closes [#381](https://github.com/hyperium/hyper/issues/381))\r\n\r\n\r\n#### Features\r\n\r\n* **server:** use SocketAddrs instead of Ipv4Addrs ([5d7be77e](https://github.com/hyperium/hyper/commit/5d7be77e4ac0d5c1d852c1208abc77a913c4f4d1))\r\n\r\n\r\n### v0.3.1 (2015-03-18)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **header:** Fix charset parsing bug. ([5a6e176f](https://github.com/hyperium/hyper/commit/5a6e176f50fe667fbdc4c933c81d2db5ba5c571d))\r\n* **headers:** Fix overflow with empty cookies ([99baaa10](https://github.com/hyperium/hyper/commit/99baaa10157f6c69ef1795a97e0db8bd794011f6))\r\n* **rustup:** update to latest rustc ([4fd8a6a9](https://github.com/hyperium/hyper/commit/4fd8a6a9dc0dc969b36f3d3ad51cee177545f883))\r\n\r\n\r\n#### Features\r\n\r\n* **server:** add Expect 100-continue support ([0b716943](https://github.com/hyperium/hyper/commit/0b7169432b5f51efe5c167be418c2c50220e46a5), closes [#369](https://github.com/hyperium/hyper/issues/369))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* Several public functions and types in the `http` module\r\n  have been removed. They have been replaced with 2 methods that handle\r\n  all of the http1 parsing.\r\n\r\n ([b87bb20f](https://github.com/hyperium/hyper/commit/b87bb20f0c25891c30ef2399da2721596fbc1fcf))\r\n\r\n\r\n## v0.3.0 (2015-03-03)\r\n\r\n\r\n#### Features\r\n\r\n* **headers:**\r\n  * add enum for Charset ([180d9a92](https://github.com/hyperium/hyper/commit/180d9a92d92541aa415c918a2265bd6b33d39655))\r\n  * add AcceptCharset header ([235089a1](https://github.com/hyperium/hyper/commit/235089a1034dc93ca62f47dcab0a93f1d49c72dd))\r\n  * add q function to ease creating Quality values ([d68773c7](https://github.com/hyperium/hyper/commit/d68773c79f998813bbd1bf50a0dbc2bc01ee0470))\r\n  * adds re-parsing ability when getting typed headers ([df756871](https://github.com/hyperium/hyper/commit/df756871edf4143135644c211106c5a8f8f5adb0))\r\n* **hyper:** switch to std::io, std::net, and std::path. ([0fd6fcd7](https://github.com/hyperium/hyper/commit/0fd6fcd7c7f30c4317678a3b0968cc08ae9c0a71), closes [#347](https://github.com/hyperium/hyper/issues/347))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* added requirement that all HeaderFormat implementations\r\n  must also be fmt::Debug. This likely as easy as slapping\r\n  #[derive(Debug)] on to any custom headers.\r\n\r\n ([df756871](https://github.com/hyperium/hyper/commit/df756871edf4143135644c211106c5a8f8f5adb0))\r\n* Check the docs. Everything was touched.\r\n\r\n ([0fd6fcd7](https://github.com/hyperium/hyper/commit/0fd6fcd7c7f30c4317678a3b0968cc08ae9c0a71))\r\n\r\n\r\n### v0.2.1 (2015-02-27)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **rustup:** str.split and associated type changes ([1b6e6a04](https://github.com/hyperium/hyper/commit/1b6e6a040fa26a8b3855ac46ccbcd5ee78065c71))\r\n\r\n\r\n#### Features\r\n\r\n* **headers:** add remove_raw method and corresponding test ([4f576780](https://github.com/hyperium/hyper/commit/4f576780c24ff3f943d5f821730ba65f4cdf8d4a), closes [#326](https://github.com/hyperium/hyper/issues/326))\r\n\r\n\r\n## v0.2.0 (2015-02-21)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **headers:** use $crate when referring to hyper modules on macros ([e246c3ac](https://github.com/hyperium/hyper/commit/e246c3ace8395cb5d281b841a416c503db1054ee), closes [#323](https://github.com/hyperium/hyper/issues/323))\r\n* **rustup:**\r\n  * Send changes ([4f5b97fe](https://github.com/hyperium/hyper/commit/4f5b97fefcea650214ca26c1aa197cd73683742f))\r\n  * CowString is gone ([98b8c4b1](https://github.com/hyperium/hyper/commit/98b8c4b13723d8fa1b4f1ba42a06bb533bf13694))\r\n  * Extend now takes an IntoIterator ([598d8f93](https://github.com/hyperium/hyper/commit/598d8f93e4a79dcc5ff58fbdc27e6b1a859786d1))\r\n  * Add PhantomData markers to phantom type users ([1904c456](https://github.com/hyperium/hyper/commit/1904c4561f00a345714beadfa077016306b2c05d))\r\n  * Remove uses of the obsolete &a[] syntax ([039e984f](https://github.com/hyperium/hyper/commit/039e984f6878d724d47f7e9fe7db765495ae2f10))\r\n  * Fix signature of IntoCow ([234fcdc3](https://github.com/hyperium/hyper/commit/234fcdc3a25deb06240848d601be9e68930a73e6))\r\n  * update feature flags ([b47f9365](https://github.com/hyperium/hyper/commit/b47f936525dde91b3456078ecf8d0c11917cc6b7))\r\n  * use module-level thread functions ([fc2076cd](https://github.com/hyperium/hyper/commit/fc2076cd53c37ea244a0b89d7dd4b1eb8aeeb1d3))\r\n  * update lifetime bounds ([f4a66b38](https://github.com/hyperium/hyper/commit/f4a66b38cb9e35bfec0bbc3c97e5298fc8ad8409))\r\n\r\n\r\n#### Features\r\n\r\n* **server:** make AcceptorPool::accept() block and allow non'-static data ([b0a72d80](https://github.com/hyperium/hyper/commit/b0a72d80d0e894220da6aa5ea29d71b278df596d))\r\n\r\n\r\n### v0.1.13 (2015-02-17)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **server:** Drain requests on drop. ([3d0f423e](https://github.com/hyperium/hyper/commit/3d0f423eb26c4f14aaf9f8a909b307f661a3c5d6), closes [#197](https://github.com/hyperium/hyper/issues/197), [#309](https://github.com/hyperium/hyper/issues/309))\r\n\r\n\r\n#### Features\r\n\r\n* **header:** Support arbitrary status codes ([73978531](https://github.com/hyperium/hyper/commit/7397853148b8221c0eb8315ae2e5f195ad2e642c))\r\n* **headers:**\r\n  * Implement PartialOrd for QualityItem ([2859d7ef](https://github.com/hyperium/hyper/commit/2859d7ef4ecadc3927fa46292ebbb225da597690), closes [#314](https://github.com/hyperium/hyper/issues/314))\r\n  * add AcceptLanguage header ([20a585e3](https://github.com/hyperium/hyper/commit/20a585e30bbb060a91839de7e95fd75a95d03d93))\r\n  * add IfMatch header ([5df06d44](https://github.com/hyperium/hyper/commit/5df06d4465fae01ef08b926f1f3be9f32a0f5c80))\r\n* **server:** Rewrite the accept loop into a custom thread pool. ([3528fb9b](https://github.com/hyperium/hyper/commit/3528fb9b015a0959268452d5b42d5544c7b98a6a))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* This removes unregistered status codes from the enum. Use\r\n`FromPrimitive` methods to create them now. StatusCode and StatusClass can no\r\nlonger be casted to `u16`, use `ToPrimitive` methods now.\r\nFor example `status.to_u16().unwrap()` to get the status code number.\r\n\r\n ([73978531](https://github.com/hyperium/hyper/commit/7397853148b8221c0eb8315ae2e5f195ad2e642c))\r\n\r\n\r\n### v0.1.12 (2015-02-13)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **net:** don't stop the server when an SSL handshake fails with EOF ([55f12660](https://github.com/hyperium/hyper/commit/55f12660891812d13a59e799b0ab5b185926479a))\r\n\r\n\r\n#### Features\r\n\r\n* **headers:** Add `If-None-Match` header field ([318b067a](https://github.com/hyperium/hyper/commit/318b067a06ecb42f0fba51928675d3b4291c7643), closes [#238](https://github.com/hyperium/hyper/issues/238))\r\n\r\n\r\n### v0.1.11 (2015-02-06)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **readme:** Make the README client example work ([9b5d6aab](https://github.com/hyperium/hyper/commit/9b5d6aab7e68cf776618151e9e69e34fd66aba6c))\r\n\r\n\r\n#### Features\r\n\r\n* **headers:** add IfUnmodifiedSince header ([b5543b67](https://github.com/hyperium/hyper/commit/b5543b67525e3d6ebc655d7e1736c8ade5b6dbb0))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* for any consumers of the Etag header, since the entity\r\ntag is now in a tuple.\r\n\r\n ([28fd5c81](https://github.com/hyperium/hyper/commit/28fd5c81f54bb0ea3eda43a4014c736d00b4b07d))\r\n\r\n\r\n### v0.1.10 (2015-02-03)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **headers:** add limit to maximum header size that should be parsed ([f18a8fb7](https://github.com/hyperium/hyper/commit/f18a8fb76f15f36dec329683abb66be203ab2e7e), closes [#256](https://github.com/hyperium/hyper/issues/256))\r\n* **rustup:**\r\n  * update FromStr ([742081c8](https://github.com/hyperium/hyper/commit/742081c8cfeeb59908a653316a6377d05ffaa55c))\r\n  * fix unused_feature warning in example server ([05a3a6b7](https://github.com/hyperium/hyper/commit/05a3a6b70badc28da33ff65e8c15003f87738e07))\r\n  * switch to unstable features ([3af8b687](https://github.com/hyperium/hyper/commit/3af8b687d4a6ef462eb74b1f5a1cbb8f191902fd))\r\n\r\n\r\n### v0.1.9 (2015-01-28)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **headers:** Don't display q if q=1 in quality item. ([91df2441](https://github.com/hyperium/hyper/commit/91df2441a0bb8c032b6fc5ccff50ed0eb98f2194), closes [#281](https://github.com/hyperium/hyper/issues/281))\r\n* **rustup:** update io import, Writer::write ([f606b603](https://github.com/hyperium/hyper/commit/f606b6039d15a0b6e46f5154a9c5482866497a0c))\r\n\r\n\r\n#### Features\r\n\r\n* **status:** add is_<status_class>() methods to StatusCodes ([2d55a22e](https://github.com/hyperium/hyper/commit/2d55a22e738fb7f37a271be4fc3cf2ebdb9b5345))\r\n\r\n\r\n### v0.1.8 (2015-01-27)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **headers:**\r\n  * make ConnectionHeader unicase ([e06e7d9a](https://github.com/hyperium/hyper/commit/e06e7d9a7ece9588b673b06df6aec4663595df30))\r\n  * make Protocol search websocket unicase ([65c70180](https://github.com/hyperium/hyper/commit/65c7018046eb556085ca47a28c980ec901980643))\r\n* **log:** update to new logging levels ([b002b6c3](https://github.com/hyperium/hyper/commit/b002b6c3f09775e5d6759bbd07dacdee318c2915))\r\n\r\n\r\n#### Features\r\n\r\n* **headers:** Add `Pragma` header field ([767c95d2](https://github.com/hyperium/hyper/commit/767c95d2b9709b496b35d0d691ff7a1f6d35cbed), closes [#237](https://github.com/hyperium/hyper/issues/237))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* Change header `Cookie` to `Cookie`\r\n\r\n ([92f43cf8](https://github.com/hyperium/hyper/commit/92f43cf873ddceca9518195af6dad1ff6ac79e11))\r\n\r\n\r\n### v0.1.7 (2015-01-27)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **rustup:** update to newest fmt trait names and slice syntax ([9e3c94d7](https://github.com/hyperium/hyper/commit/9e3c94d764522f900731fdbdee857639901037fe))\r\n\r\n\r\n#### Breaking Changes\r\n\r\n* Implementations of Header will need to adjust the\r\n    header_name method. It no longer takes any arguments.\r\n\r\n ([8215889e](https://github.com/hyperium/hyper/commit/8215889eda537d09da82a7ed12a1766bf4fd3bfe))\r\n\r\n\r\n### v0.1.6 (2015-01-27)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **headers:** make Schemes, Basic, Protocol public ([e43c35c1](https://github.com/hyperium/hyper/commit/e43c35c1ca86c0ff1278ccfe3d2cff43222627b2))\r\n\r\n\r\n### v0.1.5 (2015-01-27)\r\n\r\n\r\n### v0.1.4 (2015-01-27)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **imports:** Update TypeID import location to \"any\" ([dd2534a6](https://github.com/hyperium/hyper/commit/dd2534a6863f8b3940d2776e6b6a8e48988b9b88))\r\n\r\n\r\n### v0.1.3 (2015-01-27)\r\n\r\n\r\n#### Features\r\n\r\n* **server:** add a deconstruct method to Request. ([1014855f](https://github.com/hyperium/hyper/commit/1014855faec62ba00acdff6263c86e7dfa5fb047))\r\n\r\n\r\n### v0.1.2 (2015-01-27)\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **server:** Increase MAX_HEADER_FIELD_LENGTH to 4k ([54238b28](https://github.com/hyperium/hyper/commit/54238b28e4899e76bb3d7c2dfd8d9bc6fd489b6c))\r\n\r\n\r\n#### Features\r\n\r\n* **net:**\r\n  * Move SSL verification to unboxed closures ([bca9a53c](https://github.com/hyperium/hyper/commit/bca9a53c66c967affb8e245f26507494db39c35e))\r\n  * Allow more generic SSL verification () ([af577851](https://github.com/hyperium/hyper/commit/af5778510d1d8422fcb04873f7c726a67f15f5eb), closes [#244](https://github.com/hyperium/hyper/issues/244))\r\n\r\n\r\n### 0.1.1 (2015-01-13)\r\n\r\n#### Features\r\n\r\n* **server:**: Add TLS/SSL support serverside ([c6eef681](c6eef6812458e10de582530d7f2c5bce5156b73c), closes [#1](https://github.com/hyperium/hyper/issues/1))\r\n\r\n\r\n#### Bug Fixes\r\n\r\n* **headers:**\r\n    * fix fmt_header outputs of several headers ([aa266653](https://github.com/hyperium/hyper/commit/aa26665367bde895ce02ad2a8e1a372f00719852), closes [#246](https://github.com/hyperium/hyper/issues/246))\r\n    * don't use Show to write UserAgent header ([c8e334aa](https://github.com/hyperium/hyper/commit/c8e334aaebb5522a86d47f7e3c33836d2061cb65))\r\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Hyper\n\nYou want to contribute? You're awesome!\n\nContributions come in all shapes and sizes. Let's take a tour of some of the different wants you could contribute.\n\n## [Code of Conduct](./docs/CODE_OF_CONDUCT.md)\n\nFirstly, all interactions with the project need to abide by the code of conduct. This is to make sure everyone is treated kindly.\n\n## [Issues](./docs/ISSUES.md)\n\n- **Filing an issue** is a contribution. We appreciate you letting us know about bugs you've found, and any information that you can provide that we can use to make hyper better. Without your filing it, we may not be aware of the bug.\n- [Triaging issues](./docs/ISSUES.md#triaging) is a huge help. By your helping make issues better, the reporters can get answers sooner, and others can fix them with less effort. You can also volunteer as a frequent [triager](./docs/MAINTAINERS.md#triagers).\n- Discuss [feature requests][feat] (especially those marked [request-for-comment][b-rfc]).\n\n[feat]: https://github.com/hyperium/hyper/issues?q=is%3Aissue+is%3Aopen+label%3AC-feature\n[b-rfc]: https://github.com/hyperium/hyper/issues?q=is%3Aissue+is%3Aopen+label%3AB-rfc\n\n\n## [Pull Requests](./docs/PULL_REQUESTS.md)\n\nBy the way, consider checking the [list of easy issues](https://github.com/hyperium/hyper/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy) if you want to submit something.\n\n- [Submitting a Pull Request](./docs/PULL_REQUESTS.md#submitting-a-pull-request)\n- [Commit Guidelines](./docs/COMMITS.md)\n\n## Documentation\n\nImproving hyper's documentation is a huge help for everyone who is trying to _use_ hyper.\n\n- The API documentation (rendered at https://docs.rs/hyper) is stored as rustdoc comments directly in the source.\n- The main website has [tutorial-style guides](https://hyper.rs/guides). As of v1, they are currently in a [revamp](https://github.com/hyperium/hyper/issues/3411), and would greatly benefit from being filled out.\n\n## Help\n\nHelping others use hyper in their specific workflows is a very valuable way to contribute.\n\n- Answer questions asked directly in hyper's [Discussions](https://github.com/hyperium/hyper/discussions).\n- Join our [Discord](https://discord.gg/kkwpueZ) and help those who show up with questions.\n- **Blog about hyper.** You writing a blog post about how you use hyper to do something specific, or how you contributed a new feature, or debugged something in it, is a great idea. Not all examples can fit in the hyper repo. Search engines will help people find their use cases on your blog. And you can describe processes in more depth or from a different perspective.\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[package]\nname = \"hyper\"\nversion = \"1.8.1\"\ndescription = \"A protective and efficient HTTP library for all.\"\nreadme = \"README.md\"\nhomepage = \"https://hyper.rs\"\ndocumentation = \"https://docs.rs/hyper\"\nrepository = \"https://github.com/hyperium/hyper\"\nlicense = \"MIT\"\nauthors = [\"Sean McArthur <sean@seanmonstar.com>\"]\nkeywords = [\"http\", \"hyper\", \"hyperium\"]\ncategories = [\"network-programming\", \"web-programming::http-client\", \"web-programming::http-server\"]\nedition = \"2021\"\nrust-version = \"1.63\" # keep in sync with MSRV.md dev doc\n\ninclude = [\n  \"Cargo.toml\",\n  \"LICENSE\",\n  \"src/**/*\",\n]\n\n[dependencies]\nbytes = \"1.2\"\nhttp = \"1\"\nhttp-body = \"1\"\ntokio = { version = \"1\", features = [\"sync\"] }\n\n# Optional\n\natomic-waker = { version = \"1.1.2\", optional = true }\nfutures-channel = { version = \"0.3\", optional = true }\nfutures-core = { version = \"0.3.31\", optional = true }\nfutures-util = { version = \"0.3\", default-features = false, features = [\"alloc\"], optional = true }\nh2 = { version = \"0.4.2\", optional = true }\nhttp-body-util = { version = \"0.1\", optional = true }\nhttparse = { version = \"1.9\", optional = true }\nhttpdate = { version = \"1.0\", optional = true }\nitoa = { version = \"1\", optional = true }\npin-project-lite = { version = \"0.2.4\", optional = true }\nsmallvec = { version = \"1.12\", features = [\"const_generics\", \"const_new\"], optional = true }\ntracing = { version = \"0.1\", default-features = false, features = [\"std\"], optional = true }\nwant = { version = \"0.3\", optional = true }\n\n[dev-dependencies]\nform_urlencoded = \"1\"\nfutures-channel = { version = \"0.3\", features = [\"sink\"] }\nfutures-util = { version = \"0.3\", default-features = false, features = [\"alloc\", \"sink\"] }\nhttp-body-util = \"0.1\"\npretty_env_logger = \"0.5\"\npin-project-lite = \"0.2.4\"\nspmc = \"0.3\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nserde_json = \"1.0\"\ntokio = { version = \"1\", features = [\n    \"fs\",\n    \"macros\",\n    \"net\",\n    \"io-std\",\n    \"io-util\",\n    \"rt\",\n    \"rt-multi-thread\",\n    \"sync\",\n    \"time\",\n    \"test-util\",\n] }\ntokio-test = \"0.4\"\ntokio-util = \"0.7.10\"\n\n[features]\n# Nothing by default\ndefault = []\n\n# Easily turn it all on\nfull = [\n    \"client\",\n    \"http1\",\n    \"http2\",\n    \"server\",\n]\n\n# HTTP versions\nhttp1 = [\"dep:atomic-waker\", \"dep:futures-channel\", \"dep:futures-core\", \"dep:httparse\", \"dep:itoa\"]\nhttp2 = [\"dep:futures-channel\", \"dep:futures-core\", \"dep:h2\"]\n\n# Client/Server\nclient = [\"dep:want\", \"dep:pin-project-lite\", \"dep:smallvec\"]\nserver = [\"dep:httpdate\", \"dep:pin-project-lite\", \"dep:smallvec\"]\n\n# C-API support (currently unstable (no semver))\nffi = [\"dep:http-body-util\", \"dep:futures-util\"]\ncapi = []\n\n# Utilize tracing (currently unstable)\ntracing = [\"dep:tracing\"]\n\n# internal features used in CI\nnightly = []\n\n[lints.rust.unexpected_cfgs]\nlevel = \"warn\"\ncheck-cfg = [\n    'cfg(hyper_unstable_tracing)',\n    'cfg(hyper_unstable_ffi)'\n]\n\n[package.metadata.docs.rs]\nfeatures = [\"ffi\", \"full\", \"tracing\"]\nrustdoc-args = [\"--cfg\", \"hyper_unstable_ffi\", \"--cfg\", \"hyper_unstable_tracing\"]\n\n[package.metadata.playground]\nfeatures = [\"full\"]\n\n[package.metadata.capi.header]\ngeneration = false\nsubdirectory = false\n\n[package.metadata.capi.install.include]\nasset = [{ from=\"capi/include/hyper.h\" }]\n\n[profile.release]\ncodegen-units = 1\nincremental = false\n\n[profile.bench]\ncodegen-units = 1\nincremental = false\n\n[[example]]\nname = \"client\"\npath = \"examples/client.rs\"\nrequired-features = [\"full\"]\n\n[[example]]\nname = \"client_json\"\npath = \"examples/client_json.rs\"\nrequired-features = [\"full\"]\n\n[[example]]\nname = \"echo\"\npath = \"examples/echo.rs\"\nrequired-features = [\"full\"]\n\n[[example]]\nname = \"gateway\"\npath = \"examples/gateway.rs\"\nrequired-features = [\"full\"]\n\n[[example]]\nname = \"graceful_shutdown\"\npath = \"examples/graceful_shutdown.rs\"\nrequired-features = [\"full\"]\n\n[[example]]\nname = \"hello\"\npath = \"examples/hello.rs\"\nrequired-features = [\"full\"]\n\n[[example]]\nname = \"http_proxy\"\npath = \"examples/http_proxy.rs\"\nrequired-features = [\"full\"]\n\n[[example]]\nname = \"multi_server\"\npath = \"examples/multi_server.rs\"\nrequired-features = [\"full\"]\n\n[[example]]\nname = \"params\"\npath = \"examples/params.rs\"\nrequired-features = [\"full\"]\n\n[[example]]\nname = \"send_file\"\npath = \"examples/send_file.rs\"\nrequired-features = [\"full\"]\n\n[[example]]\nname = \"service_struct_impl\"\npath = \"examples/service_struct_impl.rs\"\nrequired-features = [\"full\"]\n\n[[example]]\nname = \"single_threaded\"\npath = \"examples/single_threaded.rs\"\nrequired-features = [\"full\"]\n\n[[example]]\nname = \"state\"\npath = \"examples/state.rs\"\nrequired-features = [\"full\"]\n\n[[example]]\nname = \"upgrades\"\npath = \"examples/upgrades.rs\"\nrequired-features = [\"full\"]\n\n\n[[example]]\nname = \"web_api\"\npath = \"examples/web_api.rs\"\nrequired-features = [\"full\"]\n\n\n[[bench]]\nname = \"body\"\npath = \"benches/body.rs\"\nrequired-features = [\"full\"]\n\n[[bench]]\nname = \"connect\"\npath = \"benches/connect.rs\"\nrequired-features = [\"full\"]\n\n[[bench]]\nname = \"end_to_end\"\npath = \"benches/end_to_end.rs\"\nrequired-features = [\"full\"]\n\n[[bench]]\nname = \"pipeline\"\npath = \"benches/pipeline.rs\"\nrequired-features = [\"full\"]\n\n[[bench]]\nname = \"server\"\npath = \"benches/server.rs\"\nrequired-features = [\"full\"]\n\n\n[[test]]\nname = \"client\"\npath = \"tests/client.rs\"\nrequired-features = [\"full\"]\n\n[[test]]\nname = \"integration\"\npath = \"tests/integration.rs\"\nrequired-features = [\"full\"]\n\n[[test]]\nname = \"server\"\npath = \"tests/server.rs\"\nrequired-features = [\"full\"]\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2014-2026 Sean McArthur\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# [hyper](https://hyper.rs)\n\n[![crates.io](https://img.shields.io/crates/v/hyper.svg)](https://crates.io/crates/hyper)\n[![Released API docs](https://docs.rs/hyper/badge.svg)](https://docs.rs/hyper)\n[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)\n[![CI](https://github.com/hyperium/hyper/workflows/CI/badge.svg)](https://github.com/hyperium/hyper/actions?query=workflow%3ACI)\n[![Discord chat][discord-badge]][discord-url]\n\nA protective and efficient HTTP library for all.\n\n- HTTP/1 and HTTP/2\n- Asynchronous design\n- Leading in performance\n- Tested and **correct**\n- Extensive production use\n- Client and Server APIs\n\n**Get started** by looking over the [guides](https://hyper.rs/guides/1/).\n\n## \"Low-level\"\n\nhyper is a relatively low-level library, meant to be a building block for\nlibraries and applications.\n\nIf you are looking for a convenient HTTP client, then you may wish to consider\n[reqwest](https://github.com/seanmonstar/reqwest).\n\nIf you are not sure what HTTP server to choose, then you may want to consider\n[axum](https://github.com/tokio-rs/axum) or\n[warp](https://github.com/seanmonstar/warp), the latter taking a more functional\napproach. Both are built on top of this library.\n\n## Contributing\n\nTo get involved, take a look at [CONTRIBUTING](CONTRIBUTING.md).\n\nIf you prefer chatting, there is an active community in the [Discord server][discord-url].\n\n## License\n\nhyper is provided under the MIT license. See [LICENSE](LICENSE).\n\n[discord-badge]: https://img.shields.io/discord/500028886025895936.svg?logo=discord\n[discord-url]: https://discord.gg/kkwpueZ\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\nhyper (and related projects in hyperium) take security seriously, and greatly appreciate responsibile disclosure.\n\n## Report a security issue\n\nTo report a security issue in hyper, or another crate in the hyperium organization, please [report a new draft GitHub Security Advisory](https://github.com/hyperium/hyper/security/advisories/new).\n\nWe will discuss it privately with you. hyper maintainers will determine the impact and release details. Participation in security issue coordination is at the discretion of hyper maintainers.\n\n## Transparency\n\nWe are committed to transparency in the security issue disclosure process. Advisories will be disclosed publicly once a patch is released, and if appropriate, added to the RustSec advisory database.\n"
  },
  {
    "path": "benches/body.rs",
    "content": "#![feature(test)]\n#![deny(warnings)]\n\nextern crate test;\n\nuse bytes::Buf;\nuse futures_util::stream;\nuse futures_util::StreamExt;\nuse http_body::Frame;\nuse http_body_util::{BodyExt, StreamBody};\n\nmacro_rules! bench_stream {\n    ($bencher:ident, bytes: $bytes:expr, count: $count:expr, $total_ident:ident, $body_pat:pat, $block:expr) => {{\n        let rt = tokio::runtime::Builder::new_current_thread()\n            .build()\n            .expect(\"rt build\");\n\n        let $total_ident: usize = $bytes * $count;\n        $bencher.bytes = $total_ident as u64;\n        let __s: &'static [&'static [u8]] = &[&[b'x'; $bytes] as &[u8]; $count] as _;\n\n        $bencher.iter(|| {\n            rt.block_on(async {\n                let $body_pat = StreamBody::new(\n                    stream::iter(__s.iter())\n                        .map(|&s| Ok::<_, std::convert::Infallible>(Frame::data(s))),\n                );\n\n                $block;\n            });\n        });\n    }};\n}\n\nmacro_rules! benches {\n    ($($name:ident, $bytes:expr, $count:expr;)+) => (\n        mod aggregate {\n            use super::*;\n\n            $(\n            #[bench]\n            fn $name(b: &mut test::Bencher) {\n                bench_stream!(b, bytes: $bytes, count: $count, total, body, {\n                    let buf = BodyExt::collect(body).await.unwrap().aggregate();\n                    assert_eq!(buf.remaining(), total);\n                });\n            }\n            )+\n        }\n\n        mod manual_into_vec {\n            use super::*;\n\n            $(\n            #[bench]\n            fn $name(b: &mut test::Bencher) {\n                bench_stream!(b, bytes: $bytes, count: $count, total, mut body, {\n                    let mut vec = Vec::new();\n                    while let Some(chunk) = body.next().await {\n                        vec.extend_from_slice(&chunk.unwrap().into_data().unwrap());\n                    }\n                    assert_eq!(vec.len(), total);\n                });\n            }\n            )+\n        }\n\n        mod to_bytes {\n            use super::*;\n\n            $(\n            #[bench]\n            fn $name(b: &mut test::Bencher) {\n                bench_stream!(b, bytes: $bytes, count: $count, total, body, {\n                    let bytes = BodyExt::collect(body).await.unwrap().to_bytes();\n                    assert_eq!(bytes.len(), total);\n                });\n            }\n            )+\n        }\n    )\n}\n\n// ===== Actual Benchmarks =====\n\nbenches! {\n    bytes_1_000_count_2, 1_000, 2;\n    bytes_1_000_count_10, 1_000, 10;\n    bytes_10_000_count_1, 10_000, 1;\n    bytes_10_000_count_10, 10_000, 10;\n}\n"
  },
  {
    "path": "benches/connect.rs",
    "content": "#![feature(test)]\n#![deny(warnings)]\n\nextern crate test;\n\n// TODO: Reimplement http_connector bench using hyper::client::conn\n// (instead of removed HttpConnector).\n\n// use http::Uri;\n// use hyper::client::connect::HttpConnector;\n// use hyper::service::Service;\n// use std::net::SocketAddr;\n// use tokio::net::TcpListener;\n\n// #[bench]\n// fn http_connector(b: &mut test::Bencher) {\n//     let _ = pretty_env_logger::try_init();\n//     let rt = tokio::runtime::Builder::new_current_thread()\n//         .enable_all()\n//         .build()\n//         .expect(\"rt build\");\n//     let listener = rt\n//         .block_on(TcpListener::bind(&SocketAddr::from(([127, 0, 0, 1], 0))))\n//         .expect(\"bind\");\n//     let addr = listener.local_addr().expect(\"local_addr\");\n//     let dst: Uri = format!(\"http://{}/\", addr).parse().expect(\"uri parse\");\n//     let mut connector = HttpConnector::new();\n\n//     rt.spawn(async move {\n//         loop {\n//             let _ = listener.accept().await;\n//         }\n//     });\n\n//     b.iter(|| {\n//         rt.block_on(async {\n//             connector.call(dst.clone()).await.expect(\"connect\");\n//         });\n//     });\n// }\n"
  },
  {
    "path": "benches/end_to_end.rs",
    "content": "#![feature(test)]\n#![deny(warnings)]\n\nextern crate test;\nmod support;\n\n// TODO: Reimplement parallel for HTTP/1\n\nuse std::convert::Infallible;\nuse std::net::SocketAddr;\n\nuse futures_util::future::join_all;\n\nuse http_body_util::BodyExt;\nuse hyper::{Method, Request, Response};\n\ntype BoxedBody = http_body_util::combinators::BoxBody<bytes::Bytes, Infallible>;\n\n// HTTP1\n\n#[bench]\nfn http1_consecutive_x1_empty(b: &mut test::Bencher) {\n    opts().bench(b)\n}\n\n#[bench]\nfn http1_consecutive_x1_req_10b(b: &mut test::Bencher) {\n    opts()\n        .method(Method::POST)\n        .request_body(&[b's'; 10])\n        .bench(b)\n}\n\n#[bench]\nfn http1_consecutive_x1_both_100kb(b: &mut test::Bencher) {\n    let body = &[b'x'; 1024 * 100];\n    opts()\n        .method(Method::POST)\n        .request_body(body)\n        .response_body(body)\n        .bench(b)\n}\n\n#[bench]\nfn http1_consecutive_x1_both_10mb(b: &mut test::Bencher) {\n    let body = &[b'x'; 1024 * 1024 * 10];\n    opts()\n        .method(Method::POST)\n        .request_body(body)\n        .response_body(body)\n        .bench(b)\n}\n\n#[bench]\n#[ignore]\nfn http1_parallel_x10_empty(b: &mut test::Bencher) {\n    opts().parallel(10).bench(b)\n}\n\n#[bench]\n#[ignore]\nfn http1_parallel_x10_req_10mb(b: &mut test::Bencher) {\n    let body = &[b'x'; 1024 * 1024 * 10];\n    opts()\n        .parallel(10)\n        .method(Method::POST)\n        .request_body(body)\n        .bench(b)\n}\n\n#[bench]\n#[ignore]\nfn http1_parallel_x10_req_10kb_100_chunks(b: &mut test::Bencher) {\n    let body = &[b'x'; 1024 * 10];\n    opts()\n        .parallel(10)\n        .method(Method::POST)\n        .request_chunks(body, 100)\n        .bench(b)\n}\n\n#[bench]\n#[ignore]\nfn http1_parallel_x10_res_1mb(b: &mut test::Bencher) {\n    let body = &[b'x'; 1024 * 1024];\n    opts().parallel(10).response_body(body).bench(b)\n}\n\n#[bench]\n#[ignore]\nfn http1_parallel_x10_res_10mb(b: &mut test::Bencher) {\n    let body = &[b'x'; 1024 * 1024 * 10];\n    opts().parallel(10).response_body(body).bench(b)\n}\n\n// HTTP2\n\nconst HTTP2_MAX_WINDOW: u32 = std::u32::MAX >> 1;\n\n#[bench]\nfn http2_consecutive_x1_empty(b: &mut test::Bencher) {\n    opts().http2().bench(b)\n}\n\n#[bench]\nfn http2_consecutive_x1_req_10b(b: &mut test::Bencher) {\n    opts()\n        .http2()\n        .method(Method::POST)\n        .request_body(&[b's'; 10])\n        .bench(b)\n}\n\n#[bench]\nfn http2_consecutive_x1_req_100kb(b: &mut test::Bencher) {\n    let body = &[b'x'; 1024 * 100];\n    opts()\n        .http2()\n        .method(Method::POST)\n        .request_body(body)\n        .bench(b)\n}\n\n#[bench]\nfn http2_parallel_x10_empty(b: &mut test::Bencher) {\n    opts().http2().parallel(10).bench(b)\n}\n\n#[bench]\nfn http2_parallel_x10_req_10mb(b: &mut test::Bencher) {\n    let body = &[b'x'; 1024 * 1024 * 10];\n    opts()\n        .http2()\n        .parallel(10)\n        .method(Method::POST)\n        .request_body(body)\n        .http2_stream_window(HTTP2_MAX_WINDOW)\n        .http2_conn_window(HTTP2_MAX_WINDOW)\n        .bench(b)\n}\n\n#[bench]\nfn http2_parallel_x10_req_10kb_100_chunks(b: &mut test::Bencher) {\n    let body = &[b'x'; 1024 * 10];\n    opts()\n        .http2()\n        .parallel(10)\n        .method(Method::POST)\n        .request_chunks(body, 100)\n        .bench(b)\n}\n\n#[bench]\nfn http2_parallel_x10_req_10kb_100_chunks_adaptive_window(b: &mut test::Bencher) {\n    let body = &[b'x'; 1024 * 10];\n    opts()\n        .http2()\n        .parallel(10)\n        .method(Method::POST)\n        .request_chunks(body, 100)\n        .http2_adaptive_window()\n        .bench(b)\n}\n\n#[bench]\nfn http2_parallel_x10_req_10kb_100_chunks_max_window(b: &mut test::Bencher) {\n    let body = &[b'x'; 1024 * 10];\n    opts()\n        .http2()\n        .parallel(10)\n        .method(Method::POST)\n        .request_chunks(body, 100)\n        .http2_stream_window(HTTP2_MAX_WINDOW)\n        .http2_conn_window(HTTP2_MAX_WINDOW)\n        .bench(b)\n}\n\n#[bench]\nfn http2_parallel_x10_res_1mb(b: &mut test::Bencher) {\n    let body = &[b'x'; 1024 * 1024];\n    opts()\n        .http2()\n        .parallel(10)\n        .response_body(body)\n        .http2_stream_window(HTTP2_MAX_WINDOW)\n        .http2_conn_window(HTTP2_MAX_WINDOW)\n        .bench(b)\n}\n\n#[bench]\nfn http2_parallel_x10_res_10mb(b: &mut test::Bencher) {\n    let body = &[b'x'; 1024 * 1024 * 10];\n    opts()\n        .http2()\n        .parallel(10)\n        .response_body(body)\n        .http2_stream_window(HTTP2_MAX_WINDOW)\n        .http2_conn_window(HTTP2_MAX_WINDOW)\n        .bench(b)\n}\n\n// ==== Benchmark Options =====\n\n#[derive(Clone)]\nstruct Opts {\n    http2: bool,\n    http2_stream_window: Option<u32>,\n    http2_conn_window: Option<u32>,\n    http2_adaptive_window: bool,\n    parallel_cnt: u32,\n    request_method: Method,\n    request_body: Option<&'static [u8]>,\n    request_chunks: usize,\n    response_body: &'static [u8],\n}\n\nfn opts() -> Opts {\n    Opts {\n        http2: false,\n        http2_stream_window: None,\n        http2_conn_window: None,\n        http2_adaptive_window: false,\n        parallel_cnt: 1,\n        request_method: Method::GET,\n        request_body: None,\n        request_chunks: 0,\n        response_body: b\"\",\n    }\n}\n\nimpl Opts {\n    fn http2(mut self) -> Self {\n        self.http2 = true;\n        self\n    }\n\n    fn http2_stream_window(mut self, sz: impl Into<Option<u32>>) -> Self {\n        assert!(!self.http2_adaptive_window);\n        self.http2_stream_window = sz.into();\n        self\n    }\n\n    fn http2_conn_window(mut self, sz: impl Into<Option<u32>>) -> Self {\n        assert!(!self.http2_adaptive_window);\n        self.http2_conn_window = sz.into();\n        self\n    }\n\n    fn http2_adaptive_window(mut self) -> Self {\n        assert!(self.http2_stream_window.is_none());\n        assert!(self.http2_conn_window.is_none());\n        self.http2_adaptive_window = true;\n        self\n    }\n\n    fn method(mut self, m: Method) -> Self {\n        self.request_method = m;\n        self\n    }\n\n    fn request_body(mut self, body: &'static [u8]) -> Self {\n        self.request_body = Some(body);\n        self\n    }\n\n    fn request_chunks(mut self, chunk: &'static [u8], cnt: usize) -> Self {\n        assert!(cnt > 0);\n        self.request_body = Some(chunk);\n        self.request_chunks = cnt;\n        self\n    }\n\n    fn response_body(mut self, body: &'static [u8]) -> Self {\n        self.response_body = body;\n        self\n    }\n\n    fn parallel(mut self, cnt: u32) -> Self {\n        assert!(cnt > 0, \"parallel count must be larger than 0\");\n        self.parallel_cnt = cnt;\n        self\n    }\n\n    fn bench(self, b: &mut test::Bencher) {\n        use std::sync::Arc;\n        let _ = pretty_env_logger::try_init();\n        // Create a runtime of current thread.\n        let rt = Arc::new(\n            tokio::runtime::Builder::new_current_thread()\n                .enable_all()\n                .build()\n                .expect(\"rt build\"),\n        );\n        let exec = rt.clone();\n\n        let req_len = self.request_body.map(|b| b.len()).unwrap_or(0) as u64;\n        let req_len = if self.request_chunks > 0 {\n            req_len * self.request_chunks as u64\n        } else {\n            req_len\n        };\n        let bytes_per_iter = (req_len + self.response_body.len() as u64) * self.parallel_cnt as u64;\n        b.bytes = bytes_per_iter;\n\n        let addr = spawn_server(&rt, &self);\n\n        enum Client {\n            Http1(hyper::client::conn::http1::SendRequest<BoxedBody>),\n            Http2(hyper::client::conn::http2::SendRequest<BoxedBody>),\n        }\n\n        let mut client = rt.block_on(async {\n            if self.http2 {\n                let tcp = tokio::net::TcpStream::connect(&addr).await.unwrap();\n                let io = support::TokioIo::new(tcp);\n                let (tx, conn) = hyper::client::conn::http2::Builder::new(support::TokioExecutor)\n                    .initial_stream_window_size(self.http2_stream_window)\n                    .initial_connection_window_size(self.http2_conn_window)\n                    .adaptive_window(self.http2_adaptive_window)\n                    .handshake(io)\n                    .await\n                    .unwrap();\n                tokio::spawn(conn);\n                Client::Http2(tx)\n            } else if self.parallel_cnt > 1 {\n                todo!(\"http/1 parallel >1\");\n            } else {\n                let tcp = tokio::net::TcpStream::connect(&addr).await.unwrap();\n                let io = support::TokioIo::new(tcp);\n                let (tx, conn) = hyper::client::conn::http1::Builder::new()\n                    .handshake(io)\n                    .await\n                    .unwrap();\n                tokio::spawn(conn);\n                Client::Http1(tx)\n            }\n        });\n\n        let url: hyper::Uri = format!(\"http://{}/hello\", addr).parse().unwrap();\n\n        let make_request = || {\n            let chunk_cnt = self.request_chunks;\n            let body = if chunk_cnt > 0 {\n                let (mut tx, rx) = futures_channel::mpsc::channel(0);\n\n                let chunk = self\n                    .request_body\n                    .expect(\"request_chunks means request_body\");\n                exec.spawn(async move {\n                    use futures_util::SinkExt;\n                    use hyper::body::Frame;\n                    for _ in 0..chunk_cnt {\n                        tx.send(Ok(Frame::data(bytes::Bytes::from(chunk))))\n                            .await\n                            .expect(\"send_data\");\n                    }\n                });\n                http_body_util::StreamBody::new(rx).boxed()\n            } else if let Some(chunk) = self.request_body {\n                http_body_util::Full::new(bytes::Bytes::from(chunk)).boxed()\n            } else {\n                http_body_util::Empty::new().boxed()\n            };\n            let mut req = Request::new(body);\n            *req.method_mut() = self.request_method.clone();\n            *req.uri_mut() = url.clone();\n            req\n        };\n\n        let mut send_request = |req| {\n            let fut = match client {\n                Client::Http1(ref mut tx) => {\n                    futures_util::future::Either::Left(tx.send_request(req))\n                }\n                Client::Http2(ref mut tx) => {\n                    futures_util::future::Either::Right(tx.send_request(req))\n                }\n            };\n            async {\n                let res = fut.await.expect(\"client wait\");\n                let mut body = res.into_body();\n                while let Some(_chunk) = body.frame().await {}\n            }\n        };\n\n        if self.parallel_cnt == 1 {\n            b.iter(|| {\n                let req = make_request();\n                rt.block_on(send_request(req));\n            });\n        } else {\n            b.iter(|| {\n                let futs = (0..self.parallel_cnt).map(|_| {\n                    let req = make_request();\n                    send_request(req)\n                });\n                // Await all spawned futures becoming completed.\n                rt.block_on(join_all(futs));\n            });\n        }\n    }\n}\n\nfn spawn_server(rt: &tokio::runtime::Runtime, opts: &Opts) -> SocketAddr {\n    use http_body_util::Full;\n    use hyper::service::service_fn;\n    use tokio::net::TcpListener;\n    let addr = \"127.0.0.1:0\".parse::<std::net::SocketAddr>().unwrap();\n\n    let listener = rt.block_on(async { TcpListener::bind(&addr).await.unwrap() });\n\n    let addr = listener.local_addr().unwrap();\n    let body = opts.response_body;\n    let opts = opts.clone();\n    rt.spawn(async move {\n        let _ = &opts;\n        while let Ok((sock, _)) = listener.accept().await {\n            let io = support::TokioIo::new(sock);\n            if opts.http2 {\n                tokio::spawn(\n                    hyper::server::conn::http2::Builder::new(support::TokioExecutor)\n                        .initial_stream_window_size(opts.http2_stream_window)\n                        .initial_connection_window_size(opts.http2_conn_window)\n                        .adaptive_window(opts.http2_adaptive_window)\n                        .serve_connection(\n                            io,\n                            service_fn(move |req: Request<hyper::body::Incoming>| async move {\n                                let mut req_body = req.into_body();\n                                while let Some(_chunk) = req_body.frame().await {}\n                                Ok::<_, std::convert::Infallible>(Response::new(\n                                    Full::<bytes::Bytes>::from(body),\n                                ))\n                            }),\n                        ),\n                );\n            } else {\n                tokio::spawn(hyper::server::conn::http1::Builder::new().serve_connection(\n                    io,\n                    service_fn(move |req: Request<hyper::body::Incoming>| async move {\n                        let mut req_body = req.into_body();\n                        while let Some(_chunk) = req_body.frame().await {}\n                        Ok::<_, std::convert::Infallible>(Response::new(\n                            Full::<bytes::Bytes>::from(body),\n                        ))\n                    }),\n                ));\n            }\n        }\n    });\n    addr\n}\n"
  },
  {
    "path": "benches/pipeline.rs",
    "content": "#![feature(test)]\n#![deny(warnings)]\n\nextern crate test;\n\nmod support;\n\nuse std::convert::Infallible;\nuse std::io::{Read, Write};\nuse std::net::{SocketAddr, TcpStream};\nuse std::sync::mpsc;\nuse std::time::Duration;\n\nuse bytes::Bytes;\nuse http_body_util::Full;\nuse tokio::net::TcpListener;\nuse tokio::sync::oneshot;\n\nuse hyper::server::conn::http1;\nuse hyper::service::service_fn;\nuse hyper::Response;\n\nconst PIPELINED_REQUESTS: usize = 16;\n\n#[bench]\nfn hello_world_16(b: &mut test::Bencher) {\n    let _ = pretty_env_logger::try_init();\n    let (_until_tx, until_rx) = oneshot::channel::<()>();\n\n    let addr = {\n        let (addr_tx, addr_rx) = mpsc::channel();\n        std::thread::spawn(move || {\n            let addr: SocketAddr = \"127.0.0.1:0\".parse().unwrap();\n            let rt = tokio::runtime::Builder::new_current_thread()\n                .enable_all()\n                .build()\n                .expect(\"rt build\");\n\n            let listener = rt.block_on(TcpListener::bind(addr)).unwrap();\n            let addr = listener.local_addr().unwrap();\n\n            rt.spawn(async move {\n                loop {\n                    let (stream, _addr) = listener.accept().await.expect(\"accept\");\n                    let io = support::TokioIo::new(stream);\n\n                    http1::Builder::new()\n                        .pipeline_flush(true)\n                        .serve_connection(\n                            io,\n                            service_fn(|_| async {\n                                Ok::<_, Infallible>(Response::new(Full::new(Bytes::from(\n                                    \"Hello, World!\",\n                                ))))\n                            }),\n                        )\n                        .await\n                        .unwrap();\n                }\n            });\n\n            addr_tx.send(addr).unwrap();\n            rt.block_on(until_rx).ok();\n        });\n\n        addr_rx.recv().unwrap()\n    };\n\n    let mut pipelined_reqs = Vec::new();\n    for _ in 0..PIPELINED_REQUESTS {\n        pipelined_reqs.extend_from_slice(b\"GET / HTTP/1.1\\r\\nHost: localhost\\r\\n\\r\\n\");\n    }\n\n    let total_bytes = {\n        let mut tcp = TcpStream::connect(addr).unwrap();\n        tcp.write_all(b\"GET / HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n\")\n            .unwrap();\n        let mut buf = Vec::new();\n        tcp.read_to_end(&mut buf).unwrap() - \"connection: close\\r\\n\".len()\n    } * PIPELINED_REQUESTS;\n\n    let mut tcp = TcpStream::connect(addr).unwrap();\n    tcp.set_read_timeout(Some(Duration::from_secs(3))).unwrap();\n    let mut buf = [0u8; 8192];\n\n    b.bytes = (pipelined_reqs.len() + total_bytes) as u64;\n    b.iter(|| {\n        tcp.write_all(&pipelined_reqs).unwrap();\n        let mut sum = 0;\n        while sum < total_bytes {\n            sum += tcp.read(&mut buf).unwrap();\n        }\n        assert_eq!(sum, total_bytes);\n    });\n}\n"
  },
  {
    "path": "benches/server.rs",
    "content": "#![feature(test)]\n#![deny(warnings)]\n\nextern crate test;\n\nmod support;\n\nuse std::io::{Read, Write};\nuse std::net::{SocketAddr, TcpListener, TcpStream};\nuse std::sync::mpsc;\nuse std::time::Duration;\n\nuse bytes::Bytes;\nuse futures_util::{stream, StreamExt};\nuse http_body_util::{BodyExt, Full, StreamBody};\nuse tokio::sync::oneshot;\n\nuse hyper::body::Frame;\nuse hyper::server::conn::http1;\nuse hyper::service::service_fn;\nuse hyper::Response;\n\nmacro_rules! bench_server {\n    ($b:ident, $header:expr, $body:expr) => {{\n        let _ = pretty_env_logger::try_init();\n        let (_until_tx, until_rx) = oneshot::channel::<()>();\n\n        let addr = {\n            let (addr_tx, addr_rx) = mpsc::channel();\n            std::thread::spawn(move || {\n                let addr: SocketAddr = \"127.0.0.1:0\".parse().unwrap();\n                let rt = tokio::runtime::Builder::new_current_thread()\n                    .enable_all()\n                    .build()\n                    .expect(\"rt build\");\n\n                let listener = rt.block_on(tokio::net::TcpListener::bind(addr)).unwrap();\n                let addr = listener.local_addr().unwrap();\n\n                rt.spawn(async move {\n                    loop {\n                        let (stream, _) = listener.accept().await.expect(\"accept\");\n                        let io = support::TokioIo::new(stream);\n\n                        http1::Builder::new()\n                            .serve_connection(\n                                io,\n                                service_fn(|_| async {\n                                    Ok::<_, hyper::Error>(\n                                        Response::builder()\n                                            .header($header.0, $header.1)\n                                            .header(\"content-type\", \"text/plain\")\n                                            .body($body())\n                                            .unwrap(),\n                                    )\n                                }),\n                            )\n                            .await\n                            .unwrap();\n                    }\n                });\n\n                addr_tx.send(addr).unwrap();\n                rt.block_on(until_rx).ok();\n            });\n\n            addr_rx.recv().unwrap()\n        };\n\n        let total_bytes = {\n            let mut tcp = TcpStream::connect(addr).unwrap();\n            tcp.write_all(b\"GET / HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n\")\n                .unwrap();\n            let mut buf = Vec::new();\n            tcp.read_to_end(&mut buf).unwrap() - \"connection: close\\r\\n\".len()\n        };\n\n        let mut tcp = TcpStream::connect(addr).unwrap();\n        tcp.set_read_timeout(Some(Duration::from_secs(3))).unwrap();\n        let mut buf = [0u8; 8192];\n\n        $b.bytes = 35 + total_bytes as u64;\n        $b.iter(|| {\n            tcp.write_all(b\"GET / HTTP/1.1\\r\\nHost: localhost\\r\\n\\r\\n\")\n                .unwrap();\n            let mut sum = 0;\n            while sum < total_bytes {\n                sum += tcp.read(&mut buf).unwrap();\n            }\n            assert_eq!(sum, total_bytes);\n        });\n    }};\n}\n\nfn body(b: &'static [u8]) -> Full<Bytes> {\n    Full::new(b.into())\n}\n\n#[bench]\nfn throughput_fixedsize_small_payload(b: &mut test::Bencher) {\n    bench_server!(b, (\"content-length\", \"13\"), || body(b\"Hello, World!\"))\n}\n\n#[bench]\nfn throughput_fixedsize_large_payload(b: &mut test::Bencher) {\n    bench_server!(b, (\"content-length\", \"1000000\"), || body(\n        &[b'x'; 1_000_000]\n    ))\n}\n\n#[bench]\nfn throughput_fixedsize_many_chunks(b: &mut test::Bencher) {\n    bench_server!(b, (\"content-length\", \"1000000\"), move || {\n        static S: &[&[u8]] = &[&[b'x'; 1_000] as &[u8]; 1_000] as _;\n        BodyExt::boxed(StreamBody::new(\n            stream::iter(S.iter()).map(|&s| Ok::<_, String>(Frame::data(s))),\n        ))\n    })\n}\n\n#[bench]\nfn throughput_chunked_small_payload(b: &mut test::Bencher) {\n    bench_server!(b, (\"transfer-encoding\", \"chunked\"), || body(\n        b\"Hello, World!\"\n    ))\n}\n\n#[bench]\nfn throughput_chunked_large_payload(b: &mut test::Bencher) {\n    bench_server!(b, (\"transfer-encoding\", \"chunked\"), || body(\n        &[b'x'; 1_000_000]\n    ))\n}\n\n#[bench]\nfn throughput_chunked_many_chunks(b: &mut test::Bencher) {\n    bench_server!(b, (\"transfer-encoding\", \"chunked\"), || {\n        static S: &[&[u8]] = &[&[b'x'; 1_000] as &[u8]; 1_000] as _;\n        BodyExt::boxed(StreamBody::new(\n            stream::iter(S.iter()).map(|&s| Ok::<_, String>(Frame::data(s))),\n        ))\n    })\n}\n\n#[bench]\nfn raw_tcp_throughput_small_payload(b: &mut test::Bencher) {\n    let (tx, rx) = mpsc::channel();\n    let listener = TcpListener::bind(\"127.0.0.1:0\").unwrap();\n    let addr = listener.local_addr().unwrap();\n    std::thread::spawn(move || {\n        let mut sock = listener.accept().unwrap().0;\n\n        let mut buf = [0u8; 8192];\n        while rx.try_recv().is_err() {\n            sock.read(&mut buf).unwrap();\n            sock.write_all(\n                b\"\\\n                HTTP/1.1 200 OK\\r\\n\\\n                Content-Length: 13\\r\\n\\\n                Content-Type: text/plain; charset=utf-8\\r\\n\\\n                Date: Fri, 12 May 2017 18:21:45 GMT\\r\\n\\\n                \\r\\n\\\n                Hello, World!\\\n            \",\n            )\n            .unwrap();\n        }\n    });\n\n    let mut tcp = TcpStream::connect(addr).unwrap();\n    let mut buf = [0u8; 4096];\n\n    b.bytes = 130 + 35;\n    b.iter(|| {\n        tcp.write_all(b\"GET / HTTP/1.1\\r\\nHost: localhost\\r\\n\\r\\n\")\n            .unwrap();\n        let n = tcp.read(&mut buf).unwrap();\n        assert_eq!(n, 130);\n    });\n    tx.send(()).unwrap();\n}\n\n#[bench]\nfn raw_tcp_throughput_large_payload(b: &mut test::Bencher) {\n    let (tx, rx) = mpsc::channel();\n    let listener = TcpListener::bind(\"127.0.0.1:0\").unwrap();\n    let addr = listener.local_addr().unwrap();\n\n    let srv_head = b\"\\\n        HTTP/1.1 200 OK\\r\\n\\\n        Content-Length: 1000000\\r\\n\\\n        Content-Type: text/plain; charset=utf-8\\r\\n\\\n        Date: Fri, 12 May 2017 18:21:45 GMT\\r\\n\\\n        \\r\\n\\\n    \";\n    std::thread::spawn(move || {\n        let mut sock = listener.accept().unwrap().0;\n\n        let mut buf = [0u8; 8192];\n        while rx.try_recv().is_err() {\n            let r = sock.read(&mut buf).unwrap();\n            extern crate test;\n            if r == 0 {\n                break;\n            }\n            sock.write_all(srv_head).unwrap();\n            sock.write_all(&[b'x'; 1_000_000]).unwrap();\n        }\n    });\n\n    let mut tcp = TcpStream::connect(addr).unwrap();\n    let mut buf = [0u8; 8192];\n\n    let expect_read = srv_head.len() + 1_000_000;\n    b.bytes = expect_read as u64 + 35;\n\n    b.iter(|| {\n        tcp.write_all(b\"GET / HTTP/1.1\\r\\nHost: localhost\\r\\n\\r\\n\")\n            .unwrap();\n        let mut sum = 0;\n        while sum < expect_read {\n            sum += tcp.read(&mut buf).unwrap();\n        }\n        assert_eq!(sum, expect_read);\n    });\n    tx.send(()).unwrap();\n}\n"
  },
  {
    "path": "benches/support/mod.rs",
    "content": "mod tokiort;\n#[allow(unused)]\npub use tokiort::{TokioExecutor, TokioIo, TokioTimer};\n"
  },
  {
    "path": "benches/support/tokiort.rs",
    "content": "#![allow(dead_code)]\n//! Various runtimes for hyper\nuse std::{\n    future::Future,\n    pin::Pin,\n    task::{Context, Poll},\n    time::{Duration, Instant},\n};\n\nuse hyper::rt::{Sleep, Timer};\nuse pin_project_lite::pin_project;\n\n#[derive(Clone)]\n/// An Executor that uses the tokio runtime.\npub struct TokioExecutor;\n\nimpl<F> hyper::rt::Executor<F> for TokioExecutor\nwhere\n    F: std::future::Future + Send + 'static,\n    F::Output: Send + 'static,\n{\n    fn execute(&self, fut: F) {\n        tokio::task::spawn(fut);\n    }\n}\n\n/// A Timer that uses the tokio runtime.\n\n#[derive(Clone, Debug)]\npub struct TokioTimer;\n\nimpl Timer for TokioTimer {\n    fn sleep(&self, duration: Duration) -> Pin<Box<dyn Sleep>> {\n        Box::pin(TokioSleep {\n            inner: tokio::time::sleep(duration),\n        })\n    }\n\n    fn sleep_until(&self, deadline: Instant) -> Pin<Box<dyn Sleep>> {\n        Box::pin(TokioSleep {\n            inner: tokio::time::sleep_until(deadline.into()),\n        })\n    }\n\n    fn now(&self) -> Instant {\n        tokio::time::Instant::now().into()\n    }\n\n    fn reset(&self, sleep: &mut Pin<Box<dyn Sleep>>, new_deadline: Instant) {\n        if let Some(sleep) = sleep.as_mut().downcast_mut_pin::<TokioSleep>() {\n            sleep.reset(new_deadline)\n        }\n    }\n}\n\nimpl TokioTimer {\n    /// Create a new TokioTimer\n    pub fn new() -> Self {\n        Self {}\n    }\n}\n\n// Use TokioSleep to get tokio::time::Sleep to implement Unpin.\n// see https://docs.rs/tokio/latest/tokio/time/struct.Sleep.html\npin_project! {\n    pub(crate) struct TokioSleep {\n        #[pin]\n        pub(crate) inner: tokio::time::Sleep,\n    }\n}\n\nimpl Future for TokioSleep {\n    type Output = ();\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        self.project().inner.poll(cx)\n    }\n}\n\nimpl Sleep for TokioSleep {}\n\nimpl TokioSleep {\n    pub fn reset(self: Pin<&mut Self>, deadline: Instant) {\n        self.project().inner.as_mut().reset(deadline.into());\n    }\n}\n\npin_project! {\n    #[derive(Debug)]\n    pub struct TokioIo<T> {\n        #[pin]\n        inner: T,\n    }\n}\n\nimpl<T> TokioIo<T> {\n    pub fn new(inner: T) -> Self {\n        Self { inner }\n    }\n\n    pub fn inner(self) -> T {\n        self.inner\n    }\n}\n\nimpl<T> hyper::rt::Read for TokioIo<T>\nwhere\n    T: tokio::io::AsyncRead,\n{\n    fn poll_read(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        mut buf: hyper::rt::ReadBufCursor<'_>,\n    ) -> Poll<Result<(), std::io::Error>> {\n        let n = unsafe {\n            let mut tbuf = tokio::io::ReadBuf::uninit(buf.as_mut());\n            match tokio::io::AsyncRead::poll_read(self.project().inner, cx, &mut tbuf) {\n                Poll::Ready(Ok(())) => tbuf.filled().len(),\n                other => return other,\n            }\n        };\n\n        unsafe {\n            buf.advance(n);\n        }\n        Poll::Ready(Ok(()))\n    }\n}\n\nimpl<T> hyper::rt::Write for TokioIo<T>\nwhere\n    T: tokio::io::AsyncWrite,\n{\n    fn poll_write(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<Result<usize, std::io::Error>> {\n        tokio::io::AsyncWrite::poll_write(self.project().inner, cx, buf)\n    }\n\n    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>> {\n        tokio::io::AsyncWrite::poll_flush(self.project().inner, cx)\n    }\n\n    fn poll_shutdown(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Result<(), std::io::Error>> {\n        tokio::io::AsyncWrite::poll_shutdown(self.project().inner, cx)\n    }\n\n    fn is_write_vectored(&self) -> bool {\n        tokio::io::AsyncWrite::is_write_vectored(&self.inner)\n    }\n\n    fn poll_write_vectored(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        bufs: &[std::io::IoSlice<'_>],\n    ) -> Poll<Result<usize, std::io::Error>> {\n        tokio::io::AsyncWrite::poll_write_vectored(self.project().inner, cx, bufs)\n    }\n}\n\nimpl<T> tokio::io::AsyncRead for TokioIo<T>\nwhere\n    T: hyper::rt::Read,\n{\n    fn poll_read(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        tbuf: &mut tokio::io::ReadBuf<'_>,\n    ) -> Poll<Result<(), std::io::Error>> {\n        //let init = tbuf.initialized().len();\n        let filled = tbuf.filled().len();\n        let sub_filled = unsafe {\n            let mut buf = hyper::rt::ReadBuf::uninit(tbuf.unfilled_mut());\n\n            match hyper::rt::Read::poll_read(self.project().inner, cx, buf.unfilled()) {\n                Poll::Ready(Ok(())) => buf.filled().len(),\n                other => return other,\n            }\n        };\n\n        let n_filled = filled + sub_filled;\n        // At least sub_filled bytes had to have been initialized.\n        let n_init = sub_filled;\n        unsafe {\n            tbuf.assume_init(n_init);\n            tbuf.set_filled(n_filled);\n        }\n\n        Poll::Ready(Ok(()))\n    }\n}\n\nimpl<T> tokio::io::AsyncWrite for TokioIo<T>\nwhere\n    T: hyper::rt::Write,\n{\n    fn poll_write(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<Result<usize, std::io::Error>> {\n        hyper::rt::Write::poll_write(self.project().inner, cx, buf)\n    }\n\n    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>> {\n        hyper::rt::Write::poll_flush(self.project().inner, cx)\n    }\n\n    fn poll_shutdown(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Result<(), std::io::Error>> {\n        hyper::rt::Write::poll_shutdown(self.project().inner, cx)\n    }\n\n    fn is_write_vectored(&self) -> bool {\n        hyper::rt::Write::is_write_vectored(&self.inner)\n    }\n\n    fn poll_write_vectored(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        bufs: &[std::io::IoSlice<'_>],\n    ) -> Poll<Result<usize, std::io::Error>> {\n        hyper::rt::Write::poll_write_vectored(self.project().inner, cx, bufs)\n    }\n}\n"
  },
  {
    "path": "capi/README.md",
    "content": "# C API for hyper\n\nThis provides auxiliary pieces for a C API to use the hyper library.\n\n## Unstable\n\nThe C API of hyper is currently **unstable**, which means it's not part of the semver contract as the rest of the Rust API is.\n\nBecause of that, it's only accessible if `--cfg hyper_unstable_ffi` is passed to `rustc` when compiling. The easiest way to do that is setting the `RUSTFLAGS` environment variable.\n\n## Building\n\nThe C API is part of the Rust library, but isn't compiled by default. Using `cargo`, staring with `1.64.0`, it can be compiled with the following command:\n\n```\nRUSTFLAGS=\"--cfg hyper_unstable_ffi\" cargo rustc --features client,http1,http2,ffi --crate-type cdylib\n```\n\n### (Optional) With `cargo-c`\n\nIf using `cargo-c`, you can build and install a shared library with the following command:\n\n```\nRUSTFLAGS=\"--cfg hyper_unstable_ffi\" cargo cbuild --features client,http1,http2,ffi --release\n```\n"
  },
  {
    "path": "capi/cbindgen.toml",
    "content": "# See https://github.com/mozilla/cbindgen/blob/master/docs.md#cbindgentoml for\n# a list of possible configuration values.\nlanguage = \"C\"\nheader = \"\"\"/*\n * Copyright 2026 Sean McArthur. MIT License.\n * Generated by gen_header.sh. Do not edit directly.\n *\n * Full docs at: https://docs.rs/hyper/latest/hyper/ffi/index.html\n */\"\"\"\ninclude_guard = \"_HYPER_H\"\nno_includes = true\nsys_includes = [\"stdint.h\", \"stddef.h\", \"stdbool.h\"]\ncpp_compat = true\ndocumentation_style = \"c\"\ndocumentation_length = \"short\"\n"
  },
  {
    "path": "capi/examples/Makefile",
    "content": "#\n# Build the example client\n#\n\nTARGET = client\nTARGET2 = upload\n\nOBJS = client.o\nOBJS2 = upload.o\n\nRPATH=$(PWD)/../../target/debug\nCFLAGS = -I../include\nLDFLAGS = -L$(RPATH) -Wl,-rpath,$(RPATH)\nLIBS = -lhyper\n\nall: $(TARGET) $(TARGET2)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $(TARGET) $(OBJS) $(LDFLAGS) $(LIBS)\n\n$(TARGET2): $(OBJS2)\n\t$(CC) -o $(TARGET2) $(OBJS2) $(LDFLAGS) $(LIBS)\n\nclean:\n\trm -f $(OBJS) $(TARGET) $(OBJS2) $(TARGET2)\n"
  },
  {
    "path": "capi/examples/client.c",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <unistd.h>\n#include <fcntl.h>\n#include <errno.h>\n#include <sys/select.h>\n#include <assert.h>\n\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netdb.h>\n#include <string.h>\n\n#include \"hyper.h\"\n\n\nstruct conn_data {\n    int fd;\n    hyper_waker *read_waker;\n    hyper_waker *write_waker;\n};\n\nstatic size_t read_cb(void *userdata, hyper_context *ctx, uint8_t *buf, size_t buf_len) {\n    struct conn_data *conn = (struct conn_data *)userdata;\n    ssize_t ret = read(conn->fd, buf, buf_len);\n\n    if (ret >= 0) {\n        return ret;\n    }\n\n    if (errno != EAGAIN) {\n        // kaboom\n        return HYPER_IO_ERROR;\n    }\n\n    // would block, register interest\n    if (conn->read_waker != NULL) {\n        hyper_waker_free(conn->read_waker);\n    }\n    conn->read_waker = hyper_context_waker(ctx);\n    return HYPER_IO_PENDING;\n}\n\nstatic size_t write_cb(void *userdata, hyper_context *ctx, const uint8_t *buf, size_t buf_len) {\n    struct conn_data *conn = (struct conn_data *)userdata;\n    ssize_t ret = write(conn->fd, buf, buf_len);\n\n    if (ret >= 0) {\n        return ret;\n    }\n\n    if (errno != EAGAIN) {\n        // kaboom\n        return HYPER_IO_ERROR;\n    }\n\n    // would block, register interest\n    if (conn->write_waker != NULL) {\n        hyper_waker_free(conn->write_waker);\n    }\n    conn->write_waker = hyper_context_waker(ctx);\n    return HYPER_IO_PENDING;\n}\n\nstatic void free_conn_data(struct conn_data *conn) {\n    if (conn->read_waker) {\n        hyper_waker_free(conn->read_waker);\n        conn->read_waker = NULL;\n    }\n    if (conn->write_waker) {\n        hyper_waker_free(conn->write_waker);\n        conn->write_waker = NULL;\n    }\n\n    free(conn);\n}\n\nstatic int connect_to(const char *host, const char *port) {\n    struct addrinfo hints;\n    memset(&hints, 0, sizeof(struct addrinfo));\n    hints.ai_family = AF_UNSPEC;\n    hints.ai_socktype = SOCK_STREAM;\n\n    struct addrinfo *result, *rp;\n    if (getaddrinfo(host, port, &hints, &result) != 0) {\n        printf(\"dns failed for %s\\n\", host);\n        return -1;\n    }\n\n    int sfd;\n    for (rp = result; rp != NULL; rp = rp->ai_next) {\n        sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);\n        if (sfd == -1) {\n            continue;\n        }\n\n        if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) {\n            break;\n        }\n\n        close(sfd);\n    }\n\n    freeaddrinfo(result);\n\n    // no address succeeded\n    if (rp == NULL) {\n        printf(\"connect failed for %s\\n\", host);\n        return -1;\n    }\n\n    return sfd;\n}\n\nstatic int print_each_header(void *userdata,\n                                         const uint8_t *name,\n                                         size_t name_len,\n                                         const uint8_t *value,\n                                         size_t value_len) {\n    printf(\"%.*s: %.*s\\n\", (int) name_len, name, (int) value_len, value);\n    return HYPER_ITER_CONTINUE;\n}\n\nstatic int print_each_chunk(void *userdata, const hyper_buf *chunk) {\n    const uint8_t *buf = hyper_buf_bytes(chunk);\n    size_t len = hyper_buf_len(chunk);\n\n    write(1, buf, len);\n\n    return HYPER_ITER_CONTINUE;\n}\n\ntypedef enum {\n    EXAMPLE_NOT_SET = 0, // tasks we don't know about won't have a userdata set\n    EXAMPLE_HANDSHAKE,\n    EXAMPLE_SEND,\n    EXAMPLE_RESP_BODY\n} example_id;\n\n#define STR_ARG(XX) (uint8_t *)XX, strlen(XX)\n\nint main(int argc, char *argv[]) {\n    const char *host = argc > 1 ? argv[1] : \"httpbin.org\";\n    const char *port = argc > 2 ? argv[2] : \"80\";\n    const char *path = argc > 3 ? argv[3] : \"/\";\n    printf(\"connecting to port %s on %s...\\n\", port, host);\n\n    int fd = connect_to(host, port);\n    if (fd < 0) {\n        return 1;\n    }\n\n    printf(\"connected to %s, now get %s\\n\", host, path);\n    if (fcntl(fd, F_SETFL, O_NONBLOCK) != 0) {\n        printf(\"failed to set socket to non-blocking\\n\");\n        return 1;\n    }\n\n    fd_set fds_read;\n    fd_set fds_write;\n    fd_set fds_excep;\n\n    struct conn_data *conn = malloc(sizeof(struct conn_data));\n\n    conn->fd = fd;\n    conn->read_waker = NULL;\n    conn->write_waker = NULL;\n\n    // Hookup the IO\n    hyper_io *io = hyper_io_new();\n    hyper_io_set_userdata(io, (void *)conn);\n    hyper_io_set_read(io, read_cb);\n    hyper_io_set_write(io, write_cb);\n\n    printf(\"http handshake (hyper v%s) ...\\n\", hyper_version());\n\n    // We need an executor generally to poll futures\n    const hyper_executor *exec = hyper_executor_new();\n\n    // Prepare client options\n    hyper_clientconn_options *opts = hyper_clientconn_options_new();\n    hyper_clientconn_options_exec(opts, exec);\n\n    hyper_task *handshake = hyper_clientconn_handshake(io, opts);\n    hyper_task_set_userdata(handshake, (void *)EXAMPLE_HANDSHAKE);\n\n    // Let's wait for the handshake to finish...\n    hyper_executor_push(exec, handshake);\n\n    // In case a task errors...\n    hyper_error *err;\n\n    // The polling state machine!\n    while (1) {\n        // Poll all ready tasks and act on them...\n        while (1) {\n            hyper_task *task = hyper_executor_poll(exec);\n            if (!task) {\n                break;\n            }\n            switch ((example_id) hyper_task_userdata(task)) {\n            case EXAMPLE_HANDSHAKE:\n                ;\n                if (hyper_task_type(task) == HYPER_TASK_ERROR) {\n                    printf(\"handshake error!\\n\");\n                    err = hyper_task_value(task);\n                    goto fail;\n                }\n                assert(hyper_task_type(task) == HYPER_TASK_CLIENTCONN);\n\n                printf(\"preparing http request ...\\n\");\n\n                hyper_clientconn *client = hyper_task_value(task);\n                hyper_task_free(task);\n\n                // Prepare the request\n                hyper_request *req = hyper_request_new();\n                if (hyper_request_set_method(req, STR_ARG(\"GET\"))) {\n                    printf(\"error setting method\\n\");\n                    return 1;\n                }\n                if (hyper_request_set_uri(req, STR_ARG(path))) {\n                    printf(\"error setting uri\\n\");\n                    return 1;\n                }\n\n                hyper_headers *req_headers = hyper_request_headers(req);\n                hyper_headers_set(req_headers,  STR_ARG(\"Host\"), STR_ARG(host));\n\n                // Send it!\n                hyper_task *send = hyper_clientconn_send(client, req);\n                hyper_task_set_userdata(send, (void *)EXAMPLE_SEND);\n                printf(\"sending ...\\n\");\n                hyper_executor_push(exec, send);\n\n                // For this example, no longer need the client\n                hyper_clientconn_free(client);\n\n                break;\n            case EXAMPLE_SEND:\n                ;\n                if (hyper_task_type(task) == HYPER_TASK_ERROR) {\n                    printf(\"send error!\\n\");\n                    err = hyper_task_value(task);\n                    goto fail;\n                }\n                assert(hyper_task_type(task) == HYPER_TASK_RESPONSE);\n\n                // Take the results\n                hyper_response *resp = hyper_task_value(task);\n                hyper_task_free(task);\n\n                uint16_t http_status = hyper_response_status(resp);\n                const uint8_t *rp = hyper_response_reason_phrase(resp);\n                size_t rp_len = hyper_response_reason_phrase_len(resp);\n\n                printf(\"\\nResponse Status: %d %.*s\\n\", http_status, (int) rp_len, rp);\n\n                hyper_headers *headers = hyper_response_headers(resp);\n                hyper_headers_foreach(headers, print_each_header, NULL);\n                printf(\"\\n\");\n\n                hyper_body *resp_body = hyper_response_body(resp);\n                hyper_task *foreach = hyper_body_foreach(resp_body, print_each_chunk, NULL);\n                hyper_task_set_userdata(foreach, (void *)EXAMPLE_RESP_BODY);\n                hyper_executor_push(exec, foreach);\n\n                // No longer need the response\n                hyper_response_free(resp);\n\n                break;\n            case EXAMPLE_RESP_BODY:\n                ;\n                if (hyper_task_type(task) == HYPER_TASK_ERROR) {\n                    printf(\"body error!\\n\");\n                    err = hyper_task_value(task);\n                    goto fail;\n                }\n\n                assert(hyper_task_type(task) == HYPER_TASK_EMPTY);\n\n                printf(\"\\n -- Done! -- \\n\");\n\n                // Cleaning up before exiting\n                hyper_task_free(task);\n                hyper_executor_free(exec);\n                free_conn_data(conn);\n\n                return 0;\n            case EXAMPLE_NOT_SET:\n                // A background task for hyper completed...\n                hyper_task_free(task);\n                break;\n            }\n        }\n\n        // All futures are pending on IO work, so select on the fds.\n\n        FD_ZERO(&fds_read);\n        FD_ZERO(&fds_write);\n        FD_ZERO(&fds_excep);\n\n        if (conn->read_waker) {\n            FD_SET(conn->fd, &fds_read);\n        }\n        if (conn->write_waker) {\n            FD_SET(conn->fd, &fds_write);\n        }\n\n        int sel_ret = select(conn->fd + 1, &fds_read, &fds_write, &fds_excep, NULL);\n\n        if (sel_ret < 0) {\n            printf(\"select() error\\n\");\n            return 1;\n        }\n\n        if (FD_ISSET(conn->fd, &fds_read)) {\n            hyper_waker_wake(conn->read_waker);\n            conn->read_waker = NULL;\n        }\n\n        if (FD_ISSET(conn->fd, &fds_write)) {\n            hyper_waker_wake(conn->write_waker);\n            conn->write_waker = NULL;\n        }\n\n    }\n\n    return 0;\n\nfail:\n    if (err) {\n        printf(\"error code: %d\\n\", hyper_error_code(err));\n        // grab the error details\n        char errbuf [256];\n        size_t errlen = hyper_error_print(err, errbuf, sizeof(errbuf));\n        printf(\"details: %.*s\\n\", (int) errlen, errbuf);\n\n        // clean up the error\n        hyper_error_free(err);\n    }\n    return 1;\n}\n"
  },
  {
    "path": "capi/examples/upload.c",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <unistd.h>\n#include <fcntl.h>\n#include <errno.h>\n#include <sys/select.h>\n#include <assert.h>\n\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netdb.h>\n#include <string.h>\n\n#include \"hyper.h\"\n\n\nstruct conn_data {\n    int fd;\n    hyper_waker *read_waker;\n    hyper_waker *write_waker;\n};\n\nstatic size_t read_cb(void *userdata, hyper_context *ctx, uint8_t *buf, size_t buf_len) {\n    struct conn_data *conn = (struct conn_data *)userdata;\n    ssize_t ret = read(conn->fd, buf, buf_len);\n\n    if (ret >= 0) {\n        return ret;\n    }\n\n    if (errno != EAGAIN) {\n        // kaboom\n        return HYPER_IO_ERROR;\n    }\n\n    // would block, register interest\n    if (conn->read_waker != NULL) {\n        hyper_waker_free(conn->read_waker);\n    }\n    conn->read_waker = hyper_context_waker(ctx);\n    return HYPER_IO_PENDING;\n}\n\nstatic size_t write_cb(void *userdata, hyper_context *ctx, const uint8_t *buf, size_t buf_len) {\n    struct conn_data *conn = (struct conn_data *)userdata;\n    ssize_t ret = write(conn->fd, buf, buf_len);\n\n    if (ret >= 0) {\n        return ret;\n    }\n\n    if (errno != EAGAIN) {\n        // kaboom\n        return HYPER_IO_ERROR;\n    }\n\n    // would block, register interest\n    if (conn->write_waker != NULL) {\n        hyper_waker_free(conn->write_waker);\n    }\n    conn->write_waker = hyper_context_waker(ctx);\n    return HYPER_IO_PENDING;\n}\n\nstatic void free_conn_data(struct conn_data *conn) {\n    if (conn->read_waker) {\n        hyper_waker_free(conn->read_waker);\n        conn->read_waker = NULL;\n    }\n    if (conn->write_waker) {\n        hyper_waker_free(conn->write_waker);\n        conn->write_waker = NULL;\n    }\n\n    free(conn);\n}\n\nstatic int connect_to(const char *host, const char *port) {\n    struct addrinfo hints;\n    memset(&hints, 0, sizeof(struct addrinfo));\n    hints.ai_family = AF_UNSPEC;\n    hints.ai_socktype = SOCK_STREAM;\n\n    struct addrinfo *result, *rp;\n    if (getaddrinfo(host, port, &hints, &result) != 0) {\n        printf(\"dns failed for %s\\n\", host);\n        return -1;\n    }\n\n    int sfd;\n    for (rp = result; rp != NULL; rp = rp->ai_next) {\n        sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);\n        if (sfd == -1) {\n            continue;\n        }\n\n        if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) {\n            break;\n        }\n\n        close(sfd);\n    }\n\n    freeaddrinfo(result);\n\n    // no address succeeded\n    if (rp == NULL) {\n        printf(\"connect failed for %s\\n\", host);\n        return -1;\n    }\n\n    return sfd;\n}\n\nstruct upload_body {\n    int fd;\n    char *buf;\n    size_t len;\n};\n\nstatic int poll_req_upload(void *userdata,\n                           hyper_context *ctx,\n                           hyper_buf **chunk) {\n    struct upload_body* upload = userdata;\n\n    ssize_t res = read(upload->fd, upload->buf, upload->len);\n    if (res > 0) {\n        *chunk = hyper_buf_copy(upload->buf, res);\n        return HYPER_POLL_READY;\n    }\n\n    if (res == 0) {\n        // All done!\n        *chunk = NULL;\n        return HYPER_POLL_READY;\n    }\n\n    // Oh no!\n    printf(\"error reading upload file: %d\", errno);\n    return HYPER_POLL_ERROR;\n}\n\nstatic int print_each_header(void *userdata,\n                                         const uint8_t *name,\n                                         size_t name_len,\n                                         const uint8_t *value,\n                                         size_t value_len) {\n    printf(\"%.*s: %.*s\\n\", (int) name_len, name, (int) value_len, value);\n    return HYPER_ITER_CONTINUE;\n}\n\nstatic void print_informational(void *userdata, hyper_response *resp) {\n    uint16_t http_status = hyper_response_status(resp);\n\n    printf(\"\\nInformational (1xx): %d\\n\", http_status);\n}\n\ntypedef enum {\n    EXAMPLE_NOT_SET = 0, // tasks we don't know about won't have a userdata set\n    EXAMPLE_HANDSHAKE,\n    EXAMPLE_SEND,\n    EXAMPLE_RESP_BODY\n} example_id;\n\n#define STR_ARG(XX) (uint8_t *)XX, strlen(XX)\n\nint main(int argc, char *argv[]) {\n    const char *file = argc > 1 ? argv[1] : NULL;\n    const char *host = argc > 2 ? argv[2] : \"httpbin.org\";\n    const char *port = argc > 3 ? argv[3] : \"80\";\n    const char *path = argc > 4 ? argv[4] : \"/post\";\n\n    if (!file) {\n        printf(\"Pass a file path as the first argument.\\n\");\n        return 1;\n    }\n\n    struct upload_body upload;\n    upload.fd = open(file, O_RDONLY);\n\n    if (upload.fd < 0) {\n        printf(\"error opening file to upload: %s\\n\", strerror(errno));\n        return 1;\n    }\n    printf(\"connecting to port %s on %s...\\n\", port, host);\n\n    int fd = connect_to(host, port);\n    if (fd < 0) {\n        return 1;\n    }\n    printf(\"connected to %s, now upload to %s\\n\", host, path);\n\n    if (fcntl(fd, F_SETFL, O_NONBLOCK) != 0) {\n        printf(\"failed to set socket to non-blocking\\n\");\n        return 1;\n    }\n\n    upload.len = 8192;\n    upload.buf = malloc(upload.len);\n\n    fd_set fds_read;\n    fd_set fds_write;\n    fd_set fds_excep;\n\n    struct conn_data *conn = malloc(sizeof(struct conn_data));\n\n    conn->fd = fd;\n    conn->read_waker = NULL;\n    conn->write_waker = NULL;\n\n\n    // Hookup the IO\n    hyper_io *io = hyper_io_new();\n    hyper_io_set_userdata(io, (void *)conn);\n    hyper_io_set_read(io, read_cb);\n    hyper_io_set_write(io, write_cb);\n\n    printf(\"http handshake (hyper v%s) ...\\n\", hyper_version());\n\n    // We need an executor generally to poll futures\n    const hyper_executor *exec = hyper_executor_new();\n\n    // Prepare client options\n    hyper_clientconn_options *opts = hyper_clientconn_options_new();\n    hyper_clientconn_options_exec(opts, exec);\n\n    hyper_task *handshake = hyper_clientconn_handshake(io, opts);\n    hyper_task_set_userdata(handshake, (void *)EXAMPLE_HANDSHAKE);\n\n    // Let's wait for the handshake to finish...\n    hyper_executor_push(exec, handshake);\n\n    // This body will get filled in eventually...\n    hyper_body *resp_body = NULL;\n\n    // The polling state machine!\n    while (1) {\n        // Poll all ready tasks and act on them...\n        while (1) {\n            hyper_task *task = hyper_executor_poll(exec);\n            if (!task) {\n                break;\n            }\n            hyper_task_return_type task_type = hyper_task_type(task);\n\n            switch ((example_id) hyper_task_userdata(task)) {\n            case EXAMPLE_HANDSHAKE:\n                ;\n                if (task_type == HYPER_TASK_ERROR) {\n                    printf(\"handshake error!\\n\");\n                    return 1;\n                }\n                assert(task_type == HYPER_TASK_CLIENTCONN);\n\n                printf(\"preparing http request ...\\n\");\n\n                hyper_clientconn *client = hyper_task_value(task);\n                hyper_task_free(task);\n\n                // Prepare the request\n                hyper_request *req = hyper_request_new();\n                if (hyper_request_set_method(req, STR_ARG(\"POST\"))) {\n                    printf(\"error setting method\\n\");\n                    return 1;\n                }\n                if (hyper_request_set_uri(req, STR_ARG(path))) {\n                    printf(\"error setting uri\\n\");\n                    return 1;\n                }\n\n                hyper_headers *req_headers = hyper_request_headers(req);\n                hyper_headers_set(req_headers, STR_ARG(\"host\"), STR_ARG(host));\n                hyper_headers_set(req_headers, STR_ARG(\"expect\"), STR_ARG(\"100-continue\"));\n\n                // NOTE: We aren't handling *waiting* for the 100 Continue,\n                // the body is sent immediately. This will just print if any\n                // informational headers are received.\n                printf(\"    with expect-continue ...\\n\");\n                hyper_request_on_informational(req, print_informational, NULL);\n\n                // Prepare the req body\n                hyper_body *body = hyper_body_new();\n                hyper_body_set_userdata(body, &upload);\n                hyper_body_set_data_func(body, poll_req_upload);\n                hyper_request_set_body(req, body);\n\n                // Send it!\n                hyper_task *send = hyper_clientconn_send(client, req);\n                hyper_task_set_userdata(send, (void *)EXAMPLE_SEND);\n                printf(\"sending ...\\n\");\n                hyper_executor_push(exec, send);\n\n                // For this example, no longer need the client\n                hyper_clientconn_free(client);\n\n                break;\n            case EXAMPLE_SEND:\n                ;\n                if (task_type == HYPER_TASK_ERROR) {\n                    printf(\"send error!\\n\");\n                    return 1;\n                }\n                assert(task_type == HYPER_TASK_RESPONSE);\n\n                // Take the results\n                hyper_response *resp = hyper_task_value(task);\n                hyper_task_free(task);\n\n                uint16_t http_status = hyper_response_status(resp);\n\n                printf(\"\\nResponse Status: %d\\n\", http_status);\n\n                hyper_headers *headers = hyper_response_headers(resp);\n                hyper_headers_foreach(headers, print_each_header, NULL);\n                printf(\"\\n\");\n\n                resp_body = hyper_response_body(resp);\n\n                // Set us up to peel data from the body a chunk at a time\n                hyper_task *body_data = hyper_body_data(resp_body);\n                hyper_task_set_userdata(body_data, (void *)EXAMPLE_RESP_BODY);\n                hyper_executor_push(exec, body_data);\n\n                // No longer need the response\n                hyper_response_free(resp);\n\n                break;\n            case EXAMPLE_RESP_BODY:\n                ;\n                if (task_type == HYPER_TASK_ERROR) {\n                    printf(\"body error!\\n\");\n                    return 1;\n                }\n\n                if (task_type == HYPER_TASK_BUF) {\n                    hyper_buf *chunk = hyper_task_value(task);\n                    write(1, hyper_buf_bytes(chunk), hyper_buf_len(chunk));\n                    hyper_buf_free(chunk);\n                    hyper_task_free(task);\n\n                    hyper_task *body_data = hyper_body_data(resp_body);\n                    hyper_task_set_userdata(body_data, (void *)EXAMPLE_RESP_BODY);\n                    hyper_executor_push(exec, body_data);\n\n                    break;\n                }\n\n                assert(task_type == HYPER_TASK_EMPTY);\n                hyper_task_free(task);\n                hyper_body_free(resp_body);\n\n                printf(\"\\n -- Done! -- \\n\");\n\n                // Cleaning up before exiting\n                hyper_executor_free(exec);\n                free_conn_data(conn);\n                free(upload.buf);\n\n                return 0;\n            case EXAMPLE_NOT_SET:\n                // A background task for hyper completed...\n                hyper_task_free(task);\n                break;\n            }\n        }\n\n        // All futures are pending on IO work, so select on the fds.\n\n        FD_ZERO(&fds_read);\n        FD_ZERO(&fds_write);\n        FD_ZERO(&fds_excep);\n\n        if (conn->read_waker) {\n            FD_SET(conn->fd, &fds_read);\n        }\n        if (conn->write_waker) {\n            FD_SET(conn->fd, &fds_write);\n        }\n\n        int sel_ret = select(conn->fd + 1, &fds_read, &fds_write, &fds_excep, NULL);\n\n        if (sel_ret < 0) {\n            printf(\"select() error\\n\");\n            return 1;\n        }\n\n        if (FD_ISSET(conn->fd, &fds_read)) {\n            hyper_waker_wake(conn->read_waker);\n            conn->read_waker = NULL;\n        }\n\n        if (FD_ISSET(conn->fd, &fds_write)) {\n            hyper_waker_wake(conn->write_waker);\n            conn->write_waker = NULL;\n        }\n    }\n\n\n    return 0;\n}\n"
  },
  {
    "path": "capi/gen_header.sh",
    "content": "#!/usr/bin/env bash\n#\n# This script regenerates hyper.h.\n# nightly build of Rust.\n#\n# Requirements:\n#\n# cargo install cbindgen\n# cargo install cargo-expand\n\nset -e\n\nCAPI_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\nheader_file=\"$CAPI_DIR/include/hyper.h\"\nheader_file_backup=\"$CAPI_DIR/include/hyper.h.backup\"\nverify_flag=$1\nfunction cleanup {\n    rm -rf \"$WORK_DIR\" || true\n    if [[ \"--verify\" == \"$verify_flag\" ]]; then\n        rm \"$header_file_backup\" || true\n    fi\n}\n\ntrap cleanup EXIT\n\nWORK_DIR=$(mktemp -d)\n\n# check if tmp dir was created\nif [[ ! \"$WORK_DIR\" || ! -d \"$WORK_DIR\" ]]; then\n    echo \"Could not create temp dir\"\n    exit 1\nfi\n\n# backup hyper.h\nif [[ \"--verify\" == \"$verify_flag\" ]]; then\n    cp \"$header_file\" \"$header_file_backup\"\nfi\n\n# Expand just the ffi module\nif ! RUSTFLAGS='--cfg hyper_unstable_ffi' cargo expand --features client,http1,http2,ffi ::ffi 2> $WORK_DIR/expand_stderr.err > $WORK_DIR/expanded.rs; then\n    cat $WORK_DIR/expand_stderr.err\nfi\n\n# Bindgen!\nif ! cbindgen \\\n    --config \"$CAPI_DIR/cbindgen.toml\" \\\n    --lockfile \"$CAPI_DIR/../Cargo.lock\" \\\n    --output \"$header_file\" \\\n    \"${@}\"\\\n    $WORK_DIR/expanded.rs 2> $WORK_DIR/cbindgen_stderr.err; then\n    bindgen_exit_code=$?\n    if [[ \"--verify\" == \"$verify_flag\" ]]; then\n        echo \"Changes from previous header (old < > new)\"\n        diff -u \"$header_file_backup\" \"$header_file\"\n    else\n        echo \"cbindgen failed:\"\n        cat $WORK_DIR/cbindgen_stderr.err\n    fi\n    exit $bindgen_exit_code\nfi\n\nexit 0\n"
  },
  {
    "path": "capi/include/hyper.h",
    "content": "/*\n * Copyright 2026 Sean McArthur. MIT License.\n * Generated by gen_header.sh. Do not edit directly.\n *\n * Full docs at: https://docs.rs/hyper/latest/hyper/ffi/index.html\n */\n\n#ifndef _HYPER_H\n#define _HYPER_H\n\n#include <stdint.h>\n#include <stddef.h>\n#include <stdbool.h>\n\n/*\n Return in iter functions to continue iterating.\n */\n#define HYPER_ITER_CONTINUE 0\n\n/*\n Return in iter functions to stop iterating.\n */\n#define HYPER_ITER_BREAK 1\n\n/*\n An HTTP Version that is unspecified.\n */\n#define HYPER_HTTP_VERSION_NONE 0\n\n/*\n The HTTP/1.0 version.\n */\n#define HYPER_HTTP_VERSION_1_0 10\n\n/*\n The HTTP/1.1 version.\n */\n#define HYPER_HTTP_VERSION_1_1 11\n\n/*\n The HTTP/2 version.\n */\n#define HYPER_HTTP_VERSION_2 20\n\n/*\n Sentinel value to return from a read or write callback that the operation\n */\n#define HYPER_IO_PENDING 4294967295\n\n/*\n Sentinel value to return from a read or write callback that the operation\n */\n#define HYPER_IO_ERROR 4294967294\n\n/*\n Return in a poll function to indicate it was ready.\n */\n#define HYPER_POLL_READY 0\n\n/*\n Return in a poll function to indicate it is still pending.\n */\n#define HYPER_POLL_PENDING 1\n\n/*\n Return in a poll function indicate an error.\n */\n#define HYPER_POLL_ERROR 3\n\n/*\n A return code for many of hyper's methods.\n */\ntypedef enum hyper_code {\n  /*\n   All is well.\n   */\n  HYPERE_OK,\n  /*\n   General error, details in the `hyper_error *`.\n   */\n  HYPERE_ERROR,\n  /*\n   A function argument was invalid.\n   */\n  HYPERE_INVALID_ARG,\n  /*\n   The IO transport returned an EOF when one wasn't expected.\n   */\n  HYPERE_UNEXPECTED_EOF,\n  /*\n   Aborted by a user supplied callback.\n   */\n  HYPERE_ABORTED_BY_CALLBACK,\n  /*\n   An optional hyper feature was not enabled.\n   */\n  HYPERE_FEATURE_NOT_ENABLED,\n  /*\n   The peer sent an HTTP message that could not be parsed.\n   */\n  HYPERE_INVALID_PEER_MESSAGE,\n} hyper_code;\n\n/*\n A descriptor for what type a `hyper_task` value is.\n */\ntypedef enum hyper_task_return_type {\n  /*\n   The value of this task is null (does not imply an error).\n   */\n  HYPER_TASK_EMPTY,\n  /*\n   The value of this task is `hyper_error *`.\n   */\n  HYPER_TASK_ERROR,\n  /*\n   The value of this task is `hyper_clientconn *`.\n   */\n  HYPER_TASK_CLIENTCONN,\n  /*\n   The value of this task is `hyper_response *`.\n   */\n  HYPER_TASK_RESPONSE,\n  /*\n   The value of this task is `hyper_buf *`.\n   */\n  HYPER_TASK_BUF,\n} hyper_task_return_type;\n\n/*\n A streaming HTTP body.\n */\ntypedef struct hyper_body hyper_body;\n\n/*\n A buffer of bytes that is sent or received on a `hyper_body`.\n */\ntypedef struct hyper_buf hyper_buf;\n\n/*\n An HTTP client connection handle.\n */\ntypedef struct hyper_clientconn hyper_clientconn;\n\n/*\n An options builder to configure an HTTP client connection.\n */\ntypedef struct hyper_clientconn_options hyper_clientconn_options;\n\n/*\n An async context for a task that contains the related waker.\n */\ntypedef struct hyper_context hyper_context;\n\n/*\n A more detailed error object returned by some hyper functions.\n */\ntypedef struct hyper_error hyper_error;\n\n/*\n A task executor for `hyper_task`s.\n */\ntypedef struct hyper_executor hyper_executor;\n\n/*\n An HTTP header map.\n */\ntypedef struct hyper_headers hyper_headers;\n\n/*\n A read/write handle for a specific connection.\n */\ntypedef struct hyper_io hyper_io;\n\n/*\n An HTTP request.\n */\ntypedef struct hyper_request hyper_request;\n\n/*\n An HTTP response.\n */\ntypedef struct hyper_response hyper_response;\n\n/*\n An async task.\n */\ntypedef struct hyper_task hyper_task;\n\n/*\n A waker that is saved and used to waken a pending task.\n */\ntypedef struct hyper_waker hyper_waker;\n\ntypedef int (*hyper_body_foreach_callback)(void*, const struct hyper_buf*);\n\ntypedef int (*hyper_body_data_callback)(void*, struct hyper_context*, struct hyper_buf**);\n\ntypedef void (*hyper_request_on_informational_callback)(void*, struct hyper_response*);\n\ntypedef int (*hyper_headers_foreach_callback)(void*, const uint8_t*, size_t, const uint8_t*, size_t);\n\ntypedef size_t (*hyper_io_read_callback)(void*, struct hyper_context*, uint8_t*, size_t);\n\ntypedef size_t (*hyper_io_write_callback)(void*, struct hyper_context*, const uint8_t*, size_t);\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif // __cplusplus\n\n/*\n Returns a static ASCII (null terminated) string of the hyper version.\n */\nconst char *hyper_version(void);\n\n/*\n Creates a new \"empty\" body.\n */\nstruct hyper_body *hyper_body_new(void);\n\n/*\n Free a body.\n */\nvoid hyper_body_free(struct hyper_body *body);\n\n/*\n Creates a task that will poll a response body for the next buffer of data.\n */\nstruct hyper_task *hyper_body_data(struct hyper_body *body);\n\n/*\n Creates a task to execute the callback with each body chunk received.\n */\nstruct hyper_task *hyper_body_foreach(struct hyper_body *body,\n                                      hyper_body_foreach_callback func,\n                                      void *userdata);\n\n/*\n Set userdata on this body, which will be passed to callback functions.\n */\nvoid hyper_body_set_userdata(struct hyper_body *body, void *userdata);\n\n/*\n Set the outgoing data callback for this body.\n */\nvoid hyper_body_set_data_func(struct hyper_body *body, hyper_body_data_callback func);\n\n/*\n Create a new `hyper_buf *` by copying the provided bytes.\n */\nstruct hyper_buf *hyper_buf_copy(const uint8_t *buf, size_t len);\n\n/*\n Get a pointer to the bytes in this buffer.\n */\nconst uint8_t *hyper_buf_bytes(const struct hyper_buf *buf);\n\n/*\n Get the length of the bytes this buffer contains.\n */\nsize_t hyper_buf_len(const struct hyper_buf *buf);\n\n/*\n Free this buffer.\n */\nvoid hyper_buf_free(struct hyper_buf *buf);\n\n/*\n Creates an HTTP client handshake task.\n */\nstruct hyper_task *hyper_clientconn_handshake(struct hyper_io *io,\n                                              struct hyper_clientconn_options *options);\n\n/*\n Creates a task to send a request on the client connection.\n */\nstruct hyper_task *hyper_clientconn_send(struct hyper_clientconn *conn, struct hyper_request *req);\n\n/*\n Free a `hyper_clientconn *`.\n */\nvoid hyper_clientconn_free(struct hyper_clientconn *conn);\n\n/*\n Creates a new set of HTTP clientconn options to be used in a handshake.\n */\nstruct hyper_clientconn_options *hyper_clientconn_options_new(void);\n\n/*\n Set whether header case is preserved.\n */\nvoid hyper_clientconn_options_set_preserve_header_case(struct hyper_clientconn_options *opts,\n                                                       int enabled);\n\n/*\n Set whether header order is preserved.\n */\nvoid hyper_clientconn_options_set_preserve_header_order(struct hyper_clientconn_options *opts,\n                                                        int enabled);\n\n/*\n Free a set of HTTP clientconn options.\n */\nvoid hyper_clientconn_options_free(struct hyper_clientconn_options *opts);\n\n/*\n Set the client background task executor.\n */\nvoid hyper_clientconn_options_exec(struct hyper_clientconn_options *opts,\n                                   const struct hyper_executor *exec);\n\n/*\n Set whether to use HTTP2.\n */\nenum hyper_code hyper_clientconn_options_http2(struct hyper_clientconn_options *opts, int enabled);\n\n/*\n Set whether HTTP/1 connections accept obsolete line folding for header values.\n */\nenum hyper_code hyper_clientconn_options_http1_allow_multiline_headers(struct hyper_clientconn_options *opts,\n                                                                       int enabled);\n\n/*\n Frees a `hyper_error`.\n */\nvoid hyper_error_free(struct hyper_error *err);\n\n/*\n Get an equivalent `hyper_code` from this error.\n */\nenum hyper_code hyper_error_code(const struct hyper_error *err);\n\n/*\n Print the details of this error to a buffer.\n */\nsize_t hyper_error_print(const struct hyper_error *err, uint8_t *dst, size_t dst_len);\n\n/*\n Construct a new HTTP request.\n */\nstruct hyper_request *hyper_request_new(void);\n\n/*\n Free an HTTP request.\n */\nvoid hyper_request_free(struct hyper_request *req);\n\n/*\n Set the HTTP Method of the request.\n */\nenum hyper_code hyper_request_set_method(struct hyper_request *req,\n                                         const uint8_t *method,\n                                         size_t method_len);\n\n/*\n Set the URI of the request.\n */\nenum hyper_code hyper_request_set_uri(struct hyper_request *req,\n                                      const uint8_t *uri,\n                                      size_t uri_len);\n\n/*\n Set the URI of the request with separate scheme, authority, and\n */\nenum hyper_code hyper_request_set_uri_parts(struct hyper_request *req,\n                                            const uint8_t *scheme,\n                                            size_t scheme_len,\n                                            const uint8_t *authority,\n                                            size_t authority_len,\n                                            const uint8_t *path_and_query,\n                                            size_t path_and_query_len);\n\n/*\n Set the preferred HTTP version of the request.\n */\nenum hyper_code hyper_request_set_version(struct hyper_request *req, int version);\n\n/*\n Gets a mutable reference to the HTTP headers of this request\n */\nstruct hyper_headers *hyper_request_headers(struct hyper_request *req);\n\n/*\n Set the body of the request.\n */\nenum hyper_code hyper_request_set_body(struct hyper_request *req, struct hyper_body *body);\n\n/*\n Set an informational (1xx) response callback.\n */\nenum hyper_code hyper_request_on_informational(struct hyper_request *req,\n                                               hyper_request_on_informational_callback callback,\n                                               void *data);\n\n/*\n Free an HTTP response.\n */\nvoid hyper_response_free(struct hyper_response *resp);\n\n/*\n Get the HTTP-Status code of this response.\n */\nuint16_t hyper_response_status(const struct hyper_response *resp);\n\n/*\n Get a pointer to the reason-phrase of this response.\n */\nconst uint8_t *hyper_response_reason_phrase(const struct hyper_response *resp);\n\n/*\n Get the length of the reason-phrase of this response.\n */\nsize_t hyper_response_reason_phrase_len(const struct hyper_response *resp);\n\n/*\n Get the HTTP version used by this response.\n */\nint hyper_response_version(const struct hyper_response *resp);\n\n/*\n Gets a reference to the HTTP headers of this response.\n */\nstruct hyper_headers *hyper_response_headers(struct hyper_response *resp);\n\n/*\n Take ownership of the body of this response.\n */\nstruct hyper_body *hyper_response_body(struct hyper_response *resp);\n\n/*\n Iterates the headers passing each name and value pair to the callback.\n */\nvoid hyper_headers_foreach(const struct hyper_headers *headers,\n                           hyper_headers_foreach_callback func,\n                           void *userdata);\n\n/*\n Sets the header with the provided name to the provided value.\n */\nenum hyper_code hyper_headers_set(struct hyper_headers *headers,\n                                  const uint8_t *name,\n                                  size_t name_len,\n                                  const uint8_t *value,\n                                  size_t value_len);\n\n/*\n Adds the provided value to the list of the provided name.\n */\nenum hyper_code hyper_headers_add(struct hyper_headers *headers,\n                                  const uint8_t *name,\n                                  size_t name_len,\n                                  const uint8_t *value,\n                                  size_t value_len);\n\n/*\n Create a new IO type used to represent a transport.\n */\nstruct hyper_io *hyper_io_new(void);\n\n/*\n Free an IO handle.\n */\nvoid hyper_io_free(struct hyper_io *io);\n\n/*\n Set the user data pointer for this IO to some value.\n */\nvoid hyper_io_set_userdata(struct hyper_io *io, void *data);\n\n/*\n Set the read function for this IO transport.\n */\nvoid hyper_io_set_read(struct hyper_io *io, hyper_io_read_callback func);\n\n/*\n Set the write function for this IO transport.\n */\nvoid hyper_io_set_write(struct hyper_io *io, hyper_io_write_callback func);\n\n/*\n Creates a new task executor.\n */\nconst struct hyper_executor *hyper_executor_new(void);\n\n/*\n Frees an executor and any incomplete tasks still part of it.\n */\nvoid hyper_executor_free(const struct hyper_executor *exec);\n\n/*\n Push a task onto the executor.\n */\nenum hyper_code hyper_executor_push(const struct hyper_executor *exec, struct hyper_task *task);\n\n/*\n Polls the executor, trying to make progress on any tasks that can do so.\n */\nstruct hyper_task *hyper_executor_poll(const struct hyper_executor *exec);\n\n/*\n Free a task.\n */\nvoid hyper_task_free(struct hyper_task *task);\n\n/*\n Takes the output value of this task.\n */\nvoid *hyper_task_value(struct hyper_task *task);\n\n/*\n Query the return type of this task.\n */\nenum hyper_task_return_type hyper_task_type(struct hyper_task *task);\n\n/*\n Set a user data pointer to be associated with this task.\n */\nvoid hyper_task_set_userdata(struct hyper_task *task, void *userdata);\n\n/*\n Retrieve the userdata that has been set via `hyper_task_set_userdata`.\n */\nvoid *hyper_task_userdata(struct hyper_task *task);\n\n/*\n Creates a waker associated with the task context.\n */\nstruct hyper_waker *hyper_context_waker(struct hyper_context *cx);\n\n/*\n Free a waker.\n */\nvoid hyper_waker_free(struct hyper_waker *waker);\n\n/*\n Wake up the task associated with a waker.\n */\nvoid hyper_waker_wake(struct hyper_waker *waker);\n\n#ifdef __cplusplus\n}  // extern \"C\"\n#endif  // __cplusplus\n\n#endif  /* _HYPER_H */\n"
  },
  {
    "path": "docs/CODE_OF_CONDUCT.md",
    "content": "# Code of Conduct\n\n## Be Kind\n\n- Don't be mean.\n- Insulting anyone is prohibited.\n- Harassment of any kind is prohibited.\n- If another person feels uncomfortable with your remarks, stop it.\n- If a moderator deems your comment or conduct as inappropriate, stop it.\n- Disagreeing is fine, but keep it to technical arguments. Never attack the person.\n- Give the benefit of the doubt. Assume good intentions.\n- Show empathy. There are 3 interpretations to any message: what we thought, what we said, and what they understand.\n- This does mean we exclude people who are not kind. We are happy to make that sacrifice.\n\n## Or Else\n\n- Violations of the Code of Conduct will result in 1 warning.\n- If the violation is major, a moderator may just ban immediately.\n- If a warning has already been given, a moderator will ban the offender.\n- There is no process for appealing a ban.\n- Any violations can be reported to sean@seanmonstar.com.\n"
  },
  {
    "path": "docs/CODE_STYLE.md",
    "content": "# Code Style\n\nhyper uses the default configuration of `rustfmt`.\n\n## cargo fmt\n\n`cargo fmt --all` does not work in hyper. Please use the following commands:\n\n```txt\n# Mac or Linux\nrustfmt --check --edition 2021 $(git ls-files '*.rs')\n\n# Powershell\nGet-ChildItem . -Filter \"*.rs\" -Recurse | foreach { rustfmt --check --edition 2021 $_.FullName }\n```\n\n> **NOTE**: If you are using `rust-analyzer`, you can add the following two lines in your `settings.json` to make sure the features get taken into account when checking the project:\n>\n>    ```json\n>     \"rust-analyzer.cargo.features\": [\"full\"],\n>     \"rust-analyzer.check.features\": [\"full\"],\n>    ```\n"
  },
  {
    "path": "docs/COMMITS.md",
    "content": "# Git Commit Guidelines\n\nWe have very precise rules over how our git commit messages can be formatted.  This leads to **more\nreadable messages** that are easy to follow when looking through the **project history**.  But also,\nwe use the git commit messages to **generate the change log**.\n\n## Commit Message Format\nEach commit message consists of a **header**, a **body** and a **footer**.  The header has a special\nformat that includes a **type**, a **scope** and a **subject**:\n\n```\n<type>(<scope>): <subject>\n<BLANK LINE>\n<body>\n<BLANK LINE>\n<footer>\n```\n\nAny line of the commit message cannot be longer 100 characters! This allows the message to be easier\nto read on github as well as in various git tools.\n\n## Type\nMust be one of the following:\n\n* **feat**: A new feature\n* **fix**: A bug fix\n* **docs**: Documentation only changes\n* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing\n  semi-colons, etc)\n* **refactor**: A code change that neither fixes a bug or adds a feature\n* **perf**: A code change that improves performance\n* **test**: Adding missing tests\n* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation\n    generation\n\n## Scope\nThe scope should refer to a module in hyper that is being touched. Examples:\n\n* client\n* server\n* http1\n* http2\n* ffi\n* upgrade\n* examples\n\n## Subject\n\nThe subject contains succinct description of the change:\n\n* use the imperative, present tense: \"change\" not \"changed\" nor \"changes\"\n* don't capitalize first letter\n* no dot (.) at the end\n\n## Body\n\nJust as in the **subject**, use the imperative, present tense: \"change\" not \"changed\" nor \"changes\"\nThe body should include the motivation for the change and contrast this with previous behavior.\n\n## Footer\n\nThe footer should contain any information about **Breaking Changes** and is also the place to\nreference GitHub issues that this commit **Closes**.\n\nThe last line of commits introducing breaking changes should be in the form `BREAKING CHANGE: <desc>`\n"
  },
  {
    "path": "docs/GOVERNANCE.md",
    "content": "# Governance\n\n## Making decisions\n\nThere's two main pieces to the way decisions are made in hyper:\n\n1. A decision-making framework\n2. The people who apply it\n\nThe people are described [lower down in this document](#roles).\n\n### Decision-making framework\n\nWe start with the users. The project wouldn't exist without them, and it exists\nin order to enable users to do amazing things with HTTP. We listen to our\nusers. Some actively contribute their thoughts, but many others we must seek\nout to learn about their usage, joys, and headaches. Those insights allow our\nexperts to determine the best solutions for the users.\n\nWe then define a set of [TENETS](./TENETS.md), which are guiding principles\nthat can be used to measure aspects of individual decisions. It should be\npossible to identify one or more tenets that apply to why a decision is made.\nAnd the set helps us balance which priorities are more important for our users.\n\nWe combine the usecases with the tenets to come up with a [VISION](./VISION.md)\nthat provides a longer-term plan of what hyper _should_ look like.\n\nFinally, we define a [ROADMAP](./ROADMAP.md) that describes what the\nshort-term, tactical changes to bring hyper closer in line with the vision.\n\n## Roles\n\nThese are the roles people can fill when participating in the project. A list\nof the people in each role is available in [MAINTAINERS](./MAINTAINERS.md).\n\n### Contributor\n\nA contributor is anyone who contributes their time to provide value for the\nproject. This could be in the form of code, documentation, filing issues,\ndiscussing designs, or helping others on the issue tracker or in chat.\n\nAll contributors MUST follow the [Code of Conduct][coc].\n\n👋  **New here?** [This could be you!][contrib]\n\n\n### Triager\n\nTriagers assess issues on the issue tracker. They help make sure the work is\nwell organized, and are critical for making new issue reporters feeling\nwelcome.\n\nResponsibilities:\n\n- Adhere to the [Code of Conduct][coc]\n- Follow the [triager's guide][triage-guide]\n\nPrivileges:\n\n- Can edit, label, and close issues\n- Member of the organization\n- Can be assigned issues and pull requests\n\nHow to become:\n\n- Make a few [contributions][contrib] to the project, to show you can follow\n  the [Code of Conduct][coc].\n- Self-nominate by making a pull request adding yourself to the\n  [list](./MAINTAINERS.md#triagers).\n\n\n### Collaborator\n\nCollaborators are contributors who have been helping out in a consistent basis.\n\nResponsibilities:\n\n- Be exemplars of the [Code of Conduct][coc]\n- Internalize the [VISION](./VISION.md)\n- Reviewing pull requests from other contributors\n- Provide feedback on proposed features and design documents\n- [Welcome new contributors][triage-guide]\n- Answer questions in issues and/or chat\n- Mentor contributors to become members\n\nPrivileges:\n\n- Can review and merge pull requests\n- Can trigger re-runs of CI, and approve CI for first-time contributors\n- Can assign issues and pull requests to other organization members\n\nHow to become:\n\n- Work at fulfilling the above responsibilities.\n- Any collaborator may nominate a contributor who has been around for some time\n  and is already filling the responsibilities.\n- Another collaborator must second the nomination.\n- If there are no objections, a maintainer will welcome the new collaborator.\n\nDon't be afraid to ask a collaborator for what you could work on to reach this\ngoal!\n\n### Maintainer\n\nMaintainers are the project admins. Besides being a collaborator, they take care\nof house-keeping duties, help lead the direction, and have the final authority when\nrequired.\n\n[coc]: ./CODE_OF_CONDUCT.md\n[contrib]: ../CONTRIBUTING.md\n[triage-guide]: ./ISSUES.md#triaging\n"
  },
  {
    "path": "docs/ISSUES.md",
    "content": "# Issues\n\nThe [issue tracker][issues] for hyper is where we track all features, bugs, and discuss proposals.\n\n## Triaging\n\nOnce an issue has been opened, it is normal for there to be discussion\naround it. Some contributors may have differing opinions about the issue,\nincluding whether the behavior being seen is a bug or a feature. This\ndiscussion is part of the process and should be kept focused, helpful, and\nprofessional.\n\nThe objective of helping with triaging issues is to help reduce the issue\nbacklog and keep the issue tracker healthy, while enabling newcomers another\nmeaningful way to get engaged and contribute.\n\n### Acknowledge\n\nAcknowledge the human. This is meant actively, such as giving a welcome, or\nthanks for a detailed report, or any other greeting that makes the person feel\nthat their contribution (issues are contributions!) is valued. It also is meant\nto be internalized, and be sure to always [treat the person kindly][COC]\nthroughout the rest of the steps of triaging.\n\n### Ask for more info\n\nFrequently, we need more information than was originally provided to fully\nevaluate an issue.\n\nIf it is a bug report, ask follow up questions that help us get a [minimum\nreproducible example][MRE]. This may take several round-trip questions. Once\nall the details are gathered, it may be helpful to edit the original issue text\nto include them all.\n\n### Categorize\n\nOnce enough information has been gathered, the issue should be categorized\nwith [labels](#labels). Ideally, most issues should be labelled with an area,\neffort, and severity. An issue _can_ have multiple areas, pick what fits. There\nshould be only one severity, and the descriptions of each should help to pick\nthe right one. The hardest label to select is \"effort\". If after reading the\ndescriptions of each effort level, you're still unsure, you can ping a\nmaintainer to pick one.\n\n### Adjust the title\n\nAn optional step when triaging is to adjust the title once more information is\nknown. Sometimes an issue starts as a question, and through discussion, it\nturns out to be a feature request, or a bug report. In those cases, the title\nshould be changed from a question, and the title should be a succinct action to\nbe taken. For example, a question about an non-existent configuration option\nmay be reworded to \"Add option to Client to do Zed\".\n\n### Mentoring\n\nThe last part of triaging is to try to make the issue a learning experience.\nAfter a discussion with the reporter, it would be good to ask if they are now\ninterested in submitting the change described in the issue.\n\nOtherwise, it would be best to leave the issue with a series of steps for\nanyone else to try to write the change. That could be pointing out that a\ndesign proposal is needed, addressing certain points. Or, if the required\nchanges are mostly know, a list of links to modules and functions where code\nneeds to be changed, and to what. That way we mentor newcomers to become\nsuccessful contributors of new [pull requests][PRs].\n\n## Labels\n\nIssues are organized with a set of labels. Most labels follow a system of being prefixed by a \"type\".\n\n### Area\n\nThe area labels describe what part of hyper is relevant.\n\n- **A-body**: streaming request and response bodies.\n- **A-client**: the HTTP client.\n- **A-dependencies**: library dependencies.\n- **A-docs**: documentation.\n- **A-error**: error reporting and types.\n- **A-ffi**: the C API.\n- **A-http1**: the HTTP/1 specifics.\n- **A-http2**: the HTTP/2 specifics.\n- **A-server**: the HTTP server.\n- **A-tests**: the unit and integration tests.\n\n### Blocked\n\nThese labels indicate an issue is \"blocked\" for some reason.\n\n- **B-breaking-change**: a breaking change that is waiting for the next semver-compatible release.\n- **B-rfc**: request for comments. More discussion is needed to explore the design.\n- **B-upstream**: waiting on something in a dependency or the compiler.\n\n### Category\n\nThe category marks what kind of issue this is.\n\n- **C-bug**: something is wrong, this is bad!\n- **C-feature**: this is a new feature request, adding something new.\n- **C-performance**: make existing working code go faster.\n- **C-refactor**: improve internal code to help readability and maintenance.\n- **C-chore**: a general chore or maintenance task.\n\n### Effort\n\nThe effort labels are a best-guess at roughly how much effort and knowledge of hyper is needed to accomplish the task.\n\n- **E-easy**: a great starting point for a new contributor.\n- **E-medium**: some knowledge of how hyper internals work would be useful.\n- **E-hard**: likely requires a deeper understanding of how hyper internals work.\n\n\n[issues]: https://github.com/hyperium/hyper/issues\n[COC]: ./CODE_OF_CONDUCT.md\n[PRs]: ./PULL_REQUESTS.md\n[MRE]: https://en.wikipedia.org/wiki/Minimal_reproducible_example\n"
  },
  {
    "path": "docs/MAINTAINERS.md",
    "content": "# The People\n\nTo see what these roles do, and how to become one, look at [GOVERNANCE](./GOVERNANCE.md).\n\n## Triagers\n\n- Eray Karatay (@programatik29)\n- Oddbjørn Grødem (@oddgrd)\n\n## Collaborators\n\n- Sean McArthur (@seanmonstar)\n- Steven Fackler (@sfackler)\n- Oliver Gould (@olix0r)\n- Eliza Weisman (@hawkw)\n- Lucio Franco (@LucioFranco)\n- Anthony Ramine (@nox)\n- David Pedersen (@davidpdrsn)\n- Adam Foltzer (@acfoltzer)\n- Noah Kennedy (@Noah-Kennedy)\n- dswij (@dswij)\n- tottoto (@tottoto)\n- katelyn martin (@cratelyn)\n\n<details>\n<summary>Emeriti</summary>\n\n### Collaborator emeriti\n\n- Jonathan Reem (@reem)\n- Carl Lerche (@carllerche)\n\n</details>\n\n## Maintainers\n\n- Sean McArthur (@seanmonstar)\n"
  },
  {
    "path": "docs/MSRV.md",
    "content": "# Minimum Support Rust Version (MSRV)\n\nhyper's current policy is to always support a Rust version at least 6 months\nold. That is, a compiler version released within the last 6 months can compile\nhyper. It is possible that an older compiler can work, but that is not\nguaranteed. We try to increase the MSRV responsibly, only when a significant\nnew feature is needed.\n\nThe current MSRV is: **1.63**.\n"
  },
  {
    "path": "docs/PULL_REQUESTS.md",
    "content": "# Pull Requests\n\nPull requests are the way to submit changes to the hyper repository.\n\n## Submitting a Pull Request\n\nIn most cases, it a good idea to discuss a potential change in an\n[issue](ISSUES.md). This will allow other contributors to provide guidance and\nfeedback _before_ significant code work is done, and can increase the\nlikelihood of getting the pull request merged.\n\n### Tests\n\nIf the change being proposed alters code (as opposed to only documentation for\nexample), it is either adding new functionality to hyper or it is fixing\nexisting, broken functionality. In both of these cases, the pull request should\ninclude one or more tests to ensure that hyper does not regress in the future.\n\n### Commits\n\nOnce code, tests, and documentation have been written, a commit needs to be\nmade. Following the [commit guidelines](COMMITS.md) will help with the review\nprocess by making your change easier to understand, and makes it easier for\nhyper to produce a valuable changelog with each release.\n\nHowever, if your message doesn't perfectly match the guidelines, **do not\nworry!** The person that eventually merges can easily fixup the message at that\ntime.\n\n### Opening the Pull Request\n\nFrom within GitHub, open a new pull request from your personal branch.\n\nOnce opened, pull requests are usually reviewed within a few days.\n\n### Discuss and Update\n\nYou will probably get feedback or requests for changes to your Pull Request.\nThis is a big part of the submission process so don't be discouraged! Some\ncontributors may sign off on the Pull Request right away, others may have more\ndetailed comments or feedback. This is a necessary part of the process in order\nto evaluate whether the changes are correct and necessary.\n\nAny community member can review a PR and you might get conflicting feedback.\nKeep an eye out for comments from code owners to provide guidance on\nconflicting feedback.\n\nYou don't need to close the PR and create a new one to address feedback. You\nmay simply push new commits to the existing branch.\n"
  },
  {
    "path": "docs/README.md",
    "content": "# Developing hyper\n\nThis is a set of documents outline how hyper is developed, how to contribute or get involved, various processes we use, and internal design explanations.\n"
  },
  {
    "path": "docs/ROADMAP-1.0.md",
    "content": "# hyper 1.0 Roadmap\n\n> This was the roadmap to arrive at hyper v1.0. It is kept for historical purposes. See [ROADMAP](./ROADMAP.md) for the latest.\n\n## Goal\n\nAlign current hyper to the [hyper VISION][VISION].\n\nThe VISION outlines a decision-making framework, use-cases, and general shape\nof hyper. This roadmap describes the currently known problems with hyper, and\nthen shows what changes are needed to make hyper 1.0 look more like what is in\nthe VISION.\n\n## Known Issues\n\n\n> **Note**: These known issues are as of hyper v0.14.x. After v1.0 is released,\nideally these issues will have been solved. Keeping this history may be helpful\nto Future Us, though.\n\n### Higher-level Client and Server problems\n\nBoth the higher-level `Client` and `Server` types have stability concerns.\n\nFor the `hyper::Server`:\n\n- The `Accept` trait is complex, and too easy to get wrong. If used with TLS, a slow TLS handshake\n  can affect all other new connections waiting for it to finish.\n- The `MakeService<&IO>` is confusing. The bounds are an assault on the eyes.\n- The `MakeService` API doesn't allow to easily annotate the HTTP connection with `tracing`.\n- Graceful shutdown doesn't give enough control.\n\n\nIt's more common for people to simply use `hyper::server::conn` at this point,\nthan to bother with the `hyper::Server`.\n\nWhile the `hyper::Client` is much easier to use, problems still exist:\n\n- The whole `Connect` design isn't stable.\n  - ALPN and proxies can provide surprising extra configuration of connections.\n  - Some `Connect` implementations may wish to view the path, in addition to the scheme, host, and port.\n  - Wants `runtime` feature\n- The Pool could be made more general or composable. At the same time, more customization is\n  desired, and it's not clear\nhow to expose it yet.\n\n\n### Runtime woes\n\nhyper has been able to support different runtimes, but it has sometimes awkward\ndefault support for Tokio.\n\n- The `runtime` cargo-feature isn't additive\n- Built-in Tokio support can be confusing\n- Executors and Timers\n  - The `runtime` feature currently enables a few options that require a timer, such as timeouts and\n    keepalive intervals. It implicitly relies on Tokio's timer context. This can be quite confusing.\n- IO traits\n  - Should we publicly depend on Tokio's traits?\n  - `futures-io`?\n    - Definitely nope.\n    - Not stable. (0.3?)\n    - No uninitialized memory.\n  - Eventual `std` traits?\n    - They've been in design for years.\n    - We cannot base our schedule on them.\n    - When they are stable, we can:\n      - Provide a bridge in `hyper-util`.\n      - Consider a 2.0 of hyper.\n  - Define our own traits, provide util wrappers?\n\n### Forwards-compatibility\n\nThere's a concern about forwards-compatibility. We want to be able to add\nsupport for new HTTP features without needing a new major version. While most\nof `http` and `hyper` are prepared for that, there's two potential problems.\n\n- New frames on an HTTP stream (body)\n   - Receiving a new frame type would require a new trait method\n     - There's no way to implement a \"receive unknown frame\" that hyper doesn't know about.\n   - Sending an unknown frame type would be even harder.\n     - Besides being able to pass an \"unknown\" type through the trait, the user would need to be\n       able to describe how that frame is encoded in HTTP/2/3.\n- New HTTP versions\n  - HTTP/3 will require a new transport abstraction. It's not as simple as just using some\n    `impl AsyncRead + AsyncWrite`. While HTTP/2 bundled the concept of stream creation internally,\n    and thus could be managed wholly on top of a read-write transport, HTTP/3 is different. Stream\n    creation is shifted to the QUIC protocol, and HTTP/3 needs to be able to use that directly.\n  - This means the existing `Connection` types for both client and server will not be able to\n    accept a QUIC transport so we can add HTTP/3 support.\n\n### Errors\n\nIt's not easy to match for specific errors.\n\nThe `Error::source()` can leak an internal dependency. For example, a\n`hyper::Error` may wrap an `h2::Error`. Users can downcast the source at\nruntime, and hyper internally changing the version of its `h2` dependency can\ncause runtime breakage for users.\n\nFormatting errors is in conflict with the current expected norm. The\n`fmt::Display` implementation for `hyper::Error` currently prints its own\nmessage, and then prints the message of any wrapped source error. The Errors\nWorking Group currently recommends that errors only print their own message\n(link?). This conflict means that error \"reporters\", which crawl a source chain\nand print each error, has a lot of duplicated information.\n\n```\nerror fetching website: error trying to connect: tcp connect error: Connection refused (os error 61)\ntcp connect error: Connection refused (os error 61)\nConnection refused (os error 61)\n```\n\nWhile there is a good reason for why hyper's `Error` types do this, at the very\nleast, it _is_ unfortunate.\n\n### You call hyper, or hyper calls you?\n\n> Note: this problem space, of who calls whom, will be explored more deeply in\n> a future article.\n\nAt times, it's been wondered whether hyper should call user code, or if user\ncode should call hyper. For instance, should a `Service` be called with a\nrequest when the connection receives one, or should the user always poll for\nthe next request.\n\nThere's a similar question around sending a message body. Should hyper ask the\nbody for more data to write, or should the user call a `write` method directly?\n\nThese both get at a root topic about [write\nobservability](https://github.com/hyperium/hyper/issues/2181). How do you know\nwhen a response, or when body data, has been written successfully? This is\ndesirable for metrics, or for triggering other side-effects. \n\nThe `Service` trait also has some other frequently mentioned issues. Does\n`poll_ready` pull its complexity weight for servers? What about returning\nerrors, what does that mean? Ideally users would turn all errors into\nappropriate `http::Response`s. But in HTTP/2 and beyond, stream errors are\ndifferent from HTTP Server Error responses. Could the `Service::Error` type do\nmore to encourage best practices?\n\n## Design\n\nThe goal is to get hyper closer to the [VISION][], using that to determine the\nbest way to solve the known issues above. The main thrust of the proposed\nchanges are to make hyper more **Flexible** and stable.\n\nIn order to keep hyper **Understandable**, however, the proposed changes *must*\nbe accompanied by providing utilities that solve the common usage patterns,\ndocumentation explaining how to use the more flexible pieces, and guides on how\nto reach for the `hyper-util`ity belt.\n\nThe majority of the changes are smaller and can be contained to the *Public\nAPI* section, since they usually only apply to a single module or type. But the\nbiggest changes are explained in detail here.\n\n### Split per HTTP version\n\nThe existing `Connection` types, both for the client and server, abstract over\nHTTP version by requiring a generic `AsyncRead + AsyncWrite` transport type.\nBut as we figure out HTTP/3, that needs to change. So to prepare now, the\n`Connection` types will be split up.\n\nFor example, there will now be `hyper::server::conn::http1::Connection` and\n`hyper::server::conn::http2::Connection` types.\n\nThese specific types will still have a very similar looking API that, as the\nVISION describes, provides **Correct** connection management as it pertains to\nHTTP.\n\nThere will be still be a type to wrap the different versions. It will no longer\nbe generic over the transport type, to prepare for being able to wrap HTTP/3\nconnections. Exactly how it will wrap, either by using internal trait objects,\nor an `enum Either` style, or using a `trait Connection` that each type\nimplements, is something to be determined. It's likely that this \"auto\" type\nwill start in `hyper-util`.\n\n### Focus on the `Connection` level\n\nAs mentioned in the *Known Issues*, the higher-level `Client` and `Server` have\nstability and complexity problems. Therefore, for hyper 1.0, the main API will\nfocus on the \"lower-level\" connection types. The `Client` and `Server` helpers\nwill be moved to `hyper-util`.\n\n## Public API\n\n### body\n\nThe `Body` struct is removed. Its internal \"variants\" are [separated into\ndistinct types](https://github.com/hyperium/hyper/issues/2345), and can start\nin either `hyper-util` or `http-body-util`.\n\nThe exported trait `HttpBody` is renamed to `Body`.\n\nA single `Body` implementation in `hyper` is the one provided by receiving\nclient responses and server requests. It has the name `Streaming`.\n\n> **Unresolved**: Other names can be considered during implementation. Another\n> option is to not publicly name the implementation, but return `Response<impl\nBody>`s.\n\nThe `Body` trait will be experimented on to see about making it possible to\nreturn more frame types beyonds just data and trailers.\n\n> **Unresolved**: What exactly this looks like will only be known after\n> experimentation.\n\n### client\n\nThe high-level `hyper::Client` will be removed, along with the\n`hyper::client::connect` module. They will be explored more in `hyper-util`.\n\nAs described in *Design*, the `client::conn` module will gain `http1` and\n`http2` sub-modules, providing per-version `SendRequest`, `Connection`, and\n`Builder` structs. An `auto` version can be explored in `hyper-util`.\n\n### error\n\nThe `hyper::Error` struct remains in place.\n\nAll errors returned from `Error::source()` are made opaque. They are wrapped an\ninternal `Opaque` newtype that still allows printing, but prevents downcasting\nto the internal dependency.\n\nA new `hyper::error::Code` struct is defined. It is an opaque struct, with\nassociated constants defining various code variants.\n\n> Alternative: define a non-exhaustive enum. It's not clear that this is\n> definitely better, though. Keeping it an opaque struct means we can add\n> secondary parts to the code in the future, or add bit flags, or similar\n> extensions.\n\nThe purpose of `Code` is to provide an abstraction over the kind of error that\nis encountered. The `Code` could be some behavior noticed inside hyper, such as\nan incomplete HTTP message. Or it can be \"translated\" from the underlying\nprotocol, if it defines protocol level errors. For example, an\n`h2::Reason::CANCEL`.\n\n### rt\n\nThe `Executor` trait stays in here.\n\nDefine a new trait `Timer`, which describes a way for users to provide a source\nof sleeping/timeout futures. Similar to `Executor`, a new generic is added to\nconnection builders to provide a `Timer`.\n\n### server\n\nThe higher-level `hyper::Server` struct, its related `Builder`, and the\n`Accept` trait are all removed.\n\nThe `AddrStream` struct will be completely removed, as it provides no value but\ncauses binary bloat.\n\nSimilar to `client`, and as describe in the *Design*, the `conn` modules will\nbe expanded to support `http1` and `http2` submodules. An `auto` version can be\nexplored in `hyper-util`.\n\n### service\n\nA vendored and simplified `Service` trait will be explored.\n\nThe error type for `Service`s used for a server will explore having the return\ntype changed from any error to one that can become a `hyper::error::Code`.\n\n> **Unresolved**: Both of the above points are not set in stone. We will\n> explore and decide if they are the best outcome during development.\n\nThe `MakeService` pieces will be removed.\n\n### Cargo Features\n\nRemove the `stream` feature. The `Stream` trait is not stable, and we cannot\ndepend on an unstable API.\n\nRemove the `tcp` and `runtime` features. The automatic executor and timer parts\nare handled by providing implementations of `Executor` and `Timer`. The\n`connect` and `Accept` parts are also moving to `hyper-util`.\n\n### Public Dependencies\n\n- `http`\n- `http-body`\n- `bytes`\n\nCannot be public while \"unstable\":\n\n- `tracing`\n\n## `hyper-util`\n\n\n### body\n\nA channel implementation of `Body` that has an API to know when the data has\nbeen successfully written is provided in `hyper_util::body::channel`.\n\n### client\n\nA `Pool` struct that implements `Service` is provided. It fills a similar role\nas the previous `hyper::Client`.\n\n> **Note**: The `Pool` might be something that goes into the `tower` crate\n> instead. Or it might stay here as a slightly more specialized racing-connect\n> pool. We'll find out as we go.\n\nA `connect` submodule that mostly mirrors the existing `hyper::client::connect`\nmodule is moved here. Connectors can be used as a source to provide `Service`s\nused by the `Pool`.\n\n### rt\n\nWe can provide Tokio-backed implementations of `Executor` and `Timer`.\n\n### server\n\nA `GracefulShutdown` helper is provided, to allow for similar style of graceful\nshutdown as the previous `hyper::Server` did, but with better control.\n\n# Appendix\n\n## Unresolved Questions\n\nThere are some parts of the proposal which are not fully resolved. They are\nmentioned in Design and API sections above, but also collected here for easy\nfinding. While they all have _plans_, they are more exploratory parts of the\nAPI, and thus they have a higher possibility of changing as we implement them.\n\nThe goal is to have these questions resolved and removed from the document by\nthe time there is a [Release Candidate][timeline].\n\n### Should there be `hyper::io` traits?\n\nDepending on `tokio` just for `AsyncRead` and `AsyncWrite` is convenient, but\ncan be confusing for users integrating hyper with other runtimes. It also ties\nour version directly to Tokio. We can consider having vendored traits, and\nproviding Tokio wrappers in `hyper-util`.\n\n### Should returned body types be `impl Body`?\n\n### How could the `Body` trait prepare for unknown frames?\n\nWe will experiment with this, and keep track of those experiments in a\ndedicated issue. It might be possible to use something like this:\n\n```rust\npub trait Body {\n    type Data;\n    fn poll_frame(..) -> Result<Option<Frame<Self::Data>>>;\n}\n\npub struct Frame<T>(Kind<T>);\n\nenum Kind<T> {\n   Data(T),\n   Trailers(HeaderMap),\n   Unknown(Box<dyn FrameThingy>),\n}\n```\n\n### Should there be a simplified `hyper::Service` trait, or should hyper depend on `tower-service`?\n\n- There's still a few uncertain decisions around tower, such as if it should be\n  changed to `async fn call`, and if `poll_ready` is the best way to handle\n  backpressure.\n- It's not clear that the backpressure is something needed at the `Server`\n  boundary, thus meaning we should remove `poll_ready` from hyper.\n- It's not 100% clear if we should keep the service pattern, or use a\n  pull-based API. This will be explored in a future blog post.\n\n## FAQ\n\n### Why did you pick _that_ name? Why not this other better name?\n\nNaming is hard. We certainly should solve it, but discussion for particular\nnames for structs and traits should be scoped to the specific issues. This\ndocument is to define the shape of the library API.\n\n### Should I publicly depend on `hyper-util`?\n\nThe `hyper-util` crate will not reach 1.0 when `hyper` does. Some types and\ntraits are being moved to `hyper-util`. As with any pre-1.0 crate, you _can_\npublicly depend on it, but it is explicitly less stable.\n\nIn most cases, it's recommended to not publicly expose your dependency on\n`hyper-util`. If you depend on a trait, such as used by the moved higher-level\n`Client` or `Server`, it may be better for your users to define your own\nabstraction, and then make an internal adapter.\n\n### Isn't this making hyper harder?\n\nWe are making hyper more **flexible**. As noted in the [VISION][], most use\ncases of hyper require it to be flexible. That _can_ mean that the exposed API\nis lower level, and that it feels more complicated. It should still be\n**understandable**.\n\nBut the hyper 1.0 effort is more than just the single `hyper` crate. Many\nuseful helpers will be migrated to a `hyper-util` crate, and likely improved in\nthe process. The [timeline][] also points out that we will have a significant\ndocumentation push. While the flexible pieces will be in hyper to compose how\nthey need, we will also write guides for the [hyper.rs][] showing people how to\naccomplish the most common tasks.\n\n[timeline]: https://seanmonstar.com/post/676912131372875776/hyper-10-timeline\n[VISION]: https://github.com/hyperium/hyper/pull/2772\n[hyper.rs]: https://hyper.rs\n"
  },
  {
    "path": "docs/ROADMAP.md",
    "content": "# Roadmap\n\n## Goal\n\nAlign current hyper to the [hyper VISION](./VISION.md).\n\nThe VISION outlines a decision-making framework, use-cases, and general shape\nof hyper. This roadmap describes the focus areas to continue to improve hyper\nto look more like what is in the VISION.\n\n## Focus Areas\n\nWhile open source is not a company, open source can be guiding. We _can_ focus\nattention to specific areas of improvement, which are based on conversations\nwith users, and prioritized by frequency and impact.\n\nTo that end, the following 4 areas are current focus of the project:\n\n1. Documentation\n2. `hyper-util`\n3. HTTP/3\n4. Observability\n\nEach area benefits from having a top level description and goal, a place to\ntrack progress, and a champion (or two) that helps push the effort.\n\n### Documentation\n\nhyper has stabilized, so investing in documentation is wise! The way it is used\nwon't change much, so documentation won't become outdated quickly. A tool that\npeople don't know how to use isn't helpful at all. This helps hyper be\n**Understandable**.\n\nThe documentation focus area includes several different forms:\n\n- The API docs as a reference.\n- Examples as form of how-to.\n- Website guides as tutorials.\n\nEach of these could benefit from dedicated planning of their overall structure,\nediting the content that already exists, and creating the rest that is sorely\nmissing.\n\n### hyper-util\n\n`hyper-util` serves two main purposes:\n\n1. Provide useful patterns that build on top of hyper.\n2. Explore, stabilize, and graduate some of those patterns into hyper itself.\n\nTo that end, there are several new features that can be worked on and iterated\non in `hyper-util` right now:\n\n- New design for a higher-level `Client`.\n- Breaking apart some patterns from `reqwest`, such as proxy helpers.\n- Server automatic version detection.\n- Improved builder patterns that make it easier to configure complicated\n  options.\n\n### HTTP/3\n\nhyper has an HTTP/3 crate, `h3`, that is generic over any QUIC implementation,\nsimilar to how hyper's HTTP/1 and HTTP/2 can be provided any IO transport. It\nsupports much of HTTP/3 already, and interoperates with most other\nimplementations. While some brave users have been trying it out the hard way\n(such as reqwest), it's time to bring HTTP/3 to more users.\n\nThe aim is to eventually support `hyper::client::conn::http3` and\n`hyper::server::conn::http3`.\n\nTo do so, work is needed:\n\n- Harden the `h3` crate itself, such as fixing any straggling interop issues,\n  and filling out the spec conformance tags we use for accountability.\n- Proposal for (initially unstable) `hyper::rt::quic` integration, allowing\n  people to bring their own QUIC.\n- Write the `hyper::proto::http3` glue that translates hyper's connection\n  patterns with the `h3` crate.\n\n### Observability\n\nIt's extremely common once operating a service using hyper to want more\nvisibility in what exactly is happening. It's important to realize that there\nare 3 concepts involved that frequently get conflated: events, tracing, and\nmetrics.\n\nSome existing ways to get some of these:\n\n- Unstable `tracing` integraton inside hyper.\n- `tower_http::trace` which instruments outside of hyper, using `Service` and\n  `Body`.\n\nHowever, there are some events and metrics that are only known inside hyper,\nand having official, stable support would be very helpful.\n\nSome potential options would be:\n\n- Stabilizing specific `tracing` events (blocked on the `tracing` crate\n  stabilizing...)\n- Provide a rudimentary, programmatic way to query metrics without another\n  crate.\n- Provide some sort of `hyper-metrics` helper.\n\n## Beyond\n\nThe above are focus areas that are the most frequently asked for, and so have\nthe most attention. That doesn't mean that nothing else can be worked on.\n\nMotivated individuals that want to help make other improvements are certainly\nwelcome!\n\n"
  },
  {
    "path": "docs/TENETS.md",
    "content": "# Charter\n\n> hyper is a protective and efficient HTTP library for all.\n\n# Tenets\n\nTenets are guiding principles. They guide how decisions are made for the whole\nproject. Ideally, we do all of them all the time. In some cases, though, we may\nbe forced to decide between slightly penalizing one goal or another. In that\ncase, we tend to support those goals that come earlier in the list over those\nthat come later (but every case is different).\n\n## 0. Open\n\nhyper is open source, always. The success of hyper depends on the health of the\ncommunity building and using it. All contributions are in the open. We don't\nmaintain private versions, and don't include features that aren't useful to\nothers.\n\n[We prioritize kindness](./CODE_OF_CONDUCT.md), compassion and empathy towards all\ncontributors. Technical skill is not a substitute for human decency.\n\n### Examples\n\nIt's not usually hard for an open source library to stay open and also meet its\nother priorities. Here's some instances where being **Open** would be more\nimportant than **Correct** or **Fast**:\n\n- Say an individual were to bring forward a contribution that makes hyper more\n  correct, or faster, perhaps fixing some serious bug. But in doing so, they\n  also insulted people, harassed other contributors or users, or shamed\n  everyone for the previous code. They felt their contribution was \"invaluable\".\n  We would not accept such a contribution, instead banning the user and\n  rewriting the code amongst the kind collaborators of the project.\n\n- Say someone brings a contribution that adds a new feature useful for\n  performance or correctness, but their work accomplishes this by integrating\n  hyper with a proprietary library. We would not accept such a contribution,\n  because we don't want such a feature limited only to those users willing to\n  compromise openness, and we don't want to bifurcate the ecosystem between those\n  who make that compromise and those who don't.\n\n## 1. Correct\n\nhyper is a memory safe and precise implementation of the HTTP specification.\nMemory safety is vital in a core Internet technology. Following the HTTP\nspecifications correctly protects users. It makes the software durable to the\n“real world”. Where feasible, hyper enforces correct usage.\n\nThis is more than just \"don't write bugs\". hyper actively protects the user.\n\n### Examples\n\n- Even though we follow the **HTTP/\\*** specs, hyper doesn't blindly implement\n  everything without considering if it is safe to do so.\n\n## 2. Fast\n\nA fast experience delights users. A faster network library means a faster\napplication, resulting in delighting our users’ users. Whether with one request,\nor millions.\n\nBeing _fast_ means we improve throughput, drive down CPU usage, and improve\nsustainability.\n\nFast _enough_. We don't sacrifice sanity for speed.\n\n## 3. HTTP/*\n\nhyper is specifically focused on HTTP. Supporting new HTTP versions is in scope,\nbut supporting separate protocols is not.\n\nThis also defines what the abstraction layer is: the API is designed around\nsending and receiving HTTP messages.\n\n## 4. Flexible\n\nhyper enables as many usecases as possible. It has no opinion on application\nstructure, and makes few assumptions about its environment. This includes being\nportable to different operating systems.\n\n### Examples\n\n- While we choose safer defaults to be **Correct**, hyper includes options to\n  _allow_ different behavior, when the user requires them.\n- Providing choice usually makes things more complex, so being **Flexible** does\n  mean it's less _easy_. That can sometimes conflict with simplest way of making\n  hyper **Understandable**.\n\n## 5. Understandable\n\nhyper is [no more complicated than it has to\nbe](https://en.wikipedia.org/wiki/Occam%27s_razor). HTTP is not simple. It may\nnot be as \"easy\" as 1-line to do everything, but it shouldn't be \"hard\" to find\nthe answers.\n\nFrom logical and misuse-resistant APIs, to stellar documentation, to transparent\nmetrics.\n"
  },
  {
    "path": "docs/VISION.md",
    "content": "# hyper Vision\n\n## Purpose\n\nThis is an overview of what the shape of hyper looks like, but also somewhat\nzoomed out, so that the _vision_ can survive while the exact minute details\nmight shift and change over time.\n\n### Charter\n\n> hyper is a protective and efficient HTTP library for all.\n\n### Tenets\n\nTenets are guiding principles. They guide how decisions are made for the whole\nproject. Ideally, we do all of them all the time. In some cases, though, we may\nbe forced to decide between slightly penalizing one goal or another. In that\ncase, we tend to support those goals that come earlier in the list over those\nthat come later (but every case is different).\n\n0. Open\n1. Correct\n2. Fast\n3. HTTP/\\*\n4. Flexible\n5. Understandable\n\nThere's a lot more detail about each in [TENETS](./TENETS.md).\n\n## Use Cases\n\nWho are the *users* of hyper? How would they use hyper?\n\n### Low-Level Client Library (curl, reqwest, aws-sdk)\n\nThese client libraries care that hyper is **Flexible**, since they are\nexpressing their own opinion on how a more-featured HTTP client should act.\nThis includes opinions on connection establishment, management, pooling, HTTP\nversion options, and even runtimes.\n\ncurl's main reason for using hyper is that it is **Safe**.\n\n### Web Server Frameworks (deno, axum)\n\nThese are using hyper's server feature to expose a different, higher-level API\nto users. Besides the obvious requirements, these require that hyper is\n**Fast**. Servers are costly, handling more requests faster is important to\nthem.\n\nThat hyper is **Flexible** is also important, in that it needs to be flexible\nenough for them to build a server framework, and allow them to express their\nown opinions about API to their users.\n\n### Services and Proxies (linkerd, cloudflare, fastly)\n\nThese are using hyper directly, likely both the client and server, in order to\nbuild efficient and powerful services, applications, and tools for their end\nusers. They care greatly that hyper is **Correct**, since web traffic can\nstretch the limits of what is valid HTTP, and exercise less-common parts of the\nspecifications.\n\nThey also require hyper to be **Fast**, for similar reasons that the web server\nframeworks do.\n\n### New Rust Web Developers\n\nThese are developers who are either new to Rust, or new to web servers, and\nhave reached for hyper to start with.\n\nIt's likely that these users don't have strong opinions about how an HTTP\nserver or client should work, just that it _should_ handle all the things they\nnormally assume it would. For these users, it would be best to quickly help\nthem compare their own expectations with hyper's capabilities, and may\nsuggest reaching for higher-level, _easier_ libraries instead.\n\nThose that stick around after that recommendation are users that wish both to\nlearn at a lower level, and to pick and choose what batteries they plug in to\nhyper as they move along. While they do care about the other tenets, that hyper\nis **Understandable** is of extra importance to them.\n\n## The Library\n\nSo with all that context in mind, what does hyper, the library, actually look\nlike? This doesn't highlight what _is_ and _isn't_ present. What currently\nneeds to change to reach this vision is left to individual version roadmaps.\n\n### Layers\n\nIn all cases, a user brings their own runtime and IO to work with hyper. The IO\nis provided to hyper, and hyper acts on top of it. hyper returns `Future`s that\nthe user then decides how to poll, likely involving their runtime options.\n\n![architecture diagram](./vision-arch.svg)\n\n\n#### Protocol Codecs\n\nhyper has dedicated codecs for the major HTTP versions. Each is internally\ndesigned to be **Correct** and **Fast** when it comes to encoding and decoding.\n\nThe individual codecs may be implemented as sub-crates, with a less-stable\npromise, to support the **Flexible** needs of some users who wish to build\ntheir own connection management, or customize encoding and decoding beyond what\nis officially supported.\n\n#### Connection State Management\n\nA **Correct** implementation includes more than just enforcing certain\ncharacters when encoding and decoding. Order of frames, and flags in certain\nframes can affect the state of the connection. Some examples of things enforced\nat this layer:\n\n- If a message has a `content-length`, enforce only that many bytes are read or\n  written.\n- Reading a `Response` before a `Request` is even written implies a mismatched\n  reply that should be interpreted as an error.\n- The presence of some headers, such as `Connection: close`, or the absence of\n  others, such as `content-length` and `transfer-encoding`, can mean that the\n  connection should terminate after the current message.\n- HTTP/2 and HTTP/3 may send connection-level frames that don't pertain to any\n  specific transaction, and must be read and handled regardless of if a user is\n  currently checking for a message.\n\n#### HTTP Role and Version Abstraction\n\nThis is the public API layer. Methods exposed are around sending and receiving\n`http::Request`s and `http::Response`s, not around framing specifics of the\ndifferent versions. These are built around a client or server `Connection`\ninterface.\n\nBy exposing this layer publicly, we take care of the **Correct** tenet, by not\nforcing the user to send the specific frames themselves. The API should be\ndesigned in a way that a user cannot easily (if at all) create an _incorrect_\nHTTP connection.\n\nMotivated by the **Flexible** tenet, there _are_ version-specific options that\ncan be configured at this level, and version-specific functionality can usually\nbe handled via `http::Extensions`.\n\n### Not quite stable, but utile (useful)\n\nBeyond what is directly in the hyper crate, there are useful (utile) parts that\nmay not meet hyper's stability promise. Developing, experimenting, and exposing\nthose parts is the purpose of the `hyper-util` crate. That crate does not have\nthe same stability level as hyper. However, the goal is that things that other\nlibraries might want to expose as a public dependency do not live in\n`hyper-util` forever, but rather stabilize and get promoted into `hyper`.\n\nExactly what gets put into `hyper-util` presently is kept in the roadmap\ndocuments.\n\n### Stability Promise\n\nWhat even is hyper's stability promise? Does it mean we are \"done\"? No. Will we\never make breaking changes again? Probably. We'll still follow the [semantic\nversioning](https://semver.org).\n\nPrior to 1.0, hyper has already only done breaking changes once a year. So 1\nyear isn't much of a promise. We'll have significant more use and understanding\nafter a few years, and that could prompt some redesign.\n\nAs of this writing, we'll promise that _major_ versions of hyper are stable for\n3 years. New features will come out in _minor_ versions frequently. If it is\ndetermined necessary to make breaking changes to the API, we'll save them for\nafter the 3 years.\n\nhyper also establishes a Minimum Supported Rust Version (MSRV). hyper will\nsupport Rust versions at least 6 months old. If a new Rust version is released\nwith a feature hyper wishes to use, we won't do so until at least 6 months\nafterwards. hyper will only ever require a new Rust version as a _minor_\nrelease (1.x), not as a patch (1.x.y).\n\n## Security\n\nThe security of hyper is a large part of what makes hyper _protective_. We make\nhyper secure via the combined efforts of being **Correct**, focusing on\n**HTTP/\\***, and making it all **Understandable**.\n\n### Memory Safety\n\nBeing **Correct** requires that hyper be memory-safe. Using the Rust language\ngets us most of the way there. But there is the ability to write `unsafe`\nRust. Does being **Correct** mean that we can _never_ write `unsafe` code\nanywhere? Even if it helps make hyper **Fast**? We can, carefully.\n\nHow do we balance the two, so that hyper is secure?\n\nhyper prefers not to have large modules of intertwined `unsafe` code. hyper\ndoes allow small `unsafe` blocks, no more than a few lines, where it's easier\nto verify that the `unsafe` code was written **Correctly**.\n\n### Meticulous Testing\n\nhyper's test suite grows and grows. There's a lot that needs to be right.\nParsers, encoders, state machines. When easily isolated, those pieces have\ninternal unit tests. But hyper also keeps a large list of growing integration\ntests that make sure all the parts are **Correct**.\n\nMaking writing new tests easy is a high priority. Investing in the testing\ninfrastructure is a proven way to make sure hyper stays **Correct** and secure.\n\n### Constant Fuzzing\n\nOne thing is to know specific cases to test for. But we can't know all the\ninputs or states that *might* cause a bug. That's why hyper has rounds of\nfuzzing built into its CI. It's also why hyper signs up for and uses resources\nto provide *constant*, around-the-clock fuzzing, always looking for something\nthat hyper should be hardened against.\n\n### Security Process\n\nhyper has an outlined\n[SECURITY](https://github.com/hyperium/hyper/blob/master/SECURITY.md) process,\nso we can safely report and fix issues.\n\n## Non-goals\n\nAfter writing this up, it is easier to articulate what sorts of things many\nmight associate with an HTTP library, but which are explicitly *not* for hyper.\nThese are all things that are definitely **out of scope**.\n\n- TLS: We learned early that bundling TLS directly in hyper [has\n  problems](https://github.com/hyperium/hyper/issues/985). People also have\n  very strong opinions about which TLS implementation to use. The design of\n  hyper allows users to bring their own TLS.\n- Routing\n- Cookies\n- Not-HTTP: WebSockets, or other protocols that are built next to HTTP. It\n  should be possible to _use_ hyper to upgrade, but the actual next-protocol\n  should be handled by a different library.\n"
  },
  {
    "path": "examples/README.md",
    "content": "# Examples of using hyper\n\nThese examples show how to do common tasks using `hyper`. You may also find the [Guides](https://hyper.rs/guides/1/) helpful.\n\nIf you checkout this repository, you can run any of the examples with the command:\n\n `cargo run --example {example_name} --features=\"full\"`\n\n### Dependencies\n\nA complete list of dependencies used across these examples:\n\n```toml\n[dependencies]\nhyper = { version = \"1\", features = [\"full\"] }\ntokio = { version = \"1\", features = [\"full\"] }\npretty_env_logger = \"0.5\"\nhttp-body-util = \"0.1\"\nbytes = \"1\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nserde_json = \"1.0\"\nform_urlencoded = \"1\"\nhttp = \"1\"\nfutures-util = { version = \"0.3\", default-features = false }\n```\n\n## Getting Started\n\n### Clients\n\n* [`client`](client.rs) - A simple CLI http client that requests the url passed in parameters and outputs the response content and details to the stdout, reading content chunk-by-chunk.\n\n* [`client_json`](client_json.rs) - A simple program that GETs some json, reads the body asynchronously, parses it with serde and outputs the result.\n\n### Servers\n\n* [`hello`](hello.rs) - A simple server that returns \"Hello World!\".\n\n* [`echo`](echo.rs) - An echo server that copies POST request's content to the response content.\n\n## Going Further\n\n* [`gateway`](gateway.rs) - A server gateway (reverse proxy) that proxies to the `hello` service above.\n\n* [`graceful_shutdown`](graceful_shutdown.rs) - A server that has a timeout for incoming connections and does graceful connection shutdown.\n\n* [`http_proxy`](http_proxy.rs) - A simple HTTP(S) proxy that handle and upgrade `CONNECT` requests and then proxy data between client and remote server.\n\n* [`multi_server`](multi_server.rs) - A server that listens to two different ports, a different `Service` per port.\n\n* [`params`](params.rs) - A webserver that accept a form, with a name and a number, checks the parameters are presents and validates the input.\n\n* [`send_file`](send_file.rs) - A server that sends back content of files using tokio-util to read the files asynchronously.\n\n* [`service_struct_impl`](service_struct_impl.rs) - A struct that manually implements the `Service` trait and uses a shared counter across requests.\n\n* [`single_threaded`](single_threaded.rs) - A server only running on 1 thread, so it can make use of `!Send` app state (like an `Rc` counter).\n\n* [`state`](state.rs) - A webserver showing basic state sharing among requests. A counter is shared, incremented for every request, and every response is sent the last count.\n\n* [`upgrades`](upgrades.rs) - A server and client demonstrating how to do HTTP upgrades (such as WebSockets).\n\n* [`web_api`](web_api.rs) - A server consisting in a service that returns incoming POST request's content in the response in uppercase and a service that calls the first service and includes the first service response in its own response.\n"
  },
  {
    "path": "examples/client.rs",
    "content": "#![deny(warnings)]\n#![warn(rust_2018_idioms)]\nuse std::env;\n\nuse bytes::Bytes;\nuse http_body_util::{BodyExt, Empty};\nuse hyper::Request;\nuse tokio::io::{self, AsyncWriteExt as _};\nuse tokio::net::TcpStream;\n\n#[path = \"../benches/support/mod.rs\"]\nmod support;\nuse support::TokioIo;\n\n// A simple type alias so as to DRY.\ntype Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;\n\n#[tokio::main]\nasync fn main() -> Result<()> {\n    pretty_env_logger::init();\n\n    // Some simple CLI args requirements...\n    let url = match env::args().nth(1) {\n        Some(url) => url,\n        None => {\n            println!(\"Usage: client <url>\");\n            return Ok(());\n        }\n    };\n\n    // HTTPS requires picking a TLS implementation, so give a better\n    // warning if the user tries to request an 'https' URL.\n    let url = url.parse::<hyper::Uri>().unwrap();\n    if url.scheme_str() != Some(\"http\") {\n        println!(\"This example only works with 'http' URLs.\");\n        return Ok(());\n    }\n\n    fetch_url(url).await\n}\n\nasync fn fetch_url(url: hyper::Uri) -> Result<()> {\n    let host = url.host().expect(\"uri has no host\");\n    let port = url.port_u16().unwrap_or(80);\n    let addr = format!(\"{}:{}\", host, port);\n    let stream = TcpStream::connect(addr).await?;\n    let io = TokioIo::new(stream);\n\n    let (mut sender, conn) = hyper::client::conn::http1::handshake(io).await?;\n    tokio::task::spawn(async move {\n        if let Err(err) = conn.await {\n            println!(\"Connection failed: {:?}\", err);\n        }\n    });\n\n    let authority = url.authority().unwrap().clone();\n\n    let path = url.path();\n    let req = Request::builder()\n        .uri(path)\n        .header(hyper::header::HOST, authority.as_str())\n        .body(Empty::<Bytes>::new())?;\n\n    let mut res = sender.send_request(req).await?;\n\n    println!(\"Response: {}\", res.status());\n    println!(\"Headers: {:#?}\\n\", res.headers());\n\n    // Stream the body, writing each chunk to stdout as we get it\n    // (instead of buffering and printing at the end).\n    while let Some(next) = res.frame().await {\n        let frame = next?;\n        if let Some(chunk) = frame.data_ref() {\n            io::stdout().write_all(chunk).await?;\n        }\n    }\n\n    println!(\"\\n\\nDone!\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/client_json.rs",
    "content": "#![deny(warnings)]\n#![warn(rust_2018_idioms)]\n\nuse bytes::Bytes;\nuse http_body_util::{BodyExt, Empty};\nuse hyper::{body::Buf, Request};\nuse serde::Deserialize;\nuse tokio::net::TcpStream;\n\n#[path = \"../benches/support/mod.rs\"]\nmod support;\nuse support::TokioIo;\n\n// A simple type alias so as to DRY.\ntype Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;\n\n#[tokio::main]\nasync fn main() -> Result<()> {\n    let url = \"http://jsonplaceholder.typicode.com/users\".parse().unwrap();\n    let users = fetch_json(url).await?;\n    // print users\n    println!(\"users: {:#?}\", users);\n\n    // print the sum of ids\n    let sum = users.iter().fold(0, |acc, user| acc + user.id);\n    println!(\"sum of ids: {}\", sum);\n    Ok(())\n}\n\nasync fn fetch_json(url: hyper::Uri) -> Result<Vec<User>> {\n    let host = url.host().expect(\"uri has no host\");\n    let port = url.port_u16().unwrap_or(80);\n    let addr = format!(\"{}:{}\", host, port);\n\n    let stream = TcpStream::connect(addr).await?;\n    let io = TokioIo::new(stream);\n\n    let (mut sender, conn) = hyper::client::conn::http1::handshake(io).await?;\n    tokio::task::spawn(async move {\n        if let Err(err) = conn.await {\n            println!(\"Connection failed: {:?}\", err);\n        }\n    });\n\n    let authority = url.authority().unwrap().clone();\n\n    // Fetch the url...\n    let req = Request::builder()\n        .uri(url)\n        .header(hyper::header::HOST, authority.as_str())\n        .body(Empty::<Bytes>::new())?;\n\n    let res = sender.send_request(req).await?;\n\n    // asynchronously aggregate the chunks of the body\n    let body = res.collect().await?.aggregate();\n\n    // try to parse as json with serde_json\n    let users = serde_json::from_reader(body.reader())?;\n\n    Ok(users)\n}\n\n#[derive(Deserialize, Debug)]\nstruct User {\n    id: i32,\n    #[allow(unused)]\n    name: String,\n}\n"
  },
  {
    "path": "examples/echo.rs",
    "content": "#![deny(warnings)]\n\nuse std::net::SocketAddr;\n\nuse bytes::Bytes;\nuse http_body_util::{combinators::BoxBody, BodyExt, Empty, Full};\nuse hyper::body::Frame;\nuse hyper::server::conn::http1;\nuse hyper::service::service_fn;\nuse hyper::{body::Body, Method, Request, Response, StatusCode};\nuse tokio::net::TcpListener;\n\n#[path = \"../benches/support/mod.rs\"]\nmod support;\nuse support::TokioIo;\n\n/// This is our service handler. It receives a Request, routes on its\n/// path, and returns a Future of a Response.\nasync fn echo(\n    req: Request<hyper::body::Incoming>,\n) -> Result<Response<BoxBody<Bytes, hyper::Error>>, hyper::Error> {\n    match (req.method(), req.uri().path()) {\n        // Serve some instructions at /\n        (&Method::GET, \"/\") => Ok(Response::new(full(\n            \"Try POSTing data to /echo such as: `curl localhost:3000/echo -XPOST -d \\\"hello world\\\"`\",\n        ))),\n\n        // Simply echo the body back to the client.\n        (&Method::POST, \"/echo\") => Ok(Response::new(req.into_body().boxed())),\n\n        // Convert to uppercase before sending back to client using a stream.\n        (&Method::POST, \"/echo/uppercase\") => {\n            let frame_stream = req.into_body().map_frame(|frame| {\n                let frame = if let Ok(data) = frame.into_data() {\n                    data.iter()\n                        .map(|byte| byte.to_ascii_uppercase())\n                        .collect::<Bytes>()\n                } else {\n                    Bytes::new()\n                };\n\n                Frame::data(frame)\n            });\n\n            Ok(Response::new(frame_stream.boxed()))\n        }\n\n        // Reverse the entire body before sending back to the client.\n        //\n        // Since we don't know the end yet, we can't simply stream\n        // the chunks as they arrive as we did with the above uppercase endpoint.\n        // So here we do `.await` on the future, waiting on concatenating the full body,\n        // then afterwards the content can be reversed. Only then can we return a `Response`.\n        (&Method::POST, \"/echo/reversed\") => {\n            // To protect our server, reject requests with bodies larger than\n            // 64kbs of data.\n            let max = req.body().size_hint().upper().unwrap_or(u64::MAX);\n            if max > 1024 * 64 {\n                let mut resp = Response::new(full(\"Body too big\"));\n                *resp.status_mut() = hyper::StatusCode::PAYLOAD_TOO_LARGE;\n                return Ok(resp);\n            }\n\n            let whole_body = req.collect().await?.to_bytes();\n\n            let reversed_body = whole_body.iter().rev().cloned().collect::<Vec<u8>>();\n            Ok(Response::new(full(reversed_body)))\n        }\n\n        // Return the 404 Not Found for other routes.\n        _ => {\n            let mut not_found = Response::new(empty());\n            *not_found.status_mut() = StatusCode::NOT_FOUND;\n            Ok(not_found)\n        }\n    }\n}\n\nfn empty() -> BoxBody<Bytes, hyper::Error> {\n    Empty::<Bytes>::new()\n        .map_err(|never| match never {})\n        .boxed()\n}\n\nfn full<T: Into<Bytes>>(chunk: T) -> BoxBody<Bytes, hyper::Error> {\n    Full::new(chunk.into())\n        .map_err(|never| match never {})\n        .boxed()\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));\n\n    let listener = TcpListener::bind(addr).await?;\n    println!(\"Listening on http://{}\", addr);\n    loop {\n        let (stream, _) = listener.accept().await?;\n        let io = TokioIo::new(stream);\n\n        tokio::task::spawn(async move {\n            if let Err(err) = http1::Builder::new()\n                .serve_connection(io, service_fn(echo))\n                .await\n            {\n                println!(\"Error serving connection: {:?}\", err);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "examples/gateway.rs",
    "content": "#![deny(warnings)]\n\nuse hyper::{server::conn::http1, service::service_fn};\nuse std::net::SocketAddr;\nuse tokio::net::{TcpListener, TcpStream};\n\n#[path = \"../benches/support/mod.rs\"]\nmod support;\nuse support::TokioIo;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    pretty_env_logger::init();\n\n    let in_addr: SocketAddr = ([127, 0, 0, 1], 3001).into();\n    let out_addr: SocketAddr = ([127, 0, 0, 1], 3000).into();\n\n    let out_addr_clone = out_addr;\n\n    let listener = TcpListener::bind(in_addr).await?;\n\n    println!(\"Listening on http://{}\", in_addr);\n    println!(\"Proxying on http://{}\", out_addr);\n\n    loop {\n        let (stream, _) = listener.accept().await?;\n        let io = TokioIo::new(stream);\n\n        // This is the `Service` that will handle the connection.\n        // `service_fn` is a helper to convert a function that\n        // returns a Response into a `Service`.\n        let service = service_fn(move |mut req| {\n            let uri_string = format!(\n                \"http://{}{}\",\n                out_addr_clone,\n                req.uri()\n                    .path_and_query()\n                    .map(|x| x.as_str())\n                    .unwrap_or(\"/\")\n            );\n            let uri = uri_string.parse().unwrap();\n            *req.uri_mut() = uri;\n\n            let host = req.uri().host().expect(\"uri has no host\");\n            let port = req.uri().port_u16().unwrap_or(80);\n            let addr = format!(\"{}:{}\", host, port);\n\n            async move {\n                let client_stream = TcpStream::connect(addr).await.unwrap();\n                let io = TokioIo::new(client_stream);\n\n                let (mut sender, conn) = hyper::client::conn::http1::handshake(io).await?;\n                tokio::task::spawn(async move {\n                    if let Err(err) = conn.await {\n                        println!(\"Connection failed: {:?}\", err);\n                    }\n                });\n\n                sender.send_request(req).await\n            }\n        });\n\n        tokio::task::spawn(async move {\n            if let Err(err) = http1::Builder::new().serve_connection(io, service).await {\n                println!(\"Failed to serve the connection: {:?}\", err);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "examples/graceful_shutdown.rs",
    "content": "#![deny(warnings)]\n\nuse std::convert::Infallible;\nuse std::net::SocketAddr;\nuse std::time::Duration;\n\nuse bytes::Bytes;\nuse http_body_util::Full;\nuse hyper::server::conn::http1;\nuse hyper::service::service_fn;\nuse hyper::{Request, Response};\nuse tokio::net::TcpListener;\nuse tokio::pin;\n\n#[path = \"../benches/support/mod.rs\"]\nmod support;\nuse support::TokioIo;\n\n// An async function that consumes a request, does nothing with it and returns a\n// response.\nasync fn hello(_: Request<hyper::body::Incoming>) -> Result<Response<Full<Bytes>>, Infallible> {\n    // Sleep for 6 seconds to simulate long processing.\n    // This is longer than the initial 5 second connection timeout,\n    // but within the 2 second graceful shutdown timeout.\n    println!(\"in hello before sleep\");\n    tokio::time::sleep(Duration::from_secs(6)).await;\n    println!(\"in hello after sleep\");\n    Ok(Response::new(Full::new(Bytes::from(\"Hello World!\"))))\n}\n\n#[tokio::main]\npub async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n    pretty_env_logger::init();\n\n    // This address is localhost\n    let addr: SocketAddr = ([127, 0, 0, 1], 3000).into();\n\n    // Use a 5 second timeout for incoming connections to the server.\n    // If a request is in progress when the 5 second timeout elapses,\n    // use a 2 second timeout for processing the final request and graceful shutdown.\n    let connection_timeouts = vec![Duration::from_secs(5), Duration::from_secs(2)];\n\n    // Bind to the port and listen for incoming TCP connections\n    let listener = TcpListener::bind(addr).await?;\n    println!(\"Listening on http://{}\", addr);\n    loop {\n        // When an incoming TCP connection is received grab a TCP stream for\n        // client<->server communication.\n        let (tcp, remote_address) = listener.accept().await?;\n\n        // Use an adapter to access something implementing `tokio::io` traits as if they implement\n        // `hyper::rt` IO traits.\n        let io = TokioIo::new(tcp);\n\n        // Print the remote address connecting to our server.\n        println!(\"accepted connection from {:?}\", remote_address);\n\n        // Clone the connection_timeouts so they can be passed to the new task.\n        let connection_timeouts_clone = connection_timeouts.clone();\n\n        // Spin up a new task in Tokio so we can continue to listen for new TCP connection on the\n        // current task without waiting for the processing of the HTTP1 connection we just received\n        // to finish\n        tokio::task::spawn(async move {\n            // Pin the connection object so we can use tokio::select! below.\n            let conn = http1::Builder::new().serve_connection(io, service_fn(hello));\n            pin!(conn);\n\n            // Iterate the timeouts.  Use tokio::select! to wait on the\n            // result of polling the connection itself,\n            // and also on tokio::time::sleep for the current timeout duration.\n            for (iter, sleep_duration) in connection_timeouts_clone.iter().enumerate() {\n                println!(\"iter = {} sleep_duration = {:?}\", iter, sleep_duration);\n                tokio::select! {\n                    res = conn.as_mut() => {\n                        // Polling the connection returned a result.\n                        // In this case print either the successful or error result for the connection\n                        // and break out of the loop.\n                        match res {\n                            Ok(()) => println!(\"after polling conn, no error\"),\n                            Err(e) =>  println!(\"error serving connection: {:?}\", e),\n                        };\n                        break;\n                    }\n                    _ = tokio::time::sleep(*sleep_duration) => {\n                        // tokio::time::sleep returned a result.\n                        // Call graceful_shutdown on the connection and continue the loop.\n                        println!(\"iter = {} got timeout_interval, calling conn.graceful_shutdown\", iter);\n                        conn.as_mut().graceful_shutdown();\n                    }\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "examples/hello-http2.rs",
    "content": "#![deny(warnings)]\n#![allow(unused_imports)]\n\nuse http_body_util::Full;\nuse hyper::body::Bytes;\n#[cfg(feature = \"server\")]\nuse hyper::server::conn::http2;\nuse hyper::service::service_fn;\nuse hyper::{Request, Response};\nuse std::convert::Infallible;\nuse std::net::SocketAddr;\nuse tokio::net::TcpListener;\n\n// This would normally come from the `hyper-util` crate, but we can't depend\n// on that here because it would be a cyclical dependency.\n#[path = \"../benches/support/mod.rs\"]\nmod support;\nuse support::TokioIo;\n\n// An async function that consumes a request, does nothing with it and returns a\n// response.\n#[cfg(feature = \"server\")]\nasync fn hello(_: Request<hyper::body::Incoming>) -> Result<Response<Full<Bytes>>, Infallible> {\n    Ok(Response::new(Full::new(Bytes::from(\"Hello, World!\"))))\n}\n\n#[derive(Clone)]\n// An Executor that uses the tokio runtime.\npub struct TokioExecutor;\n\n// Implement the `hyper::rt::Executor` trait for `TokioExecutor` so that it can be used to spawn\n// tasks in the hyper runtime.\n// An Executor allows us to manage execution of tasks which can help us improve the efficiency and\n// scalability of the server.\nimpl<F> hyper::rt::Executor<F> for TokioExecutor\nwhere\n    F: std::future::Future + Send + 'static,\n    F::Output: Send + 'static,\n{\n    fn execute(&self, fut: F) {\n        tokio::task::spawn(fut);\n    }\n}\n\n#[cfg(feature = \"server\")]\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n    pretty_env_logger::init();\n\n    // This address is localhost\n    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));\n\n    // Bind to the port and listen for incoming TCP connections\n    let listener = TcpListener::bind(addr).await?;\n\n    loop {\n        // When an incoming TCP connection is received grab a TCP stream for\n        // client-server communication.\n        //\n        // Note, this is a .await point, this loop will loop forever but is not a busy loop. The\n        // .await point allows the Tokio runtime to pull the task off of the thread until the task\n        // has work to do. In this case, a connection arrives on the port we are listening on and\n        // the task is woken up, at which point the task is then put back on a thread, and is\n        // driven forward by the runtime, eventually yielding a TCP stream.\n        let (stream, _) = listener.accept().await?;\n        // Use an adapter to access something implementing `tokio::io` traits as if they implement\n        // `hyper::rt` IO traits.\n        let io = TokioIo::new(stream);\n\n        // Spin up a new task in Tokio so we can continue to listen for new TCP connection on the\n        // current task without waiting for the processing of the HTTP/2 connection we just received\n        // to finish\n        tokio::task::spawn(async move {\n            // Handle the connection from the client using HTTP/2 with an executor and pass any\n            // HTTP requests received on that connection to the `hello` function\n            if let Err(err) = http2::Builder::new(TokioExecutor)\n                .serve_connection(io, service_fn(hello))\n                .await\n            {\n                eprintln!(\"Error serving connection: {}\", err);\n            }\n        });\n    }\n}\n\n#[cfg(not(feature = \"server\"))]\nfn main() {\n    panic!(\"This example requires the 'server' feature to be enabled\");\n}\n"
  },
  {
    "path": "examples/hello.rs",
    "content": "#![deny(warnings)]\n\nuse std::convert::Infallible;\nuse std::net::SocketAddr;\n\nuse bytes::Bytes;\nuse http_body_util::Full;\nuse hyper::server::conn::http1;\nuse hyper::service::service_fn;\nuse hyper::{Request, Response};\nuse tokio::net::TcpListener;\n\n// This would normally come from the `hyper-util` crate, but we can't depend\n// on that here because it would be a cyclical dependency.\n#[path = \"../benches/support/mod.rs\"]\nmod support;\nuse support::{TokioIo, TokioTimer};\n\n// An async function that consumes a request, does nothing with it and returns a\n// response.\nasync fn hello(_: Request<impl hyper::body::Body>) -> Result<Response<Full<Bytes>>, Infallible> {\n    Ok(Response::new(Full::new(Bytes::from(\"Hello World!\"))))\n}\n\n#[tokio::main]\npub async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n    pretty_env_logger::init();\n\n    // This address is localhost\n    let addr: SocketAddr = ([127, 0, 0, 1], 3000).into();\n\n    // Bind to the port and listen for incoming TCP connections\n    let listener = TcpListener::bind(addr).await?;\n    println!(\"Listening on http://{}\", addr);\n    loop {\n        // When an incoming TCP connection is received grab a TCP stream for\n        // client<->server communication.\n        //\n        // Note, this is a .await point, this loop will loop forever but is not a busy loop. The\n        // .await point allows the Tokio runtime to pull the task off of the thread until the task\n        // has work to do. In this case, a connection arrives on the port we are listening on and\n        // the task is woken up, at which point the task is then put back on a thread, and is\n        // driven forward by the runtime, eventually yielding a TCP stream.\n        let (tcp, _) = listener.accept().await?;\n        // Use an adapter to access something implementing `tokio::io` traits as if they implement\n        // `hyper::rt` IO traits.\n        let io = TokioIo::new(tcp);\n\n        // Spin up a new task in Tokio so we can continue to listen for new TCP connection on the\n        // current task without waiting for the processing of the HTTP1 connection we just received\n        // to finish\n        tokio::task::spawn(async move {\n            // Handle the connection from the client using HTTP1 and pass any\n            // HTTP requests received on that connection to the `hello` function\n            if let Err(err) = http1::Builder::new()\n                .timer(TokioTimer::new())\n                .serve_connection(io, service_fn(hello))\n                .await\n            {\n                println!(\"Error serving connection: {:?}\", err);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "examples/http_proxy.rs",
    "content": "#![deny(warnings)]\n\nuse std::net::SocketAddr;\n\nuse bytes::Bytes;\nuse http_body_util::{combinators::BoxBody, BodyExt, Empty, Full};\nuse hyper::service::service_fn;\nuse hyper::upgrade::Upgraded;\nuse hyper::{Method, Request, Response};\n\nuse tokio::net::{TcpListener, TcpStream};\n\n#[path = \"../benches/support/mod.rs\"]\nmod support;\nuse support::TokioIo;\n\ntype ClientBuilder = hyper::client::conn::http1::Builder;\ntype ServerBuilder = hyper::server::conn::http1::Builder;\n\n// To try this example:\n// 1. cargo run --example http_proxy\n// 2. config http_proxy in command line\n//    $ export http_proxy=http://127.0.0.1:8100\n//    $ export https_proxy=http://127.0.0.1:8100\n// 3. send requests\n//    $ curl -i https://www.some_domain.com/\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = SocketAddr::from(([127, 0, 0, 1], 8100));\n\n    let listener = TcpListener::bind(addr).await?;\n    println!(\"Listening on http://{}\", addr);\n\n    loop {\n        let (stream, _) = listener.accept().await?;\n        let io = TokioIo::new(stream);\n\n        tokio::task::spawn(async move {\n            if let Err(err) = ServerBuilder::new()\n                .preserve_header_case(true)\n                .title_case_headers(true)\n                .serve_connection(io, service_fn(proxy))\n                .with_upgrades()\n                .await\n            {\n                println!(\"Failed to serve connection: {:?}\", err);\n            }\n        });\n    }\n}\n\nasync fn proxy(\n    req: Request<hyper::body::Incoming>,\n) -> Result<Response<BoxBody<Bytes, hyper::Error>>, hyper::Error> {\n    println!(\"req: {:?}\", req);\n\n    if Method::CONNECT == req.method() {\n        // Received an HTTP request like:\n        // ```\n        // CONNECT www.domain.com:443 HTTP/1.1\n        // Host: www.domain.com:443\n        // Proxy-Connection: Keep-Alive\n        // ```\n        //\n        // When HTTP method is CONNECT we should return an empty body\n        // then we can eventually upgrade the connection and talk a new protocol.\n        //\n        // Note: only after client received an empty body with STATUS_OK can the\n        // connection be upgraded, so we can't return a response inside\n        // `on_upgrade` future.\n        if let Some(addr) = host_addr(req.uri()) {\n            tokio::task::spawn(async move {\n                match hyper::upgrade::on(req).await {\n                    Ok(upgraded) => {\n                        if let Err(e) = tunnel(upgraded, addr).await {\n                            eprintln!(\"server io error: {}\", e);\n                        };\n                    }\n                    Err(e) => eprintln!(\"upgrade error: {}\", e),\n                }\n            });\n\n            Ok(Response::new(empty()))\n        } else {\n            eprintln!(\"CONNECT host is not socket addr: {:?}\", req.uri());\n            let mut resp = Response::new(full(\"CONNECT must be to a socket address\"));\n            *resp.status_mut() = http::StatusCode::BAD_REQUEST;\n\n            Ok(resp)\n        }\n    } else {\n        let host = req.uri().host().expect(\"uri has no host\");\n        let port = req.uri().port_u16().unwrap_or(80);\n\n        let stream = TcpStream::connect((host, port)).await.unwrap();\n        let io = TokioIo::new(stream);\n\n        let (mut sender, conn) = ClientBuilder::new()\n            .preserve_header_case(true)\n            .title_case_headers(true)\n            .handshake(io)\n            .await?;\n        tokio::task::spawn(async move {\n            if let Err(err) = conn.await {\n                println!(\"Connection failed: {:?}\", err);\n            }\n        });\n\n        let resp = sender.send_request(req).await?;\n        Ok(resp.map(|b| b.boxed()))\n    }\n}\n\nfn host_addr(uri: &http::Uri) -> Option<String> {\n    uri.authority().map(|auth| auth.to_string())\n}\n\nfn empty() -> BoxBody<Bytes, hyper::Error> {\n    Empty::<Bytes>::new()\n        .map_err(|never| match never {})\n        .boxed()\n}\n\nfn full<T: Into<Bytes>>(chunk: T) -> BoxBody<Bytes, hyper::Error> {\n    Full::new(chunk.into())\n        .map_err(|never| match never {})\n        .boxed()\n}\n\n// Create a TCP connection to host:port, build a tunnel between the connection and\n// the upgraded connection\nasync fn tunnel(upgraded: Upgraded, addr: String) -> std::io::Result<()> {\n    // Connect to remote server\n    let mut server = TcpStream::connect(addr).await?;\n    let mut upgraded = TokioIo::new(upgraded);\n\n    // Proxying data\n    let (from_client, from_server) =\n        tokio::io::copy_bidirectional(&mut upgraded, &mut server).await?;\n\n    // Print message when done\n    println!(\n        \"client wrote {} bytes and received {} bytes\",\n        from_client, from_server\n    );\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/multi_server.rs",
    "content": "#![deny(warnings)]\n#![warn(rust_2018_idioms)]\n\nuse std::net::SocketAddr;\n\nuse bytes::Bytes;\nuse futures_util::future::join;\nuse http_body_util::Full;\nuse hyper::server::conn::http1;\nuse hyper::service::service_fn;\nuse hyper::{Request, Response};\nuse tokio::net::TcpListener;\n\n#[path = \"../benches/support/mod.rs\"]\nmod support;\nuse support::TokioIo;\n\nstatic INDEX1: &[u8] = b\"The 1st service!\";\nstatic INDEX2: &[u8] = b\"The 2nd service!\";\n\nasync fn index1(_: Request<hyper::body::Incoming>) -> Result<Response<Full<Bytes>>, hyper::Error> {\n    Ok(Response::new(Full::new(Bytes::from(INDEX1))))\n}\n\nasync fn index2(_: Request<hyper::body::Incoming>) -> Result<Response<Full<Bytes>>, hyper::Error> {\n    Ok(Response::new(Full::new(Bytes::from(INDEX2))))\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n    pretty_env_logger::init();\n\n    let addr1: SocketAddr = ([127, 0, 0, 1], 1337).into();\n    let addr2: SocketAddr = ([127, 0, 0, 1], 1338).into();\n\n    let srv1 = async move {\n        let listener = TcpListener::bind(addr1).await.unwrap();\n        loop {\n            let (stream, _) = listener.accept().await.unwrap();\n            let io = TokioIo::new(stream);\n\n            tokio::task::spawn(async move {\n                if let Err(err) = http1::Builder::new()\n                    .serve_connection(io, service_fn(index1))\n                    .await\n                {\n                    println!(\"Error serving connection: {:?}\", err);\n                }\n            });\n        }\n    };\n\n    let srv2 = async move {\n        let listener = TcpListener::bind(addr2).await.unwrap();\n        loop {\n            let (stream, _) = listener.accept().await.unwrap();\n            let io = TokioIo::new(stream);\n\n            tokio::task::spawn(async move {\n                if let Err(err) = http1::Builder::new()\n                    .serve_connection(io, service_fn(index2))\n                    .await\n                {\n                    println!(\"Error serving connection: {:?}\", err);\n                }\n            });\n        }\n    };\n\n    println!(\"Listening on http://{} and http://{}\", addr1, addr2);\n\n    let _ret = join(srv1, srv2).await;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/params.rs",
    "content": "// #![deny(warnings)]  // FIXME: https://github.com/rust-lang/rust/issues/62411\n#![warn(rust_2018_idioms)]\n\nuse bytes::Bytes;\nuse http_body_util::{combinators::BoxBody, BodyExt, Empty, Full};\nuse hyper::server::conn::http1;\nuse hyper::service::service_fn;\nuse hyper::{Method, Request, Response, StatusCode};\nuse tokio::net::TcpListener;\n\nuse std::collections::HashMap;\nuse std::convert::Infallible;\nuse std::net::SocketAddr;\n\n#[path = \"../benches/support/mod.rs\"]\nmod support;\nuse support::TokioIo;\n\nstatic INDEX: &[u8] = b\"<html><body><form action=\\\"post\\\" method=\\\"post\\\">Name: <input type=\\\"text\\\" name=\\\"name\\\"><br>Number: <input type=\\\"text\\\" name=\\\"number\\\"><br><input type=\\\"submit\\\"></body></html>\";\nstatic MISSING: &[u8] = b\"Missing field\";\nstatic NOTNUMERIC: &[u8] = b\"Number field is not numeric\";\n\n// Using service_fn, we can turn this function into a `Service`.\nasync fn param_example(\n    req: Request<hyper::body::Incoming>,\n) -> Result<Response<BoxBody<Bytes, Infallible>>, hyper::Error> {\n    match (req.method(), req.uri().path()) {\n        (&Method::GET, \"/\") | (&Method::GET, \"/post\") => Ok(Response::new(full(INDEX))),\n        (&Method::POST, \"/post\") => {\n            // Concatenate the body...\n            let b = req.collect().await?.to_bytes();\n            // Parse the request body. form_urlencoded::parse\n            // always succeeds, but in general parsing may\n            // fail (for example, an invalid post of json), so\n            // returning early with BadRequest may be\n            // necessary.\n            //\n            // Warning: this is a simplified use case. In\n            // principle names can appear multiple times in a\n            // form, and the values should be rolled up into a\n            // HashMap<String, Vec<String>>. However in this\n            // example the simpler approach is sufficient.\n            let params = form_urlencoded::parse(b.as_ref())\n                .into_owned()\n                .collect::<HashMap<String, String>>();\n\n            // Validate the request parameters, returning\n            // early if an invalid input is detected.\n            let name = if let Some(n) = params.get(\"name\") {\n                n\n            } else {\n                return Ok(Response::builder()\n                    .status(StatusCode::UNPROCESSABLE_ENTITY)\n                    .body(full(MISSING))\n                    .expect(\"constant status won't error\"));\n            };\n            let number = if let Some(n) = params.get(\"number\") {\n                if let Ok(v) = n.parse::<f64>() {\n                    v\n                } else {\n                    return Ok(Response::builder()\n                        .status(StatusCode::UNPROCESSABLE_ENTITY)\n                        .body(full(NOTNUMERIC))\n                        .expect(\"constant status won't error\"));\n                }\n            } else {\n                return Ok(Response::builder()\n                    .status(StatusCode::UNPROCESSABLE_ENTITY)\n                    .body(full(MISSING))\n                    .expect(\"constant status won't error\"));\n            };\n\n            // Render the response. This will often involve\n            // calls to a database or web service, which will\n            // require creating a new stream for the response\n            // body. Since those may fail, other error\n            // responses such as InternalServiceError may be\n            // needed here, too.\n            let body = format!(\"Hello {}, your number is {}\", name, number);\n            Ok(Response::new(full(body)))\n        }\n        (&Method::GET, \"/get\") => {\n            let query = if let Some(q) = req.uri().query() {\n                q\n            } else {\n                return Ok(Response::builder()\n                    .status(StatusCode::UNPROCESSABLE_ENTITY)\n                    .body(full(MISSING))\n                    .expect(\"constant status won't error\"));\n            };\n            let params = form_urlencoded::parse(query.as_bytes())\n                .into_owned()\n                .collect::<HashMap<String, String>>();\n            let page = if let Some(p) = params.get(\"page\") {\n                p\n            } else {\n                return Ok(Response::builder()\n                    .status(StatusCode::UNPROCESSABLE_ENTITY)\n                    .body(full(MISSING))\n                    .expect(\"constant status won't error\"));\n            };\n            let body = format!(\"You requested {}\", page);\n            Ok(Response::new(full(body)))\n        }\n        _ => Ok(Response::builder()\n            .status(StatusCode::NOT_FOUND)\n            .body(empty())\n            .expect(\"constant status won't error\")),\n    }\n}\n\nfn empty() -> BoxBody<Bytes, Infallible> {\n    Empty::<Bytes>::new().boxed()\n}\n\nfn full<T: Into<Bytes>>(chunk: T) -> BoxBody<Bytes, Infallible> {\n    Full::new(chunk.into()).boxed()\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n    pretty_env_logger::init();\n\n    let addr: SocketAddr = ([127, 0, 0, 1], 1337).into();\n\n    let listener = TcpListener::bind(addr).await?;\n    println!(\"Listening on http://{}\", addr);\n    loop {\n        let (stream, _) = listener.accept().await?;\n        let io = TokioIo::new(stream);\n\n        tokio::task::spawn(async move {\n            if let Err(err) = http1::Builder::new()\n                .serve_connection(io, service_fn(param_example))\n                .await\n            {\n                println!(\"Error serving connection: {:?}\", err);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "examples/send_file.rs",
    "content": "#![deny(warnings)]\n\nuse std::net::SocketAddr;\n\nuse bytes::Bytes;\nuse futures_util::TryStreamExt;\nuse http_body_util::{combinators::BoxBody, BodyExt, Full, StreamBody};\nuse hyper::body::Frame;\nuse hyper::server::conn::http1;\nuse hyper::service::service_fn;\nuse hyper::{Method, Request, Response, Result, StatusCode};\nuse tokio::{fs::File, net::TcpListener};\nuse tokio_util::io::ReaderStream;\n\n#[path = \"../benches/support/mod.rs\"]\nmod support;\nuse support::TokioIo;\n\nstatic INDEX: &str = \"examples/send_file_index.html\";\nstatic NOTFOUND: &[u8] = b\"Not Found\";\n\n#[tokio::main]\nasync fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {\n    pretty_env_logger::init();\n\n    let addr: SocketAddr = \"127.0.0.1:1337\".parse().unwrap();\n\n    let listener = TcpListener::bind(addr).await?;\n    println!(\"Listening on http://{}\", addr);\n\n    loop {\n        let (stream, _) = listener.accept().await?;\n        let io = TokioIo::new(stream);\n\n        tokio::task::spawn(async move {\n            if let Err(err) = http1::Builder::new()\n                .serve_connection(io, service_fn(response_examples))\n                .await\n            {\n                println!(\"Failed to serve connection: {:?}\", err);\n            }\n        });\n    }\n}\n\nasync fn response_examples(\n    req: Request<hyper::body::Incoming>,\n) -> Result<Response<BoxBody<Bytes, std::io::Error>>> {\n    match (req.method(), req.uri().path()) {\n        (&Method::GET, \"/\") | (&Method::GET, \"/index.html\") => simple_file_send(INDEX).await,\n        (&Method::GET, \"/no_file.html\") => {\n            // Test what happens when file cannot be found\n            simple_file_send(\"this_file_should_not_exist.html\").await\n        }\n        _ => Ok(not_found()),\n    }\n}\n\n/// HTTP status code 404\nfn not_found() -> Response<BoxBody<Bytes, std::io::Error>> {\n    Response::builder()\n        .status(StatusCode::NOT_FOUND)\n        .body(Full::new(NOTFOUND.into()).map_err(|e| match e {}).boxed())\n        .expect(\"constant status won't error\")\n}\n\nasync fn simple_file_send(filename: &str) -> Result<Response<BoxBody<Bytes, std::io::Error>>> {\n    // Open file for reading\n    let file = File::open(filename).await;\n    if file.is_err() {\n        eprintln!(\"ERROR: Unable to open file.\");\n        return Ok(not_found());\n    }\n\n    let file: File = file.unwrap();\n\n    // Wrap to a tokio_util::io::ReaderStream\n    let reader_stream = ReaderStream::new(file);\n\n    // Convert to http_body_util::BoxBody\n    let stream_body = StreamBody::new(reader_stream.map_ok(Frame::data));\n    let boxed_body = stream_body.boxed();\n\n    // Send response\n    let response = Response::builder()\n        .status(StatusCode::OK)\n        .body(boxed_body)\n        .expect(\"constant status won't error\");\n\n    Ok(response)\n}\n"
  },
  {
    "path": "examples/send_file_index.html",
    "content": "<html>\n  <head>\n    <title>Hyper responding example</title>\n  </head>\n  <body>\n    <h1>Hyper responding example, streamed in chunks</h1>\n    <a href=\"index.html\">index.html</a> Top Level<br>\n    <a href=\"no_file.html\">no_file.html</a> A 404 test, the requested file does not exist<br>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/service_struct_impl.rs",
    "content": "use bytes::Bytes;\nuse http_body_util::Full;\nuse hyper::server::conn::http1;\nuse hyper::service::Service;\nuse hyper::{body::Incoming as IncomingBody, Request, Response};\nuse tokio::net::TcpListener;\n\nuse std::future::Future;\nuse std::net::SocketAddr;\nuse std::pin::Pin;\nuse std::sync::{Arc, Mutex};\n\n#[path = \"../benches/support/mod.rs\"]\nmod support;\nuse support::TokioIo;\n\ntype Counter = i32;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {\n    let addr: SocketAddr = ([127, 0, 0, 1], 3000).into();\n\n    let listener = TcpListener::bind(addr).await?;\n    println!(\"Listening on http://{}\", addr);\n\n    let svc = Svc {\n        counter: Arc::new(Mutex::new(0)),\n    };\n\n    loop {\n        let (stream, _) = listener.accept().await?;\n        let io = TokioIo::new(stream);\n        let svc_clone = svc.clone();\n        tokio::task::spawn(async move {\n            if let Err(err) = http1::Builder::new().serve_connection(io, svc_clone).await {\n                println!(\"Failed to serve connection: {:?}\", err);\n            }\n        });\n    }\n}\n\n#[derive(Debug, Clone)]\nstruct Svc {\n    counter: Arc<Mutex<Counter>>,\n}\n\nimpl Service<Request<IncomingBody>> for Svc {\n    type Response = Response<Full<Bytes>>;\n    type Error = hyper::Error;\n    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;\n\n    fn call(&self, req: Request<IncomingBody>) -> Self::Future {\n        fn mk_response(s: String) -> Result<Response<Full<Bytes>>, hyper::Error> {\n            Ok(Response::new(Full::new(Bytes::from(s))))\n        }\n\n        if req.uri().path() != \"/favicon.ico\" {\n            *self.counter.lock().expect(\"lock poisoned\") += 1;\n        }\n\n        let res = match req.uri().path() {\n            \"/\" => mk_response(format!(\"home! counter = {:?}\", self.counter)),\n            \"/posts\" => mk_response(format!(\"posts, of course! counter = {:?}\", self.counter)),\n            \"/authors\" => mk_response(format!(\n                \"authors extraordinare! counter = {:?}\",\n                self.counter\n            )),\n            _ => mk_response(\"oh no! not found\".into()),\n        };\n\n        Box::pin(async { res })\n    }\n}\n"
  },
  {
    "path": "examples/single_threaded.rs",
    "content": "#![deny(warnings)]\n/// This example shows how to use hyper with a single-threaded runtime.\n/// This example exists also to test if the code compiles when `Body` is not `Send`.\n///\n/// This Example includes HTTP/1 and HTTP/2 server and client.\n///\n/// In HTTP/1 it is possible to use a `!Send` `Body`type.\n/// In HTTP/2 it is possible to use a `!Send` `Body` and `IO` type.\n///\n/// The `Body` and `IOTypeNotSend` structs in this example are `!Send`\n///\n/// For HTTP/2 this only works if the `Executor` trait is implemented without the `Send` bound.\nuse http_body_util::BodyExt;\nuse hyper::server::conn::http2;\nuse std::cell::Cell;\nuse std::net::SocketAddr;\nuse std::rc::Rc;\nuse tokio::io::{self, AsyncWriteExt};\nuse tokio::net::TcpListener;\n\nuse hyper::body::{Body as HttpBody, Bytes, Frame};\nuse hyper::service::service_fn;\nuse hyper::Request;\nuse hyper::{Error, Response};\nuse std::marker::PhantomData;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\nuse std::thread;\nuse tokio::net::TcpStream;\n\n#[path = \"../benches/support/mod.rs\"]\nmod support;\nuse support::TokioIo;\n\nstruct Body {\n    // Our Body type is !Send and !Sync:\n    _marker: PhantomData<*const ()>,\n    data: Option<Bytes>,\n}\n\nimpl From<String> for Body {\n    fn from(a: String) -> Self {\n        Body {\n            _marker: PhantomData,\n            data: Some(a.into()),\n        }\n    }\n}\n\nimpl HttpBody for Body {\n    type Data = Bytes;\n    type Error = Error;\n\n    fn poll_frame(\n        self: Pin<&mut Self>,\n        _: &mut Context<'_>,\n    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {\n        Poll::Ready(self.get_mut().data.take().map(|d| Ok(Frame::data(d))))\n    }\n}\n\nfn main() {\n    pretty_env_logger::init();\n\n    let server_http2 = thread::spawn(move || {\n        // Configure a runtime for the server that runs everything on the current thread\n        let rt = tokio::runtime::Builder::new_current_thread()\n            .enable_all()\n            .build()\n            .expect(\"build runtime\");\n\n        // Combine it with a `LocalSet,  which means it can spawn !Send futures...\n        let local = tokio::task::LocalSet::new();\n        local.block_on(&rt, http2_server()).unwrap();\n    });\n\n    let client_http2 = thread::spawn(move || {\n        // Configure a runtime for the client that runs everything on the current thread\n        let rt = tokio::runtime::Builder::new_current_thread()\n            .enable_all()\n            .build()\n            .expect(\"build runtime\");\n\n        // Combine it with a `LocalSet,  which means it can spawn !Send futures...\n        let local = tokio::task::LocalSet::new();\n        local\n            .block_on(\n                &rt,\n                http2_client(\"http://localhost:3000\".parse::<hyper::Uri>().unwrap()),\n            )\n            .unwrap();\n    });\n\n    let server_http1 = thread::spawn(move || {\n        // Configure a runtime for the server that runs everything on the current thread\n        let rt = tokio::runtime::Builder::new_current_thread()\n            .enable_all()\n            .build()\n            .expect(\"build runtime\");\n\n        // Combine it with a `LocalSet,  which means it can spawn !Send futures...\n        let local = tokio::task::LocalSet::new();\n        local.block_on(&rt, http1_server()).unwrap();\n    });\n\n    let client_http1 = thread::spawn(move || {\n        // Configure a runtime for the client that runs everything on the current thread\n        let rt = tokio::runtime::Builder::new_current_thread()\n            .enable_all()\n            .build()\n            .expect(\"build runtime\");\n\n        // Combine it with a `LocalSet,  which means it can spawn !Send futures...\n        let local = tokio::task::LocalSet::new();\n        local\n            .block_on(\n                &rt,\n                http1_client(\"http://localhost:3001\".parse::<hyper::Uri>().unwrap()),\n            )\n            .unwrap();\n    });\n\n    server_http2.join().unwrap();\n    client_http2.join().unwrap();\n\n    server_http1.join().unwrap();\n    client_http1.join().unwrap();\n}\n\nasync fn http1_server() -> Result<(), Box<dyn std::error::Error>> {\n    let addr = SocketAddr::from(([127, 0, 0, 1], 3001));\n\n    let listener = TcpListener::bind(addr).await?;\n\n    // For each connection, clone the counter to use in our service...\n    let counter = Rc::new(Cell::new(0));\n\n    loop {\n        let (stream, _) = listener.accept().await?;\n\n        let io = IOTypeNotSend::new(TokioIo::new(stream));\n\n        let cnt = counter.clone();\n\n        let service = service_fn(move |_| {\n            let prev = cnt.get();\n            cnt.set(prev + 1);\n            let value = cnt.get();\n            async move { Ok::<_, Error>(Response::new(Body::from(format!(\"Request #{}\", value)))) }\n        });\n\n        tokio::task::spawn_local(async move {\n            if let Err(err) = hyper::server::conn::http1::Builder::new()\n                .serve_connection(io, service)\n                .await\n            {\n                println!(\"Error serving connection: {:?}\", err);\n            }\n        });\n    }\n}\n\nasync fn http1_client(url: hyper::Uri) -> Result<(), Box<dyn std::error::Error>> {\n    let host = url.host().expect(\"uri has no host\");\n    let port = url.port_u16().unwrap_or(80);\n    let addr = format!(\"{}:{}\", host, port);\n    let stream = TcpStream::connect(addr).await?;\n\n    let io = IOTypeNotSend::new(TokioIo::new(stream));\n\n    let (mut sender, conn) = hyper::client::conn::http1::handshake(io).await?;\n\n    tokio::task::spawn_local(async move {\n        if let Err(err) = conn.await {\n            let mut stdout = io::stdout();\n            stdout\n                .write_all(format!(\"Connection failed: {:?}\", err).as_bytes())\n                .await\n                .unwrap();\n            stdout.flush().await.unwrap();\n        }\n    });\n\n    let authority = url.authority().unwrap().clone();\n\n    // Make 4 requests\n    for _ in 0..4 {\n        let req = Request::builder()\n            .uri(url.clone())\n            .header(hyper::header::HOST, authority.as_str())\n            .body(Body::from(\"test\".to_string()))?;\n\n        let mut res = sender.send_request(req).await?;\n\n        let mut stdout = io::stdout();\n        stdout\n            .write_all(format!(\"Response: {}\\n\", res.status()).as_bytes())\n            .await\n            .unwrap();\n        stdout\n            .write_all(format!(\"Headers: {:#?}\\n\", res.headers()).as_bytes())\n            .await\n            .unwrap();\n        stdout.flush().await.unwrap();\n\n        // Print the response body\n        while let Some(next) = res.frame().await {\n            let frame = next?;\n            if let Some(chunk) = frame.data_ref() {\n                stdout.write_all(chunk).await.unwrap();\n            }\n        }\n        stdout.write_all(b\"\\n-----------------\\n\").await.unwrap();\n        stdout.flush().await.unwrap();\n    }\n    Ok(())\n}\n\nasync fn http2_server() -> Result<(), Box<dyn std::error::Error>> {\n    let mut stdout = io::stdout();\n\n    let addr: SocketAddr = ([127, 0, 0, 1], 3000).into();\n    // Using a !Send request counter is fine on 1 thread...\n    let counter = Rc::new(Cell::new(0));\n\n    let listener = TcpListener::bind(addr).await?;\n\n    stdout\n        .write_all(format!(\"Listening on http://{}\", addr).as_bytes())\n        .await\n        .unwrap();\n    stdout.flush().await.unwrap();\n\n    loop {\n        let (stream, _) = listener.accept().await?;\n        let io = IOTypeNotSend::new(TokioIo::new(stream));\n\n        // For each connection, clone the counter to use in our service...\n        let cnt = counter.clone();\n\n        let service = service_fn(move |_| {\n            let prev = cnt.get();\n            cnt.set(prev + 1);\n            let value = cnt.get();\n            async move { Ok::<_, Error>(Response::new(Body::from(format!(\"Request #{}\", value)))) }\n        });\n\n        tokio::task::spawn_local(async move {\n            if let Err(err) = http2::Builder::new(LocalExec)\n                .serve_connection(io, service)\n                .await\n            {\n                let mut stdout = io::stdout();\n                stdout\n                    .write_all(format!(\"Error serving connection: {:?}\", err).as_bytes())\n                    .await\n                    .unwrap();\n                stdout.flush().await.unwrap();\n            }\n        });\n    }\n}\n\nasync fn http2_client(url: hyper::Uri) -> Result<(), Box<dyn std::error::Error>> {\n    let host = url.host().expect(\"uri has no host\");\n    let port = url.port_u16().unwrap_or(80);\n    let addr = format!(\"{}:{}\", host, port);\n    let stream = TcpStream::connect(addr).await?;\n\n    let stream = IOTypeNotSend::new(TokioIo::new(stream));\n\n    let (mut sender, conn) = hyper::client::conn::http2::handshake(LocalExec, stream).await?;\n\n    tokio::task::spawn_local(async move {\n        if let Err(err) = conn.await {\n            let mut stdout = io::stdout();\n            stdout\n                .write_all(format!(\"Connection failed: {:?}\", err).as_bytes())\n                .await\n                .unwrap();\n            stdout.flush().await.unwrap();\n        }\n    });\n\n    let authority = url.authority().unwrap().clone();\n\n    // Make 4 requests\n    for _ in 0..4 {\n        let req = Request::builder()\n            .uri(url.clone())\n            .header(hyper::header::HOST, authority.as_str())\n            .body(Body::from(\"test\".to_string()))?;\n\n        let mut res = sender.send_request(req).await?;\n\n        let mut stdout = io::stdout();\n        stdout\n            .write_all(format!(\"Response: {}\\n\", res.status()).as_bytes())\n            .await\n            .unwrap();\n        stdout\n            .write_all(format!(\"Headers: {:#?}\\n\", res.headers()).as_bytes())\n            .await\n            .unwrap();\n        stdout.flush().await.unwrap();\n\n        // Print the response body\n        while let Some(next) = res.frame().await {\n            let frame = next?;\n            if let Some(chunk) = frame.data_ref() {\n                stdout.write_all(chunk).await.unwrap();\n            }\n        }\n        stdout.write_all(b\"\\n-----------------\\n\").await.unwrap();\n        stdout.flush().await.unwrap();\n    }\n    Ok(())\n}\n\n// NOTE: This part is only needed for HTTP/2. HTTP/1 doesn't need an executor.\n//\n// Since the Server needs to spawn some background tasks, we needed\n// to configure an Executor that can spawn !Send futures...\n#[derive(Clone, Copy, Debug)]\nstruct LocalExec;\n\nimpl<F> hyper::rt::Executor<F> for LocalExec\nwhere\n    F: std::future::Future + 'static, // not requiring `Send`\n{\n    fn execute(&self, fut: F) {\n        // This will spawn into the currently running `LocalSet`.\n        tokio::task::spawn_local(fut);\n    }\n}\n\nstruct IOTypeNotSend {\n    _marker: PhantomData<*const ()>,\n    stream: TokioIo<TcpStream>,\n}\n\nimpl IOTypeNotSend {\n    fn new(stream: TokioIo<TcpStream>) -> Self {\n        Self {\n            _marker: PhantomData,\n            stream,\n        }\n    }\n}\n\nimpl hyper::rt::Write for IOTypeNotSend {\n    fn poll_write(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<Result<usize, std::io::Error>> {\n        Pin::new(&mut self.stream).poll_write(cx, buf)\n    }\n\n    fn poll_flush(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Result<(), std::io::Error>> {\n        Pin::new(&mut self.stream).poll_flush(cx)\n    }\n\n    fn poll_shutdown(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Result<(), std::io::Error>> {\n        Pin::new(&mut self.stream).poll_shutdown(cx)\n    }\n}\n\nimpl hyper::rt::Read for IOTypeNotSend {\n    fn poll_read(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: hyper::rt::ReadBufCursor<'_>,\n    ) -> Poll<std::io::Result<()>> {\n        Pin::new(&mut self.stream).poll_read(cx, buf)\n    }\n}\n"
  },
  {
    "path": "examples/state.rs",
    "content": "#![deny(warnings)]\n\nuse std::net::SocketAddr;\nuse std::sync::{\n    atomic::{AtomicUsize, Ordering},\n    Arc,\n};\n\nuse bytes::Bytes;\nuse http_body_util::Full;\nuse hyper::{server::conn::http1, service::service_fn};\nuse hyper::{Error, Response};\nuse tokio::net::TcpListener;\n\n#[path = \"../benches/support/mod.rs\"]\nmod support;\nuse support::TokioIo;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    pretty_env_logger::init();\n\n    let addr: SocketAddr = ([127, 0, 0, 1], 3000).into();\n\n    // For the most basic of state, we just share a counter, that increments\n    // with each request, and we send its value back in the response.\n    let counter = Arc::new(AtomicUsize::new(0));\n\n    let listener = TcpListener::bind(addr).await?;\n    println!(\"Listening on http://{}\", addr);\n    loop {\n        let (stream, _) = listener.accept().await?;\n        let io = TokioIo::new(stream);\n\n        // Each connection could send multiple requests, so\n        // the `Service` needs a clone to handle later requests.\n        let counter = counter.clone();\n\n        // This is the `Service` that will handle the connection.\n        // `service_fn` is a helper to convert a function that\n        // returns a Response into a `Service`.\n        let service = service_fn(move |_req| {\n            // Get the current count, and also increment by 1, in a single\n            // atomic operation.\n            let count = counter.fetch_add(1, Ordering::AcqRel);\n            async move {\n                Ok::<_, Error>(Response::new(Full::new(Bytes::from(format!(\n                    \"Request #{}\",\n                    count\n                )))))\n            }\n        });\n\n        if let Err(err) = http1::Builder::new().serve_connection(io, service).await {\n            println!(\"Error serving connection: {:?}\", err);\n        }\n    }\n}\n"
  },
  {
    "path": "examples/upgrades.rs",
    "content": "#![deny(warnings)]\n\n// Note: `hyper::upgrade` docs link to this upgrade.\nuse std::net::SocketAddr;\nuse std::str;\n\nuse tokio::io::{AsyncReadExt, AsyncWriteExt};\nuse tokio::net::{TcpListener, TcpStream};\nuse tokio::sync::watch;\n\nuse bytes::Bytes;\nuse http_body_util::Empty;\nuse hyper::header::{HeaderValue, UPGRADE};\nuse hyper::server::conn::http1;\nuse hyper::service::service_fn;\nuse hyper::upgrade::Upgraded;\nuse hyper::{Request, Response, StatusCode};\n\n#[path = \"../benches/support/mod.rs\"]\nmod support;\nuse support::TokioIo;\n\n// A simple type alias so as to DRY.\ntype Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;\n\n/// Handle server-side I/O after HTTP upgraded.\nasync fn server_upgraded_io(upgraded: Upgraded) -> Result<()> {\n    let mut upgraded = TokioIo::new(upgraded);\n    // we have an upgraded connection that we can read and\n    // write on directly.\n    //\n    // since we completely control this example, we know exactly\n    // how many bytes the client will write, so just read exact...\n    let mut vec = vec![0; 7];\n    upgraded.read_exact(&mut vec).await?;\n    println!(\"server[foobar] recv: {:?}\", str::from_utf8(&vec));\n\n    // and now write back the server 'foobar' protocol's\n    // response...\n    upgraded.write_all(b\"bar=foo\").await?;\n    println!(\"server[foobar] sent\");\n    Ok(())\n}\n\n/// Our server HTTP handler to initiate HTTP upgrades.\nasync fn server_upgrade(mut req: Request<hyper::body::Incoming>) -> Result<Response<Empty<Bytes>>> {\n    let mut res = Response::new(Empty::new());\n\n    // Send a 400 to any request that doesn't have\n    // an `Upgrade` header.\n    if !req.headers().contains_key(UPGRADE) {\n        *res.status_mut() = StatusCode::BAD_REQUEST;\n        return Ok(res);\n    }\n\n    // Setup a future that will eventually receive the upgraded\n    // connection and talk a new protocol, and spawn the future\n    // into the runtime.\n    //\n    // Note: This can't possibly be fulfilled until the 101 response\n    // is returned below, so it's better to spawn this future instead\n    // waiting for it to complete to then return a response.\n    tokio::task::spawn(async move {\n        match hyper::upgrade::on(&mut req).await {\n            Ok(upgraded) => {\n                if let Err(e) = server_upgraded_io(upgraded).await {\n                    eprintln!(\"server foobar io error: {}\", e)\n                };\n            }\n            Err(e) => eprintln!(\"upgrade error: {}\", e),\n        }\n    });\n\n    // Now return a 101 Response saying we agree to the upgrade to some\n    // made-up 'foobar' protocol.\n    *res.status_mut() = StatusCode::SWITCHING_PROTOCOLS;\n    res.headers_mut()\n        .insert(UPGRADE, HeaderValue::from_static(\"foobar\"));\n    Ok(res)\n}\n\n/// Handle client-side I/O after HTTP upgraded.\nasync fn client_upgraded_io(upgraded: Upgraded) -> Result<()> {\n    let mut upgraded = TokioIo::new(upgraded);\n    // We've gotten an upgraded connection that we can read\n    // and write directly on. Let's start out 'foobar' protocol.\n    upgraded.write_all(b\"foo=bar\").await?;\n    println!(\"client[foobar] sent\");\n\n    let mut vec = Vec::new();\n    upgraded.read_to_end(&mut vec).await?;\n    println!(\"client[foobar] recv: {:?}\", str::from_utf8(&vec));\n\n    Ok(())\n}\n\n/// Our client HTTP handler to initiate HTTP upgrades.\nasync fn client_upgrade_request(addr: SocketAddr) -> Result<()> {\n    let req = Request::builder()\n        .uri(format!(\"http://{}/\", addr))\n        .header(UPGRADE, \"foobar\")\n        .body(Empty::<Bytes>::new())\n        .expect(\"uri/header parse won't error\");\n\n    let stream = TcpStream::connect(addr).await?;\n    let io = TokioIo::new(stream);\n    let (mut sender, conn) = hyper::client::conn::http1::handshake(io).await?;\n\n    tokio::task::spawn(async move {\n        // Don't forget to enable upgrades on the connection.\n        if let Err(err) = conn.with_upgrades().await {\n            println!(\"Connection failed: {:?}\", err);\n        }\n    });\n\n    let res = sender.send_request(req).await?;\n\n    if res.status() != StatusCode::SWITCHING_PROTOCOLS {\n        panic!(\"Our server didn't upgrade: {}\", res.status());\n    }\n\n    match hyper::upgrade::on(res).await {\n        Ok(upgraded) => {\n            if let Err(e) = client_upgraded_io(upgraded).await {\n                eprintln!(\"client foobar io error: {}\", e)\n            };\n        }\n        Err(e) => eprintln!(\"upgrade error: {}\", e),\n    }\n\n    Ok(())\n}\n\n#[tokio::main]\nasync fn main() {\n    // For this example, we just make a server and our own client to talk to\n    // it, so the exact port isn't important. Instead, let the OS give us an\n    // unused port.\n    let addr: SocketAddr = ([127, 0, 0, 1], 0).into();\n\n    let listener = TcpListener::bind(addr).await.expect(\"failed to bind\");\n\n    // We need the assigned address for the client to send it messages.\n    let addr = listener.local_addr().unwrap();\n\n    // For this example, a oneshot is used to signal that after 1 request,\n    // the server should be shutdown.\n    let (tx, mut rx) = watch::channel(false);\n\n    // Spawn server on the default executor,\n    // which is usually a thread-pool from tokio default runtime.\n    tokio::task::spawn(async move {\n        loop {\n            tokio::select! {\n                res = listener.accept() => {\n                    let (stream, _) = res.expect(\"Failed to accept\");\n                    let io = TokioIo::new(stream);\n\n                    let mut rx = rx.clone();\n                    tokio::task::spawn(async move {\n                        let conn = http1::Builder::new().serve_connection(io, service_fn(server_upgrade));\n\n                        // Don't forget to enable upgrades on the connection.\n                        let mut conn = conn.with_upgrades();\n\n                        let mut conn = Pin::new(&mut conn);\n\n                        tokio::select! {\n                            res = &mut conn => {\n                                if let Err(err) = res {\n                                    println!(\"Error serving connection: {:?}\", err);\n                                }\n                            }\n                            // Continue polling the connection after enabling graceful shutdown.\n                            _ = rx.changed() => {\n                                conn.graceful_shutdown();\n                            }\n                        }\n                    });\n                }\n                _ = rx.changed() => {\n                    break;\n                }\n            }\n        }\n    });\n\n    // Client requests a HTTP connection upgrade.\n    let request = client_upgrade_request(addr);\n    if let Err(e) = request.await {\n        eprintln!(\"client error: {}\", e);\n    }\n\n    // Complete the oneshot so that the server stops\n    // listening and the process can close down.\n    let _ = tx.send(true);\n}\n"
  },
  {
    "path": "examples/web_api.rs",
    "content": "#![deny(warnings)]\n\nuse std::net::SocketAddr;\n\nuse bytes::{Buf, Bytes};\nuse http_body_util::{BodyExt, Full};\nuse hyper::server::conn::http1;\nuse hyper::service::service_fn;\nuse hyper::{body::Incoming as IncomingBody, header, Method, Request, Response, StatusCode};\nuse tokio::net::{TcpListener, TcpStream};\n\n#[path = \"../benches/support/mod.rs\"]\nmod support;\nuse support::TokioIo;\n\ntype GenericError = Box<dyn std::error::Error + Send + Sync>;\ntype Result<T> = std::result::Result<T, GenericError>;\ntype BoxBody = http_body_util::combinators::BoxBody<Bytes, hyper::Error>;\n\nstatic INDEX: &[u8] = b\"<a href=\\\"test.html\\\">test.html</a>\";\nstatic INTERNAL_SERVER_ERROR: &[u8] = b\"Internal Server Error\";\nstatic NOTFOUND: &[u8] = b\"Not Found\";\nstatic POST_DATA: &str = r#\"{\"original\": \"data\"}\"#;\nstatic URL: &str = \"http://127.0.0.1:1337/json_api\";\n\nasync fn client_request_response() -> Result<Response<BoxBody>> {\n    let req = Request::builder()\n        .method(Method::POST)\n        .uri(URL)\n        .header(header::CONTENT_TYPE, \"application/json\")\n        .body(Full::new(Bytes::from(POST_DATA)))\n        .expect(\"uri/header parse from constants won't error\");\n\n    let host = req.uri().host().expect(\"uri has no host\");\n    let port = req.uri().port_u16().expect(\"uri has no port\");\n    let stream = TcpStream::connect(format!(\"{}:{}\", host, port)).await?;\n    let io = TokioIo::new(stream);\n\n    let (mut sender, conn) = hyper::client::conn::http1::handshake(io).await?;\n\n    tokio::task::spawn(async move {\n        if let Err(err) = conn.await {\n            println!(\"Connection error: {:?}\", err);\n        }\n    });\n\n    let web_res = sender.send_request(req).await?;\n\n    let res_body = web_res.into_body().boxed();\n\n    Ok(Response::new(res_body))\n}\n\nasync fn api_post_response(req: Request<IncomingBody>) -> Result<Response<BoxBody>> {\n    // Aggregate the body...\n    let whole_body = req.collect().await?.aggregate();\n    // Decode as JSON...\n    let mut data: serde_json::Value = serde_json::from_reader(whole_body.reader())?;\n    // Change the JSON...\n    data[\"test\"] = serde_json::Value::from(\"test_value\");\n    // And respond with the new JSON.\n    let json = serde_json::to_string(&data)?;\n    let response = Response::builder()\n        .status(StatusCode::OK)\n        .header(header::CONTENT_TYPE, \"application/json\")\n        .body(full(json))?;\n    Ok(response)\n}\n\nasync fn api_get_response() -> Result<Response<BoxBody>> {\n    let data = vec![\"foo\", \"bar\"];\n    let res = match serde_json::to_string(&data) {\n        Ok(json) => Response::builder()\n            .header(header::CONTENT_TYPE, \"application/json\")\n            .body(full(json))\n            .expect(\"header parse from constant won't error\"),\n        Err(_) => Response::builder()\n            .status(StatusCode::INTERNAL_SERVER_ERROR)\n            .body(full(INTERNAL_SERVER_ERROR))\n            .expect(\"constant status won't error\"),\n    };\n    Ok(res)\n}\n\nasync fn response_examples(req: Request<IncomingBody>) -> Result<Response<BoxBody>> {\n    match (req.method(), req.uri().path()) {\n        (&Method::GET, \"/\") | (&Method::GET, \"/index.html\") => Ok(Response::new(full(INDEX))),\n        (&Method::GET, \"/test.html\") => client_request_response().await,\n        (&Method::POST, \"/json_api\") => api_post_response(req).await,\n        (&Method::GET, \"/json_api\") => api_get_response().await,\n        _ => {\n            // Return 404 not found response.\n            Ok(Response::builder()\n                .status(StatusCode::NOT_FOUND)\n                .body(full(NOTFOUND))\n                .expect(\"constant status won't error\"))\n        }\n    }\n}\n\nfn full<T: Into<Bytes>>(chunk: T) -> BoxBody {\n    Full::new(chunk.into())\n        .map_err(|never| match never {})\n        .boxed()\n}\n\n#[tokio::main]\nasync fn main() -> Result<()> {\n    pretty_env_logger::init();\n\n    let addr: SocketAddr = \"127.0.0.1:1337\".parse().unwrap();\n\n    let listener = TcpListener::bind(&addr).await?;\n    println!(\"Listening on http://{}\", addr);\n    loop {\n        let (stream, _) = listener.accept().await?;\n        let io = TokioIo::new(stream);\n\n        tokio::task::spawn(async move {\n            let service = service_fn(response_examples);\n\n            if let Err(err) = http1::Builder::new().serve_connection(io, service).await {\n                println!(\"Failed to serve connection: {:?}\", err);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "src/body/incoming.rs",
    "content": "use std::fmt;\n#[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse bytes::Bytes;\n#[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\nuse futures_channel::{mpsc, oneshot};\n#[cfg(all(\n    any(feature = \"http1\", feature = \"http2\"),\n    any(feature = \"client\", feature = \"server\")\n))]\nuse futures_core::ready;\n#[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\nuse futures_core::{stream::FusedStream, Stream}; // for mpsc::Receiver\n#[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\nuse http::HeaderMap;\nuse http_body::{Body, Frame, SizeHint};\n\n#[cfg(all(\n    any(feature = \"http1\", feature = \"http2\"),\n    any(feature = \"client\", feature = \"server\")\n))]\nuse super::DecodedLength;\n#[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\nuse crate::common::watch;\n#[cfg(all(feature = \"http2\", any(feature = \"client\", feature = \"server\")))]\nuse crate::proto::h2::ping;\n\n#[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\ntype BodySender = mpsc::Sender<Result<Bytes, crate::Error>>;\n#[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\ntype TrailersSender = oneshot::Sender<HeaderMap>;\n\n/// A stream of `Bytes`, used when receiving bodies from the network.\n///\n/// Note that Users should not instantiate this struct directly. When working with the hyper client,\n/// `Incoming` is returned to you in responses. Similarly, when operating with the hyper server,\n/// it is provided within requests.\n///\n/// # Examples\n///\n/// ```rust,ignore\n/// async fn echo(\n///    req: Request<hyper::body::Incoming>,\n/// ) -> Result<Response<BoxBody<Bytes, hyper::Error>>, hyper::Error> {\n///    //Here, you can process `Incoming`\n/// }\n/// ```\n#[must_use = \"streams do nothing unless polled\"]\npub struct Incoming {\n    kind: Kind,\n}\n\nenum Kind {\n    Empty,\n    #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n    Chan {\n        content_length: DecodedLength,\n        want_tx: watch::Sender,\n        data_rx: mpsc::Receiver<Result<Bytes, crate::Error>>,\n        trailers_rx: oneshot::Receiver<HeaderMap>,\n    },\n    #[cfg(all(feature = \"http2\", any(feature = \"client\", feature = \"server\")))]\n    H2 {\n        content_length: DecodedLength,\n        data_done: bool,\n        ping: ping::Recorder,\n        recv: h2::RecvStream,\n    },\n    #[cfg(feature = \"ffi\")]\n    Ffi(crate::ffi::UserBody),\n}\n\n/// A sender half created through [`Body::channel()`].\n///\n/// Useful when wanting to stream chunks from another thread.\n///\n/// ## Body Closing\n///\n/// Note that the request body will always be closed normally when the sender is dropped (meaning\n/// that the empty terminating chunk will be sent to the remote). If you desire to close the\n/// connection with an incomplete response (e.g. in the case of an error during asynchronous\n/// processing), call the [`Sender::abort()`] method to abort the body in an abnormal fashion.\n///\n/// [`Body::channel()`]: struct.Body.html#method.channel\n/// [`Sender::abort()`]: struct.Sender.html#method.abort\n#[must_use = \"Sender does nothing unless sent on\"]\n#[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\npub(crate) struct Sender {\n    want_rx: watch::Receiver,\n    data_tx: BodySender,\n    trailers_tx: Option<TrailersSender>,\n}\n\n#[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\nconst WANT_PENDING: usize = 1;\n#[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\nconst WANT_READY: usize = 2;\n\nimpl Incoming {\n    /// Create a `Body` stream with an associated sender half.\n    ///\n    /// Useful when wanting to stream chunks from another thread.\n    #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n    #[inline]\n    #[cfg(test)]\n    pub(crate) fn channel() -> (Sender, Incoming) {\n        Self::new_channel(DecodedLength::CHUNKED, /*wanter =*/ false)\n    }\n\n    #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n    pub(crate) fn new_channel(content_length: DecodedLength, wanter: bool) -> (Sender, Incoming) {\n        let (data_tx, data_rx) = mpsc::channel(0);\n        let (trailers_tx, trailers_rx) = oneshot::channel();\n\n        // If wanter is true, `Sender::poll_ready()` won't becoming ready\n        // until the `Body` has been polled for data once.\n        let want = if wanter { WANT_PENDING } else { WANT_READY };\n\n        let (want_tx, want_rx) = watch::channel(want);\n\n        let tx = Sender {\n            want_rx,\n            data_tx,\n            trailers_tx: Some(trailers_tx),\n        };\n        let rx = Incoming::new(Kind::Chan {\n            content_length,\n            want_tx,\n            data_rx,\n            trailers_rx,\n        });\n\n        (tx, rx)\n    }\n\n    fn new(kind: Kind) -> Incoming {\n        Incoming { kind }\n    }\n\n    #[allow(dead_code)]\n    pub(crate) fn empty() -> Incoming {\n        Incoming::new(Kind::Empty)\n    }\n\n    #[cfg(feature = \"ffi\")]\n    pub(crate) fn ffi() -> Incoming {\n        Incoming::new(Kind::Ffi(crate::ffi::UserBody::new()))\n    }\n\n    #[cfg(all(feature = \"http2\", any(feature = \"client\", feature = \"server\")))]\n    pub(crate) fn h2(\n        recv: h2::RecvStream,\n        mut content_length: DecodedLength,\n        ping: ping::Recorder,\n    ) -> Self {\n        // If the stream is already EOS, then the \"unknown length\" is clearly\n        // actually ZERO.\n        if !content_length.is_exact() && recv.is_end_stream() {\n            content_length = DecodedLength::ZERO;\n        }\n\n        Incoming::new(Kind::H2 {\n            data_done: false,\n            ping,\n            content_length,\n            recv,\n        })\n    }\n\n    #[cfg(feature = \"ffi\")]\n    pub(crate) fn as_ffi_mut(&mut self) -> &mut crate::ffi::UserBody {\n        match self.kind {\n            Kind::Ffi(ref mut body) => return body,\n            _ => {\n                self.kind = Kind::Ffi(crate::ffi::UserBody::new());\n            }\n        }\n\n        match self.kind {\n            Kind::Ffi(ref mut body) => body,\n            _ => unreachable!(),\n        }\n    }\n}\n\nimpl Body for Incoming {\n    type Data = Bytes;\n    type Error = crate::Error;\n\n    fn poll_frame(\n        #[cfg_attr(\n            not(all(\n                any(feature = \"http1\", feature = \"http2\"),\n                any(feature = \"client\", feature = \"server\")\n            )),\n            allow(unused_mut)\n        )]\n        mut self: Pin<&mut Self>,\n        #[cfg_attr(\n            not(all(\n                any(feature = \"http1\", feature = \"http2\"),\n                any(feature = \"client\", feature = \"server\")\n            )),\n            allow(unused_variables)\n        )]\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {\n        match self.kind {\n            Kind::Empty => Poll::Ready(None),\n            #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n            Kind::Chan {\n                content_length: ref mut len,\n                ref mut data_rx,\n                ref mut want_tx,\n                ref mut trailers_rx,\n            } => {\n                want_tx.send(WANT_READY);\n\n                if !data_rx.is_terminated() {\n                    if let Some(chunk) = ready!(Pin::new(data_rx).poll_next(cx)?) {\n                        len.sub_if(chunk.len() as u64);\n                        return Poll::Ready(Some(Ok(Frame::data(chunk))));\n                    }\n                }\n\n                // check trailers after data is terminated\n                match ready!(Pin::new(trailers_rx).poll(cx)) {\n                    Ok(t) => Poll::Ready(Some(Ok(Frame::trailers(t)))),\n                    Err(_) => Poll::Ready(None),\n                }\n            }\n            #[cfg(all(feature = \"http2\", any(feature = \"client\", feature = \"server\")))]\n            Kind::H2 {\n                ref mut data_done,\n                ref ping,\n                recv: ref mut h2,\n                content_length: ref mut len,\n            } => {\n                if !*data_done {\n                    match ready!(h2.poll_data(cx)) {\n                        Some(Ok(bytes)) => {\n                            let _ = h2.flow_control().release_capacity(bytes.len());\n                            len.sub_if(bytes.len() as u64);\n                            ping.record_data(bytes.len());\n                            return Poll::Ready(Some(Ok(Frame::data(bytes))));\n                        }\n                        Some(Err(e)) => {\n                            return match e.reason() {\n                                // These reasons should cause the body reading to stop, but not fail it.\n                                // The same logic as for `Read for H2Upgraded` is applied here.\n                                Some(h2::Reason::NO_ERROR) | Some(h2::Reason::CANCEL) => {\n                                    Poll::Ready(None)\n                                }\n                                _ => Poll::Ready(Some(Err(crate::Error::new_body(e)))),\n                            };\n                        }\n                        None => {\n                            *data_done = true;\n                            // fall through to trailers\n                        }\n                    }\n                }\n\n                // after data, check trailers\n                match ready!(h2.poll_trailers(cx)) {\n                    Ok(t) => {\n                        ping.record_non_data();\n                        Poll::Ready(Ok(t.map(Frame::trailers)).transpose())\n                    }\n                    Err(e) => Poll::Ready(Some(Err(crate::Error::new_h2(e)))),\n                }\n            }\n\n            #[cfg(feature = \"ffi\")]\n            Kind::Ffi(ref mut body) => body.poll_data(cx),\n        }\n    }\n\n    fn is_end_stream(&self) -> bool {\n        match self.kind {\n            Kind::Empty => true,\n            #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n            Kind::Chan { content_length, .. } => content_length == DecodedLength::ZERO,\n            #[cfg(all(feature = \"http2\", any(feature = \"client\", feature = \"server\")))]\n            Kind::H2 { recv: ref h2, .. } => h2.is_end_stream(),\n            #[cfg(feature = \"ffi\")]\n            Kind::Ffi(..) => false,\n        }\n    }\n\n    fn size_hint(&self) -> SizeHint {\n        #[cfg(all(\n            any(feature = \"http1\", feature = \"http2\"),\n            any(feature = \"client\", feature = \"server\")\n        ))]\n        fn opt_len(decoded_length: DecodedLength) -> SizeHint {\n            if let Some(content_length) = decoded_length.into_opt() {\n                SizeHint::with_exact(content_length)\n            } else {\n                SizeHint::default()\n            }\n        }\n\n        match self.kind {\n            Kind::Empty => SizeHint::with_exact(0),\n            #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n            Kind::Chan { content_length, .. } => opt_len(content_length),\n            #[cfg(all(feature = \"http2\", any(feature = \"client\", feature = \"server\")))]\n            Kind::H2 { content_length, .. } => opt_len(content_length),\n            #[cfg(feature = \"ffi\")]\n            Kind::Ffi(..) => SizeHint::default(),\n        }\n    }\n}\n\nimpl fmt::Debug for Incoming {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        #[cfg(any(\n            all(\n                any(feature = \"http1\", feature = \"http2\"),\n                any(feature = \"client\", feature = \"server\")\n            ),\n            feature = \"ffi\"\n        ))]\n        #[derive(Debug)]\n        struct Streaming;\n        #[derive(Debug)]\n        struct Empty;\n\n        let mut builder = f.debug_tuple(\"Body\");\n        match self.kind {\n            Kind::Empty => builder.field(&Empty),\n            #[cfg(any(\n                all(\n                    any(feature = \"http1\", feature = \"http2\"),\n                    any(feature = \"client\", feature = \"server\")\n                ),\n                feature = \"ffi\"\n            ))]\n            _ => builder.field(&Streaming),\n        };\n\n        builder.finish()\n    }\n}\n\n#[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\nimpl Sender {\n    /// Check to see if this `Sender` can send more data.\n    pub(crate) fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {\n        // Check if the receiver end has tried polling for the body yet\n        ready!(self.poll_want(cx)?);\n        self.data_tx\n            .poll_ready(cx)\n            .map_err(|_| crate::Error::new_closed())\n    }\n\n    fn poll_want(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {\n        match self.want_rx.load(cx) {\n            WANT_READY => Poll::Ready(Ok(())),\n            WANT_PENDING => Poll::Pending,\n            watch::CLOSED => Poll::Ready(Err(crate::Error::new_closed())),\n            unexpected => unreachable!(\"want_rx value: {}\", unexpected),\n        }\n    }\n\n    #[cfg(test)]\n    async fn ready(&mut self) -> crate::Result<()> {\n        futures_util::future::poll_fn(|cx| self.poll_ready(cx)).await\n    }\n\n    /// Send data on data channel when it is ready.\n    #[cfg(test)]\n    #[allow(unused)]\n    pub(crate) async fn send_data(&mut self, chunk: Bytes) -> crate::Result<()> {\n        self.ready().await?;\n        self.data_tx\n            .try_send(Ok(chunk))\n            .map_err(|_| crate::Error::new_closed())\n    }\n\n    /// Send trailers on trailers channel.\n    #[allow(unused)]\n    pub(crate) async fn send_trailers(&mut self, trailers: HeaderMap) -> crate::Result<()> {\n        let tx = match self.trailers_tx.take() {\n            Some(tx) => tx,\n            None => return Err(crate::Error::new_closed()),\n        };\n        tx.send(trailers).map_err(|_| crate::Error::new_closed())\n    }\n\n    /// Try to send data on this channel.\n    ///\n    /// # Errors\n    ///\n    /// Returns `Err(Bytes)` if the channel could not (currently) accept\n    /// another `Bytes`.\n    ///\n    /// # Note\n    ///\n    /// This is mostly useful for when trying to send from some other thread\n    /// that doesn't have an async context. If in an async context, prefer\n    /// `send_data()` instead.\n    #[cfg(feature = \"http1\")]\n    pub(crate) fn try_send_data(&mut self, chunk: Bytes) -> Result<(), Bytes> {\n        self.data_tx\n            .try_send(Ok(chunk))\n            .map_err(|err| err.into_inner().expect(\"just sent Ok\"))\n    }\n\n    #[cfg(feature = \"http1\")]\n    pub(crate) fn try_send_trailers(\n        &mut self,\n        trailers: HeaderMap,\n    ) -> Result<(), Option<HeaderMap>> {\n        let tx = match self.trailers_tx.take() {\n            Some(tx) => tx,\n            None => return Err(None),\n        };\n\n        tx.send(trailers).map_err(Some)\n    }\n\n    #[cfg(test)]\n    pub(crate) fn abort(mut self) {\n        self.send_error(crate::Error::new_body_write_aborted());\n    }\n\n    pub(crate) fn send_error(&mut self, err: crate::Error) {\n        let _ = self\n            .data_tx\n            // clone so the send works even if buffer is full\n            .clone()\n            .try_send(Err(err));\n    }\n}\n\n#[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\nimpl fmt::Debug for Sender {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        #[derive(Debug)]\n        struct Open;\n        #[derive(Debug)]\n        struct Closed;\n\n        let mut builder = f.debug_tuple(\"Sender\");\n        match self.want_rx.peek() {\n            watch::CLOSED => builder.field(&Closed),\n            _ => builder.field(&Open),\n        };\n\n        builder.finish()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n    use std::mem;\n    #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n    use std::task::Poll;\n\n    #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n    use super::{Body, Incoming, SizeHint};\n    #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n    use super::{DecodedLength, Sender};\n    #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n    use http_body_util::BodyExt;\n\n    #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n    #[test]\n    fn test_size_of() {\n        // These are mostly to help catch *accidentally* increasing\n        // the size by too much.\n\n        let body_size = mem::size_of::<Incoming>();\n        let body_expected_size = mem::size_of::<u64>() * 5;\n        assert!(\n            body_size <= body_expected_size,\n            \"Body size = {} <= {}\",\n            body_size,\n            body_expected_size,\n        );\n\n        //assert_eq!(body_size, mem::size_of::<Option<Incoming>>(), \"Option<Incoming>\");\n\n        assert_eq!(\n            mem::size_of::<Sender>(),\n            mem::size_of::<usize>() * 5,\n            \"Sender\"\n        );\n\n        assert_eq!(\n            mem::size_of::<Sender>(),\n            mem::size_of::<Option<Sender>>(),\n            \"Option<Sender>\"\n        );\n    }\n\n    #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n    #[test]\n    fn size_hint() {\n        fn eq(body: Incoming, b: SizeHint, note: &str) {\n            let a = body.size_hint();\n            assert_eq!(a.lower(), b.lower(), \"lower for {:?}\", note);\n            assert_eq!(a.upper(), b.upper(), \"upper for {:?}\", note);\n        }\n\n        eq(Incoming::empty(), SizeHint::with_exact(0), \"empty\");\n\n        eq(Incoming::channel().1, SizeHint::new(), \"channel\");\n\n        eq(\n            Incoming::new_channel(DecodedLength::new(4), /*wanter =*/ false).1,\n            SizeHint::with_exact(4),\n            \"channel with length\",\n        );\n    }\n\n    #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn channel_abort() {\n        let (tx, mut rx) = Incoming::channel();\n\n        tx.abort();\n\n        let err = rx.frame().await.unwrap().unwrap_err();\n        assert!(err.is_body_write_aborted(), \"{:?}\", err);\n    }\n\n    #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n    #[cfg(all(not(miri), feature = \"http1\"))]\n    #[tokio::test]\n    async fn channel_abort_when_buffer_is_full() {\n        let (mut tx, mut rx) = Incoming::channel();\n\n        tx.try_send_data(\"chunk 1\".into()).expect(\"send 1\");\n        // buffer is full, but can still send abort\n        tx.abort();\n\n        let chunk1 = rx\n            .frame()\n            .await\n            .expect(\"item 1\")\n            .expect(\"chunk 1\")\n            .into_data()\n            .unwrap();\n        assert_eq!(chunk1, \"chunk 1\");\n\n        let err = rx.frame().await.unwrap().unwrap_err();\n        assert!(err.is_body_write_aborted(), \"{:?}\", err);\n    }\n\n    #[cfg(feature = \"http1\")]\n    #[test]\n    fn channel_buffers_one() {\n        let (mut tx, _rx) = Incoming::channel();\n\n        tx.try_send_data(\"chunk 1\".into()).expect(\"send 1\");\n\n        // buffer is now full\n        let chunk2 = tx.try_send_data(\"chunk 2\".into()).expect_err(\"send 2\");\n        assert_eq!(chunk2, \"chunk 2\");\n    }\n\n    #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn channel_empty() {\n        let (_, mut rx) = Incoming::channel();\n\n        assert!(rx.frame().await.is_none());\n    }\n\n    #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n    #[test]\n    fn channel_ready() {\n        let (mut tx, _rx) = Incoming::new_channel(DecodedLength::CHUNKED, /*wanter = */ false);\n\n        let mut tx_ready = tokio_test::task::spawn(tx.ready());\n\n        assert!(tx_ready.poll().is_ready(), \"tx is ready immediately\");\n    }\n\n    #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n    #[test]\n    fn channel_wanter() {\n        let (mut tx, mut rx) =\n            Incoming::new_channel(DecodedLength::CHUNKED, /*wanter = */ true);\n\n        let mut tx_ready = tokio_test::task::spawn(tx.ready());\n        let mut rx_data = tokio_test::task::spawn(rx.frame());\n\n        assert!(\n            tx_ready.poll().is_pending(),\n            \"tx isn't ready before rx has been polled\"\n        );\n\n        assert!(rx_data.poll().is_pending(), \"poll rx.data\");\n        assert!(tx_ready.is_woken(), \"rx poll wakes tx\");\n\n        assert!(\n            tx_ready.poll().is_ready(),\n            \"tx is ready after rx has been polled\"\n        );\n    }\n\n    #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n    #[test]\n    fn channel_notices_closure() {\n        let (mut tx, rx) = Incoming::new_channel(DecodedLength::CHUNKED, /*wanter = */ true);\n\n        let mut tx_ready = tokio_test::task::spawn(tx.ready());\n\n        assert!(\n            tx_ready.poll().is_pending(),\n            \"tx isn't ready before rx has been polled\"\n        );\n\n        drop(rx);\n        assert!(tx_ready.is_woken(), \"dropping rx wakes tx\");\n\n        match tx_ready.poll() {\n            Poll::Ready(Err(ref e)) if e.is_closed() => (),\n            unexpected => panic!(\"tx poll ready unexpected: {:?}\", unexpected),\n        }\n    }\n}\n"
  },
  {
    "path": "src/body/length.rs",
    "content": "use std::fmt;\n\n#[derive(Clone, Copy, PartialEq, Eq)]\npub(crate) struct DecodedLength(u64);\n\n#[cfg(any(feature = \"http1\", feature = \"http2\"))]\nimpl From<Option<u64>> for DecodedLength {\n    fn from(len: Option<u64>) -> Self {\n        len.and_then(|len| {\n            // If the length is u64::MAX, oh well, just reported chunked.\n            Self::checked_new(len).ok()\n        })\n        .unwrap_or(DecodedLength::CHUNKED)\n    }\n}\n\n#[cfg(any(feature = \"http1\", feature = \"http2\", test))]\nconst MAX_LEN: u64 = u64::MAX - 2;\n\nimpl DecodedLength {\n    pub(crate) const CLOSE_DELIMITED: DecodedLength = DecodedLength(u64::MAX);\n    pub(crate) const CHUNKED: DecodedLength = DecodedLength(u64::MAX - 1);\n    pub(crate) const ZERO: DecodedLength = DecodedLength(0);\n\n    #[cfg(test)]\n    pub(crate) fn new(len: u64) -> Self {\n        debug_assert!(len <= MAX_LEN);\n        DecodedLength(len)\n    }\n\n    /// Takes the length as a content-length without other checks.\n    ///\n    /// Should only be called if previously confirmed this isn't\n    /// CLOSE_DELIMITED or CHUNKED.\n    #[inline]\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    pub(crate) fn danger_len(self) -> u64 {\n        debug_assert!(self.0 < Self::CHUNKED.0);\n        self.0\n    }\n\n    /// Converts to an Option<u64> representing a Known or Unknown length.\n    #[cfg(all(\n        any(feature = \"http1\", feature = \"http2\"),\n        any(feature = \"client\", feature = \"server\")\n    ))]\n    pub(crate) fn into_opt(self) -> Option<u64> {\n        match self {\n            DecodedLength::CHUNKED | DecodedLength::CLOSE_DELIMITED => None,\n            DecodedLength(known) => Some(known),\n        }\n    }\n\n    /// Checks the `u64` is within the maximum allowed for content-length.\n    #[cfg(any(feature = \"http1\", feature = \"http2\"))]\n    pub(crate) fn checked_new(len: u64) -> Result<Self, crate::error::Parse> {\n        if len <= MAX_LEN {\n            Ok(DecodedLength(len))\n        } else {\n            warn!(\"content-length bigger than maximum: {} > {}\", len, MAX_LEN);\n            Err(crate::error::Parse::TooLarge)\n        }\n    }\n\n    #[cfg(all(\n        any(feature = \"http1\", feature = \"http2\"),\n        any(feature = \"client\", feature = \"server\")\n    ))]\n    pub(crate) fn sub_if(&mut self, amt: u64) {\n        match *self {\n            DecodedLength::CHUNKED | DecodedLength::CLOSE_DELIMITED => (),\n            DecodedLength(ref mut known) => {\n                *known -= amt;\n            }\n        }\n    }\n\n    /// Returns whether this represents an exact length.\n    ///\n    /// This includes 0, which of course is an exact known length.\n    ///\n    /// It would return false if \"chunked\" or otherwise size-unknown.\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http2\"))]\n    pub(crate) fn is_exact(&self) -> bool {\n        self.0 <= MAX_LEN\n    }\n}\n\nimpl fmt::Debug for DecodedLength {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match *self {\n            DecodedLength::CLOSE_DELIMITED => f.write_str(\"CLOSE_DELIMITED\"),\n            DecodedLength::CHUNKED => f.write_str(\"CHUNKED\"),\n            DecodedLength(n) => f.debug_tuple(\"DecodedLength\").field(&n).finish(),\n        }\n    }\n}\n\nimpl fmt::Display for DecodedLength {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match *self {\n            DecodedLength::CLOSE_DELIMITED => f.write_str(\"close-delimited\"),\n            DecodedLength::CHUNKED => f.write_str(\"chunked encoding\"),\n            DecodedLength::ZERO => f.write_str(\"empty\"),\n            DecodedLength(n) => write!(f, \"content-length ({} bytes)\", n),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn sub_if_known() {\n        let mut len = DecodedLength::new(30);\n        len.sub_if(20);\n\n        assert_eq!(len.0, 10);\n    }\n\n    #[test]\n    fn sub_if_chunked() {\n        let mut len = DecodedLength::CHUNKED;\n        len.sub_if(20);\n\n        assert_eq!(len, DecodedLength::CHUNKED);\n    }\n}\n"
  },
  {
    "path": "src/body/mod.rs",
    "content": "//! Streaming bodies for Requests and Responses\n//!\n//! For both [Clients](crate::client) and [Servers](crate::server), requests and\n//! responses use streaming bodies, instead of complete buffering. This\n//! allows applications to not use memory they don't need, and allows exerting\n//! back-pressure on connections by only reading when asked.\n//!\n//! There are two pieces to this in hyper:\n//!\n//! - **The [`Body`] trait** describes all possible bodies.\n//!   hyper allows any body type that implements `Body`, allowing\n//!   applications to have fine-grained control over their streaming.\n//! - **The [`Incoming`] concrete type**, which is an implementation\n//!   of `Body`, and returned by hyper as a \"receive stream\" (so, for server\n//!   requests and client responses).\n//!\n//! There are additional implementations available in [`http-body-util`][],\n//! such as a `Full` or `Empty` body.\n//!\n//! [`http-body-util`]: https://docs.rs/http-body-util\n\npub use bytes::{Buf, Bytes};\npub use http_body::Body;\npub use http_body::Frame;\npub use http_body::SizeHint;\n\npub use self::incoming::Incoming;\n\n#[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\npub(crate) use self::incoming::Sender;\n#[cfg(all(\n    any(feature = \"http1\", feature = \"http2\"),\n    any(feature = \"client\", feature = \"server\")\n))]\npub(crate) use self::length::DecodedLength;\n\nmod incoming;\n#[cfg(all(\n    any(feature = \"http1\", feature = \"http2\"),\n    any(feature = \"client\", feature = \"server\")\n))]\nmod length;\n\nfn _assert_send_sync() {\n    fn _assert_send<T: Send>() {}\n    fn _assert_sync<T: Sync>() {}\n\n    _assert_send::<Incoming>();\n    _assert_sync::<Incoming>();\n}\n"
  },
  {
    "path": "src/cfg.rs",
    "content": "macro_rules! cfg_feature {\n    (\n        #![$meta:meta]\n        $($item:item)*\n    ) => {\n        $(\n            #[cfg($meta)]\n            #[cfg_attr(docsrs, doc(cfg($meta)))]\n            $item\n        )*\n    }\n}\n\nmacro_rules! cfg_proto {\n    ($($item:item)*) => {\n        cfg_feature! {\n            #![all(\n                any(feature = \"http1\", feature = \"http2\"),\n                any(feature = \"client\", feature = \"server\"),\n            )]\n            $($item)*\n        }\n    }\n}\n\ncfg_proto! {\n    macro_rules! cfg_client {\n        ($($item:item)*) => {\n            cfg_feature! {\n                #![feature = \"client\"]\n                $($item)*\n            }\n        }\n    }\n\n    macro_rules! cfg_server {\n        ($($item:item)*) => {\n            cfg_feature! {\n                #![feature = \"server\"]\n                $($item)*\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/client/conn/http1.rs",
    "content": "//! HTTP/1 client connections\n\nuse std::error::Error as StdError;\nuse std::fmt;\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse crate::rt::{Read, Write};\nuse bytes::Bytes;\nuse futures_core::ready;\nuse http::{Request, Response};\nuse httparse::ParserConfig;\n\nuse super::super::dispatch::{self, TrySendError};\nuse crate::body::{Body, Incoming as IncomingBody};\nuse crate::proto;\n\ntype Dispatcher<T, B> =\n    proto::dispatch::Dispatcher<proto::dispatch::Client<B>, B, T, proto::h1::ClientTransaction>;\n\n/// The sender side of an established connection.\npub struct SendRequest<B> {\n    dispatch: dispatch::Sender<Request<B>, Response<IncomingBody>>,\n}\n\n/// Deconstructed parts of a `Connection`.\n///\n/// This allows taking apart a `Connection` at a later time, in order to\n/// reclaim the IO object, and additional related pieces.\n#[derive(Debug)]\n#[non_exhaustive]\npub struct Parts<T> {\n    /// The original IO object used in the handshake.\n    pub io: T,\n    /// A buffer of bytes that have been read but not processed as HTTP.\n    ///\n    /// For instance, if the `Connection` is used for an HTTP upgrade request,\n    /// it is possible the server sent back the first bytes of the new protocol\n    /// along with the response upgrade.\n    ///\n    /// You will want to check for any existing bytes if you plan to continue\n    /// communicating on the IO object.\n    pub read_buf: Bytes,\n}\n\n/// A future that processes all HTTP state for the IO object.\n///\n/// In most cases, this should just be spawned into an executor, so that it\n/// can process incoming and outgoing messages, notice hangups, and the like.\n///\n/// Instances of this type are typically created via the [`handshake`] function\n#[must_use = \"futures do nothing unless polled\"]\npub struct Connection<T, B>\nwhere\n    T: Read + Write,\n    B: Body + 'static,\n{\n    inner: Dispatcher<T, B>,\n}\n\nimpl<T, B> Connection<T, B>\nwhere\n    T: Read + Write + Unpin,\n    B: Body + 'static,\n    B::Error: Into<Box<dyn StdError + Send + Sync>>,\n{\n    /// Return the inner IO object, and additional information.\n    ///\n    /// Only works for HTTP/1 connections. HTTP/2 connections will panic.\n    pub fn into_parts(self) -> Parts<T> {\n        let (io, read_buf, _) = self.inner.into_inner();\n        Parts { io, read_buf }\n    }\n\n    /// Poll the connection for completion, but without calling `shutdown`\n    /// on the underlying IO.\n    ///\n    /// This is useful to allow running a connection while doing an HTTP\n    /// upgrade. Once the upgrade is completed, the connection would be \"done\",\n    /// but it is not desired to actually shutdown the IO object. Instead you\n    /// would take it back using `into_parts`.\n    ///\n    /// Use [`poll_fn`](https://docs.rs/futures/0.1.25/futures/future/fn.poll_fn.html)\n    /// and [`try_ready!`](https://docs.rs/futures/0.1.25/futures/macro.try_ready.html)\n    /// to work with this function; or use the `without_shutdown` wrapper.\n    pub fn poll_without_shutdown(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {\n        self.inner.poll_without_shutdown(cx)\n    }\n\n    /// Prevent shutdown of the underlying IO object at the end of service the request,\n    /// instead run `into_parts`. This is a convenience wrapper over `poll_without_shutdown`.\n    pub async fn without_shutdown(self) -> crate::Result<Parts<T>> {\n        let mut conn = Some(self);\n        crate::common::future::poll_fn(move |cx| -> Poll<crate::Result<Parts<T>>> {\n            ready!(conn.as_mut().unwrap().poll_without_shutdown(cx))?;\n            Poll::Ready(Ok(conn.take().unwrap().into_parts()))\n        })\n        .await\n    }\n}\n\n/// A builder to configure an HTTP connection.\n///\n/// After setting options, the builder is used to create a handshake future.\n///\n/// **Note**: The default values of options are *not considered stable*. They\n/// are subject to change at any time.\n#[derive(Clone, Debug)]\npub struct Builder {\n    h09_responses: bool,\n    h1_parser_config: ParserConfig,\n    h1_writev: Option<bool>,\n    h1_title_case_headers: bool,\n    h1_preserve_header_case: bool,\n    h1_max_headers: Option<usize>,\n    #[cfg(feature = \"ffi\")]\n    h1_preserve_header_order: bool,\n    h1_read_buf_exact_size: Option<usize>,\n    h1_max_buf_size: Option<usize>,\n}\n\n/// Returns a handshake future over some IO.\n///\n/// This is a shortcut for `Builder::new().handshake(io)`.\n/// See [`client::conn`](crate::client::conn) for more.\npub async fn handshake<T, B>(io: T) -> crate::Result<(SendRequest<B>, Connection<T, B>)>\nwhere\n    T: Read + Write + Unpin,\n    B: Body + 'static,\n    B::Data: Send,\n    B::Error: Into<Box<dyn StdError + Send + Sync>>,\n{\n    Builder::new().handshake(io).await\n}\n\n// ===== impl SendRequest\n\nimpl<B> SendRequest<B> {\n    /// Polls to determine whether this sender can be used yet for a request.\n    ///\n    /// If the associated connection is closed, this returns an Error.\n    pub fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {\n        self.dispatch.poll_ready(cx)\n    }\n\n    /// Waits until the dispatcher is ready\n    ///\n    /// If the associated connection is closed, this returns an Error.\n    pub async fn ready(&mut self) -> crate::Result<()> {\n        crate::common::future::poll_fn(|cx| self.poll_ready(cx)).await\n    }\n\n    /// Checks if the connection is currently ready to send a request.\n    ///\n    /// # Note\n    ///\n    /// This is mostly a hint. Due to inherent latency of networks, it is\n    /// possible that even after checking this is ready, sending a request\n    /// may still fail because the connection was closed in the meantime.\n    pub fn is_ready(&self) -> bool {\n        self.dispatch.is_ready()\n    }\n\n    /// Checks if the connection side has been closed.\n    pub fn is_closed(&self) -> bool {\n        self.dispatch.is_closed()\n    }\n}\n\nimpl<B> SendRequest<B>\nwhere\n    B: Body + 'static,\n{\n    /// Sends a `Request` on the associated connection.\n    ///\n    /// Returns a future that if successful, yields the `Response`.\n    ///\n    /// `req` must have a `Host` header.\n    ///\n    /// # Uri\n    ///\n    /// The `Uri` of the request is serialized as-is.\n    ///\n    /// - Usually you want origin-form (`/path?query`).\n    /// - For sending to an HTTP proxy, you want to send in absolute-form\n    ///   (`https://hyper.rs/guides`).\n    ///\n    /// This is however not enforced or validated and it is up to the user\n    /// of this method to ensure the `Uri` is correct for their intended purpose.\n    pub fn send_request(\n        &mut self,\n        req: Request<B>,\n    ) -> impl Future<Output = crate::Result<Response<IncomingBody>>> {\n        let sent = self.dispatch.send(req);\n\n        async move {\n            match sent {\n                Ok(rx) => match rx.await {\n                    Ok(Ok(resp)) => Ok(resp),\n                    Ok(Err(err)) => Err(err),\n                    // this is definite bug if it happens, but it shouldn't happen!\n                    Err(_canceled) => panic!(\"dispatch dropped without returning error\"),\n                },\n                Err(_req) => {\n                    debug!(\"connection was not ready\");\n                    Err(crate::Error::new_canceled().with(\"connection was not ready\"))\n                }\n            }\n        }\n    }\n\n    /// Sends a `Request` on the associated connection.\n    ///\n    /// Returns a future that if successful, yields the `Response`.\n    ///\n    /// # Error\n    ///\n    /// If there was an error before trying to serialize the request to the\n    /// connection, the message will be returned as part of this error.\n    pub fn try_send_request(\n        &mut self,\n        req: Request<B>,\n    ) -> impl Future<Output = Result<Response<IncomingBody>, TrySendError<Request<B>>>> {\n        let sent = self.dispatch.try_send(req);\n        async move {\n            match sent {\n                Ok(rx) => match rx.await {\n                    Ok(Ok(res)) => Ok(res),\n                    Ok(Err(err)) => Err(err),\n                    // this is definite bug if it happens, but it shouldn't happen!\n                    Err(_) => panic!(\"dispatch dropped without returning error\"),\n                },\n                Err(req) => {\n                    debug!(\"connection was not ready\");\n                    let error = crate::Error::new_canceled().with(\"connection was not ready\");\n                    Err(TrySendError {\n                        error,\n                        message: Some(req),\n                    })\n                }\n            }\n        }\n    }\n}\n\nimpl<B> fmt::Debug for SendRequest<B> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"SendRequest\").finish()\n    }\n}\n\n// ===== impl Connection\n\nimpl<T, B> Connection<T, B>\nwhere\n    T: Read + Write + Unpin + Send,\n    B: Body + 'static,\n    B::Error: Into<Box<dyn StdError + Send + Sync>>,\n{\n    /// Enable this connection to support higher-level HTTP upgrades.\n    ///\n    /// See [the `upgrade` module](crate::upgrade) for more.\n    pub fn with_upgrades(self) -> upgrades::UpgradeableConnection<T, B> {\n        upgrades::UpgradeableConnection { inner: Some(self) }\n    }\n}\n\nimpl<T, B> fmt::Debug for Connection<T, B>\nwhere\n    T: Read + Write + fmt::Debug,\n    B: Body + 'static,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Connection\").finish()\n    }\n}\n\nimpl<T, B> Future for Connection<T, B>\nwhere\n    T: Read + Write + Unpin,\n    B: Body + 'static,\n    B::Data: Send,\n    B::Error: Into<Box<dyn StdError + Send + Sync>>,\n{\n    type Output = crate::Result<()>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        match ready!(Pin::new(&mut self.inner).poll(cx))? {\n            proto::Dispatched::Shutdown => Poll::Ready(Ok(())),\n            proto::Dispatched::Upgrade(pending) => {\n                // With no `Send` bound on `I`, we can't try to do\n                // upgrades here. In case a user was trying to use\n                // `upgrade` with this API, send a special\n                // error letting them know about that.\n                pending.manual();\n                Poll::Ready(Ok(()))\n            }\n        }\n    }\n}\n\n// ===== impl Builder\n\nimpl Builder {\n    /// Creates a new connection builder.\n    #[inline]\n    pub fn new() -> Builder {\n        Builder {\n            h09_responses: false,\n            h1_writev: None,\n            h1_read_buf_exact_size: None,\n            h1_parser_config: Default::default(),\n            h1_title_case_headers: false,\n            h1_preserve_header_case: false,\n            h1_max_headers: None,\n            #[cfg(feature = \"ffi\")]\n            h1_preserve_header_order: false,\n            h1_max_buf_size: None,\n        }\n    }\n\n    /// Set whether HTTP/0.9 responses should be tolerated.\n    ///\n    /// Default is false.\n    pub fn http09_responses(&mut self, enabled: bool) -> &mut Builder {\n        self.h09_responses = enabled;\n        self\n    }\n\n    /// Set whether HTTP/1 connections will accept spaces between header names\n    /// and the colon that follow them in responses.\n    ///\n    /// You probably don't need this, here is what [RFC 7230 Section 3.2.4.] has\n    /// to say about it:\n    ///\n    /// > No whitespace is allowed between the header field-name and colon. In\n    /// > the past, differences in the handling of such whitespace have led to\n    /// > security vulnerabilities in request routing and response handling. A\n    /// > server MUST reject any received request message that contains\n    /// > whitespace between a header field-name and colon with a response code\n    /// > of 400 (Bad Request). A proxy MUST remove any such whitespace from a\n    /// > response message before forwarding the message downstream.\n    ///\n    /// Default is false.\n    ///\n    /// [RFC 7230 Section 3.2.4.]: https://tools.ietf.org/html/rfc7230#section-3.2.4\n    pub fn allow_spaces_after_header_name_in_responses(&mut self, enabled: bool) -> &mut Builder {\n        self.h1_parser_config\n            .allow_spaces_after_header_name_in_responses(enabled);\n        self\n    }\n\n    /// Set whether HTTP/1 connections will accept obsolete line folding for\n    /// header values.\n    ///\n    /// Newline codepoints (`\\r` and `\\n`) will be transformed to spaces when\n    /// parsing.\n    ///\n    /// You probably don't need this, here is what [RFC 7230 Section 3.2.4.] has\n    /// to say about it:\n    ///\n    /// > A server that receives an obs-fold in a request message that is not\n    /// > within a message/http container MUST either reject the message by\n    /// > sending a 400 (Bad Request), preferably with a representation\n    /// > explaining that obsolete line folding is unacceptable, or replace\n    /// > each received obs-fold with one or more SP octets prior to\n    /// > interpreting the field value or forwarding the message downstream.\n    ///\n    /// > A proxy or gateway that receives an obs-fold in a response message\n    /// > that is not within a message/http container MUST either discard the\n    /// > message and replace it with a 502 (Bad Gateway) response, preferably\n    /// > with a representation explaining that unacceptable line folding was\n    /// > received, or replace each received obs-fold with one or more SP\n    /// > octets prior to interpreting the field value or forwarding the\n    /// > message downstream.\n    ///\n    /// > A user agent that receives an obs-fold in a response message that is\n    /// > not within a message/http container MUST replace each received\n    /// > obs-fold with one or more SP octets prior to interpreting the field\n    /// > value.\n    ///\n    /// Default is false.\n    ///\n    /// [RFC 7230 Section 3.2.4.]: https://tools.ietf.org/html/rfc7230#section-3.2.4\n    pub fn allow_obsolete_multiline_headers_in_responses(&mut self, enabled: bool) -> &mut Builder {\n        self.h1_parser_config\n            .allow_obsolete_multiline_headers_in_responses(enabled);\n        self\n    }\n\n    /// Set whether HTTP/1 connections will silently ignored malformed header lines.\n    ///\n    /// If this is enabled and a header line does not start with a valid header\n    /// name, or does not include a colon at all, the line will be silently ignored\n    /// and no error will be reported.\n    ///\n    /// Default is false.\n    pub fn ignore_invalid_headers_in_responses(&mut self, enabled: bool) -> &mut Builder {\n        self.h1_parser_config\n            .ignore_invalid_headers_in_responses(enabled);\n        self\n    }\n\n    /// Set whether HTTP/1 connections should try to use vectored writes,\n    /// or always flatten into a single buffer.\n    ///\n    /// Note that setting this to false may mean more copies of body data,\n    /// but may also improve performance when an IO transport doesn't\n    /// support vectored writes well, such as most TLS implementations.\n    ///\n    /// Setting this to true will force hyper to use queued strategy\n    /// which may eliminate unnecessary cloning on some TLS backends\n    ///\n    /// Default is `auto`. In this mode hyper will try to guess which\n    /// mode to use\n    pub fn writev(&mut self, enabled: bool) -> &mut Builder {\n        self.h1_writev = Some(enabled);\n        self\n    }\n\n    /// Set whether HTTP/1 connections will write header names as title case at\n    /// the socket level.\n    ///\n    /// Default is false.\n    pub fn title_case_headers(&mut self, enabled: bool) -> &mut Builder {\n        self.h1_title_case_headers = enabled;\n        self\n    }\n\n    /// Set whether to support preserving original header cases.\n    ///\n    /// Currently, this will record the original cases received, and store them\n    /// in a private extension on the `Response`. It will also look for and use\n    /// such an extension in any provided `Request`.\n    ///\n    /// Since the relevant extension is still private, there is no way to\n    /// interact with the original cases. The only effect this can have now is\n    /// to forward the cases in a proxy-like fashion.\n    ///\n    /// Default is false.\n    pub fn preserve_header_case(&mut self, enabled: bool) -> &mut Builder {\n        self.h1_preserve_header_case = enabled;\n        self\n    }\n\n    /// Set the maximum number of headers.\n    ///\n    /// When a response is received, the parser will reserve a buffer to store headers for optimal\n    /// performance.\n    ///\n    /// If client receives more headers than the buffer size, the error \"message header too large\"\n    /// is returned.\n    ///\n    /// Note that headers is allocated on the stack by default, which has higher performance. After\n    /// setting this value, headers will be allocated in heap memory, that is, heap memory\n    /// allocation will occur for each response, and there will be a performance drop of about 5%.\n    ///\n    /// Default is 100.\n    pub fn max_headers(&mut self, val: usize) -> &mut Self {\n        self.h1_max_headers = Some(val);\n        self\n    }\n\n    /// Set whether to support preserving original header order.\n    ///\n    /// Currently, this will record the order in which headers are received, and store this\n    /// ordering in a private extension on the `Response`. It will also look for and use\n    /// such an extension in any provided `Request`.\n    ///\n    /// Default is false.\n    #[cfg(feature = \"ffi\")]\n    pub fn preserve_header_order(&mut self, enabled: bool) -> &mut Builder {\n        self.h1_preserve_header_order = enabled;\n        self\n    }\n\n    /// Sets the exact size of the read buffer to *always* use.\n    ///\n    /// Note that setting this option unsets the `max_buf_size` option.\n    ///\n    /// Default is an adaptive read buffer.\n    pub fn read_buf_exact_size(&mut self, sz: Option<usize>) -> &mut Builder {\n        self.h1_read_buf_exact_size = sz;\n        self.h1_max_buf_size = None;\n        self\n    }\n\n    /// Set the maximum buffer size for the connection.\n    ///\n    /// Default is ~400kb.\n    ///\n    /// Note that setting this option unsets the `read_exact_buf_size` option.\n    ///\n    /// # Panics\n    ///\n    /// The minimum value allowed is 8192. This method panics if the passed `max` is less than the minimum.\n    pub fn max_buf_size(&mut self, max: usize) -> &mut Self {\n        assert!(\n            max >= proto::h1::MINIMUM_MAX_BUFFER_SIZE,\n            \"the max_buf_size cannot be smaller than the minimum that h1 specifies.\"\n        );\n\n        self.h1_max_buf_size = Some(max);\n        self.h1_read_buf_exact_size = None;\n        self\n    }\n\n    /// Constructs a connection with the configured options and IO.\n    /// See [`client::conn`](crate::client::conn) for more.\n    ///\n    /// Note, if [`Connection`] is not `await`-ed, [`SendRequest`] will\n    /// do nothing.\n    pub fn handshake<T, B>(\n        &self,\n        io: T,\n    ) -> impl Future<Output = crate::Result<(SendRequest<B>, Connection<T, B>)>>\n    where\n        T: Read + Write + Unpin,\n        B: Body + 'static,\n        B::Data: Send,\n        B::Error: Into<Box<dyn StdError + Send + Sync>>,\n    {\n        let opts = self.clone();\n\n        async move {\n            trace!(\"client handshake HTTP/1\");\n\n            let (tx, rx) = dispatch::channel();\n            let mut conn = proto::Conn::new(io);\n            conn.set_h1_parser_config(opts.h1_parser_config);\n            if let Some(writev) = opts.h1_writev {\n                if writev {\n                    conn.set_write_strategy_queue();\n                } else {\n                    conn.set_write_strategy_flatten();\n                }\n            }\n            if opts.h1_title_case_headers {\n                conn.set_title_case_headers();\n            }\n            if opts.h1_preserve_header_case {\n                conn.set_preserve_header_case();\n            }\n            if let Some(max_headers) = opts.h1_max_headers {\n                conn.set_http1_max_headers(max_headers);\n            }\n            #[cfg(feature = \"ffi\")]\n            if opts.h1_preserve_header_order {\n                conn.set_preserve_header_order();\n            }\n\n            if opts.h09_responses {\n                conn.set_h09_responses();\n            }\n\n            if let Some(sz) = opts.h1_read_buf_exact_size {\n                conn.set_read_buf_exact_size(sz);\n            }\n            if let Some(max) = opts.h1_max_buf_size {\n                conn.set_max_buf_size(max);\n            }\n            let cd = proto::h1::dispatch::Client::new(rx);\n            let proto = proto::h1::Dispatcher::new(cd, conn);\n\n            Ok((SendRequest { dispatch: tx }, Connection { inner: proto }))\n        }\n    }\n}\n\nmod upgrades {\n    use crate::upgrade::Upgraded;\n\n    use super::*;\n\n    // A future binding a connection with a Service with Upgrade support.\n    //\n    // This type is unnameable outside the crate.\n    #[must_use = \"futures do nothing unless polled\"]\n    #[allow(missing_debug_implementations)]\n    pub struct UpgradeableConnection<T, B>\n    where\n        T: Read + Write + Unpin + Send + 'static,\n        B: Body + 'static,\n        B::Error: Into<Box<dyn StdError + Send + Sync>>,\n    {\n        pub(super) inner: Option<Connection<T, B>>,\n    }\n\n    impl<I, B> Future for UpgradeableConnection<I, B>\n    where\n        I: Read + Write + Unpin + Send + 'static,\n        B: Body + 'static,\n        B::Data: Send,\n        B::Error: Into<Box<dyn StdError + Send + Sync>>,\n    {\n        type Output = crate::Result<()>;\n\n        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n            match ready!(Pin::new(&mut self.inner.as_mut().unwrap().inner).poll(cx)) {\n                Ok(proto::Dispatched::Shutdown) => Poll::Ready(Ok(())),\n                Ok(proto::Dispatched::Upgrade(pending)) => {\n                    let Parts { io, read_buf } = self.inner.take().unwrap().into_parts();\n                    pending.fulfill(Upgraded::new(io, read_buf));\n                    Poll::Ready(Ok(()))\n                }\n                Err(e) => Poll::Ready(Err(e)),\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/client/conn/http2.rs",
    "content": "//! HTTP/2 client connections\n\nuse std::error::Error;\nuse std::fmt;\nuse std::future::Future;\nuse std::marker::PhantomData;\nuse std::pin::Pin;\nuse std::sync::Arc;\nuse std::task::{Context, Poll};\nuse std::time::Duration;\n\nuse crate::rt::{Read, Write};\nuse futures_core::ready;\nuse http::{Request, Response};\n\nuse super::super::dispatch::{self, TrySendError};\nuse crate::body::{Body, Incoming as IncomingBody};\nuse crate::common::time::Time;\nuse crate::proto;\nuse crate::rt::bounds::Http2ClientConnExec;\nuse crate::rt::Timer;\n\n/// The sender side of an established connection.\npub struct SendRequest<B> {\n    dispatch: dispatch::UnboundedSender<Request<B>, Response<IncomingBody>>,\n}\n\nimpl<B> Clone for SendRequest<B> {\n    fn clone(&self) -> SendRequest<B> {\n        SendRequest {\n            dispatch: self.dispatch.clone(),\n        }\n    }\n}\n\n/// A future that processes all HTTP state for the IO object.\n///\n/// In most cases, this should just be spawned into an executor, so that it\n/// can process incoming and outgoing messages, notice hangups, and the like.\n///\n/// Instances of this type are typically created via the [`handshake`] function\n#[must_use = \"futures do nothing unless polled\"]\npub struct Connection<T, B, E>\nwhere\n    T: Read + Write + Unpin,\n    B: Body + 'static,\n    E: Http2ClientConnExec<B, T> + Unpin,\n    B::Error: Into<Box<dyn Error + Send + Sync>>,\n{\n    inner: (PhantomData<T>, proto::h2::ClientTask<B, E, T>),\n}\n\n/// A builder to configure an HTTP connection.\n///\n/// After setting options, the builder is used to create a handshake future.\n///\n/// **Note**: The default values of options are *not considered stable*. They\n/// are subject to change at any time.\n#[derive(Clone, Debug)]\npub struct Builder<Ex> {\n    pub(super) exec: Ex,\n    pub(super) timer: Time,\n    h2_builder: proto::h2::client::Config,\n}\n\n/// Returns a handshake future over some IO.\n///\n/// This is a shortcut for `Builder::new(exec).handshake(io)`.\n/// See [`client::conn`](crate::client::conn) for more.\npub async fn handshake<E, T, B>(\n    exec: E,\n    io: T,\n) -> crate::Result<(SendRequest<B>, Connection<T, B, E>)>\nwhere\n    T: Read + Write + Unpin,\n    B: Body + 'static,\n    B::Data: Send,\n    B::Error: Into<Box<dyn Error + Send + Sync>>,\n    E: Http2ClientConnExec<B, T> + Unpin + Clone,\n{\n    Builder::new(exec).handshake(io).await\n}\n\n// ===== impl SendRequest\n\nimpl<B> SendRequest<B> {\n    /// Polls to determine whether this sender can be used yet for a request.\n    ///\n    /// If the associated connection is closed, this returns an Error.\n    pub fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<crate::Result<()>> {\n        if self.is_closed() {\n            Poll::Ready(Err(crate::Error::new_closed()))\n        } else {\n            Poll::Ready(Ok(()))\n        }\n    }\n\n    /// Waits until the dispatcher is ready\n    ///\n    /// If the associated connection is closed, this returns an Error.\n    pub async fn ready(&mut self) -> crate::Result<()> {\n        crate::common::future::poll_fn(|cx| self.poll_ready(cx)).await\n    }\n\n    /// Checks if the connection is currently ready to send a request.\n    ///\n    /// # Note\n    ///\n    /// This is mostly a hint. Due to inherent latency of networks, it is\n    /// possible that even after checking this is ready, sending a request\n    /// may still fail because the connection was closed in the meantime.\n    pub fn is_ready(&self) -> bool {\n        self.dispatch.is_ready()\n    }\n\n    /// Checks if the connection side has been closed.\n    pub fn is_closed(&self) -> bool {\n        self.dispatch.is_closed()\n    }\n}\n\nimpl<B> SendRequest<B>\nwhere\n    B: Body + 'static,\n{\n    /// Sends a `Request` on the associated connection.\n    ///\n    /// Returns a future that if successful, yields the `Response`.\n    ///\n    /// `req` must have a `Host` header.\n    ///\n    /// Absolute-form `Uri`s are not required. If received, they will be serialized\n    /// as-is.\n    pub fn send_request(\n        &mut self,\n        req: Request<B>,\n    ) -> impl Future<Output = crate::Result<Response<IncomingBody>>> {\n        let sent = self.dispatch.send(req);\n\n        async move {\n            match sent {\n                Ok(rx) => match rx.await {\n                    Ok(Ok(resp)) => Ok(resp),\n                    Ok(Err(err)) => Err(err),\n                    // this is definite bug if it happens, but it shouldn't happen!\n                    Err(_canceled) => panic!(\"dispatch dropped without returning error\"),\n                },\n                Err(_req) => {\n                    debug!(\"connection was not ready\");\n\n                    Err(crate::Error::new_canceled().with(\"connection was not ready\"))\n                }\n            }\n        }\n    }\n\n    /// Sends a `Request` on the associated connection.\n    ///\n    /// Returns a future that if successful, yields the `Response`.\n    ///\n    /// # Error\n    ///\n    /// If there was an error before trying to serialize the request to the\n    /// connection, the message will be returned as part of this error.\n    pub fn try_send_request(\n        &mut self,\n        req: Request<B>,\n    ) -> impl Future<Output = Result<Response<IncomingBody>, TrySendError<Request<B>>>> {\n        let sent = self.dispatch.try_send(req);\n        async move {\n            match sent {\n                Ok(rx) => match rx.await {\n                    Ok(Ok(res)) => Ok(res),\n                    Ok(Err(err)) => Err(err),\n                    // this is definite bug if it happens, but it shouldn't happen!\n                    Err(_) => panic!(\"dispatch dropped without returning error\"),\n                },\n                Err(req) => {\n                    debug!(\"connection was not ready\");\n                    let error = crate::Error::new_canceled().with(\"connection was not ready\");\n                    Err(TrySendError {\n                        error,\n                        message: Some(req),\n                    })\n                }\n            }\n        }\n    }\n}\n\nimpl<B> fmt::Debug for SendRequest<B> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"SendRequest\").finish()\n    }\n}\n\n// ===== impl Connection\n\nimpl<T, B, E> Connection<T, B, E>\nwhere\n    T: Read + Write + Unpin + 'static,\n    B: Body + Unpin + 'static,\n    B::Data: Send,\n    B::Error: Into<Box<dyn Error + Send + Sync>>,\n    E: Http2ClientConnExec<B, T> + Unpin,\n{\n    /// Returns whether the [extended CONNECT protocol][1] is enabled or not.\n    ///\n    /// This setting is configured by the server peer by sending the\n    /// [`SETTINGS_ENABLE_CONNECT_PROTOCOL` parameter][2] in a `SETTINGS` frame.\n    /// This method returns the currently acknowledged value received from the\n    /// remote.\n    ///\n    /// [1]: https://datatracker.ietf.org/doc/html/rfc8441#section-4\n    /// [2]: https://datatracker.ietf.org/doc/html/rfc8441#section-3\n    pub fn is_extended_connect_protocol_enabled(&self) -> bool {\n        self.inner.1.is_extended_connect_protocol_enabled()\n    }\n}\n\nimpl<T, B, E> fmt::Debug for Connection<T, B, E>\nwhere\n    T: Read + Write + fmt::Debug + 'static + Unpin,\n    B: Body + 'static,\n    E: Http2ClientConnExec<B, T> + Unpin,\n    B::Error: Into<Box<dyn Error + Send + Sync>>,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Connection\").finish()\n    }\n}\n\nimpl<T, B, E> Future for Connection<T, B, E>\nwhere\n    T: Read + Write + Unpin + 'static,\n    B: Body + 'static + Unpin,\n    B::Data: Send,\n    E: Unpin,\n    B::Error: Into<Box<dyn Error + Send + Sync>>,\n    E: Http2ClientConnExec<B, T> + Unpin,\n{\n    type Output = crate::Result<()>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        match ready!(Pin::new(&mut self.inner.1).poll(cx))? {\n            proto::Dispatched::Shutdown => Poll::Ready(Ok(())),\n            #[cfg(feature = \"http1\")]\n            proto::Dispatched::Upgrade(_pending) => unreachable!(\"http2 cannot upgrade\"),\n        }\n    }\n}\n\n// ===== impl Builder\n\nimpl<Ex> Builder<Ex>\nwhere\n    Ex: Clone,\n{\n    /// Creates a new connection builder.\n    #[inline]\n    pub fn new(exec: Ex) -> Builder<Ex> {\n        Builder {\n            exec,\n            timer: Time::Empty,\n            h2_builder: Default::default(),\n        }\n    }\n\n    /// Provide a timer to execute background HTTP2 tasks.\n    pub fn timer<M>(&mut self, timer: M) -> &mut Builder<Ex>\n    where\n        M: Timer + Send + Sync + 'static,\n    {\n        self.timer = Time::Timer(Arc::new(timer));\n        self\n    }\n\n    /// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2\n    /// stream-level flow control.\n    ///\n    /// Passing `None` will do nothing.\n    ///\n    /// If not set, hyper will use a default.\n    ///\n    /// [spec]: https://httpwg.org/specs/rfc9113.html#SETTINGS_INITIAL_WINDOW_SIZE\n    pub fn initial_stream_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {\n        if let Some(sz) = sz.into() {\n            self.h2_builder.adaptive_window = false;\n            self.h2_builder.initial_stream_window_size = sz;\n        }\n        self\n    }\n\n    /// Sets the max connection-level flow control for HTTP2\n    ///\n    /// Passing `None` will do nothing.\n    ///\n    /// If not set, hyper will use a default.\n    pub fn initial_connection_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {\n        if let Some(sz) = sz.into() {\n            self.h2_builder.adaptive_window = false;\n            self.h2_builder.initial_conn_window_size = sz;\n        }\n        self\n    }\n\n    /// Sets the initial maximum of locally initiated (send) streams.\n    ///\n    /// This value will be overwritten by the value included in the initial\n    /// SETTINGS frame received from the peer as part of a [connection preface].\n    ///\n    /// Passing `None` will do nothing.\n    ///\n    /// If not set, hyper will use a default.\n    ///\n    /// [connection preface]: https://httpwg.org/specs/rfc9113.html#preface\n    pub fn initial_max_send_streams(&mut self, initial: impl Into<Option<usize>>) -> &mut Self {\n        if let Some(initial) = initial.into() {\n            self.h2_builder.initial_max_send_streams = initial;\n        }\n        self\n    }\n\n    /// Sets whether to use an adaptive flow control.\n    ///\n    /// Enabling this will override the limits set in\n    /// `initial_stream_window_size` and\n    /// `initial_connection_window_size`.\n    pub fn adaptive_window(&mut self, enabled: bool) -> &mut Self {\n        use proto::h2::SPEC_WINDOW_SIZE;\n\n        self.h2_builder.adaptive_window = enabled;\n        if enabled {\n            self.h2_builder.initial_conn_window_size = SPEC_WINDOW_SIZE;\n            self.h2_builder.initial_stream_window_size = SPEC_WINDOW_SIZE;\n        }\n        self\n    }\n\n    /// Sets the maximum frame size to use for HTTP2.\n    ///\n    /// Default is currently 16KB, but can change.\n    pub fn max_frame_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {\n        self.h2_builder.max_frame_size = sz.into();\n        self\n    }\n\n    /// Sets the max size of received header frames.\n    ///\n    /// Default is currently 16KB, but can change.\n    pub fn max_header_list_size(&mut self, max: u32) -> &mut Self {\n        self.h2_builder.max_header_list_size = max;\n        self\n    }\n\n    /// Sets the header table size.\n    ///\n    /// This setting informs the peer of the maximum size of the header compression\n    /// table used to encode header blocks, in octets. The encoder may select any value\n    /// equal to or less than the header table size specified by the sender.\n    ///\n    /// The default value of crate `h2` is 4,096.\n    pub fn header_table_size(&mut self, size: impl Into<Option<u32>>) -> &mut Self {\n        self.h2_builder.header_table_size = size.into();\n        self\n    }\n\n    /// Sets the maximum number of concurrent streams.\n    ///\n    /// The maximum concurrent streams setting only controls the maximum number\n    /// of streams that can be initiated by the remote peer. In other words,\n    /// when this setting is set to 100, this does not limit the number of\n    /// concurrent streams that can be created by the caller.\n    ///\n    /// It is recommended that this value be no smaller than 100, so as to not\n    /// unnecessarily limit parallelism. However, any value is legal, including\n    /// 0. If `max` is set to 0, then the remote will not be permitted to\n    /// initiate streams.\n    ///\n    /// Note that streams in the reserved state, i.e., push promises that have\n    /// been reserved but the stream has not started, do not count against this\n    /// setting.\n    ///\n    /// Also note that if the remote *does* exceed the value set here, it is not\n    /// a protocol level error. Instead, the `h2` library will immediately reset\n    /// the stream.\n    ///\n    /// See [Section 5.1.2] in the HTTP/2 spec for more details.\n    ///\n    /// [Section 5.1.2]: https://httpwg.org/specs/rfc7540.html#rfc.section.5.1.2\n    pub fn max_concurrent_streams(&mut self, max: impl Into<Option<u32>>) -> &mut Self {\n        self.h2_builder.max_concurrent_streams = max.into();\n        self\n    }\n\n    /// Sets an interval for HTTP2 Ping frames should be sent to keep a\n    /// connection alive.\n    ///\n    /// Pass `None` to disable HTTP2 keep-alive.\n    ///\n    /// Default is currently disabled.\n    pub fn keep_alive_interval(&mut self, interval: impl Into<Option<Duration>>) -> &mut Self {\n        self.h2_builder.keep_alive_interval = interval.into();\n        self\n    }\n\n    /// Sets a timeout for receiving an acknowledgement of the keep-alive ping.\n    ///\n    /// If the ping is not acknowledged within the timeout, the connection will\n    /// be closed. Does nothing if `keep_alive_interval` is disabled.\n    ///\n    /// Default is 20 seconds.\n    pub fn keep_alive_timeout(&mut self, timeout: Duration) -> &mut Self {\n        self.h2_builder.keep_alive_timeout = timeout;\n        self\n    }\n\n    /// Sets whether HTTP2 keep-alive should apply while the connection is idle.\n    ///\n    /// If disabled, keep-alive pings are only sent while there are open\n    /// request/responses streams. If enabled, pings are also sent when no\n    /// streams are active. Does nothing if `keep_alive_interval` is\n    /// disabled.\n    ///\n    /// Default is `false`.\n    pub fn keep_alive_while_idle(&mut self, enabled: bool) -> &mut Self {\n        self.h2_builder.keep_alive_while_idle = enabled;\n        self\n    }\n\n    /// Sets the maximum number of HTTP2 concurrent locally reset streams.\n    ///\n    /// See the documentation of [`h2::client::Builder::max_concurrent_reset_streams`] for more\n    /// details.\n    ///\n    /// The default value is determined by the `h2` crate.\n    ///\n    /// [`h2::client::Builder::max_concurrent_reset_streams`]: https://docs.rs/h2/client/struct.Builder.html#method.max_concurrent_reset_streams\n    pub fn max_concurrent_reset_streams(&mut self, max: usize) -> &mut Self {\n        self.h2_builder.max_concurrent_reset_streams = Some(max);\n        self\n    }\n\n    /// Set the maximum write buffer size for each HTTP/2 stream.\n    ///\n    /// Default is currently 1MB, but may change.\n    ///\n    /// # Panics\n    ///\n    /// The value must be no larger than `u32::MAX`.\n    pub fn max_send_buf_size(&mut self, max: usize) -> &mut Self {\n        assert!(max <= u32::MAX as usize);\n        self.h2_builder.max_send_buffer_size = max;\n        self\n    }\n\n    /// Configures the maximum number of pending reset streams allowed before a GOAWAY will be sent.\n    ///\n    /// This will default to the default value set by the [`h2` crate](https://crates.io/crates/h2).\n    /// As of v0.4.0, it is 20.\n    ///\n    /// See <https://github.com/hyperium/hyper/issues/2877> for more information.\n    pub fn max_pending_accept_reset_streams(&mut self, max: impl Into<Option<usize>>) -> &mut Self {\n        self.h2_builder.max_pending_accept_reset_streams = max.into();\n        self\n    }\n\n    /// Configures the maximum number of local resets due to protocol errors made by the remote end.\n    ///\n    /// See the documentation of [`h2::client::Builder::max_local_error_reset_streams`] for more\n    /// details.\n    ///\n    /// The default value is 1024.\n    pub fn max_local_error_reset_streams(&mut self, max: impl Into<Option<usize>>) -> &mut Self {\n        self.h2_builder.max_local_error_reset_streams = max.into();\n        self\n    }\n\n    /// Constructs a connection with the configured options and IO.\n    /// See [`client::conn`](crate::client::conn) for more.\n    ///\n    /// Note, if [`Connection`] is not `await`-ed, [`SendRequest`] will\n    /// do nothing.\n    pub fn handshake<T, B>(\n        &self,\n        io: T,\n    ) -> impl Future<Output = crate::Result<(SendRequest<B>, Connection<T, B, Ex>)>>\n    where\n        T: Read + Write + Unpin,\n        B: Body + 'static,\n        B::Data: Send,\n        B::Error: Into<Box<dyn Error + Send + Sync>>,\n        Ex: Http2ClientConnExec<B, T> + Unpin,\n    {\n        let opts = self.clone();\n\n        async move {\n            trace!(\"client handshake HTTP/2\");\n\n            let (tx, rx) = dispatch::channel();\n            let h2 = proto::h2::client::handshake(io, rx, &opts.h2_builder, opts.exec, opts.timer)\n                .await?;\n            Ok((\n                SendRequest {\n                    dispatch: tx.unbound(),\n                },\n                Connection {\n                    inner: (PhantomData, h2),\n                },\n            ))\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n\n    #[tokio::test]\n    #[ignore] // only compilation is checked\n    async fn send_sync_executor_of_non_send_futures() {\n        #[derive(Clone)]\n        struct LocalTokioExecutor;\n\n        impl<F> crate::rt::Executor<F> for LocalTokioExecutor\n        where\n            F: std::future::Future + 'static, // not requiring `Send`\n        {\n            fn execute(&self, fut: F) {\n                // This will spawn into the currently running `LocalSet`.\n                tokio::task::spawn_local(fut);\n            }\n        }\n\n        #[allow(unused)]\n        async fn run(io: impl crate::rt::Read + crate::rt::Write + Unpin + 'static) {\n            let (_sender, conn) = crate::client::conn::http2::handshake::<\n                _,\n                _,\n                http_body_util::Empty<bytes::Bytes>,\n            >(LocalTokioExecutor, io)\n            .await\n            .unwrap();\n\n            tokio::task::spawn_local(async move {\n                conn.await.unwrap();\n            });\n        }\n    }\n\n    #[tokio::test]\n    #[ignore] // only compilation is checked\n    async fn not_send_not_sync_executor_of_not_send_futures() {\n        #[derive(Clone)]\n        struct LocalTokioExecutor {\n            _x: std::marker::PhantomData<std::rc::Rc<()>>,\n        }\n\n        impl<F> crate::rt::Executor<F> for LocalTokioExecutor\n        where\n            F: std::future::Future + 'static, // not requiring `Send`\n        {\n            fn execute(&self, fut: F) {\n                // This will spawn into the currently running `LocalSet`.\n                tokio::task::spawn_local(fut);\n            }\n        }\n\n        #[allow(unused)]\n        async fn run(io: impl crate::rt::Read + crate::rt::Write + Unpin + 'static) {\n            let (_sender, conn) =\n                crate::client::conn::http2::handshake::<_, _, http_body_util::Empty<bytes::Bytes>>(\n                    LocalTokioExecutor {\n                        _x: Default::default(),\n                    },\n                    io,\n                )\n                .await\n                .unwrap();\n\n            tokio::task::spawn_local(async move {\n                conn.await.unwrap();\n            });\n        }\n    }\n\n    #[tokio::test]\n    #[ignore] // only compilation is checked\n    async fn send_not_sync_executor_of_not_send_futures() {\n        #[derive(Clone)]\n        struct LocalTokioExecutor {\n            _x: std::marker::PhantomData<std::cell::Cell<()>>,\n        }\n\n        impl<F> crate::rt::Executor<F> for LocalTokioExecutor\n        where\n            F: std::future::Future + 'static, // not requiring `Send`\n        {\n            fn execute(&self, fut: F) {\n                // This will spawn into the currently running `LocalSet`.\n                tokio::task::spawn_local(fut);\n            }\n        }\n\n        #[allow(unused)]\n        async fn run(io: impl crate::rt::Read + crate::rt::Write + Unpin + 'static) {\n            let (_sender, conn) =\n                crate::client::conn::http2::handshake::<_, _, http_body_util::Empty<bytes::Bytes>>(\n                    LocalTokioExecutor {\n                        _x: Default::default(),\n                    },\n                    io,\n                )\n                .await\n                .unwrap();\n\n            tokio::task::spawn_local(async move {\n                conn.await.unwrap();\n            });\n        }\n    }\n\n    #[tokio::test]\n    #[ignore] // only compilation is checked\n    async fn send_sync_executor_of_send_futures() {\n        #[derive(Clone)]\n        struct TokioExecutor;\n\n        impl<F> crate::rt::Executor<F> for TokioExecutor\n        where\n            F: std::future::Future + 'static + Send,\n            F::Output: Send + 'static,\n        {\n            fn execute(&self, fut: F) {\n                tokio::task::spawn(fut);\n            }\n        }\n\n        #[allow(unused)]\n        async fn run(io: impl crate::rt::Read + crate::rt::Write + Send + Unpin + 'static) {\n            let (_sender, conn) = crate::client::conn::http2::handshake::<\n                _,\n                _,\n                http_body_util::Empty<bytes::Bytes>,\n            >(TokioExecutor, io)\n            .await\n            .unwrap();\n\n            tokio::task::spawn(async move {\n                conn.await.unwrap();\n            });\n        }\n    }\n\n    #[tokio::test]\n    #[ignore] // only compilation is checked\n    async fn send_not_sync_executor_of_send_futures() {\n        #[derive(Clone)]\n        struct TokioExecutor {\n            // !Sync\n            _x: std::marker::PhantomData<std::cell::Cell<()>>,\n        }\n\n        impl<F> crate::rt::Executor<F> for TokioExecutor\n        where\n            F: std::future::Future + 'static + Send,\n            F::Output: Send + 'static,\n        {\n            fn execute(&self, fut: F) {\n                tokio::task::spawn(fut);\n            }\n        }\n\n        #[allow(unused)]\n        async fn run(io: impl crate::rt::Read + crate::rt::Write + Send + Unpin + 'static) {\n            let (_sender, conn) =\n                crate::client::conn::http2::handshake::<_, _, http_body_util::Empty<bytes::Bytes>>(\n                    TokioExecutor {\n                        _x: Default::default(),\n                    },\n                    io,\n                )\n                .await\n                .unwrap();\n\n            tokio::task::spawn_local(async move {\n                // can't use spawn here because when executor is !Send\n                conn.await.unwrap();\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/client/conn/mod.rs",
    "content": "//! Lower-level client connection API.\n//!\n//! The types in this module are to provide a lower-level API based around a\n//! single connection. Connecting to a host, pooling connections, and the like\n//! are not handled at this level. This module provides the building blocks to\n//! customize those things externally.\n//!\n//! If you are looking for a convenient HTTP client, then you may wish to\n//! consider [reqwest](https://github.com/seanmonstar/reqwest) for a high level\n//! client or [`hyper-util`'s client](https://docs.rs/hyper-util/latest/hyper_util/client/index.html)\n//! if you want to keep it more low level / basic.\n//!\n//! ## Example\n//!\n//! See the [client guide](https://hyper.rs/guides/1/client/basic/).\n\n#[cfg(feature = \"http1\")]\npub mod http1;\n#[cfg(feature = \"http2\")]\npub mod http2;\n\npub use super::dispatch::TrySendError;\n"
  },
  {
    "path": "src/client/dispatch.rs",
    "content": "use std::task::{Context, Poll};\n#[cfg(feature = \"http2\")]\nuse std::{future::Future, pin::Pin};\n\n#[cfg(feature = \"http2\")]\nuse http::{Request, Response};\n#[cfg(feature = \"http2\")]\nuse http_body::Body;\n#[cfg(feature = \"http2\")]\nuse pin_project_lite::pin_project;\nuse tokio::sync::{mpsc, oneshot};\n\n#[cfg(feature = \"http2\")]\nuse crate::{body::Incoming, proto::h2::client::ResponseFutMap};\n\npub(crate) type RetryPromise<T, U> = oneshot::Receiver<Result<U, TrySendError<T>>>;\npub(crate) type Promise<T> = oneshot::Receiver<Result<T, crate::Error>>;\n\n/// An error when calling `try_send_request`.\n///\n/// There is a possibility of an error occurring on a connection in-between the\n/// time that a request is queued and when it is actually written to the IO\n/// transport. If that happens, it is safe to return the request back to the\n/// caller, as it was never fully sent.\n#[derive(Debug)]\npub struct TrySendError<T> {\n    pub(crate) error: crate::Error,\n    pub(crate) message: Option<T>,\n}\n\npub(crate) fn channel<T, U>() -> (Sender<T, U>, Receiver<T, U>) {\n    let (tx, rx) = mpsc::unbounded_channel();\n    let (giver, taker) = want::new();\n    let tx = Sender {\n        #[cfg(feature = \"http1\")]\n        buffered_once: false,\n        giver,\n        inner: tx,\n    };\n    let rx = Receiver { inner: rx, taker };\n    (tx, rx)\n}\n\n/// A bounded sender of requests and callbacks for when responses are ready.\n///\n/// While the inner sender is unbounded, the Giver is used to determine\n/// if the Receiver is ready for another request.\npub(crate) struct Sender<T, U> {\n    /// One message is always allowed, even if the Receiver hasn't asked\n    /// for it yet. This boolean keeps track of whether we've sent one\n    /// without notice.\n    #[cfg(feature = \"http1\")]\n    buffered_once: bool,\n    /// The Giver helps watch that the Receiver side has been polled\n    /// when the queue is empty. This helps us know when a request and\n    /// response have been fully processed, and a connection is ready\n    /// for more.\n    giver: want::Giver,\n    /// Actually bounded by the Giver, plus `buffered_once`.\n    inner: mpsc::UnboundedSender<Envelope<T, U>>,\n}\n\n/// An unbounded version.\n///\n/// Cannot poll the Giver, but can still use it to determine if the Receiver\n/// has been dropped. However, this version can be cloned.\n#[cfg(feature = \"http2\")]\npub(crate) struct UnboundedSender<T, U> {\n    /// Only used for `is_closed`, since mpsc::UnboundedSender cannot be checked.\n    giver: want::SharedGiver,\n    inner: mpsc::UnboundedSender<Envelope<T, U>>,\n}\n\nimpl<T, U> Sender<T, U> {\n    #[cfg(feature = \"http1\")]\n    pub(crate) fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {\n        self.giver\n            .poll_want(cx)\n            .map_err(|_| crate::Error::new_closed())\n    }\n\n    #[cfg(feature = \"http1\")]\n    pub(crate) fn is_ready(&self) -> bool {\n        self.giver.is_wanting()\n    }\n\n    #[cfg(feature = \"http1\")]\n    pub(crate) fn is_closed(&self) -> bool {\n        self.giver.is_canceled()\n    }\n\n    #[cfg(feature = \"http1\")]\n    fn can_send(&mut self) -> bool {\n        if self.giver.give() || !self.buffered_once {\n            // If the receiver is ready *now*, then of course we can send.\n            //\n            // If the receiver isn't ready yet, but we don't have anything\n            // in the channel yet, then allow one message.\n            self.buffered_once = true;\n            true\n        } else {\n            false\n        }\n    }\n\n    #[cfg(feature = \"http1\")]\n    pub(crate) fn try_send(&mut self, val: T) -> Result<RetryPromise<T, U>, T> {\n        if !self.can_send() {\n            return Err(val);\n        }\n        let (tx, rx) = oneshot::channel();\n        self.inner\n            .send(Envelope(Some((val, Callback::Retry(Some(tx))))))\n            .map(move |_| rx)\n            .map_err(|mut e| (e.0).0.take().expect(\"envelope not dropped\").0)\n    }\n\n    #[cfg(feature = \"http1\")]\n    pub(crate) fn send(&mut self, val: T) -> Result<Promise<U>, T> {\n        if !self.can_send() {\n            return Err(val);\n        }\n        let (tx, rx) = oneshot::channel();\n        self.inner\n            .send(Envelope(Some((val, Callback::NoRetry(Some(tx))))))\n            .map(move |_| rx)\n            .map_err(|mut e| (e.0).0.take().expect(\"envelope not dropped\").0)\n    }\n\n    #[cfg(feature = \"http2\")]\n    pub(crate) fn unbound(self) -> UnboundedSender<T, U> {\n        UnboundedSender {\n            giver: self.giver.shared(),\n            inner: self.inner,\n        }\n    }\n}\n\n#[cfg(feature = \"http2\")]\nimpl<T, U> UnboundedSender<T, U> {\n    pub(crate) fn is_ready(&self) -> bool {\n        !self.giver.is_canceled()\n    }\n\n    pub(crate) fn is_closed(&self) -> bool {\n        self.giver.is_canceled()\n    }\n\n    pub(crate) fn try_send(&mut self, val: T) -> Result<RetryPromise<T, U>, T> {\n        let (tx, rx) = oneshot::channel();\n        self.inner\n            .send(Envelope(Some((val, Callback::Retry(Some(tx))))))\n            .map(move |_| rx)\n            .map_err(|mut e| (e.0).0.take().expect(\"envelope not dropped\").0)\n    }\n\n    pub(crate) fn send(&mut self, val: T) -> Result<Promise<U>, T> {\n        let (tx, rx) = oneshot::channel();\n        self.inner\n            .send(Envelope(Some((val, Callback::NoRetry(Some(tx))))))\n            .map(move |_| rx)\n            .map_err(|mut e| (e.0).0.take().expect(\"envelope not dropped\").0)\n    }\n}\n\n#[cfg(feature = \"http2\")]\nimpl<T, U> Clone for UnboundedSender<T, U> {\n    fn clone(&self) -> Self {\n        UnboundedSender {\n            giver: self.giver.clone(),\n            inner: self.inner.clone(),\n        }\n    }\n}\n\npub(crate) struct Receiver<T, U> {\n    inner: mpsc::UnboundedReceiver<Envelope<T, U>>,\n    taker: want::Taker,\n}\n\nimpl<T, U> Receiver<T, U> {\n    pub(crate) fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<(T, Callback<T, U>)>> {\n        match self.inner.poll_recv(cx) {\n            Poll::Ready(item) => {\n                Poll::Ready(item.map(|mut env| env.0.take().expect(\"envelope not dropped\")))\n            }\n            Poll::Pending => {\n                self.taker.want();\n                Poll::Pending\n            }\n        }\n    }\n\n    #[cfg(feature = \"http1\")]\n    pub(crate) fn close(&mut self) {\n        self.taker.cancel();\n        self.inner.close();\n    }\n\n    #[cfg(feature = \"http1\")]\n    pub(crate) fn try_recv(&mut self) -> Option<(T, Callback<T, U>)> {\n        match crate::common::task::now_or_never(self.inner.recv()) {\n            Some(Some(mut env)) => env.0.take(),\n            _ => None,\n        }\n    }\n}\n\nimpl<T, U> Drop for Receiver<T, U> {\n    fn drop(&mut self) {\n        // Notify the giver about the closure first, before dropping\n        // the mpsc::Receiver.\n        self.taker.cancel();\n    }\n}\n\nstruct Envelope<T, U>(Option<(T, Callback<T, U>)>);\n\nimpl<T, U> Drop for Envelope<T, U> {\n    fn drop(&mut self) {\n        if let Some((val, cb)) = self.0.take() {\n            cb.send(Err(TrySendError {\n                error: crate::Error::new_canceled().with(\"connection closed\"),\n                message: Some(val),\n            }));\n        }\n    }\n}\n\npub(crate) enum Callback<T, U> {\n    #[allow(unused)]\n    Retry(Option<oneshot::Sender<Result<U, TrySendError<T>>>>),\n    NoRetry(Option<oneshot::Sender<Result<U, crate::Error>>>),\n}\n\nimpl<T, U> Drop for Callback<T, U> {\n    fn drop(&mut self) {\n        match self {\n            Callback::Retry(tx) => {\n                if let Some(tx) = tx.take() {\n                    let _ = tx.send(Err(TrySendError {\n                        error: dispatch_gone(),\n                        message: None,\n                    }));\n                }\n            }\n            Callback::NoRetry(tx) => {\n                if let Some(tx) = tx.take() {\n                    let _ = tx.send(Err(dispatch_gone()));\n                }\n            }\n        }\n    }\n}\n\n#[cold]\nfn dispatch_gone() -> crate::Error {\n    // FIXME(nox): What errors do we want here?\n    crate::Error::new_user_dispatch_gone().with(if std::thread::panicking() {\n        \"user code panicked\"\n    } else {\n        \"runtime dropped the dispatch task\"\n    })\n}\n\nimpl<T, U> Callback<T, U> {\n    #[cfg(feature = \"http2\")]\n    pub(crate) fn is_canceled(&self) -> bool {\n        match *self {\n            Callback::Retry(Some(ref tx)) => tx.is_closed(),\n            Callback::NoRetry(Some(ref tx)) => tx.is_closed(),\n            _ => unreachable!(),\n        }\n    }\n\n    pub(crate) fn poll_canceled(&mut self, cx: &mut Context<'_>) -> Poll<()> {\n        match *self {\n            Callback::Retry(Some(ref mut tx)) => tx.poll_closed(cx),\n            Callback::NoRetry(Some(ref mut tx)) => tx.poll_closed(cx),\n            _ => unreachable!(),\n        }\n    }\n\n    pub(crate) fn send(mut self, val: Result<U, TrySendError<T>>) {\n        match self {\n            Callback::Retry(ref mut tx) => {\n                let _ = tx.take().unwrap().send(val);\n            }\n            Callback::NoRetry(ref mut tx) => {\n                let _ = tx.take().unwrap().send(val.map_err(|e| e.error));\n            }\n        }\n    }\n}\n\nimpl<T> TrySendError<T> {\n    /// Take the message from this error.\n    ///\n    /// The message will not always have been recovered. If an error occurs\n    /// after the message has been serialized onto the connection, it will not\n    /// be available here.\n    pub fn take_message(&mut self) -> Option<T> {\n        self.message.take()\n    }\n\n    /// Returns a reference to the recovered message.\n    ///\n    /// The message will not always have been recovered. If an error occurs\n    /// after the message has been serialized onto the connection, it will not\n    /// be available here.\n    pub fn message(&self) -> Option<&T> {\n        self.message.as_ref()\n    }\n\n    /// Consumes this to return the inner error.\n    pub fn into_error(self) -> crate::Error {\n        self.error\n    }\n\n    /// Returns a reference to the inner error.\n    pub fn error(&self) -> &crate::Error {\n        &self.error\n    }\n}\n\n#[cfg(feature = \"http2\")]\npin_project! {\n    pub struct SendWhen<B, E>\n    where\n        B: Body,\n        B: 'static,\n    {\n        #[pin]\n        pub(crate) when: ResponseFutMap<B, E>,\n        #[pin]\n        pub(crate) call_back: Option<Callback<Request<B>, Response<Incoming>>>,\n    }\n}\n\n#[cfg(feature = \"http2\")]\nimpl<B, E> Future for SendWhen<B, E>\nwhere\n    B: Body + 'static,\n    E: crate::rt::bounds::Http2UpgradedExec<B::Data>,\n{\n    type Output = ();\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let mut this = self.project();\n\n        let mut call_back = this.call_back.take().expect(\"polled after complete\");\n\n        match Pin::new(&mut this.when).poll(cx) {\n            Poll::Ready(Ok(res)) => {\n                call_back.send(Ok(res));\n                Poll::Ready(())\n            }\n            Poll::Pending => {\n                // check if the callback is canceled\n                match call_back.poll_canceled(cx) {\n                    Poll::Ready(v) => v,\n                    Poll::Pending => {\n                        // Move call_back back to struct before return\n                        this.call_back.set(Some(call_back));\n                        return Poll::Pending;\n                    }\n                };\n                trace!(\"send_when canceled\");\n                Poll::Ready(())\n            }\n            Poll::Ready(Err((error, message))) => {\n                call_back.send(Err(TrySendError { error, message }));\n                Poll::Ready(())\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    #[cfg(feature = \"nightly\")]\n    extern crate test;\n\n    use std::future::Future;\n    use std::pin::Pin;\n    use std::task::{Context, Poll};\n\n    use super::{channel, Callback, Receiver};\n\n    #[derive(Debug)]\n    struct Custom(#[allow(dead_code)] i32);\n\n    impl<T, U> Future for Receiver<T, U> {\n        type Output = Option<(T, Callback<T, U>)>;\n\n        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n            self.poll_recv(cx)\n        }\n    }\n\n    /// Helper to check if the future is ready after polling once.\n    struct PollOnce<'a, F>(&'a mut F);\n\n    impl<F, T> Future for PollOnce<'_, F>\n    where\n        F: Future<Output = T> + Unpin,\n    {\n        type Output = Option<()>;\n\n        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n            match Pin::new(&mut self.0).poll(cx) {\n                Poll::Ready(_) => Poll::Ready(Some(())),\n                Poll::Pending => Poll::Ready(None),\n            }\n        }\n    }\n\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn drop_receiver_sends_cancel_errors() {\n        let _ = pretty_env_logger::try_init();\n\n        let (mut tx, mut rx) = channel::<Custom, ()>();\n\n        // must poll once for try_send to succeed\n        assert!(PollOnce(&mut rx).await.is_none(), \"rx empty\");\n\n        let promise = tx.try_send(Custom(43)).unwrap();\n        drop(rx);\n\n        let fulfilled = promise.await;\n        let err = fulfilled\n            .expect(\"fulfilled\")\n            .expect_err(\"promise should error\");\n        match (err.error.is_canceled(), err.message) {\n            (true, Some(_)) => (),\n            e => panic!(\"expected Error::Cancel(_), found {:?}\", e),\n        }\n    }\n\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn sender_checks_for_want_on_send() {\n        let (mut tx, mut rx) = channel::<Custom, ()>();\n\n        // one is allowed to buffer, second is rejected\n        let _ = tx.try_send(Custom(1)).expect(\"1 buffered\");\n        tx.try_send(Custom(2)).expect_err(\"2 not ready\");\n\n        assert!(PollOnce(&mut rx).await.is_some(), \"rx once\");\n\n        // Even though 1 has been popped, only 1 could be buffered for the\n        // lifetime of the channel.\n        tx.try_send(Custom(2)).expect_err(\"2 still not ready\");\n\n        assert!(PollOnce(&mut rx).await.is_none(), \"rx empty\");\n\n        let _ = tx.try_send(Custom(2)).expect(\"2 ready\");\n    }\n\n    #[cfg(feature = \"http2\")]\n    #[test]\n    fn unbounded_sender_doesnt_bound_on_want() {\n        let (tx, rx) = channel::<Custom, ()>();\n        let mut tx = tx.unbound();\n\n        let _ = tx.try_send(Custom(1)).unwrap();\n        let _ = tx.try_send(Custom(2)).unwrap();\n        let _ = tx.try_send(Custom(3)).unwrap();\n\n        drop(rx);\n\n        let _ = tx.try_send(Custom(4)).unwrap_err();\n    }\n\n    #[cfg(feature = \"nightly\")]\n    #[bench]\n    fn giver_queue_throughput(b: &mut test::Bencher) {\n        use crate::{body::Incoming, Request, Response};\n\n        let rt = tokio::runtime::Builder::new_current_thread()\n            .build()\n            .unwrap();\n        let (mut tx, mut rx) = channel::<Request<Incoming>, Response<Incoming>>();\n\n        b.iter(move || {\n            let _ = tx.send(Request::new(Incoming::empty())).unwrap();\n            rt.block_on(async {\n                loop {\n                    let poll_once = PollOnce(&mut rx);\n                    let opt = poll_once.await;\n                    if opt.is_none() {\n                        break;\n                    }\n                }\n            });\n        })\n    }\n\n    #[cfg(feature = \"nightly\")]\n    #[bench]\n    fn giver_queue_not_ready(b: &mut test::Bencher) {\n        let rt = tokio::runtime::Builder::new_current_thread()\n            .build()\n            .unwrap();\n        let (_tx, mut rx) = channel::<i32, ()>();\n        b.iter(move || {\n            rt.block_on(async {\n                let poll_once = PollOnce(&mut rx);\n                assert!(poll_once.await.is_none());\n            });\n        })\n    }\n\n    #[cfg(feature = \"nightly\")]\n    #[bench]\n    fn giver_queue_cancel(b: &mut test::Bencher) {\n        let (_tx, mut rx) = channel::<i32, ()>();\n\n        b.iter(move || {\n            rx.taker.cancel();\n        })\n    }\n}\n"
  },
  {
    "path": "src/client/mod.rs",
    "content": "//! HTTP Client\n//!\n//! hyper provides HTTP over a single connection. See the [`conn`] module.\n//!\n//! ## Examples\n//!\n//! * [`client`] - A simple CLI http client that requests the url passed in parameters and outputs the response content and details to the stdout, reading content chunk-by-chunk.\n//!\n//! * [`client_json`] - A simple program that GETs some json, reads the body asynchronously, parses it with serde and outputs the result.\n//!\n//! [`client`]: https://github.com/hyperium/hyper/blob/master/examples/client.rs\n//! [`client_json`]: https://github.com/hyperium/hyper/blob/master/examples/client_json.rs\n\n#[cfg(test)]\nmod tests;\n\ncfg_feature! {\n    #![any(feature = \"http1\", feature = \"http2\")]\n\n    pub mod conn;\n    pub(super) mod dispatch;\n}\n"
  },
  {
    "path": "src/client/tests.rs",
    "content": "/*\n// FIXME: re-implement tests with `async/await`\n#[test]\nfn retryable_request() {\n    let _ = pretty_env_logger::try_init();\n\n    let mut rt = Runtime::new().expect(\"new rt\");\n    let mut connector = MockConnector::new();\n\n    let sock1 = connector.mock(\"http://mock.local\");\n    let sock2 = connector.mock(\"http://mock.local\");\n\n    let client = Client::builder()\n        .build::<_, crate::Body>(connector);\n\n    client.pool.no_timer();\n\n    {\n\n        let req = Request::builder()\n            .uri(\"http://mock.local/a\")\n            .body(Default::default())\n            .unwrap();\n        let res1 = client.request(req);\n        let srv1 = poll_fn(|| {\n            try_ready!(sock1.read(&mut [0u8; 512]));\n            try_ready!(sock1.write(b\"HTTP/1.1 200 OK\\r\\nContent-Length: 0\\r\\n\\r\\n\"));\n            Ok(Async::Ready(()))\n        }).map_err(|e: std::io::Error| panic!(\"srv1 poll_fn error: {}\", e));\n        rt.block_on(res1.join(srv1)).expect(\"res1\");\n    }\n    drop(sock1);\n\n    let req = Request::builder()\n        .uri(\"http://mock.local/b\")\n        .body(Default::default())\n        .unwrap();\n    let res2 = client.request(req)\n        .map(|res| {\n            assert_eq!(res.status().as_u16(), 222);\n        });\n    let srv2 = poll_fn(|| {\n        try_ready!(sock2.read(&mut [0u8; 512]));\n        try_ready!(sock2.write(b\"HTTP/1.1 222 OK\\r\\nContent-Length: 0\\r\\n\\r\\n\"));\n        Ok(Async::Ready(()))\n    }).map_err(|e: std::io::Error| panic!(\"srv2 poll_fn error: {}\", e));\n\n    rt.block_on(res2.join(srv2)).expect(\"res2\");\n}\n\n#[test]\nfn conn_reset_after_write() {\n    let _ = pretty_env_logger::try_init();\n\n    let mut rt = Runtime::new().expect(\"new rt\");\n    let mut connector = MockConnector::new();\n\n    let sock1 = connector.mock(\"http://mock.local\");\n\n    let client = Client::builder()\n        .build::<_, crate::Body>(connector);\n\n    client.pool.no_timer();\n\n    {\n        let req = Request::builder()\n            .uri(\"http://mock.local/a\")\n            .body(Default::default())\n            .unwrap();\n        let res1 = client.request(req);\n        let srv1 = poll_fn(|| {\n            try_ready!(sock1.read(&mut [0u8; 512]));\n            try_ready!(sock1.write(b\"HTTP/1.1 200 OK\\r\\nContent-Length: 0\\r\\n\\r\\n\"));\n            Ok(Async::Ready(()))\n        }).map_err(|e: std::io::Error| panic!(\"srv1 poll_fn error: {}\", e));\n        rt.block_on(res1.join(srv1)).expect(\"res1\");\n    }\n\n    let req = Request::builder()\n        .uri(\"http://mock.local/a\")\n        .body(Default::default())\n        .unwrap();\n    let res2 = client.request(req);\n    let mut sock1 = Some(sock1);\n    let srv2 = poll_fn(|| {\n        // We purposefully keep the socket open until the client\n        // has written the second request, and THEN disconnect.\n        //\n        // Not because we expect servers to be jerks, but to trigger\n        // state where we write on an assumedly good connection, and\n        // only reset the close AFTER we wrote bytes.\n        try_ready!(sock1.as_mut().unwrap().read(&mut [0u8; 512]));\n        sock1.take();\n        Ok(Async::Ready(()))\n    }).map_err(|e: std::io::Error| panic!(\"srv2 poll_fn error: {}\", e));\n    let err = rt.block_on(res2.join(srv2)).expect_err(\"res2\");\n    assert!(err.is_incomplete_message(), \"{:?}\", err);\n}\n\n#[test]\nfn checkout_win_allows_connect_future_to_be_pooled() {\n    let _ = pretty_env_logger::try_init();\n\n    let mut rt = Runtime::new().expect(\"new rt\");\n    let mut connector = MockConnector::new();\n\n\n    let (tx, rx) = oneshot::channel::<()>();\n    let sock1 = connector.mock(\"http://mock.local\");\n    let sock2 = connector.mock_fut(\"http://mock.local\", rx);\n\n    let client = Client::builder()\n        .build::<_, crate::Body>(connector);\n\n    client.pool.no_timer();\n\n    let uri = \"http://mock.local/a\".parse::<crate::Uri>().expect(\"uri parse\");\n\n    // First request just sets us up to have a connection able to be put\n    // back in the pool. *However*, it doesn't insert immediately. The\n    // body has 1 pending byte, and we will only drain in request 2, once\n    // the connect future has been started.\n    let mut body = {\n        let res1 = client.get(uri.clone())\n            .map(|res| res.into_body().concat2());\n        let srv1 = poll_fn(|| {\n            try_ready!(sock1.read(&mut [0u8; 512]));\n            // Chunked is used so as to force 2 body reads.\n            try_ready!(sock1.write(b\"\\\n                HTTP/1.1 200 OK\\r\\n\\\n                transfer-encoding: chunked\\r\\n\\\n                \\r\\n\\\n                1\\r\\nx\\r\\n\\\n                0\\r\\n\\r\\n\\\n            \"));\n            Ok(Async::Ready(()))\n        }).map_err(|e: std::io::Error| panic!(\"srv1 poll_fn error: {}\", e));\n\n        rt.block_on(res1.join(srv1)).expect(\"res1\").0\n    };\n\n\n    // The second request triggers the only mocked connect future, but then\n    // the drained body allows the first socket to go back to the pool,\n    // \"winning\" the checkout race.\n    {\n        let res2 = client.get(uri.clone());\n        let drain = poll_fn(move || {\n            body.poll()\n        });\n        let srv2 = poll_fn(|| {\n            try_ready!(sock1.read(&mut [0u8; 512]));\n            try_ready!(sock1.write(b\"HTTP/1.1 200 OK\\r\\nConnection: close\\r\\n\\r\\nx\"));\n            Ok(Async::Ready(()))\n        }).map_err(|e: std::io::Error| panic!(\"srv2 poll_fn error: {}\", e));\n\n        rt.block_on(res2.join(drain).join(srv2)).expect(\"res2\");\n    }\n\n    // \"Release\" the mocked connect future, and let the runtime spin once so\n    // it's all setup...\n    {\n        let mut tx = Some(tx);\n        let client = &client;\n        let key = client.pool.h1_key(\"http://mock.local\");\n        let mut tick_cnt = 0;\n        let fut = poll_fn(move || {\n            tx.take();\n\n            if client.pool.idle_count(&key) == 0 {\n                tick_cnt += 1;\n                assert!(tick_cnt < 10, \"ticked too many times waiting for idle\");\n                trace!(\"no idle yet; tick count: {}\", tick_cnt);\n                ::futures::task::current().notify();\n                Ok(Async::NotReady)\n            } else {\n                Ok::<_, ()>(Async::Ready(()))\n            }\n        });\n        rt.block_on(fut).unwrap();\n    }\n\n    // Third request just tests out that the \"loser\" connection was pooled. If\n    // it isn't, this will panic since the MockConnector doesn't have any more\n    // mocks to give out.\n    {\n        let res3 = client.get(uri);\n        let srv3 = poll_fn(|| {\n            try_ready!(sock2.read(&mut [0u8; 512]));\n            try_ready!(sock2.write(b\"HTTP/1.1 200 OK\\r\\nContent-Length: 0\\r\\n\\r\\n\"));\n            Ok(Async::Ready(()))\n        }).map_err(|e: std::io::Error| panic!(\"srv3 poll_fn error: {}\", e));\n\n        rt.block_on(res3.join(srv3)).expect(\"res3\");\n    }\n}\n\n#[cfg(feature = \"nightly\")]\n#[bench]\nfn bench_http1_get_0b(b: &mut test::Bencher) {\n    let _ = pretty_env_logger::try_init();\n\n    let mut rt = Runtime::new().expect(\"new rt\");\n    let mut connector = MockConnector::new();\n\n\n    let client = Client::builder()\n        .build::<_, crate::Body>(connector.clone());\n\n    client.pool.no_timer();\n\n    let uri = Uri::from_static(\"http://mock.local/a\");\n\n    b.iter(move || {\n        let sock1 = connector.mock(\"http://mock.local\");\n        let res1 = client\n            .get(uri.clone())\n            .and_then(|res| {\n                res.into_body().for_each(|_| Ok(()))\n            });\n        let srv1 = poll_fn(|| {\n            try_ready!(sock1.read(&mut [0u8; 512]));\n            try_ready!(sock1.write(b\"HTTP/1.1 200 OK\\r\\nContent-Length: 0\\r\\n\\r\\n\"));\n            Ok(Async::Ready(()))\n        }).map_err(|e: std::io::Error| panic!(\"srv1 poll_fn error: {}\", e));\n        rt.block_on(res1.join(srv1)).expect(\"res1\");\n    });\n}\n\n#[cfg(feature = \"nightly\")]\n#[bench]\nfn bench_http1_get_10b(b: &mut test::Bencher) {\n    let _ = pretty_env_logger::try_init();\n\n    let mut rt = Runtime::new().expect(\"new rt\");\n    let mut connector = MockConnector::new();\n\n\n    let client = Client::builder()\n        .build::<_, crate::Body>(connector.clone());\n\n    client.pool.no_timer();\n\n    let uri = Uri::from_static(\"http://mock.local/a\");\n\n    b.iter(move || {\n        let sock1 = connector.mock(\"http://mock.local\");\n        let res1 = client\n            .get(uri.clone())\n            .and_then(|res| {\n                res.into_body().for_each(|_| Ok(()))\n            });\n        let srv1 = poll_fn(|| {\n            try_ready!(sock1.read(&mut [0u8; 512]));\n            try_ready!(sock1.write(b\"HTTP/1.1 200 OK\\r\\nContent-Length: 10\\r\\n\\r\\n0123456789\"));\n            Ok(Async::Ready(()))\n        }).map_err(|e: std::io::Error| panic!(\"srv1 poll_fn error: {}\", e));\n        rt.block_on(res1.join(srv1)).expect(\"res1\");\n    });\n}\n*/\n"
  },
  {
    "path": "src/common/buf.rs",
    "content": "use std::collections::VecDeque;\nuse std::io::IoSlice;\n\nuse bytes::{Buf, BufMut, Bytes, BytesMut};\n\npub(crate) struct BufList<T> {\n    bufs: VecDeque<T>,\n}\n\nimpl<T: Buf> BufList<T> {\n    pub(crate) fn new() -> BufList<T> {\n        BufList {\n            bufs: VecDeque::new(),\n        }\n    }\n\n    #[inline]\n    pub(crate) fn push(&mut self, buf: T) {\n        debug_assert!(buf.has_remaining());\n        self.bufs.push_back(buf);\n    }\n\n    #[inline]\n    pub(crate) fn bufs_cnt(&self) -> usize {\n        self.bufs.len()\n    }\n}\n\nimpl<T: Buf> Buf for BufList<T> {\n    #[inline]\n    fn remaining(&self) -> usize {\n        self.bufs.iter().map(|buf| buf.remaining()).sum()\n    }\n\n    #[inline]\n    fn chunk(&self) -> &[u8] {\n        self.bufs.front().map(Buf::chunk).unwrap_or_default()\n    }\n\n    #[inline]\n    fn advance(&mut self, mut cnt: usize) {\n        while cnt > 0 {\n            {\n                let front = &mut self.bufs[0];\n                let rem = front.remaining();\n                if rem > cnt {\n                    front.advance(cnt);\n                    return;\n                } else {\n                    front.advance(rem);\n                    cnt -= rem;\n                }\n            }\n            self.bufs.pop_front();\n        }\n    }\n\n    #[inline]\n    fn chunks_vectored<'t>(&'t self, dst: &mut [IoSlice<'t>]) -> usize {\n        if dst.is_empty() {\n            return 0;\n        }\n        let mut vecs = 0;\n        for buf in &self.bufs {\n            vecs += buf.chunks_vectored(&mut dst[vecs..]);\n            if vecs == dst.len() {\n                break;\n            }\n        }\n        vecs\n    }\n\n    #[inline]\n    fn copy_to_bytes(&mut self, len: usize) -> Bytes {\n        // Our inner buffer may have an optimized version of copy_to_bytes, and if the whole\n        // request can be fulfilled by the front buffer, we can take advantage.\n        match self.bufs.front_mut() {\n            Some(front) if front.remaining() == len => {\n                let b = front.copy_to_bytes(len);\n                self.bufs.pop_front();\n                b\n            }\n            Some(front) if front.remaining() > len => front.copy_to_bytes(len),\n            _ => {\n                assert!(len <= self.remaining(), \"`len` greater than remaining\");\n                let mut bm = BytesMut::with_capacity(len);\n                bm.put(self.take(len));\n                bm.freeze()\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use std::ptr;\n\n    use super::*;\n\n    fn hello_world_buf() -> BufList<Bytes> {\n        BufList {\n            bufs: vec![Bytes::from(\"Hello\"), Bytes::from(\" \"), Bytes::from(\"World\")].into(),\n        }\n    }\n\n    #[test]\n    fn to_bytes_shorter() {\n        let mut bufs = hello_world_buf();\n        let old_ptr = bufs.chunk().as_ptr();\n        let start = bufs.copy_to_bytes(4);\n        assert_eq!(start, \"Hell\");\n        assert!(ptr::eq(old_ptr, start.as_ptr()));\n        assert_eq!(bufs.chunk(), b\"o\");\n        assert!(ptr::eq(old_ptr.wrapping_add(4), bufs.chunk().as_ptr()));\n        assert_eq!(bufs.remaining(), 7);\n    }\n\n    #[test]\n    fn to_bytes_eq() {\n        let mut bufs = hello_world_buf();\n        let old_ptr = bufs.chunk().as_ptr();\n        let start = bufs.copy_to_bytes(5);\n        assert_eq!(start, \"Hello\");\n        assert!(ptr::eq(old_ptr, start.as_ptr()));\n        assert_eq!(bufs.chunk(), b\" \");\n        assert_eq!(bufs.remaining(), 6);\n    }\n\n    #[test]\n    fn to_bytes_longer() {\n        let mut bufs = hello_world_buf();\n        let start = bufs.copy_to_bytes(7);\n        assert_eq!(start, \"Hello W\");\n        assert_eq!(bufs.remaining(), 4);\n    }\n\n    #[test]\n    fn one_long_buf_to_bytes() {\n        let mut buf = BufList::new();\n        buf.push(b\"Hello World\" as &[_]);\n        assert_eq!(buf.copy_to_bytes(5), \"Hello\");\n        assert_eq!(buf.chunk(), b\" World\");\n    }\n\n    #[test]\n    #[should_panic(expected = \"`len` greater than remaining\")]\n    fn buf_to_bytes_too_many() {\n        hello_world_buf().copy_to_bytes(42);\n    }\n}\n"
  },
  {
    "path": "src/common/date.rs",
    "content": "use std::cell::RefCell;\nuse std::fmt::{self, Write};\nuse std::str;\nuse std::time::{Duration, SystemTime, UNIX_EPOCH};\n\n#[cfg(feature = \"http2\")]\nuse http::header::HeaderValue;\nuse httpdate::HttpDate;\n\n// \"Sun, 06 Nov 1994 08:49:37 GMT\".len()\npub(crate) const DATE_VALUE_LENGTH: usize = 29;\n\n#[cfg(feature = \"http1\")]\npub(crate) fn extend(dst: &mut Vec<u8>) {\n    CACHED.with(|cache| {\n        dst.extend_from_slice(cache.borrow().buffer());\n    })\n}\n\n#[cfg(feature = \"http1\")]\npub(crate) fn update() {\n    CACHED.with(|cache| {\n        cache.borrow_mut().check();\n    })\n}\n\n#[cfg(feature = \"http2\")]\npub(crate) fn update_and_header_value() -> HeaderValue {\n    CACHED.with(|cache| {\n        let mut cache = cache.borrow_mut();\n        cache.check();\n        cache.header_value.clone()\n    })\n}\n\nstruct CachedDate {\n    bytes: [u8; DATE_VALUE_LENGTH],\n    pos: usize,\n    #[cfg(feature = \"http2\")]\n    header_value: HeaderValue,\n    next_update: SystemTime,\n}\n\nthread_local!(static CACHED: RefCell<CachedDate> = RefCell::new(CachedDate::new()));\n\nimpl CachedDate {\n    fn new() -> Self {\n        let mut cache = CachedDate {\n            bytes: [0; DATE_VALUE_LENGTH],\n            pos: 0,\n            #[cfg(feature = \"http2\")]\n            header_value: HeaderValue::from_static(\"\"),\n            next_update: SystemTime::now(),\n        };\n        cache.update(cache.next_update);\n        cache\n    }\n\n    fn buffer(&self) -> &[u8] {\n        &self.bytes[..]\n    }\n\n    fn check(&mut self) {\n        let now = SystemTime::now();\n        if now > self.next_update {\n            self.update(now);\n        }\n    }\n\n    fn update(&mut self, now: SystemTime) {\n        let nanos = now\n            .duration_since(UNIX_EPOCH)\n            .unwrap_or_default()\n            .subsec_nanos();\n\n        self.render(now);\n        self.next_update = now + Duration::new(1, 0) - Duration::from_nanos(nanos as u64);\n    }\n\n    fn render(&mut self, now: SystemTime) {\n        self.pos = 0;\n        let _ = write!(self, \"{}\", HttpDate::from(now));\n        debug_assert!(self.pos == DATE_VALUE_LENGTH);\n        self.render_http2();\n    }\n\n    #[cfg(feature = \"http2\")]\n    fn render_http2(&mut self) {\n        self.header_value = HeaderValue::from_bytes(self.buffer())\n            .expect(\"Date format should be valid HeaderValue\");\n    }\n\n    #[cfg(not(feature = \"http2\"))]\n    fn render_http2(&mut self) {}\n}\n\nimpl fmt::Write for CachedDate {\n    fn write_str(&mut self, s: &str) -> fmt::Result {\n        let len = s.len();\n        self.bytes[self.pos..self.pos + len].copy_from_slice(s.as_bytes());\n        self.pos += len;\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[cfg(feature = \"nightly\")]\n    use test::Bencher;\n\n    #[test]\n    fn test_date_len() {\n        assert_eq!(DATE_VALUE_LENGTH, \"Sun, 06 Nov 1994 08:49:37 GMT\".len());\n    }\n\n    #[cfg(feature = \"nightly\")]\n    #[bench]\n    fn bench_date_check(b: &mut Bencher) {\n        let mut date = CachedDate::new();\n        // cache the first update\n        date.check();\n\n        b.iter(|| {\n            date.check();\n        });\n    }\n\n    #[cfg(feature = \"nightly\")]\n    #[bench]\n    fn bench_date_render(b: &mut Bencher) {\n        let mut date = CachedDate::new();\n        let now = SystemTime::now();\n        date.render(now);\n        b.bytes = date.buffer().len() as u64;\n\n        b.iter(|| {\n            date.render(now);\n            test::black_box(&date);\n        });\n    }\n}\n"
  },
  {
    "path": "src/common/either.rs",
    "content": "use pin_project_lite::pin_project;\nuse std::{\n    future::Future,\n    pin::Pin,\n    task::{Context, Poll},\n};\n\npin_project! {\n    /// One of two possible futures that have the same output type.\n    #[project = EitherProj]\n    pub(crate) enum Either<F1, F2> {\n        Left {\n            #[pin]\n            fut: F1\n        },\n        Right {\n            #[pin]\n            fut: F2,\n        },\n    }\n}\n\nimpl<F1, F2> Either<F1, F2> {\n    pub(crate) fn left(fut: F1) -> Self {\n        Either::Left { fut }\n    }\n\n    pub(crate) fn right(fut: F2) -> Self {\n        Either::Right { fut }\n    }\n}\n\nimpl<F1, F2> Future for Either<F1, F2>\nwhere\n    F1: Future,\n    F2: Future<Output = F1::Output>,\n{\n    type Output = F1::Output;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        match self.project() {\n            EitherProj::Left { fut } => fut.poll(cx),\n            EitherProj::Right { fut } => fut.poll(cx),\n        }\n    }\n}\n"
  },
  {
    "path": "src/common/future.rs",
    "content": "use std::{\n    future::Future,\n    pin::Pin,\n    task::{Context, Poll},\n};\n\n// TODO: replace with `std::future::poll_fn` once MSRV >= 1.64\npub(crate) fn poll_fn<T, F>(f: F) -> PollFn<F>\nwhere\n    F: FnMut(&mut Context<'_>) -> Poll<T>,\n{\n    PollFn { f }\n}\n\npub(crate) struct PollFn<F> {\n    f: F,\n}\n\nimpl<F> Unpin for PollFn<F> {}\n\nimpl<T, F> Future for PollFn<F>\nwhere\n    F: FnMut(&mut Context<'_>) -> Poll<T>,\n{\n    type Output = T;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        (self.as_mut().f)(cx)\n    }\n}\n"
  },
  {
    "path": "src/common/io/compat.rs",
    "content": "use std::pin::Pin;\nuse std::task::{Context, Poll};\n\n/// This adapts from `hyper` IO traits to the ones in Tokio.\n///\n/// This is currently used by `h2`, and by hyper internal unit tests.\n#[derive(Debug)]\npub(crate) struct Compat<T>(pub(crate) T);\n\nimpl<T> Compat<T> {\n    pub(crate) fn new(io: T) -> Self {\n        Compat(io)\n    }\n\n    fn p(self: Pin<&mut Self>) -> Pin<&mut T> {\n        // SAFETY: The simplest of projections. This is just\n        // a wrapper, we don't do anything that would undo the projection.\n        unsafe { self.map_unchecked_mut(|me| &mut me.0) }\n    }\n}\n\nimpl<T> tokio::io::AsyncRead for Compat<T>\nwhere\n    T: crate::rt::Read,\n{\n    fn poll_read(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        tbuf: &mut tokio::io::ReadBuf<'_>,\n    ) -> Poll<Result<(), std::io::Error>> {\n        let init = tbuf.initialized().len();\n        let filled = tbuf.filled().len();\n        let (new_init, new_filled) = unsafe {\n            let mut buf = crate::rt::ReadBuf::uninit(tbuf.inner_mut());\n            buf.set_init(init);\n            buf.set_filled(filled);\n\n            match crate::rt::Read::poll_read(self.p(), cx, buf.unfilled()) {\n                Poll::Ready(Ok(())) => (buf.init_len(), buf.len()),\n                other => return other,\n            }\n        };\n\n        let n_init = new_init - init;\n        unsafe {\n            tbuf.assume_init(n_init);\n            tbuf.set_filled(new_filled);\n        }\n\n        Poll::Ready(Ok(()))\n    }\n}\n\nimpl<T> tokio::io::AsyncWrite for Compat<T>\nwhere\n    T: crate::rt::Write,\n{\n    fn poll_write(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<Result<usize, std::io::Error>> {\n        crate::rt::Write::poll_write(self.p(), cx, buf)\n    }\n\n    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>> {\n        crate::rt::Write::poll_flush(self.p(), cx)\n    }\n\n    fn poll_shutdown(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Result<(), std::io::Error>> {\n        crate::rt::Write::poll_shutdown(self.p(), cx)\n    }\n\n    fn is_write_vectored(&self) -> bool {\n        crate::rt::Write::is_write_vectored(&self.0)\n    }\n\n    fn poll_write_vectored(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        bufs: &[std::io::IoSlice<'_>],\n    ) -> Poll<Result<usize, std::io::Error>> {\n        crate::rt::Write::poll_write_vectored(self.p(), cx, bufs)\n    }\n}\n\n#[cfg(test)]\nimpl<T> crate::rt::Read for Compat<T>\nwhere\n    T: tokio::io::AsyncRead,\n{\n    fn poll_read(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        mut buf: crate::rt::ReadBufCursor<'_>,\n    ) -> Poll<Result<(), std::io::Error>> {\n        let n = unsafe {\n            let mut tbuf = tokio::io::ReadBuf::uninit(buf.as_mut());\n            match tokio::io::AsyncRead::poll_read(self.p(), cx, &mut tbuf) {\n                Poll::Ready(Ok(())) => tbuf.filled().len(),\n                other => return other,\n            }\n        };\n\n        unsafe {\n            buf.advance(n);\n        }\n        Poll::Ready(Ok(()))\n    }\n}\n\n#[cfg(test)]\nimpl<T> crate::rt::Write for Compat<T>\nwhere\n    T: tokio::io::AsyncWrite,\n{\n    fn poll_write(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<Result<usize, std::io::Error>> {\n        tokio::io::AsyncWrite::poll_write(self.p(), cx, buf)\n    }\n\n    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>> {\n        tokio::io::AsyncWrite::poll_flush(self.p(), cx)\n    }\n\n    fn poll_shutdown(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Result<(), std::io::Error>> {\n        tokio::io::AsyncWrite::poll_shutdown(self.p(), cx)\n    }\n\n    fn is_write_vectored(&self) -> bool {\n        tokio::io::AsyncWrite::is_write_vectored(&self.0)\n    }\n\n    fn poll_write_vectored(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        bufs: &[std::io::IoSlice<'_>],\n    ) -> Poll<Result<usize, std::io::Error>> {\n        tokio::io::AsyncWrite::poll_write_vectored(self.p(), cx, bufs)\n    }\n}\n"
  },
  {
    "path": "src/common/io/mod.rs",
    "content": "#[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http2\"))]\nmod compat;\nmod rewind;\n\n#[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http2\"))]\npub(crate) use self::compat::Compat;\npub(crate) use self::rewind::Rewind;\n"
  },
  {
    "path": "src/common/io/rewind.rs",
    "content": "use std::pin::Pin;\nuse std::task::{Context, Poll};\nuse std::{cmp, io};\n\nuse bytes::{Buf, Bytes};\n\nuse crate::rt::{Read, ReadBufCursor, Write};\n\n/// Combine a buffer with an IO, rewinding reads to use the buffer.\n#[derive(Debug)]\npub(crate) struct Rewind<T> {\n    pre: Option<Bytes>,\n    inner: T,\n}\n\nimpl<T> Rewind<T> {\n    #[cfg(all(\n        test,\n        any(feature = \"client\", feature = \"server\"),\n        any(feature = \"http1\", feature = \"http2\")\n    ))]\n    pub(crate) fn new(io: T) -> Self {\n        Rewind {\n            pre: None,\n            inner: io,\n        }\n    }\n\n    pub(crate) fn new_buffered(io: T, buf: Bytes) -> Self {\n        Rewind {\n            pre: Some(buf),\n            inner: io,\n        }\n    }\n\n    #[cfg(all(\n        test,\n        any(feature = \"client\", feature = \"server\"),\n        any(feature = \"http1\", feature = \"http2\")\n    ))]\n    pub(crate) fn rewind(&mut self, bs: Bytes) {\n        debug_assert!(self.pre.is_none());\n        self.pre = Some(bs);\n    }\n\n    pub(crate) fn into_inner(self) -> (T, Bytes) {\n        (self.inner, self.pre.unwrap_or_default())\n    }\n\n    // pub(crate) fn get_mut(&mut self) -> &mut T {\n    //     &mut self.inner\n    // }\n}\n\nimpl<T> Read for Rewind<T>\nwhere\n    T: Read + Unpin,\n{\n    fn poll_read(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        mut buf: ReadBufCursor<'_>,\n    ) -> Poll<io::Result<()>> {\n        if let Some(mut prefix) = self.pre.take() {\n            // If there are no remaining bytes, let the bytes get dropped.\n            if !prefix.is_empty() {\n                let copy_len = cmp::min(prefix.len(), buf.remaining());\n                // TODO: There should be a way to do following two lines cleaner...\n                buf.put_slice(&prefix[..copy_len]);\n                prefix.advance(copy_len);\n                // Put back what's left\n                if !prefix.is_empty() {\n                    self.pre = Some(prefix);\n                }\n\n                return Poll::Ready(Ok(()));\n            }\n        }\n        Pin::new(&mut self.inner).poll_read(cx, buf)\n    }\n}\n\nimpl<T> Write for Rewind<T>\nwhere\n    T: Write + Unpin,\n{\n    fn poll_write(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<io::Result<usize>> {\n        Pin::new(&mut self.inner).poll_write(cx, buf)\n    }\n\n    fn poll_write_vectored(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        bufs: &[io::IoSlice<'_>],\n    ) -> Poll<io::Result<usize>> {\n        Pin::new(&mut self.inner).poll_write_vectored(cx, bufs)\n    }\n\n    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        Pin::new(&mut self.inner).poll_flush(cx)\n    }\n\n    fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        Pin::new(&mut self.inner).poll_shutdown(cx)\n    }\n\n    fn is_write_vectored(&self) -> bool {\n        self.inner.is_write_vectored()\n    }\n}\n\n#[cfg(all(\n    any(feature = \"client\", feature = \"server\"),\n    any(feature = \"http1\", feature = \"http2\"),\n))]\n#[cfg(test)]\nmod tests {\n    use super::super::Compat;\n    use super::Rewind;\n    use bytes::Bytes;\n    use tokio::io::AsyncReadExt;\n\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn partial_rewind() {\n        let underlying = [104, 101, 108, 108, 111];\n\n        let mock = tokio_test::io::Builder::new().read(&underlying).build();\n\n        let mut stream = Compat::new(Rewind::new(Compat::new(mock)));\n\n        // Read off some bytes, ensure we filled o1\n        let mut buf = [0; 2];\n        stream.read_exact(&mut buf).await.expect(\"read1\");\n\n        // Rewind the stream so that it is as if we never read in the first place.\n        stream.0.rewind(Bytes::copy_from_slice(&buf[..]));\n\n        let mut buf = [0; 5];\n        stream.read_exact(&mut buf).await.expect(\"read1\");\n\n        // At this point we should have read everything that was in the MockStream\n        assert_eq!(&buf, &underlying);\n    }\n\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn full_rewind() {\n        let underlying = [104, 101, 108, 108, 111];\n\n        let mock = tokio_test::io::Builder::new().read(&underlying).build();\n\n        let mut stream = Compat::new(Rewind::new(Compat::new(mock)));\n\n        let mut buf = [0; 5];\n        stream.read_exact(&mut buf).await.expect(\"read1\");\n\n        // Rewind the stream so that it is as if we never read in the first place.\n        stream.0.rewind(Bytes::copy_from_slice(&buf[..]));\n\n        let mut buf = [0; 5];\n        stream.read_exact(&mut buf).await.expect(\"read1\");\n\n        assert_eq!(&buf, &underlying);\n    }\n}\n"
  },
  {
    "path": "src/common/mod.rs",
    "content": "#[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\npub(crate) mod buf;\n#[cfg(all(feature = \"server\", any(feature = \"http1\", feature = \"http2\")))]\npub(crate) mod date;\n#[cfg(all(feature = \"client\", feature = \"http2\"))]\npub(crate) mod either;\n#[cfg(any(\n    all(feature = \"client\", any(feature = \"http1\", feature = \"http2\")),\n    all(feature = \"server\", feature = \"http1\"),\n))]\npub(crate) mod future;\npub(crate) mod io;\n#[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\npub(crate) mod task;\n#[cfg(any(\n    all(feature = \"server\", feature = \"http1\"),\n    all(any(feature = \"client\", feature = \"server\"), feature = \"http2\"),\n))]\npub(crate) mod time;\n#[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\npub(crate) mod watch;\n"
  },
  {
    "path": "src/common/task.rs",
    "content": "use std::task::{Context, Poll};\n#[cfg(feature = \"client\")]\nuse std::task::{RawWaker, RawWakerVTable, Waker};\n\n/// A function to help \"yield\" a future, such that it is re-scheduled immediately.\n///\n/// Useful for spin counts, so a future doesn't hog too much time.\npub(crate) fn yield_now(cx: &mut Context<'_>) -> Poll<std::convert::Infallible> {\n    cx.waker().wake_by_ref();\n    Poll::Pending\n}\n\n// TODO: replace with `std::task::Waker::noop()` once MSRV >= 1.85\n#[cfg(feature = \"client\")]\nfn noop_waker() -> Waker {\n    const NOOP_RAW_WAKER: RawWaker = RawWaker::new(std::ptr::null(), &NOOP_VTABLE);\n    const NOOP_VTABLE: RawWakerVTable = RawWakerVTable::new(\n        // `clone` returns the same noop waker again\n        |_: *const ()| NOOP_RAW_WAKER,\n        // `wake`, `wake_by_ref`, and `drop` do nothing\n        |_: *const ()| {},\n        |_: *const ()| {},\n        |_: *const ()| {},\n    );\n\n    // SAFETY: all functions in the vtable are safe to call, and Waker's safety does not require\n    // them to actually do anything.\n    unsafe { Waker::from_raw(NOOP_RAW_WAKER) }\n}\n\n/// Poll the future once and return `Some` if it is ready, else `None`.\n///\n/// If the future wasn't ready, it future likely can't be driven to completion any more: the polling\n/// uses a no-op waker, so knowledge of what the pending future was waiting for is lost.\n#[cfg(feature = \"client\")]\npub(crate) fn now_or_never<F: std::future::Future>(fut: F) -> Option<F::Output> {\n    let waker = noop_waker();\n    let mut cx = Context::from_waker(&waker);\n    // TODO: replace with std::pin::pin! once MSRV >= 1.68\n    tokio::pin!(fut);\n    match fut.poll(&mut cx) {\n        Poll::Ready(res) => Some(res),\n        Poll::Pending => None,\n    }\n}\n"
  },
  {
    "path": "src/common/time.rs",
    "content": "#[cfg(any(\n    all(any(feature = \"client\", feature = \"server\"), feature = \"http2\"),\n    all(feature = \"server\", feature = \"http1\"),\n))]\nuse std::time::Duration;\nuse std::{fmt, sync::Arc};\nuse std::{pin::Pin, time::Instant};\n\nuse crate::rt::Sleep;\nuse crate::rt::Timer;\n\n/// A user-provided timer to time background tasks.\n#[derive(Clone)]\npub(crate) enum Time {\n    Timer(Arc<dyn Timer + Send + Sync>),\n    Empty,\n}\n\n#[cfg(all(feature = \"server\", feature = \"http1\"))]\n#[derive(Clone, Copy, Debug)]\npub(crate) enum Dur {\n    Default(Option<Duration>),\n    Configured(Option<Duration>),\n}\n\nimpl fmt::Debug for Time {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Time\").finish()\n    }\n}\n\nimpl Time {\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http2\"))]\n    pub(crate) fn sleep(&self, duration: Duration) -> Pin<Box<dyn Sleep>> {\n        match *self {\n            Time::Empty => {\n                panic!(\"You must supply a timer.\")\n            }\n            Time::Timer(ref t) => t.sleep(duration),\n        }\n    }\n\n    #[cfg(all(feature = \"server\", feature = \"http1\"))]\n    pub(crate) fn sleep_until(&self, deadline: Instant) -> Pin<Box<dyn Sleep>> {\n        match *self {\n            Time::Empty => {\n                panic!(\"You must supply a timer.\")\n            }\n            Time::Timer(ref t) => t.sleep_until(deadline),\n        }\n    }\n\n    pub(crate) fn now(&self) -> Instant {\n        match *self {\n            Time::Empty => Instant::now(),\n            Time::Timer(ref t) => t.now(),\n        }\n    }\n\n    pub(crate) fn reset(&self, sleep: &mut Pin<Box<dyn Sleep>>, new_deadline: Instant) {\n        match *self {\n            Time::Empty => {\n                panic!(\"You must supply a timer.\")\n            }\n            Time::Timer(ref t) => t.reset(sleep, new_deadline),\n        }\n    }\n\n    #[cfg(all(feature = \"server\", feature = \"http1\"))]\n    pub(crate) fn check(&self, dur: Dur, name: &'static str) -> Option<Duration> {\n        match dur {\n            Dur::Default(Some(dur)) => match self {\n                Time::Empty => {\n                    warn!(\"timeout `{}` has default, but no timer set\", name,);\n                    None\n                }\n                Time::Timer(..) => Some(dur),\n            },\n            Dur::Configured(Some(dur)) => match self {\n                Time::Empty => panic!(\"timeout `{}` set, but no timer set\", name,),\n                Time::Timer(..) => Some(dur),\n            },\n            Dur::Default(None) | Dur::Configured(None) => None,\n        }\n    }\n}\n"
  },
  {
    "path": "src/common/watch.rs",
    "content": "//! An SPSC broadcast channel.\n//!\n//! - The value can only be a `usize`.\n//! - The consumer is only notified if the value is different.\n//! - The value `0` is reserved for closed.\n\nuse atomic_waker::AtomicWaker;\nuse std::sync::{\n    atomic::{AtomicUsize, Ordering},\n    Arc,\n};\nuse std::task;\n\ntype Value = usize;\n\npub(crate) const CLOSED: usize = 0;\n\npub(crate) fn channel(initial: Value) -> (Sender, Receiver) {\n    debug_assert!(\n        initial != CLOSED,\n        \"watch::channel initial state of 0 is reserved\"\n    );\n\n    let shared = Arc::new(Shared {\n        value: AtomicUsize::new(initial),\n        waker: AtomicWaker::new(),\n    });\n\n    (\n        Sender {\n            shared: shared.clone(),\n        },\n        Receiver { shared },\n    )\n}\n\npub(crate) struct Sender {\n    shared: Arc<Shared>,\n}\n\npub(crate) struct Receiver {\n    shared: Arc<Shared>,\n}\n\nstruct Shared {\n    value: AtomicUsize,\n    waker: AtomicWaker,\n}\n\nimpl Sender {\n    pub(crate) fn send(&mut self, value: Value) {\n        if self.shared.value.swap(value, Ordering::SeqCst) != value {\n            self.shared.waker.wake();\n        }\n    }\n}\n\nimpl Drop for Sender {\n    fn drop(&mut self) {\n        self.send(CLOSED);\n    }\n}\n\nimpl Receiver {\n    pub(crate) fn load(&mut self, cx: &mut task::Context<'_>) -> Value {\n        self.shared.waker.register(cx.waker());\n        self.shared.value.load(Ordering::SeqCst)\n    }\n\n    pub(crate) fn peek(&self) -> Value {\n        self.shared.value.load(Ordering::Relaxed)\n    }\n}\n"
  },
  {
    "path": "src/error.rs",
    "content": "//! Error and Result module.\nuse std::error::Error as StdError;\nuse std::fmt;\n\n/// Result type often returned from methods that can have hyper `Error`s.\npub type Result<T> = std::result::Result<T, Error>;\n\ntype Cause = Box<dyn StdError + Send + Sync>;\n\n/// Represents errors that can occur handling HTTP streams.\n///\n/// # Formatting\n///\n/// The `Display` implementation of this type will only print the details of\n/// this level of error, even though it may have been caused by another error\n/// and contain that error in its source. To print all the relevant\n/// information, including the source chain, using something like\n/// `std::error::Report`, or equivalent 3rd party types.\n///\n/// The contents of the formatted error message of this specific `Error` type\n/// is unspecified. **You must not depend on it.** The wording and details may\n/// change in any version, with the goal of improving error messages.\n///\n/// # Source\n///\n/// A `hyper::Error` may be caused by another error. To aid in debugging,\n/// those are exposed in `Error::source()` as erased types. While it is\n/// possible to check the exact type of the sources, they **can not be depended\n/// on**. They may come from private internal dependencies, and are subject to\n/// change at any moment.\npub struct Error {\n    inner: Box<ErrorImpl>,\n}\n\nstruct ErrorImpl {\n    kind: Kind,\n    cause: Option<Cause>,\n}\n\n#[derive(Debug)]\npub(super) enum Kind {\n    Parse(Parse),\n    User(User),\n    /// A message reached EOF, but is not complete.\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    IncompleteMessage,\n    /// A connection received a message (or bytes) when not waiting for one.\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    UnexpectedMessage,\n    /// A pending item was dropped before ever being processed.\n    Canceled,\n    /// Indicates a channel (client or body sender) is closed.\n    #[cfg(any(\n        all(feature = \"http1\", any(feature = \"client\", feature = \"server\")),\n        all(feature = \"http2\", feature = \"client\")\n    ))]\n    ChannelClosed,\n    /// An `io::Error` that occurred while trying to read or write to a network stream.\n    #[cfg(all(\n        any(feature = \"client\", feature = \"server\"),\n        any(feature = \"http1\", feature = \"http2\")\n    ))]\n    Io,\n    /// User took too long to send headers\n    #[cfg(all(feature = \"http1\", feature = \"server\"))]\n    HeaderTimeout,\n    /// Error while reading a body from connection.\n    #[cfg(all(\n        any(feature = \"client\", feature = \"server\"),\n        any(feature = \"http1\", feature = \"http2\")\n    ))]\n    Body,\n    /// Error while writing a body to connection.\n    #[cfg(all(\n        any(feature = \"client\", feature = \"server\"),\n        any(feature = \"http1\", feature = \"http2\")\n    ))]\n    BodyWrite,\n    /// Error calling AsyncWrite::shutdown()\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    Shutdown,\n\n    /// A general error from h2.\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http2\"))]\n    Http2,\n}\n\n#[derive(Debug)]\npub(super) enum Parse {\n    Method,\n    #[cfg(feature = \"http1\")]\n    Version,\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    VersionH2,\n    Uri,\n    #[cfg(all(feature = \"http1\", feature = \"server\"))]\n    UriTooLong,\n    #[cfg(feature = \"http1\")]\n    Header(Header),\n    #[cfg(any(feature = \"http1\", feature = \"http2\"))]\n    #[cfg_attr(feature = \"http2\", allow(unused))]\n    TooLarge,\n    Status,\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    Internal,\n}\n\n#[derive(Debug)]\n#[cfg(feature = \"http1\")]\npub(super) enum Header {\n    Token,\n    #[cfg(any(feature = \"client\", feature = \"server\"))]\n    ContentLengthInvalid,\n    #[cfg(feature = \"server\")]\n    TransferEncodingInvalid,\n    #[cfg(any(feature = \"client\", feature = \"server\"))]\n    TransferEncodingUnexpected,\n}\n\n#[derive(Debug)]\npub(super) enum User {\n    /// Error calling user's Body::poll_data().\n    #[cfg(all(\n        any(feature = \"client\", feature = \"server\"),\n        any(feature = \"http1\", feature = \"http2\")\n    ))]\n    Body,\n    /// The user aborted writing of the outgoing body.\n    #[cfg(any(\n        all(feature = \"http1\", any(feature = \"client\", feature = \"server\")),\n        feature = \"ffi\"\n    ))]\n    BodyWriteAborted,\n    /// User tried to send a connect request with a nonzero body\n    #[cfg(all(feature = \"client\", feature = \"http2\"))]\n    InvalidConnectWithBody,\n    /// Error from future of user's Service.\n    #[cfg(any(\n        all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"),\n        all(feature = \"server\", feature = \"http2\")\n    ))]\n    Service,\n    /// User tried to send a certain header in an unexpected context.\n    ///\n    /// For example, sending both `content-length` and `transfer-encoding`.\n    #[cfg(any(feature = \"http1\", feature = \"http2\"))]\n    #[cfg(feature = \"server\")]\n    UnexpectedHeader,\n    /// User tried to respond with a 1xx (not 101) response code.\n    #[cfg(feature = \"http1\")]\n    #[cfg(feature = \"server\")]\n    UnsupportedStatusCode,\n\n    /// User tried polling for an upgrade that doesn't exist.\n    NoUpgrade,\n\n    /// User polled for an upgrade, but low-level API is not using upgrades.\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    ManualUpgrade,\n\n    /// The dispatch task is gone.\n    #[cfg(all(feature = \"client\", any(feature = \"http1\", feature = \"http2\")))]\n    DispatchGone,\n\n    /// User aborted in an FFI callback.\n    #[cfg(feature = \"ffi\")]\n    AbortedByCallback,\n}\n\n// Sentinel type to indicate the error was caused by a timeout.\n#[derive(Debug)]\npub(super) struct TimedOut;\n\nimpl Error {\n    /// Returns true if this was an HTTP parse error.\n    pub fn is_parse(&self) -> bool {\n        matches!(self.inner.kind, Kind::Parse(_))\n    }\n\n    /// Returns true if this was an HTTP parse error caused by a message that was too large.\n    #[cfg(all(feature = \"http1\", feature = \"server\"))]\n    pub fn is_parse_too_large(&self) -> bool {\n        matches!(\n            self.inner.kind,\n            Kind::Parse(Parse::TooLarge) | Kind::Parse(Parse::UriTooLong)\n        )\n    }\n\n    /// Returns true if this was an HTTP parse error caused by an invalid response status code or\n    /// reason phrase.\n    pub fn is_parse_status(&self) -> bool {\n        matches!(self.inner.kind, Kind::Parse(Parse::Status))\n    }\n\n    /// Returns true if this error was caused by user code.\n    pub fn is_user(&self) -> bool {\n        matches!(self.inner.kind, Kind::User(_))\n    }\n\n    /// Returns true if this was about a `Request` that was canceled.\n    pub fn is_canceled(&self) -> bool {\n        matches!(self.inner.kind, Kind::Canceled)\n    }\n\n    /// Returns true if a sender's channel is closed.\n    pub fn is_closed(&self) -> bool {\n        #[cfg(not(any(\n            all(feature = \"http1\", any(feature = \"client\", feature = \"server\")),\n            all(feature = \"http2\", feature = \"client\")\n        )))]\n        return false;\n\n        #[cfg(any(\n            all(feature = \"http1\", any(feature = \"client\", feature = \"server\")),\n            all(feature = \"http2\", feature = \"client\")\n        ))]\n        matches!(self.inner.kind, Kind::ChannelClosed)\n    }\n\n    /// Returns true if the connection closed before a message could complete.\n    ///\n    /// This means that the supplied IO connection reported EOF (closed) while\n    /// hyper's HTTP state indicates more of the message (either request or\n    /// response) needed to be transmitted.\n    ///\n    /// Some cases this could happen (not exhaustive):\n    ///\n    /// - A request is written on a connection, and the next `read` reports\n    ///   EOF (perhaps a server just closed an \"idle\" connection).\n    /// - A message body is only partially receive before the connection\n    ///   reports EOF.\n    /// - A client writes a request to your server, and then closes the write\n    ///   half while waiting for your response. If you need to support this,\n    ///   consider enabling [`half_close`].\n    ///\n    /// [`half_close`]: crate::server::conn::http1::Builder::half_close()\n    pub fn is_incomplete_message(&self) -> bool {\n        #[cfg(not(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\")))]\n        return false;\n\n        #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n        matches!(self.inner.kind, Kind::IncompleteMessage)\n    }\n\n    /// Returns true if the body write was aborted.\n    pub fn is_body_write_aborted(&self) -> bool {\n        #[cfg(not(any(\n            all(feature = \"http1\", any(feature = \"client\", feature = \"server\")),\n            feature = \"ffi\"\n        )))]\n        return false;\n\n        #[cfg(any(\n            all(feature = \"http1\", any(feature = \"client\", feature = \"server\")),\n            feature = \"ffi\"\n        ))]\n        matches!(self.inner.kind, Kind::User(User::BodyWriteAborted))\n    }\n\n    /// Returns true if the error was caused while calling `AsyncWrite::shutdown()`.\n    pub fn is_shutdown(&self) -> bool {\n        #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n        if matches!(self.inner.kind, Kind::Shutdown) {\n            return true;\n        }\n        false\n    }\n\n    /// Returns true if the error was caused by a timeout.\n    pub fn is_timeout(&self) -> bool {\n        #[cfg(all(feature = \"http1\", feature = \"server\"))]\n        if matches!(self.inner.kind, Kind::HeaderTimeout) {\n            return true;\n        }\n        self.find_source::<TimedOut>().is_some()\n    }\n\n    pub(super) fn new(kind: Kind) -> Error {\n        Error {\n            inner: Box::new(ErrorImpl { kind, cause: None }),\n        }\n    }\n\n    pub(super) fn with<C: Into<Cause>>(mut self, cause: C) -> Error {\n        self.inner.cause = Some(cause.into());\n        self\n    }\n\n    #[cfg(any(all(feature = \"http1\", feature = \"server\"), feature = \"ffi\"))]\n    pub(super) fn kind(&self) -> &Kind {\n        &self.inner.kind\n    }\n\n    pub(crate) fn find_source<E: StdError + 'static>(&self) -> Option<&E> {\n        let mut cause = self.source();\n        while let Some(err) = cause {\n            if let Some(typed) = err.downcast_ref() {\n                return Some(typed);\n            }\n            cause = err.source();\n        }\n\n        // else\n        None\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http2\"))]\n    pub(super) fn h2_reason(&self) -> h2::Reason {\n        // Find an h2::Reason somewhere in the cause stack, if it exists,\n        // otherwise assume an INTERNAL_ERROR.\n        self.find_source::<h2::Error>()\n            .and_then(|h2_err| h2_err.reason())\n            .unwrap_or(h2::Reason::INTERNAL_ERROR)\n    }\n\n    pub(super) fn new_canceled() -> Error {\n        Error::new(Kind::Canceled)\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    pub(super) fn new_incomplete() -> Error {\n        Error::new(Kind::IncompleteMessage)\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    pub(super) fn new_too_large() -> Error {\n        Error::new(Kind::Parse(Parse::TooLarge))\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    pub(super) fn new_version_h2() -> Error {\n        Error::new(Kind::Parse(Parse::VersionH2))\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    pub(super) fn new_unexpected_message() -> Error {\n        Error::new(Kind::UnexpectedMessage)\n    }\n\n    #[cfg(all(\n        any(feature = \"client\", feature = \"server\"),\n        any(feature = \"http1\", feature = \"http2\")\n    ))]\n    pub(super) fn new_io(cause: std::io::Error) -> Error {\n        Error::new(Kind::Io).with(cause)\n    }\n\n    #[cfg(any(\n        all(feature = \"http1\", any(feature = \"client\", feature = \"server\")),\n        all(feature = \"http2\", feature = \"client\")\n    ))]\n    pub(super) fn new_closed() -> Error {\n        Error::new(Kind::ChannelClosed)\n    }\n\n    #[cfg(all(\n        any(feature = \"client\", feature = \"server\"),\n        any(feature = \"http1\", feature = \"http2\")\n    ))]\n    pub(super) fn new_body<E: Into<Cause>>(cause: E) -> Error {\n        Error::new(Kind::Body).with(cause)\n    }\n\n    #[cfg(all(\n        any(feature = \"client\", feature = \"server\"),\n        any(feature = \"http1\", feature = \"http2\")\n    ))]\n    pub(super) fn new_body_write<E: Into<Cause>>(cause: E) -> Error {\n        Error::new(Kind::BodyWrite).with(cause)\n    }\n\n    #[cfg(any(\n        all(feature = \"http1\", any(feature = \"client\", feature = \"server\")),\n        feature = \"ffi\"\n    ))]\n    pub(super) fn new_body_write_aborted() -> Error {\n        Error::new(Kind::User(User::BodyWriteAborted))\n    }\n\n    fn new_user(user: User) -> Error {\n        Error::new(Kind::User(user))\n    }\n\n    #[cfg(any(feature = \"http1\", feature = \"http2\"))]\n    #[cfg(feature = \"server\")]\n    pub(super) fn new_user_header() -> Error {\n        Error::new_user(User::UnexpectedHeader)\n    }\n\n    #[cfg(all(feature = \"http1\", feature = \"server\"))]\n    pub(super) fn new_header_timeout() -> Error {\n        Error::new(Kind::HeaderTimeout)\n    }\n\n    #[cfg(feature = \"http1\")]\n    #[cfg(feature = \"server\")]\n    pub(super) fn new_user_unsupported_status_code() -> Error {\n        Error::new_user(User::UnsupportedStatusCode)\n    }\n\n    pub(super) fn new_user_no_upgrade() -> Error {\n        Error::new_user(User::NoUpgrade)\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    pub(super) fn new_user_manual_upgrade() -> Error {\n        Error::new_user(User::ManualUpgrade)\n    }\n\n    #[cfg(any(\n        all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"),\n        all(feature = \"server\", feature = \"http2\")\n    ))]\n    pub(super) fn new_user_service<E: Into<Cause>>(cause: E) -> Error {\n        Error::new_user(User::Service).with(cause)\n    }\n\n    #[cfg(all(\n        any(feature = \"client\", feature = \"server\"),\n        any(feature = \"http1\", feature = \"http2\")\n    ))]\n    pub(super) fn new_user_body<E: Into<Cause>>(cause: E) -> Error {\n        Error::new_user(User::Body).with(cause)\n    }\n\n    #[cfg(all(feature = \"client\", feature = \"http2\"))]\n    pub(super) fn new_user_invalid_connect() -> Error {\n        Error::new_user(User::InvalidConnectWithBody)\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    pub(super) fn new_shutdown(cause: std::io::Error) -> Error {\n        Error::new(Kind::Shutdown).with(cause)\n    }\n\n    #[cfg(feature = \"ffi\")]\n    pub(super) fn new_user_aborted_by_callback() -> Error {\n        Error::new_user(User::AbortedByCallback)\n    }\n\n    #[cfg(all(feature = \"client\", any(feature = \"http1\", feature = \"http2\")))]\n    pub(super) fn new_user_dispatch_gone() -> Error {\n        Error::new(Kind::User(User::DispatchGone))\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http2\"))]\n    pub(super) fn new_h2(cause: ::h2::Error) -> Error {\n        if cause.is_io() {\n            Error::new_io(cause.into_io().expect(\"h2::Error::is_io\"))\n        } else {\n            Error::new(Kind::Http2).with(cause)\n        }\n    }\n\n    fn description(&self) -> &str {\n        match self.inner.kind {\n            Kind::Parse(Parse::Method) => \"invalid HTTP method parsed\",\n            #[cfg(feature = \"http1\")]\n            Kind::Parse(Parse::Version) => \"invalid HTTP version parsed\",\n            #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n            Kind::Parse(Parse::VersionH2) => \"invalid HTTP version parsed (found HTTP2 preface)\",\n            Kind::Parse(Parse::Uri) => \"invalid URI\",\n            #[cfg(all(feature = \"http1\", feature = \"server\"))]\n            Kind::Parse(Parse::UriTooLong) => \"URI too long\",\n            #[cfg(feature = \"http1\")]\n            Kind::Parse(Parse::Header(Header::Token)) => \"invalid HTTP header parsed\",\n            #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n            Kind::Parse(Parse::Header(Header::ContentLengthInvalid)) => {\n                \"invalid content-length parsed\"\n            }\n            #[cfg(all(feature = \"http1\", feature = \"server\"))]\n            Kind::Parse(Parse::Header(Header::TransferEncodingInvalid)) => {\n                \"invalid transfer-encoding parsed\"\n            }\n            #[cfg(all(feature = \"http1\", any(feature = \"client\", feature = \"server\")))]\n            Kind::Parse(Parse::Header(Header::TransferEncodingUnexpected)) => {\n                \"unexpected transfer-encoding parsed\"\n            }\n            #[cfg(any(feature = \"http1\", feature = \"http2\"))]\n            Kind::Parse(Parse::TooLarge) => \"message head is too large\",\n            Kind::Parse(Parse::Status) => \"invalid HTTP status-code parsed\",\n            #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n            Kind::Parse(Parse::Internal) => {\n                \"internal error inside Hyper and/or its dependencies, please report\"\n            }\n            #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n            Kind::IncompleteMessage => \"connection closed before message completed\",\n            #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n            Kind::UnexpectedMessage => \"received unexpected message from connection\",\n            #[cfg(any(\n                all(feature = \"http1\", any(feature = \"client\", feature = \"server\")),\n                all(feature = \"http2\", feature = \"client\")\n            ))]\n            Kind::ChannelClosed => \"channel closed\",\n            Kind::Canceled => \"operation was canceled\",\n            #[cfg(all(feature = \"http1\", feature = \"server\"))]\n            Kind::HeaderTimeout => \"read header from client timeout\",\n            #[cfg(all(\n                any(feature = \"client\", feature = \"server\"),\n                any(feature = \"http1\", feature = \"http2\")\n            ))]\n            Kind::Body => \"error reading a body from connection\",\n            #[cfg(all(\n                any(feature = \"client\", feature = \"server\"),\n                any(feature = \"http1\", feature = \"http2\")\n            ))]\n            Kind::BodyWrite => \"error writing a body to connection\",\n            #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n            Kind::Shutdown => \"error shutting down connection\",\n            #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http2\"))]\n            Kind::Http2 => \"http2 error\",\n            #[cfg(all(\n                any(feature = \"client\", feature = \"server\"),\n                any(feature = \"http1\", feature = \"http2\")\n            ))]\n            Kind::Io => \"connection error\",\n\n            #[cfg(all(\n                any(feature = \"client\", feature = \"server\"),\n                any(feature = \"http1\", feature = \"http2\")\n            ))]\n            Kind::User(User::Body) => \"error from user's Body stream\",\n            #[cfg(any(\n                all(feature = \"http1\", any(feature = \"client\", feature = \"server\")),\n                feature = \"ffi\"\n            ))]\n            Kind::User(User::BodyWriteAborted) => \"user body write aborted\",\n            #[cfg(all(feature = \"client\", feature = \"http2\"))]\n            Kind::User(User::InvalidConnectWithBody) => {\n                \"user sent CONNECT request with non-zero body\"\n            }\n            #[cfg(any(\n                all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"),\n                all(feature = \"server\", feature = \"http2\")\n            ))]\n            Kind::User(User::Service) => \"error from user's Service\",\n            #[cfg(any(feature = \"http1\", feature = \"http2\"))]\n            #[cfg(feature = \"server\")]\n            Kind::User(User::UnexpectedHeader) => \"user sent unexpected header\",\n            #[cfg(feature = \"http1\")]\n            #[cfg(feature = \"server\")]\n            Kind::User(User::UnsupportedStatusCode) => {\n                \"response has 1xx status code, not supported by server\"\n            }\n            Kind::User(User::NoUpgrade) => \"no upgrade available\",\n            #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n            Kind::User(User::ManualUpgrade) => \"upgrade expected but low level API in use\",\n            #[cfg(all(feature = \"client\", any(feature = \"http1\", feature = \"http2\")))]\n            Kind::User(User::DispatchGone) => \"dispatch task is gone\",\n            #[cfg(feature = \"ffi\")]\n            Kind::User(User::AbortedByCallback) => \"operation aborted by an application callback\",\n        }\n    }\n}\n\nimpl fmt::Debug for Error {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let mut f = f.debug_tuple(\"hyper::Error\");\n        f.field(&self.inner.kind);\n        if let Some(ref cause) = self.inner.cause {\n            f.field(cause);\n        }\n        f.finish()\n    }\n}\n\nimpl fmt::Display for Error {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(self.description())\n    }\n}\n\nimpl StdError for Error {\n    fn source(&self) -> Option<&(dyn StdError + 'static)> {\n        self.inner\n            .cause\n            .as_ref()\n            .map(|cause| &**cause as &(dyn StdError + 'static))\n    }\n}\n\n#[doc(hidden)]\nimpl From<Parse> for Error {\n    fn from(err: Parse) -> Error {\n        Error::new(Kind::Parse(err))\n    }\n}\n\n#[cfg(feature = \"http1\")]\nimpl Parse {\n    #[cfg(any(feature = \"client\", feature = \"server\"))]\n    pub(crate) fn content_length_invalid() -> Self {\n        Parse::Header(Header::ContentLengthInvalid)\n    }\n\n    #[cfg(feature = \"server\")]\n    pub(crate) fn transfer_encoding_invalid() -> Self {\n        Parse::Header(Header::TransferEncodingInvalid)\n    }\n\n    #[cfg(any(feature = \"client\", feature = \"server\"))]\n    pub(crate) fn transfer_encoding_unexpected() -> Self {\n        Parse::Header(Header::TransferEncodingUnexpected)\n    }\n}\n\n#[cfg(feature = \"http1\")]\nimpl From<httparse::Error> for Parse {\n    fn from(err: httparse::Error) -> Parse {\n        match err {\n            httparse::Error::HeaderName\n            | httparse::Error::HeaderValue\n            | httparse::Error::NewLine\n            | httparse::Error::Token => Parse::Header(Header::Token),\n            httparse::Error::Status => Parse::Status,\n            httparse::Error::TooManyHeaders => Parse::TooLarge,\n            httparse::Error::Version => Parse::Version,\n        }\n    }\n}\n\nimpl From<http::method::InvalidMethod> for Parse {\n    fn from(_: http::method::InvalidMethod) -> Parse {\n        Parse::Method\n    }\n}\n\nimpl From<http::status::InvalidStatusCode> for Parse {\n    fn from(_: http::status::InvalidStatusCode) -> Parse {\n        Parse::Status\n    }\n}\n\nimpl From<http::uri::InvalidUri> for Parse {\n    fn from(_: http::uri::InvalidUri) -> Parse {\n        Parse::Uri\n    }\n}\n\nimpl From<http::uri::InvalidUriParts> for Parse {\n    fn from(_: http::uri::InvalidUriParts) -> Parse {\n        Parse::Uri\n    }\n}\n\n// ===== impl TimedOut ====\n\nimpl fmt::Display for TimedOut {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"operation timed out\")\n    }\n}\n\nimpl StdError for TimedOut {}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::mem;\n\n    fn assert_send_sync<T: Send + Sync + 'static>() {}\n\n    #[test]\n    fn error_satisfies_send_sync() {\n        assert_send_sync::<Error>()\n    }\n\n    #[test]\n    fn error_size_of() {\n        assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());\n    }\n\n    #[cfg(feature = \"http2\")]\n    #[test]\n    fn h2_reason_unknown() {\n        let closed = Error::new_closed();\n        assert_eq!(closed.h2_reason(), h2::Reason::INTERNAL_ERROR);\n    }\n\n    #[cfg(feature = \"http2\")]\n    #[test]\n    fn h2_reason_one_level() {\n        let body_err = Error::new_user_body(h2::Error::from(h2::Reason::ENHANCE_YOUR_CALM));\n        assert_eq!(body_err.h2_reason(), h2::Reason::ENHANCE_YOUR_CALM);\n    }\n\n    #[cfg(feature = \"http2\")]\n    #[test]\n    fn h2_reason_nested() {\n        let recvd = Error::new_h2(h2::Error::from(h2::Reason::HTTP_1_1_REQUIRED));\n        // Suppose a user were proxying the received error\n        let svc_err = Error::new_user_service(recvd);\n        assert_eq!(svc_err.h2_reason(), h2::Reason::HTTP_1_1_REQUIRED);\n    }\n}\n"
  },
  {
    "path": "src/ext/h1_reason_phrase.rs",
    "content": "use bytes::Bytes;\n\n/// A reason phrase in an HTTP/1 response.\n///\n/// # Clients\n///\n/// For clients, a `ReasonPhrase` will be present in the extensions of the `http::Response` returned\n/// for a request if the reason phrase is different from the canonical reason phrase for the\n/// response's status code. For example, if a server returns `HTTP/1.1 200 Awesome`, the\n/// `ReasonPhrase` will be present and contain `Awesome`, but if a server returns `HTTP/1.1 200 OK`,\n/// the response will not contain a `ReasonPhrase`.\n///\n/// ```no_run\n/// # #[cfg(all(feature = \"tcp\", feature = \"client\", feature = \"http1\"))]\n/// # async fn fake_fetch() -> hyper::Result<()> {\n/// use hyper::{Client, Uri};\n/// use hyper::ext::ReasonPhrase;\n///\n/// let res = Client::new().get(Uri::from_static(\"http://example.com/non_canonical_reason\")).await?;\n///\n/// // Print out the non-canonical reason phrase, if it has one...\n/// if let Some(reason) = res.extensions().get::<ReasonPhrase>() {\n///     println!(\"non-canonical reason: {}\", std::str::from_utf8(reason.as_bytes()).unwrap());\n/// }\n/// # Ok(())\n/// # }\n/// ```\n///\n/// # Servers\n///\n/// When a `ReasonPhrase` is present in the extensions of the `http::Response` written by a server,\n/// its contents will be written in place of the canonical reason phrase when responding via HTTP/1.\n#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]\npub struct ReasonPhrase(Bytes);\n\nimpl ReasonPhrase {\n    /// Gets the reason phrase as bytes.\n    pub fn as_bytes(&self) -> &[u8] {\n        &self.0\n    }\n\n    /// Converts a static byte slice to a reason phrase.\n    pub const fn from_static(reason: &'static [u8]) -> Self {\n        // TODO: this can be made const once MSRV is >= 1.57.0\n        if find_invalid_byte(reason).is_some() {\n            panic!(\"invalid byte in static reason phrase\");\n        }\n        Self(Bytes::from_static(reason))\n    }\n\n    // Not public on purpose.\n    /// Converts a `Bytes` directly into a `ReasonPhrase` without validating.\n    ///\n    /// Use with care; invalid bytes in a reason phrase can cause serious security problems if\n    /// emitted in a response.\n    #[cfg(feature = \"client\")]\n    pub(crate) fn from_bytes_unchecked(reason: Bytes) -> Self {\n        Self(reason)\n    }\n}\n\nimpl TryFrom<&[u8]> for ReasonPhrase {\n    type Error = InvalidReasonPhrase;\n\n    fn try_from(reason: &[u8]) -> Result<Self, Self::Error> {\n        if let Some(bad_byte) = find_invalid_byte(reason) {\n            Err(InvalidReasonPhrase { bad_byte })\n        } else {\n            Ok(Self(Bytes::copy_from_slice(reason)))\n        }\n    }\n}\n\nimpl TryFrom<Vec<u8>> for ReasonPhrase {\n    type Error = InvalidReasonPhrase;\n\n    fn try_from(reason: Vec<u8>) -> Result<Self, Self::Error> {\n        if let Some(bad_byte) = find_invalid_byte(&reason) {\n            Err(InvalidReasonPhrase { bad_byte })\n        } else {\n            Ok(Self(Bytes::from(reason)))\n        }\n    }\n}\n\nimpl TryFrom<String> for ReasonPhrase {\n    type Error = InvalidReasonPhrase;\n\n    fn try_from(reason: String) -> Result<Self, Self::Error> {\n        if let Some(bad_byte) = find_invalid_byte(reason.as_bytes()) {\n            Err(InvalidReasonPhrase { bad_byte })\n        } else {\n            Ok(Self(Bytes::from(reason)))\n        }\n    }\n}\n\nimpl TryFrom<Bytes> for ReasonPhrase {\n    type Error = InvalidReasonPhrase;\n\n    fn try_from(reason: Bytes) -> Result<Self, Self::Error> {\n        if let Some(bad_byte) = find_invalid_byte(&reason) {\n            Err(InvalidReasonPhrase { bad_byte })\n        } else {\n            Ok(Self(reason))\n        }\n    }\n}\n\nimpl From<ReasonPhrase> for Bytes {\n    fn from(reason: ReasonPhrase) -> Self {\n        reason.0\n    }\n}\n\nimpl AsRef<[u8]> for ReasonPhrase {\n    fn as_ref(&self) -> &[u8] {\n        &self.0\n    }\n}\n\n/// Error indicating an invalid byte when constructing a `ReasonPhrase`.\n///\n/// See [the spec][spec] for details on allowed bytes.\n///\n/// [spec]: https://httpwg.org/http-core/draft-ietf-httpbis-messaging-latest.html#rfc.section.4.p.7\n#[derive(Debug)]\npub struct InvalidReasonPhrase {\n    bad_byte: u8,\n}\n\nimpl std::fmt::Display for InvalidReasonPhrase {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"Invalid byte in reason phrase: {}\", self.bad_byte)\n    }\n}\n\nimpl std::error::Error for InvalidReasonPhrase {}\n\nconst fn is_valid_byte(b: u8) -> bool {\n    // See https://www.rfc-editor.org/rfc/rfc5234.html#appendix-B.1\n    const fn is_vchar(b: u8) -> bool {\n        0x21 <= b && b <= 0x7E\n    }\n\n    // See https://httpwg.org/http-core/draft-ietf-httpbis-semantics-latest.html#fields.values\n    //\n    // The 0xFF comparison is technically redundant, but it matches the text of the spec more\n    // clearly and will be optimized away.\n    #[allow(unused_comparisons, clippy::absurd_extreme_comparisons)]\n    const fn is_obs_text(b: u8) -> bool {\n        0x80 <= b && b <= 0xFF\n    }\n\n    // See https://httpwg.org/http-core/draft-ietf-httpbis-messaging-latest.html#rfc.section.4.p.7\n    b == b'\\t' || b == b' ' || is_vchar(b) || is_obs_text(b)\n}\n\nconst fn find_invalid_byte(bytes: &[u8]) -> Option<u8> {\n    let mut i = 0;\n    while i < bytes.len() {\n        let b = bytes[i];\n        if !is_valid_byte(b) {\n            return Some(b);\n        }\n        i += 1;\n    }\n    None\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn basic_valid() {\n        const PHRASE: &[u8] = b\"OK\";\n        assert_eq!(ReasonPhrase::from_static(PHRASE).as_bytes(), PHRASE);\n        assert_eq!(ReasonPhrase::try_from(PHRASE).unwrap().as_bytes(), PHRASE);\n    }\n\n    #[test]\n    fn empty_valid() {\n        const PHRASE: &[u8] = b\"\";\n        assert_eq!(ReasonPhrase::from_static(PHRASE).as_bytes(), PHRASE);\n        assert_eq!(ReasonPhrase::try_from(PHRASE).unwrap().as_bytes(), PHRASE);\n    }\n\n    #[test]\n    fn obs_text_valid() {\n        const PHRASE: &[u8] = b\"hyp\\xe9r\";\n        assert_eq!(ReasonPhrase::from_static(PHRASE).as_bytes(), PHRASE);\n        assert_eq!(ReasonPhrase::try_from(PHRASE).unwrap().as_bytes(), PHRASE);\n    }\n\n    const NEWLINE_PHRASE: &[u8] = b\"hyp\\ner\";\n\n    #[test]\n    #[should_panic]\n    fn newline_invalid_panic() {\n        ReasonPhrase::from_static(NEWLINE_PHRASE);\n    }\n\n    #[test]\n    fn newline_invalid_err() {\n        assert!(ReasonPhrase::try_from(NEWLINE_PHRASE).is_err());\n    }\n\n    const CR_PHRASE: &[u8] = b\"hyp\\rer\";\n\n    #[test]\n    #[should_panic]\n    fn cr_invalid_panic() {\n        ReasonPhrase::from_static(CR_PHRASE);\n    }\n\n    #[test]\n    fn cr_invalid_err() {\n        assert!(ReasonPhrase::try_from(CR_PHRASE).is_err());\n    }\n}\n"
  },
  {
    "path": "src/ext/informational.rs",
    "content": "use std::sync::Arc;\n\n#[derive(Clone)]\npub(crate) struct OnInformational(Arc<dyn OnInformationalCallback + Send + Sync>);\n\n/// Add a callback for 1xx informational responses.\n///\n/// # Example\n///\n/// ```\n/// # let some_body = ();\n/// let mut req = hyper::Request::new(some_body);\n///\n/// hyper::ext::on_informational(&mut req, |res| {\n///     println!(\"informational: {:?}\", res.status());\n/// });\n///\n/// // send request on a client connection...\n/// ```\npub fn on_informational<B, F>(req: &mut http::Request<B>, callback: F)\nwhere\n    F: Fn(Response<'_>) + Send + Sync + 'static,\n{\n    on_informational_raw(req, OnInformationalClosure(callback));\n}\n\npub(crate) fn on_informational_raw<B, C>(req: &mut http::Request<B>, callback: C)\nwhere\n    C: OnInformationalCallback + Send + Sync + 'static,\n{\n    req.extensions_mut()\n        .insert(OnInformational(Arc::new(callback)));\n}\n\n// Sealed, not actually nameable bounds\npub(crate) trait OnInformationalCallback {\n    fn on_informational(&self, res: http::Response<()>);\n}\n\nimpl OnInformational {\n    pub(crate) fn call(&self, res: http::Response<()>) {\n        self.0.on_informational(res);\n    }\n}\n\nstruct OnInformationalClosure<F>(F);\n\nimpl<F> OnInformationalCallback for OnInformationalClosure<F>\nwhere\n    F: Fn(Response<'_>) + Send + Sync + 'static,\n{\n    fn on_informational(&self, res: http::Response<()>) {\n        let res = Response(&res);\n        (self.0)(res);\n    }\n}\n\n// A facade over http::Response.\n//\n// It purposefully hides being able to move the response out of the closure,\n// while also not being able to expect it to be a reference `&Response`.\n// (Otherwise, a closure can be written as `|res: &_|`, and then be broken if\n// we make the closure take ownership.)\n//\n// With the type not being nameable, we could change from being a facade to\n// being either a real reference, or moving the http::Response into the closure,\n// in a backwards-compatible change in the future.\n#[derive(Debug)]\npub struct Response<'a>(&'a http::Response<()>);\n\nimpl Response<'_> {\n    #[inline]\n    pub fn status(&self) -> http::StatusCode {\n        self.0.status()\n    }\n\n    #[inline]\n    pub fn version(&self) -> http::Version {\n        self.0.version()\n    }\n\n    #[inline]\n    pub fn headers(&self) -> &http::HeaderMap {\n        self.0.headers()\n    }\n}\n"
  },
  {
    "path": "src/ext/mod.rs",
    "content": "//! Extensions for HTTP messages in Hyper.\n//!\n//! This module provides types and utilities that extend the capabilities of HTTP requests and responses\n//! in Hyper. Extensions are additional pieces of information or features that can be attached to HTTP\n//! messages via the [`http::Extensions`] map, which is\n//! accessible through methods like [`http::Request::extensions`] and [`http::Response::extensions`].\n//!\n//! # What are extensions?\n//!\n//! Extensions allow Hyper to associate extra metadata or behaviors with HTTP messages, beyond the standard\n//! headers and body. These can be used by advanced users and library authors to access protocol-specific\n//! features, track original header casing, handle informational responses, and more.\n//!\n//! # How to access extensions\n//!\n//! Extensions are stored in the `Extensions` map of a request or response. You can access them using:\n//!\n//! ```rust\n//! # let response = http::Response::new(());\n//! if let Some(ext) = response.extensions().get::<hyper::ext::ReasonPhrase>() {\n//!     // use the extension\n//! }\n//! ```\n//!\n//! # Extension Groups\n//!\n//! The extensions in this module can be grouped as follows:\n//!\n//! - **HTTP/1 Reason Phrase**: [`ReasonPhrase`] — Access non-canonical reason phrases in HTTP/1 responses.\n//! - **Informational Responses**: [`on_informational`] — Register callbacks for 1xx HTTP/1 responses on the client.\n//! - **Header Case Tracking**: Internal types for tracking the original casing and order of headers as received.\n//! - **HTTP/2 Protocol Extensions**: [`Protocol`] — Access the `:protocol` pseudo-header for Extended CONNECT in HTTP/2.\n//!\n//! Some extensions are only available for specific protocols (HTTP/1 or HTTP/2) or use cases (client, server, FFI).\n//!\n//! See the documentation on each item for details about its usage and requirements.\n\n#[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\nuse bytes::Bytes;\n#[cfg(any(\n    all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"),\n    feature = \"ffi\"\n))]\nuse http::header::HeaderName;\n#[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\nuse http::header::{HeaderMap, IntoHeaderName, ValueIter};\n#[cfg(feature = \"ffi\")]\nuse std::collections::HashMap;\n#[cfg(feature = \"http2\")]\nuse std::fmt;\n\n#[cfg(any(feature = \"http1\", feature = \"ffi\"))]\nmod h1_reason_phrase;\n#[cfg(any(feature = \"http1\", feature = \"ffi\"))]\npub use h1_reason_phrase::ReasonPhrase;\n\n#[cfg(all(feature = \"http1\", feature = \"client\"))]\nmod informational;\n#[cfg(all(feature = \"http1\", feature = \"client\"))]\npub use informational::on_informational;\n#[cfg(all(feature = \"http1\", feature = \"client\"))]\npub(crate) use informational::OnInformational;\n#[cfg(all(feature = \"http1\", feature = \"client\", feature = \"ffi\"))]\npub(crate) use informational::{on_informational_raw, OnInformationalCallback};\n\n#[cfg(feature = \"http2\")]\n/// Extension type representing the `:protocol` pseudo-header in HTTP/2.\n///\n/// The `Protocol` extension allows access to the value of the `:protocol` pseudo-header\n/// used by the [Extended CONNECT Protocol](https://datatracker.ietf.org/doc/html/rfc8441#section-4).\n/// This extension is only sent on HTTP/2 CONNECT requests, most commonly with the value `websocket`.\n///\n/// # Example\n///\n/// ```rust\n/// use hyper::ext::Protocol;\n/// use http::{Request, Method, Version};\n///\n/// let mut req = Request::new(());\n/// *req.method_mut() = Method::CONNECT;\n/// *req.version_mut() = Version::HTTP_2;\n/// req.extensions_mut().insert(Protocol::from_static(\"websocket\"));\n/// // Now the request will include the `:protocol` pseudo-header with value \"websocket\"\n/// ```\n#[derive(Clone, Eq, PartialEq)]\npub struct Protocol {\n    inner: h2::ext::Protocol,\n}\n\n#[cfg(feature = \"http2\")]\nimpl Protocol {\n    /// Converts a static string to a protocol name.\n    pub const fn from_static(value: &'static str) -> Self {\n        Self {\n            inner: h2::ext::Protocol::from_static(value),\n        }\n    }\n\n    /// Returns a str representation of the header.\n    pub fn as_str(&self) -> &str {\n        self.inner.as_str()\n    }\n\n    #[cfg(feature = \"server\")]\n    pub(crate) fn from_inner(inner: h2::ext::Protocol) -> Self {\n        Self { inner }\n    }\n\n    #[cfg(all(feature = \"client\", feature = \"http2\"))]\n    pub(crate) fn into_inner(self) -> h2::ext::Protocol {\n        self.inner\n    }\n}\n\n#[cfg(feature = \"http2\")]\nimpl<'a> From<&'a str> for Protocol {\n    fn from(value: &'a str) -> Self {\n        Self {\n            inner: h2::ext::Protocol::from(value),\n        }\n    }\n}\n\n#[cfg(feature = \"http2\")]\nimpl AsRef<[u8]> for Protocol {\n    fn as_ref(&self) -> &[u8] {\n        self.inner.as_ref()\n    }\n}\n\n#[cfg(feature = \"http2\")]\nimpl fmt::Debug for Protocol {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        self.inner.fmt(f)\n    }\n}\n\n/// A map from header names to their original casing as received in an HTTP message.\n///\n/// If an HTTP/1 response `res` is parsed on a connection whose option\n/// [`preserve_header_case`] was set to true and the response included\n/// the following headers:\n///\n/// ```ignore\n/// x-Bread: Baguette\n/// X-BREAD: Pain\n/// x-bread: Ficelle\n/// ```\n///\n/// Then `res.extensions().get::<HeaderCaseMap>()` will return a map with:\n///\n/// ```ignore\n/// HeaderCaseMap({\n///     \"x-bread\": [\"x-Bread\", \"X-BREAD\", \"x-bread\"],\n/// })\n/// ```\n///\n/// [`preserve_header_case`]: /client/struct.Client.html#method.preserve_header_case\n#[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n#[derive(Clone, Debug)]\npub(crate) struct HeaderCaseMap(HeaderMap<Bytes>);\n\n#[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\nimpl HeaderCaseMap {\n    /// Returns a view of all spellings associated with that header name,\n    /// in the order they were found.\n    #[cfg(feature = \"client\")]\n    pub(crate) fn get_all<'a>(\n        &'a self,\n        name: &HeaderName,\n    ) -> impl Iterator<Item = impl AsRef<[u8]> + 'a> + 'a {\n        self.get_all_internal(name)\n    }\n\n    /// Returns a view of all spellings associated with that header name,\n    /// in the order they were found.\n    #[cfg(any(feature = \"client\", feature = \"server\"))]\n    pub(crate) fn get_all_internal(&self, name: &HeaderName) -> ValueIter<'_, Bytes> {\n        self.0.get_all(name).into_iter()\n    }\n\n    #[cfg(any(feature = \"client\", feature = \"server\"))]\n    pub(crate) fn default() -> Self {\n        Self(Default::default())\n    }\n\n    #[cfg(any(test, feature = \"ffi\"))]\n    pub(crate) fn insert(&mut self, name: HeaderName, orig: Bytes) {\n        self.0.insert(name, orig);\n    }\n\n    #[cfg(any(feature = \"client\", feature = \"server\"))]\n    pub(crate) fn append<N>(&mut self, name: N, orig: Bytes)\n    where\n        N: IntoHeaderName,\n    {\n        self.0.append(name, orig);\n    }\n}\n\n#[cfg(feature = \"ffi\")]\n#[derive(Clone, Debug)]\n/// Hashmap<Headername, numheaders with that name>\npub(crate) struct OriginalHeaderOrder {\n    /// Stores how many entries a Headername maps to. This is used\n    /// for accounting.\n    num_entries: HashMap<HeaderName, usize>,\n    /// Stores the ordering of the headers. ex: `vec[i] = (headerName, idx)`,\n    /// The vector is ordered such that the ith element\n    /// represents the ith header that came in off the line.\n    /// The `HeaderName` and `idx` are then used elsewhere to index into\n    /// the multi map that stores the header values.\n    entry_order: Vec<(HeaderName, usize)>,\n}\n\n#[cfg(all(feature = \"http1\", feature = \"ffi\"))]\nimpl OriginalHeaderOrder {\n    pub(crate) fn default() -> Self {\n        OriginalHeaderOrder {\n            num_entries: HashMap::new(),\n            entry_order: Vec::new(),\n        }\n    }\n\n    pub(crate) fn insert(&mut self, name: HeaderName) {\n        if !self.num_entries.contains_key(&name) {\n            let idx = 0;\n            self.num_entries.insert(name.clone(), 1);\n            self.entry_order.push((name, idx));\n        }\n        // Replacing an already existing element does not\n        // change ordering, so we only care if its the first\n        // header name encountered\n    }\n\n    pub(crate) fn append<N>(&mut self, name: N)\n    where\n        N: IntoHeaderName + Into<HeaderName> + Clone,\n    {\n        let name: HeaderName = name.into();\n        let idx;\n        if self.num_entries.contains_key(&name) {\n            idx = self.num_entries[&name];\n            *self.num_entries.get_mut(&name).unwrap() += 1;\n        } else {\n            idx = 0;\n            self.num_entries.insert(name.clone(), 1);\n        }\n        self.entry_order.push((name, idx));\n    }\n\n    // No doc test is run here because `RUSTFLAGS='--cfg hyper_unstable_ffi'`\n    // is needed to compile. Once ffi is stabilized `no_run` should be removed\n    // here.\n    /// This returns an iterator that provides header names and indexes\n    /// in the original order received.\n    ///\n    /// # Examples\n    /// ```no_run\n    /// use hyper::ext::OriginalHeaderOrder;\n    /// use hyper::header::{HeaderName, HeaderValue, HeaderMap};\n    ///\n    /// let mut h_order = OriginalHeaderOrder::default();\n    /// let mut h_map = Headermap::new();\n    ///\n    /// let name1 = b\"Set-CookiE\";\n    /// let value1 = b\"a=b\";\n    /// h_map.append(name1);\n    /// h_order.append(name1);\n    ///\n    /// let name2 = b\"Content-Encoding\";\n    /// let value2 = b\"gzip\";\n    /// h_map.append(name2, value2);\n    /// h_order.append(name2);\n    ///\n    /// let name3 = b\"SET-COOKIE\";\n    /// let value3 = b\"c=d\";\n    /// h_map.append(name3, value3);\n    /// h_order.append(name3)\n    ///\n    /// let mut iter = h_order.get_in_order()\n    ///\n    /// let (name, idx) = iter.next();\n    /// assert_eq!(b\"a=b\", h_map.get_all(name).nth(idx).unwrap());\n    ///\n    /// let (name, idx) = iter.next();\n    /// assert_eq!(b\"gzip\", h_map.get_all(name).nth(idx).unwrap());\n    ///\n    /// let (name, idx) = iter.next();\n    /// assert_eq!(b\"c=d\", h_map.get_all(name).nth(idx).unwrap());\n    /// ```\n    pub(crate) fn get_in_order(&self) -> impl Iterator<Item = &(HeaderName, usize)> {\n        self.entry_order.iter()\n    }\n}\n"
  },
  {
    "path": "src/ffi/body.rs",
    "content": "use std::ffi::{c_int, c_void};\nuse std::mem::ManuallyDrop;\nuse std::ptr;\nuse std::task::{Context, Poll};\n\nuse http_body_util::BodyExt as _;\n\nuse super::task::{hyper_context, hyper_task, hyper_task_return_type, AsTaskType};\nuse super::{UserDataPointer, HYPER_ITER_CONTINUE};\nuse crate::body::{Bytes, Frame, Incoming as IncomingBody};\nuse crate::ffi::size_t;\n\n/// A streaming HTTP body.\n///\n/// This is used both for sending requests (with `hyper_request_set_body`) and\n/// for receiving responses (with `hyper_response_body`).\n///\n/// For outgoing request bodies, call `hyper_body_set_data_func` to provide the\n/// data.\n///\n/// For incoming response bodies, call `hyper_body_data` to get a task that will\n/// yield a chunk of data each time it is polled. That task must be then be\n/// added to the executor with `hyper_executor_push`.\n///\n/// Methods:\n///\n/// - hyper_body_new:           Create a new “empty” body.\n/// - hyper_body_set_userdata:  Set userdata on this body, which will be passed to callback functions.\n/// - hyper_body_set_data_func: Set the data callback for this body.\n/// - hyper_body_data:          Creates a task that will poll a response body for the next buffer of data.\n/// - hyper_body_foreach:       Creates a task to execute the callback with each body chunk received.\n/// - hyper_body_free:          Free a body.\npub struct hyper_body(pub(super) IncomingBody);\n\n/// A buffer of bytes that is sent or received on a `hyper_body`.\n///\n/// Obtain one of these in the callback of `hyper_body_foreach` or by receiving\n/// a task of type `HYPER_TASK_BUF` from `hyper_executor_poll` (after calling\n/// `hyper_body_data` and pushing the resulting task).\n///\n/// Methods:\n///\n/// - hyper_buf_bytes: Get a pointer to the bytes in this buffer.\n/// - hyper_buf_copy:  Create a new hyper_buf * by copying the provided bytes.\n/// - hyper_buf_free:  Free this buffer.\n/// - hyper_buf_len:   Get the length of the bytes this buffer contains.\npub struct hyper_buf(pub(crate) Bytes);\n\npub(crate) struct UserBody {\n    data_func: hyper_body_data_callback,\n    userdata: *mut c_void,\n}\n\n// ===== Body =====\n\ntype hyper_body_foreach_callback = extern \"C\" fn(*mut c_void, *const hyper_buf) -> c_int;\n\ntype hyper_body_data_callback =\n    extern \"C\" fn(*mut c_void, *mut hyper_context<'_>, *mut *mut hyper_buf) -> c_int;\n\nffi_fn! {\n    /// Creates a new \"empty\" body.\n    ///\n    /// If not configured, this body acts as an empty payload.\n    ///\n    /// To avoid a memory leak, the body must eventually be consumed by\n    /// `hyper_body_free`, `hyper_body_foreach`, or `hyper_request_set_body`.\n    fn hyper_body_new() -> *mut hyper_body {\n        Box::into_raw(Box::new(hyper_body(IncomingBody::ffi())))\n    } ?= ptr::null_mut()\n}\n\nffi_fn! {\n    /// Free a body.\n    ///\n    /// This should only be used if the request isn't consumed by\n    /// `hyper_body_foreach` or `hyper_request_set_body`.\n    fn hyper_body_free(body: *mut hyper_body) {\n        drop(non_null!(Box::from_raw(body) ?= ()));\n    }\n}\n\nffi_fn! {\n    /// Creates a task that will poll a response body for the next buffer of data.\n    ///\n    /// The task may have different types depending on the outcome:\n    ///\n    /// - `HYPER_TASK_BUF`: Success, and more data was received.\n    /// - `HYPER_TASK_ERROR`: An error retrieving the data.\n    /// - `HYPER_TASK_EMPTY`: The body has finished streaming data.\n    ///\n    /// When the application receives the task from `hyper_executor_poll`,\n    /// if the task type is `HYPER_TASK_BUF`, it should cast the task to\n    /// `hyper_buf *` and consume all the bytes in the buffer. Then\n    /// the application should call `hyper_body_data` again for the same\n    /// `hyper_body *`, to create a task for the next buffer of data.\n    /// Repeat until the polled task type is `HYPER_TASK_ERROR` or\n    /// `HYPER_TASK_EMPTY`.\n    ///\n    /// To avoid a memory leak, the task must eventually be consumed by\n    /// `hyper_task_free`, or taken ownership of by `hyper_executor_push`\n    /// without subsequently being given back by `hyper_executor_poll`.\n    ///\n    /// This does not consume the `hyper_body *`, so it may be used again.\n    /// However, the `hyper_body *` MUST NOT be used or freed until the\n    /// related task is returned from `hyper_executor_poll`.\n    ///\n    /// For a more convenient method, see also `hyper_body_foreach`.\n    fn hyper_body_data(body: *mut hyper_body) -> *mut hyper_task {\n        // This doesn't take ownership of the Body, so don't allow destructor\n        let mut body = ManuallyDrop::new(non_null!(Box::from_raw(body) ?= ptr::null_mut()));\n\n        Box::into_raw(hyper_task::boxed(async move {\n            loop {\n                match body.0.frame().await {\n                    Some(Ok(frame)) => {\n                        if let Ok(data) = frame.into_data() {\n                            return Ok(Some(hyper_buf(data)));\n                        } else {\n                            continue;\n                        }\n                    },\n                    Some(Err(e)) => return Err(e),\n                    None => return Ok(None),\n                }\n            }\n        }))\n    } ?= ptr::null_mut()\n}\n\nffi_fn! {\n    /// Creates a task to execute the callback with each body chunk received.\n    ///\n    /// To avoid a memory leak, the task must eventually be consumed by\n    /// `hyper_task_free`, or taken ownership of by `hyper_executor_push`\n    /// without subsequently being given back by `hyper_executor_poll`.\n    ///\n    /// The `hyper_buf` pointer is only a borrowed reference. It cannot live outside\n    /// the execution of the callback. You must make a copy of the bytes to retain them.\n    ///\n    /// The callback should return `HYPER_ITER_CONTINUE` to continue iterating\n    /// chunks as they are received, or `HYPER_ITER_BREAK` to cancel. Each\n    /// invocation of the callback must consume all the bytes it is provided.\n    /// There is no mechanism to signal to Hyper that only a subset of bytes were\n    /// consumed.\n    ///\n    /// This will consume the `hyper_body *`, you shouldn't use it anymore or free it.\n    fn hyper_body_foreach(body: *mut hyper_body, func: hyper_body_foreach_callback, userdata: *mut c_void) -> *mut hyper_task {\n        let mut body = non_null!(Box::from_raw(body) ?= ptr::null_mut());\n        let userdata = UserDataPointer(userdata);\n\n        Box::into_raw(hyper_task::boxed(async move {\n            let _ = &userdata;\n            while let Some(item) = body.0.frame().await {\n                let frame = item?;\n                if let Ok(chunk) = frame.into_data() {\n                    if HYPER_ITER_CONTINUE != func(userdata.0, &hyper_buf(chunk)) {\n                        return Err(crate::Error::new_user_aborted_by_callback());\n                    }\n                }\n            }\n            Ok(())\n        }))\n    } ?= ptr::null_mut()\n}\n\nffi_fn! {\n    /// Set userdata on this body, which will be passed to callback functions.\n    fn hyper_body_set_userdata(body: *mut hyper_body, userdata: *mut c_void) {\n        let b = non_null!(&mut *body ?= ());\n        b.0.as_ffi_mut().userdata = userdata;\n    }\n}\n\nffi_fn! {\n    /// Set the outgoing data callback for this body.\n    ///\n    /// The callback is called each time hyper needs to send more data for the\n    /// body. It is passed the value from `hyper_body_set_userdata`.\n    ///\n    /// If there is data available, the `hyper_buf **` argument should be set\n    /// to a `hyper_buf *` containing the data, and `HYPER_POLL_READY` should\n    /// be returned.\n    ///\n    /// Returning `HYPER_POLL_READY` while the `hyper_buf **` argument points\n    /// to `NULL` will indicate the body has completed all data.\n    ///\n    /// If there is more data to send, but it isn't yet available, a\n    /// `hyper_waker` should be saved from the `hyper_context *` argument, and\n    /// `HYPER_POLL_PENDING` should be returned. You must wake the saved waker\n    /// to signal the task when data is available.\n    ///\n    /// If some error has occurred, you can return `HYPER_POLL_ERROR` to abort\n    /// the body.\n    fn hyper_body_set_data_func(body: *mut hyper_body, func: hyper_body_data_callback) {\n        let b = non_null!{ &mut *body ?= () };\n        b.0.as_ffi_mut().data_func = func;\n    }\n}\n\n// ===== impl UserBody =====\n\nimpl UserBody {\n    pub(crate) fn new() -> UserBody {\n        UserBody {\n            data_func: data_noop,\n            userdata: std::ptr::null_mut(),\n        }\n    }\n\n    pub(crate) fn poll_data(\n        &mut self,\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<crate::Result<Frame<Bytes>>>> {\n        let mut out = std::ptr::null_mut();\n        match (self.data_func)(self.userdata, hyper_context::wrap(cx), &mut out) {\n            super::task::HYPER_POLL_READY => {\n                if out.is_null() {\n                    Poll::Ready(None)\n                } else {\n                    let buf = unsafe { Box::from_raw(out) };\n                    Poll::Ready(Some(Ok(Frame::data(buf.0))))\n                }\n            }\n            super::task::HYPER_POLL_PENDING => Poll::Pending,\n            super::task::HYPER_POLL_ERROR => {\n                Poll::Ready(Some(Err(crate::Error::new_body_write_aborted())))\n            }\n            unexpected => Poll::Ready(Some(Err(crate::Error::new_body_write(format!(\n                \"unexpected hyper_body_data_func return code {}\",\n                unexpected\n            ))))),\n        }\n    }\n}\n\n/// cbindgen:ignore\nextern \"C\" fn data_noop(\n    _userdata: *mut c_void,\n    _: *mut hyper_context<'_>,\n    _: *mut *mut hyper_buf,\n) -> c_int {\n    super::task::HYPER_POLL_READY\n}\n\nunsafe impl Send for UserBody {}\nunsafe impl Sync for UserBody {}\n\n// ===== Bytes =====\n\nffi_fn! {\n    /// Create a new `hyper_buf *` by copying the provided bytes.\n    ///\n    /// This makes an owned copy of the bytes, so the `buf` argument can be\n    /// freed (with `hyper_buf_free`) or changed afterwards.\n    ///\n    /// To avoid a memory leak, the copy must eventually be consumed by\n    /// `hyper_buf_free`.\n    ///\n    /// This returns `NULL` if allocating a new buffer fails.\n    fn hyper_buf_copy(buf: *const u8, len: size_t) -> *mut hyper_buf {\n        let slice = unsafe {\n            std::slice::from_raw_parts(buf, len)\n        };\n        Box::into_raw(Box::new(hyper_buf(Bytes::copy_from_slice(slice))))\n    } ?= ptr::null_mut()\n}\n\nffi_fn! {\n    /// Get a pointer to the bytes in this buffer.\n    ///\n    /// This should be used in conjunction with `hyper_buf_len` to get the length\n    /// of the bytes data.\n    ///\n    /// This pointer is borrowed data, and not valid once the `hyper_buf` is\n    /// consumed/freed.\n    fn hyper_buf_bytes(buf: *const hyper_buf) -> *const u8 {\n        unsafe { (*buf).0.as_ptr() }\n    } ?= ptr::null()\n}\n\nffi_fn! {\n    /// Get the length of the bytes this buffer contains.\n    fn hyper_buf_len(buf: *const hyper_buf) -> size_t {\n        unsafe { (*buf).0.len() }\n    }\n}\n\nffi_fn! {\n    /// Free this buffer.\n    ///\n    /// This should be used for any buffer once it is no longer needed.\n    fn hyper_buf_free(buf: *mut hyper_buf) {\n        drop(unsafe { Box::from_raw(buf) });\n    }\n}\n\nunsafe impl AsTaskType for hyper_buf {\n    fn as_task_type(&self) -> hyper_task_return_type {\n        hyper_task_return_type::HYPER_TASK_BUF\n    }\n}\n"
  },
  {
    "path": "src/ffi/client.rs",
    "content": "use std::ffi::c_int;\nuse std::ptr;\nuse std::sync::Arc;\n\nuse crate::client::conn;\nuse crate::rt::Executor as _;\n\nuse super::error::hyper_code;\nuse super::http_types::{hyper_request, hyper_response};\nuse super::io::hyper_io;\nuse super::task::{hyper_executor, hyper_task, hyper_task_return_type, AsTaskType, WeakExec};\n\n/// An options builder to configure an HTTP client connection.\n///\n/// Methods:\n///\n/// - hyper_clientconn_options_new:     Creates a new set of HTTP clientconn options to be used in a handshake.\n/// - hyper_clientconn_options_exec:    Set the client background task executor.\n/// - hyper_clientconn_options_http2:   Set whether to use HTTP2.\n/// - hyper_clientconn_options_set_preserve_header_case:  Set whether header case is preserved.\n/// - hyper_clientconn_options_set_preserve_header_order: Set whether header order is preserved.\n/// - hyper_clientconn_options_http1_allow_multiline_headers: Set whether HTTP/1 connections accept obsolete line folding for header values.\n/// - hyper_clientconn_options_free:    Free a set of HTTP clientconn options.\npub struct hyper_clientconn_options {\n    http1_allow_obsolete_multiline_headers_in_responses: bool,\n    http1_preserve_header_case: bool,\n    http1_preserve_header_order: bool,\n    http2: bool,\n    /// Use a `Weak` to prevent cycles.\n    exec: WeakExec,\n}\n\n/// An HTTP client connection handle.\n///\n/// These are used to send one or more requests on a single connection.\n///\n/// It's possible to send multiple requests on a single connection, such\n/// as when HTTP/1 keep-alive or HTTP/2 is used.\n///\n/// To create a `hyper_clientconn`:\n///\n///   1. Create a `hyper_io` with `hyper_io_new`.\n///   2. Create a `hyper_clientconn_options` with `hyper_clientconn_options_new`.\n///   3. Call `hyper_clientconn_handshake` with the `hyper_io` and `hyper_clientconn_options`.\n///      This creates a `hyper_task`.\n///   5. Call `hyper_task_set_userdata` to assign an application-specific pointer to the task.\n///      This allows keeping track of multiple connections that may be handshaking\n///      simultaneously.\n///   4. Add the `hyper_task` to an executor with `hyper_executor_push`.\n///   5. Poll that executor until it yields a task of type `HYPER_TASK_CLIENTCONN`.\n///   6. Extract the `hyper_clientconn` from the task with `hyper_task_value`.\n///      This will require a cast from `void *` to `hyper_clientconn *`.\n///\n/// This process results in a `hyper_clientconn` that permanently owns the\n/// `hyper_io`. Because the `hyper_io` in turn owns a TCP or TLS connection, that means\n/// the `hyper_clientconn` owns the connection for both the clientconn's lifetime\n/// and the connection's lifetime.\n///\n/// In other words, each connection (`hyper_io`) must have exactly one `hyper_clientconn`\n/// associated with it. That's because `hyper_clientconn_handshake` sends the\n/// [HTTP/2 Connection Preface] (for HTTP/2 connections). Since that preface can't\n/// be sent twice, handshake can't be called twice.\n///\n/// [HTTP/2 Connection Preface]: https://datatracker.ietf.org/doc/html/rfc9113#name-http-2-connection-preface\n///\n/// Methods:\n///\n/// - hyper_clientconn_handshake:  Creates an HTTP client handshake task.\n/// - hyper_clientconn_send:       Creates a task to send a request on the client connection.\n/// - hyper_clientconn_free:       Free a hyper_clientconn *.\npub struct hyper_clientconn {\n    tx: Tx,\n}\n\nenum Tx {\n    #[cfg(feature = \"http1\")]\n    Http1(conn::http1::SendRequest<crate::body::Incoming>),\n    #[cfg(feature = \"http2\")]\n    Http2(conn::http2::SendRequest<crate::body::Incoming>),\n}\n\n// ===== impl hyper_clientconn =====\n\nffi_fn! {\n    /// Creates an HTTP client handshake task.\n    ///\n    /// Both the `io` and the `options` are consumed in this function call.\n    /// They should not be used or freed afterwards.\n    ///\n    /// The returned task must be polled with an executor until the handshake\n    /// completes, at which point the value can be taken.\n    ///\n    /// To avoid a memory leak, the task must eventually be consumed by\n    /// `hyper_task_free`, or taken ownership of by `hyper_executor_push`\n    /// without subsequently being given back by `hyper_executor_poll`.\n    fn hyper_clientconn_handshake(io: *mut hyper_io, options: *mut hyper_clientconn_options) -> *mut hyper_task {\n        let options = non_null! { Box::from_raw(options) ?= ptr::null_mut() };\n        let io = non_null! { Box::from_raw(io) ?= ptr::null_mut() };\n\n        Box::into_raw(hyper_task::boxed(async move {\n            #[cfg(feature = \"http2\")]\n            {\n            if options.http2 {\n                return conn::http2::Builder::new(options.exec.clone())\n                    .handshake::<_, crate::body::Incoming>(io)\n                    .await\n                    .map(|(tx, conn)| {\n                        options.exec.execute(Box::pin(async move {\n                            let _ = conn.await;\n                        }));\n                        hyper_clientconn { tx: Tx::Http2(tx) }\n                    });\n                }\n            }\n\n            conn::http1::Builder::new()\n                .allow_obsolete_multiline_headers_in_responses(options.http1_allow_obsolete_multiline_headers_in_responses)\n                .preserve_header_case(options.http1_preserve_header_case)\n                .preserve_header_order(options.http1_preserve_header_order)\n                .handshake::<_, crate::body::Incoming>(io)\n                .await\n                .map(|(tx, conn)| {\n                    options.exec.execute(Box::pin(async move {\n                        let _ = conn.await;\n                    }));\n                    hyper_clientconn { tx: Tx::Http1(tx) }\n                })\n        }))\n    } ?= std::ptr::null_mut()\n}\n\nffi_fn! {\n    /// Creates a task to send a request on the client connection.\n    ///\n    /// This consumes the request. You should not use or free the request\n    /// afterwards.\n    ///\n    /// Returns a task that needs to be polled until it is ready. When ready, the\n    /// task yields a `hyper_response *`.\n    ///\n    /// To avoid a memory leak, the task must eventually be consumed by\n    /// `hyper_task_free`, or taken ownership of by `hyper_executor_push`\n    /// without subsequently being given back by `hyper_executor_poll`.\n    fn hyper_clientconn_send(conn: *mut hyper_clientconn, req: *mut hyper_request) -> *mut hyper_task {\n        let mut req = non_null! { Box::from_raw(req) ?= ptr::null_mut() };\n\n        // Update request with original-case map of headers\n        req.finalize_request();\n\n        let fut = match non_null! { &mut *conn ?= ptr::null_mut() }.tx {\n            Tx::Http1(ref mut tx) => futures_util::future::Either::Left(tx.send_request(req.0)),\n            Tx::Http2(ref mut tx) => futures_util::future::Either::Right(tx.send_request(req.0)),\n        };\n\n        let fut = async move {\n            fut.await.map(hyper_response::wrap)\n        };\n\n        Box::into_raw(hyper_task::boxed(fut))\n    } ?= std::ptr::null_mut()\n}\n\nffi_fn! {\n    /// Free a `hyper_clientconn *`.\n    ///\n    /// This should be used for any connection once it is no longer needed.\n    fn hyper_clientconn_free(conn: *mut hyper_clientconn) {\n        drop(non_null! { Box::from_raw(conn) ?= () });\n    }\n}\n\nunsafe impl AsTaskType for hyper_clientconn {\n    fn as_task_type(&self) -> hyper_task_return_type {\n        hyper_task_return_type::HYPER_TASK_CLIENTCONN\n    }\n}\n\n// ===== impl hyper_clientconn_options =====\n\nffi_fn! {\n    /// Creates a new set of HTTP clientconn options to be used in a handshake.\n    ///\n    /// To avoid a memory leak, the options must eventually be consumed by\n    /// `hyper_clientconn_options_free` or `hyper_clientconn_handshake`.\n    fn hyper_clientconn_options_new() -> *mut hyper_clientconn_options {\n        Box::into_raw(Box::new(hyper_clientconn_options {\n            http1_allow_obsolete_multiline_headers_in_responses: false,\n            http1_preserve_header_case: false,\n            http1_preserve_header_order: false,\n            http2: false,\n            exec: WeakExec::new(),\n        }))\n    } ?= std::ptr::null_mut()\n}\n\nffi_fn! {\n    /// Set whether header case is preserved.\n    ///\n    /// Pass `0` to allow lowercase normalization (default), `1` to retain original case.\n    fn hyper_clientconn_options_set_preserve_header_case(opts: *mut hyper_clientconn_options, enabled: c_int) {\n        let opts = non_null! { &mut *opts ?= () };\n        opts.http1_preserve_header_case = enabled != 0;\n    }\n}\n\nffi_fn! {\n    /// Set whether header order is preserved.\n    ///\n    /// Pass `0` to allow reordering (default), `1` to retain original ordering.\n    fn hyper_clientconn_options_set_preserve_header_order(opts: *mut hyper_clientconn_options, enabled: c_int) {\n        let opts = non_null! { &mut *opts ?= () };\n        opts.http1_preserve_header_order = enabled != 0;\n    }\n}\n\nffi_fn! {\n    /// Free a set of HTTP clientconn options.\n    ///\n    /// This should only be used if the options aren't consumed by\n    /// `hyper_clientconn_handshake`.\n    fn hyper_clientconn_options_free(opts: *mut hyper_clientconn_options) {\n        drop(non_null! { Box::from_raw(opts) ?= () });\n    }\n}\n\nffi_fn! {\n    /// Set the client background task executor.\n    ///\n    /// This does not consume the `options` or the `exec`.\n    fn hyper_clientconn_options_exec(opts: *mut hyper_clientconn_options, exec: *const hyper_executor) {\n        let opts = non_null! { &mut *opts ?= () };\n\n        let exec = non_null! { Arc::from_raw(exec) ?= () };\n        let weak_exec = hyper_executor::downgrade(&exec);\n        std::mem::forget(exec);\n\n        opts.exec = weak_exec;\n    }\n}\n\nffi_fn! {\n    /// Set whether to use HTTP2.\n    ///\n    /// Pass `0` to disable, `1` to enable.\n    fn hyper_clientconn_options_http2(opts: *mut hyper_clientconn_options, enabled: c_int) -> hyper_code {\n        #[cfg(feature = \"http2\")]\n        {\n            let opts = non_null! { &mut *opts ?= hyper_code::HYPERE_INVALID_ARG };\n            opts.http2 = enabled != 0;\n            hyper_code::HYPERE_OK\n        }\n\n        #[cfg(not(feature = \"http2\"))]\n        {\n            drop(opts);\n            drop(enabled);\n            hyper_code::HYPERE_FEATURE_NOT_ENABLED\n        }\n    }\n}\n\nffi_fn! {\n    /// Set whether HTTP/1 connections accept obsolete line folding for header values.\n    ///\n    /// Newline codepoints (\\r and \\n) will be transformed to spaces when parsing.\n    ///\n    /// Pass `0` to disable, `1` to enable.\n    ///\n    fn hyper_clientconn_options_http1_allow_multiline_headers(opts: *mut hyper_clientconn_options, enabled: c_int) -> hyper_code {\n        let opts = non_null! { &mut *opts ?= hyper_code::HYPERE_INVALID_ARG };\n        opts.http1_allow_obsolete_multiline_headers_in_responses = enabled != 0;\n        hyper_code::HYPERE_OK\n    }\n}\n"
  },
  {
    "path": "src/ffi/error.rs",
    "content": "use crate::ffi::size_t;\n\n/// A more detailed error object returned by some hyper functions.\n///\n/// Compare with `hyper_code`, which is a simpler error returned from\n/// some hyper functions.\n///\n/// Methods:\n///\n/// - hyper_error_code:  Get an equivalent hyper_code from this error.\n/// - hyper_error_print: Print the details of this error to a buffer.\n/// - hyper_error_free:  Frees a hyper_error.\npub struct hyper_error(crate::Error);\n\n/// A return code for many of hyper's methods.\n#[repr(C)]\npub enum hyper_code {\n    /// All is well.\n    HYPERE_OK,\n    /// General error, details in the `hyper_error *`.\n    HYPERE_ERROR,\n    /// A function argument was invalid.\n    HYPERE_INVALID_ARG,\n    /// The IO transport returned an EOF when one wasn't expected.\n    ///\n    /// This typically means an HTTP request or response was expected, but the\n    /// connection closed cleanly without sending (all of) it.\n    HYPERE_UNEXPECTED_EOF,\n    /// Aborted by a user supplied callback.\n    HYPERE_ABORTED_BY_CALLBACK,\n    /// An optional hyper feature was not enabled.\n    #[cfg_attr(feature = \"http2\", allow(unused))]\n    HYPERE_FEATURE_NOT_ENABLED,\n    /// The peer sent an HTTP message that could not be parsed.\n    HYPERE_INVALID_PEER_MESSAGE,\n}\n\n// ===== impl hyper_error =====\n\nimpl hyper_error {\n    fn code(&self) -> hyper_code {\n        use crate::error::Kind as ErrorKind;\n        use crate::error::User;\n\n        match self.0.kind() {\n            ErrorKind::Parse(_) => hyper_code::HYPERE_INVALID_PEER_MESSAGE,\n            ErrorKind::IncompleteMessage => hyper_code::HYPERE_UNEXPECTED_EOF,\n            ErrorKind::User(User::AbortedByCallback) => hyper_code::HYPERE_ABORTED_BY_CALLBACK,\n            // TODO: add more variants\n            _ => hyper_code::HYPERE_ERROR,\n        }\n    }\n\n    fn print_to(&self, dst: &mut [u8]) -> usize {\n        use std::io::Write;\n\n        let mut dst = std::io::Cursor::new(dst);\n\n        // A write! error doesn't matter. As much as possible will have been\n        // written, and the Cursor position will know how far that is (even\n        // if that is zero).\n        let _ = write!(dst, \"{}\", &self.0);\n        dst.position() as usize\n    }\n}\n\nffi_fn! {\n    /// Frees a `hyper_error`.\n    ///\n    /// This should be used for any error once it is no longer needed.\n    fn hyper_error_free(err: *mut hyper_error) {\n        drop(non_null!(Box::from_raw(err) ?= ()));\n    }\n}\n\nffi_fn! {\n    /// Get an equivalent `hyper_code` from this error.\n    fn hyper_error_code(err: *const hyper_error) -> hyper_code {\n        non_null!(&*err ?= hyper_code::HYPERE_INVALID_ARG).code()\n    }\n}\n\nffi_fn! {\n    /// Print the details of this error to a buffer.\n    ///\n    /// The `dst_len` value must be the maximum length that the buffer can\n    /// store.\n    ///\n    /// The return value is number of bytes that were written to `dst`.\n    fn hyper_error_print(err: *const hyper_error, dst: *mut u8, dst_len: size_t) -> size_t {\n        let dst = unsafe {\n            std::slice::from_raw_parts_mut(dst, dst_len)\n        };\n        non_null!(&*err ?= 0).print_to(dst)\n    }\n}\n"
  },
  {
    "path": "src/ffi/http_types.rs",
    "content": "use std::ffi::{c_int, c_void};\n\nuse bytes::Bytes;\n\nuse super::body::hyper_body;\nuse super::error::hyper_code;\nuse super::task::{hyper_task_return_type, AsTaskType};\nuse super::{UserDataPointer, HYPER_ITER_CONTINUE};\nuse crate::body::Incoming as IncomingBody;\nuse crate::ext::{HeaderCaseMap, OriginalHeaderOrder, ReasonPhrase};\nuse crate::ffi::size_t;\nuse crate::header::{HeaderName, HeaderValue};\nuse crate::{HeaderMap, Method, Request, Response, Uri};\n\n/// An HTTP request.\n///\n/// Once you've finished constructing a request, you can send it with\n/// `hyper_clientconn_send`.\n///\n/// Methods:\n///\n/// - hyper_request_new:              Construct a new HTTP request.\n/// - hyper_request_headers:          Gets a mutable reference to the HTTP headers of this request\n/// - hyper_request_set_body:         Set the body of the request.\n/// - hyper_request_set_method:       Set the HTTP Method of the request.\n/// - hyper_request_set_uri:          Set the URI of the request.\n/// - hyper_request_set_uri_parts:    Set the URI of the request with separate scheme, authority, and path/query strings.\n/// - hyper_request_set_version:      Set the preferred HTTP version of the request.\n/// - hyper_request_on_informational: Set an informational (1xx) response callback.\n/// - hyper_request_free:             Free an HTTP request.\npub struct hyper_request(pub(super) Request<IncomingBody>);\n\n/// An HTTP response.\n///\n/// Obtain one of these by making a request with `hyper_clientconn_send`, then\n/// polling the executor unntil you get a `hyper_task` of type\n/// `HYPER_TASK_RESPONSE`. To figure out which request this response\n/// corresponds to, check the userdata of the task, which you should\n/// previously have set to an application-specific identifier for the\n/// request.\n///\n/// Methods:\n///\n/// - hyper_response_status:            Get the HTTP-Status code of this response.\n/// - hyper_response_version:           Get the HTTP version used by this response.\n/// - hyper_response_reason_phrase:     Get a pointer to the reason-phrase of this response.\n/// - hyper_response_reason_phrase_len: Get the length of the reason-phrase of this response.\n/// - hyper_response_headers:           Gets a reference to the HTTP headers of this response.\n/// - hyper_response_body:              Take ownership of the body of this response.\n/// - hyper_response_free:              Free an HTTP response.\npub struct hyper_response(pub(super) Response<IncomingBody>);\n\n/// An HTTP header map.\n///\n/// These can be part of a request or response.\n///\n/// Obtain a pointer to read or modify these from `hyper_request_headers`\n/// or `hyper_response_headers`.\n///\n/// Methods:\n///\n/// - hyper_headers_add:     Adds the provided value to the list of the provided name.\n/// - hyper_headers_foreach: Iterates the headers passing each name and value pair to the callback.\n/// - hyper_headers_set:     Sets the header with the provided name to the provided value.\n#[derive(Clone)]\npub struct hyper_headers {\n    pub(super) headers: HeaderMap,\n    orig_casing: HeaderCaseMap,\n    orig_order: OriginalHeaderOrder,\n}\n\n#[derive(Clone)]\nstruct OnInformational {\n    func: hyper_request_on_informational_callback,\n    data: UserDataPointer,\n}\n\ntype hyper_request_on_informational_callback = extern \"C\" fn(*mut c_void, *mut hyper_response);\n\n// ===== impl hyper_request =====\n\nffi_fn! {\n    /// Construct a new HTTP request.\n    ///\n    /// The default request has an empty body. To send a body, call `hyper_request_set_body`.\n    ///\n    ///\n    /// To avoid a memory leak, the request must eventually be consumed by\n    /// `hyper_request_free` or `hyper_clientconn_send`.\n    fn hyper_request_new() -> *mut hyper_request {\n        Box::into_raw(Box::new(hyper_request(Request::new(IncomingBody::empty()))))\n    } ?= std::ptr::null_mut()\n}\n\nffi_fn! {\n    /// Free an HTTP request.\n    ///\n    /// This should only be used if the request isn't consumed by\n    /// `hyper_clientconn_send`.\n    fn hyper_request_free(req: *mut hyper_request) {\n        drop(non_null!(Box::from_raw(req) ?= ()));\n    }\n}\n\nffi_fn! {\n    /// Set the HTTP Method of the request.\n    fn hyper_request_set_method(req: *mut hyper_request, method: *const u8, method_len: size_t) -> hyper_code {\n        let bytes = unsafe {\n            std::slice::from_raw_parts(method, method_len as usize)\n        };\n        let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);\n        match Method::from_bytes(bytes) {\n            Ok(m) => {\n                *req.0.method_mut() = m;\n                hyper_code::HYPERE_OK\n            },\n            Err(_) => {\n                hyper_code::HYPERE_INVALID_ARG\n            }\n        }\n    }\n}\n\nffi_fn! {\n    /// Set the URI of the request.\n    ///\n    /// The request's URI is best described as the `request-target` from the RFCs. So in HTTP/1,\n    /// whatever is set will get sent as-is in the first line (GET $uri HTTP/1.1). It\n    /// supports the 4 defined variants, origin-form, absolute-form, authority-form, and\n    /// asterisk-form.\n    ///\n    /// The underlying type was built to efficiently support HTTP/2 where the request-target is\n    /// split over :scheme, :authority, and :path. As such, each part can be set explicitly, or the\n    /// type can parse a single contiguous string and if a scheme is found, that slot is \"set\". If\n    /// the string just starts with a path, only the path portion is set. All pseudo headers that\n    /// have been parsed/set are sent when the connection type is HTTP/2.\n    ///\n    /// To set each slot explicitly, use `hyper_request_set_uri_parts`.\n    fn hyper_request_set_uri(req: *mut hyper_request, uri: *const u8, uri_len: size_t) -> hyper_code {\n        let bytes = unsafe {\n            std::slice::from_raw_parts(uri, uri_len as usize)\n        };\n        let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);\n        match Uri::from_maybe_shared(bytes) {\n            Ok(u) => {\n                *req.0.uri_mut() = u;\n                hyper_code::HYPERE_OK\n            },\n            Err(_) => {\n                hyper_code::HYPERE_INVALID_ARG\n            }\n        }\n    }\n}\n\nffi_fn! {\n    /// Set the URI of the request with separate scheme, authority, and\n    /// path/query strings.\n    ///\n    /// Each of `scheme`, `authority`, and `path_and_query` should either be\n    /// null, to skip providing a component, or point to a UTF-8 encoded\n    /// string. If any string pointer argument is non-null, its corresponding\n    /// `len` parameter must be set to the string's length.\n    fn hyper_request_set_uri_parts(\n        req: *mut hyper_request,\n        scheme: *const u8,\n        scheme_len: size_t,\n        authority: *const u8,\n        authority_len: size_t,\n        path_and_query: *const u8,\n        path_and_query_len: size_t\n    ) -> hyper_code {\n        let mut builder = Uri::builder();\n        if !scheme.is_null() {\n            let scheme_bytes = unsafe {\n                std::slice::from_raw_parts(scheme, scheme_len as usize)\n            };\n            builder = builder.scheme(scheme_bytes);\n        }\n        if !authority.is_null() {\n            let authority_bytes = unsafe {\n                std::slice::from_raw_parts(authority, authority_len as usize)\n            };\n            builder = builder.authority(authority_bytes);\n        }\n        if !path_and_query.is_null() {\n            let path_and_query_bytes = unsafe {\n                std::slice::from_raw_parts(path_and_query, path_and_query_len as usize)\n            };\n            builder = builder.path_and_query(path_and_query_bytes);\n        }\n        let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);\n        match builder.build() {\n            Ok(u) => {\n                *req.0.uri_mut() = u;\n                hyper_code::HYPERE_OK\n            },\n            Err(_) => {\n                hyper_code::HYPERE_INVALID_ARG\n            }\n        }\n    }\n}\n\nffi_fn! {\n    /// Set the preferred HTTP version of the request.\n    ///\n    /// The version value should be one of the `HYPER_HTTP_VERSION_` constants.\n    ///\n    /// Note that this won't change the major HTTP version of the connection,\n    /// since that is determined at the handshake step.\n    fn hyper_request_set_version(req: *mut hyper_request, version: c_int) -> hyper_code {\n        use http::Version;\n\n        let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);\n        *req.0.version_mut() = match version {\n            super::HYPER_HTTP_VERSION_NONE => Version::HTTP_11,\n            super::HYPER_HTTP_VERSION_1_0 => Version::HTTP_10,\n            super::HYPER_HTTP_VERSION_1_1 => Version::HTTP_11,\n            super::HYPER_HTTP_VERSION_2 => Version::HTTP_2,\n            _ => {\n                // We don't know this version\n                return hyper_code::HYPERE_INVALID_ARG;\n            }\n        };\n        hyper_code::HYPERE_OK\n    }\n}\n\nffi_fn! {\n    /// Gets a mutable reference to the HTTP headers of this request\n    ///\n    /// This is not an owned reference, so it should not be accessed after the\n    /// `hyper_request` has been consumed.\n    fn hyper_request_headers(req: *mut hyper_request) -> *mut hyper_headers {\n        let req = non_null!(&mut *req ?= std::ptr::null_mut());\n        hyper_headers::get_or_default(req.0.extensions_mut())\n    } ?= std::ptr::null_mut()\n}\n\nffi_fn! {\n    /// Set the body of the request.\n    ///\n    /// You can get a `hyper_body` by calling `hyper_body_new`.\n    ///\n    /// This takes ownership of the `hyper_body *`, you must not use it or\n    /// free it after setting it on the request.\n    fn hyper_request_set_body(req: *mut hyper_request, body: *mut hyper_body) -> hyper_code {\n        let body = non_null!(Box::from_raw(body) ?= hyper_code::HYPERE_INVALID_ARG);\n        let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);\n        *req.0.body_mut() = body.0;\n        hyper_code::HYPERE_OK\n    }\n}\n\nffi_fn! {\n    /// Set an informational (1xx) response callback.\n    ///\n    /// The callback is called each time hyper receives an informational (1xx)\n    /// response for this request.\n    ///\n    /// The third argument is an opaque user data pointer, which is passed to\n    /// the callback each time.\n    ///\n    /// The callback is passed the `void *` data pointer, and a\n    /// `hyper_response *` which can be inspected as any other response. The\n    /// body of the response will always be empty.\n    ///\n    /// NOTE: The `hyper_response *` is just borrowed data, and will not\n    /// be valid after the callback finishes. You must copy any data you wish\n    /// to persist.\n    fn hyper_request_on_informational(req: *mut hyper_request, callback: hyper_request_on_informational_callback, data: *mut c_void) -> hyper_code {\n        #[cfg(feature = \"client\")]\n        {\n        let ext = OnInformational {\n            func: callback,\n            data: UserDataPointer(data),\n        };\n        let req = non_null!(&mut *req ?= hyper_code::HYPERE_INVALID_ARG);\n        crate::ext::on_informational_raw(&mut req.0, ext);\n        hyper_code::HYPERE_OK\n        }\n        #[cfg(not(feature = \"client\"))]\n        {\n        drop((req, callback, data));\n        hyper_code::HYPERE_FEATURE_NOT_ENABLED\n        }\n    }\n}\n\nimpl hyper_request {\n    pub(super) fn finalize_request(&mut self) {\n        if let Some(headers) = self.0.extensions_mut().remove::<hyper_headers>() {\n            *self.0.headers_mut() = headers.headers;\n            self.0.extensions_mut().insert(headers.orig_casing);\n            self.0.extensions_mut().insert(headers.orig_order);\n        }\n    }\n}\n\n// ===== impl hyper_response =====\n\nffi_fn! {\n    /// Free an HTTP response.\n    ///\n    /// This should be used for any response once it is no longer needed.\n    fn hyper_response_free(resp: *mut hyper_response) {\n        drop(non_null!(Box::from_raw(resp) ?= ()));\n    }\n}\n\nffi_fn! {\n    /// Get the HTTP-Status code of this response.\n    ///\n    /// It will always be within the range of 100-599.\n    fn hyper_response_status(resp: *const hyper_response) -> u16 {\n        non_null!(&*resp ?= 0).0.status().as_u16()\n    }\n}\n\nffi_fn! {\n    /// Get a pointer to the reason-phrase of this response.\n    ///\n    /// This buffer is not null-terminated.\n    ///\n    /// This buffer is owned by the response, and should not be used after\n    /// the response has been freed.\n    ///\n    /// Use `hyper_response_reason_phrase_len()` to get the length of this\n    /// buffer.\n    fn hyper_response_reason_phrase(resp: *const hyper_response) -> *const u8 {\n        non_null!(&*resp ?= std::ptr::null()).reason_phrase().as_ptr()\n    } ?= std::ptr::null()\n}\n\nffi_fn! {\n    /// Get the length of the reason-phrase of this response.\n    ///\n    /// Use `hyper_response_reason_phrase()` to get the buffer pointer.\n    fn hyper_response_reason_phrase_len(resp: *const hyper_response) -> size_t {\n        non_null!(&*resp ?= 0).reason_phrase().len()\n    }\n}\n\nffi_fn! {\n    /// Get the HTTP version used by this response.\n    ///\n    /// The returned value could be:\n    ///\n    /// - `HYPER_HTTP_VERSION_1_0`\n    /// - `HYPER_HTTP_VERSION_1_1`\n    /// - `HYPER_HTTP_VERSION_2`\n    /// - `HYPER_HTTP_VERSION_NONE` if newer (or older).\n    fn hyper_response_version(resp: *const hyper_response) -> c_int {\n        use http::Version;\n\n        match non_null!(&*resp ?= 0).0.version() {\n            Version::HTTP_10 => super::HYPER_HTTP_VERSION_1_0,\n            Version::HTTP_11 => super::HYPER_HTTP_VERSION_1_1,\n            Version::HTTP_2 => super::HYPER_HTTP_VERSION_2,\n            _ => super::HYPER_HTTP_VERSION_NONE,\n        }\n    }\n}\n\nffi_fn! {\n    /// Gets a reference to the HTTP headers of this response.\n    ///\n    /// This is not an owned reference, so it should not be accessed after the\n    /// `hyper_response` has been freed.\n    fn hyper_response_headers(resp: *mut hyper_response) -> *mut hyper_headers {\n        let resp = non_null!(&mut *resp ?= std::ptr::null_mut());\n        hyper_headers::get_or_default(resp.0.extensions_mut())\n    } ?= std::ptr::null_mut()\n}\n\nffi_fn! {\n    /// Take ownership of the body of this response.\n    ///\n    /// It is safe to free the response even after taking ownership of its body.\n    ///\n    /// To avoid a memory leak, the body must eventually be consumed by\n    /// `hyper_body_free`, `hyper_body_foreach`, or `hyper_request_set_body`.\n    fn hyper_response_body(resp: *mut hyper_response) -> *mut hyper_body {\n        let body = std::mem::replace(non_null!(&mut *resp ?= std::ptr::null_mut()).0.body_mut(), IncomingBody::empty());\n        Box::into_raw(Box::new(hyper_body(body)))\n    } ?= std::ptr::null_mut()\n}\n\nimpl hyper_response {\n    pub(super) fn wrap(mut resp: Response<IncomingBody>) -> hyper_response {\n        let headers = std::mem::take(resp.headers_mut());\n        let orig_casing = resp\n            .extensions_mut()\n            .remove::<HeaderCaseMap>()\n            .unwrap_or_else(HeaderCaseMap::default);\n        let orig_order = resp\n            .extensions_mut()\n            .remove::<OriginalHeaderOrder>()\n            .unwrap_or_else(OriginalHeaderOrder::default);\n        resp.extensions_mut().insert(hyper_headers {\n            headers,\n            orig_casing,\n            orig_order,\n        });\n\n        hyper_response(resp)\n    }\n\n    fn reason_phrase(&self) -> &[u8] {\n        if let Some(reason) = self.0.extensions().get::<ReasonPhrase>() {\n            return reason.as_bytes();\n        }\n\n        if let Some(reason) = self.0.status().canonical_reason() {\n            return reason.as_bytes();\n        }\n\n        &[]\n    }\n}\n\nunsafe impl AsTaskType for hyper_response {\n    fn as_task_type(&self) -> hyper_task_return_type {\n        hyper_task_return_type::HYPER_TASK_RESPONSE\n    }\n}\n\n// ===== impl Headers =====\n\ntype hyper_headers_foreach_callback =\n    extern \"C\" fn(*mut c_void, *const u8, size_t, *const u8, size_t) -> c_int;\n\nimpl hyper_headers {\n    pub(super) fn get_or_default(ext: &mut http::Extensions) -> &mut hyper_headers {\n        if let None = ext.get_mut::<hyper_headers>() {\n            ext.insert(hyper_headers::default());\n        }\n\n        ext.get_mut::<hyper_headers>().unwrap()\n    }\n}\n\nffi_fn! {\n    /// Iterates the headers passing each name and value pair to the callback.\n    ///\n    /// The `userdata` pointer is also passed to the callback.\n    ///\n    /// The callback should return `HYPER_ITER_CONTINUE` to keep iterating, or\n    /// `HYPER_ITER_BREAK` to stop.\n    fn hyper_headers_foreach(headers: *const hyper_headers, func: hyper_headers_foreach_callback, userdata: *mut c_void) {\n        let headers = non_null!(&*headers ?= ());\n        // For each header name/value pair, there may be a value in the casemap\n        // that corresponds to the HeaderValue. So, we iterator all the keys,\n        // and for each one, try to pair the originally cased name with the value.\n        //\n        // TODO: consider adding http::HeaderMap::entries() iterator\n        let mut ordered_iter =  headers.orig_order.get_in_order().peekable();\n        if ordered_iter.peek().is_some() {\n            for (name, idx) in ordered_iter {\n                let (name_ptr, name_len) = if let Some(orig_name) = headers.orig_casing.get_all(name).nth(*idx) {\n                    (orig_name.as_ref().as_ptr(), orig_name.as_ref().len())\n                } else {\n                    (\n                    name.as_str().as_bytes().as_ptr(),\n                    name.as_str().as_bytes().len(),\n                    )\n                };\n\n                let val_ptr;\n                let val_len;\n                if let Some(value) = headers.headers.get_all(name).iter().nth(*idx) {\n                    val_ptr = value.as_bytes().as_ptr();\n                    val_len = value.as_bytes().len();\n                } else {\n                    // Stop iterating, something has gone wrong.\n                    return;\n                }\n\n                if HYPER_ITER_CONTINUE != func(userdata, name_ptr, name_len, val_ptr, val_len) {\n                    return;\n                }\n            }\n        } else {\n            for name in headers.headers.keys() {\n                let mut names = headers.orig_casing.get_all(name);\n\n                for value in headers.headers.get_all(name) {\n                    let (name_ptr, name_len) = if let Some(orig_name) = names.next() {\n                        (orig_name.as_ref().as_ptr(), orig_name.as_ref().len())\n                    } else {\n                        (\n                            name.as_str().as_bytes().as_ptr(),\n                            name.as_str().as_bytes().len(),\n                        )\n                    };\n\n                    let val_ptr = value.as_bytes().as_ptr();\n                    let val_len = value.as_bytes().len();\n\n                    if HYPER_ITER_CONTINUE != func(userdata, name_ptr, name_len, val_ptr, val_len) {\n                        return;\n                    }\n                }\n            }\n        }\n    }\n}\n\nffi_fn! {\n    /// Sets the header with the provided name to the provided value.\n    ///\n    /// This overwrites any previous value set for the header.\n    fn hyper_headers_set(headers: *mut hyper_headers, name: *const u8, name_len: size_t, value: *const u8, value_len: size_t) -> hyper_code {\n        let headers = non_null!(&mut *headers ?= hyper_code::HYPERE_INVALID_ARG);\n        match unsafe { raw_name_value(name, name_len, value, value_len) } {\n            Ok((name, value, orig_name)) => {\n                headers.headers.insert(&name, value);\n                headers.orig_casing.insert(name.clone(), orig_name.clone());\n                headers.orig_order.insert(name);\n                hyper_code::HYPERE_OK\n            }\n            Err(code) => code,\n        }\n    }\n}\n\nffi_fn! {\n    /// Adds the provided value to the list of the provided name.\n    ///\n    /// If there were already existing values for the name, this will append the\n    /// new value to the internal list.\n    fn hyper_headers_add(headers: *mut hyper_headers, name: *const u8, name_len: size_t, value: *const u8, value_len: size_t) -> hyper_code {\n        let headers = non_null!(&mut *headers ?= hyper_code::HYPERE_INVALID_ARG);\n\n        match unsafe { raw_name_value(name, name_len, value, value_len) } {\n            Ok((name, value, orig_name)) => {\n                headers.headers.append(&name, value);\n                headers.orig_casing.append(&name, orig_name.clone());\n                headers.orig_order.append(name);\n                hyper_code::HYPERE_OK\n            }\n            Err(code) => code,\n        }\n    }\n}\n\nimpl Default for hyper_headers {\n    fn default() -> Self {\n        Self {\n            headers: Default::default(),\n            orig_casing: HeaderCaseMap::default(),\n            orig_order: OriginalHeaderOrder::default(),\n        }\n    }\n}\n\nunsafe fn raw_name_value(\n    name: *const u8,\n    name_len: size_t,\n    value: *const u8,\n    value_len: size_t,\n) -> Result<(HeaderName, HeaderValue, Bytes), hyper_code> {\n    let name = std::slice::from_raw_parts(name, name_len);\n    let orig_name = Bytes::copy_from_slice(name);\n    let name = match HeaderName::from_bytes(name) {\n        Ok(name) => name,\n        Err(_) => return Err(hyper_code::HYPERE_INVALID_ARG),\n    };\n    let value = std::slice::from_raw_parts(value, value_len);\n    let value = match HeaderValue::from_bytes(value) {\n        Ok(val) => val,\n        Err(_) => return Err(hyper_code::HYPERE_INVALID_ARG),\n    };\n\n    Ok((name, value, orig_name))\n}\n\n// ===== impl OnInformational =====\n\n#[cfg(feature = \"client\")]\nimpl crate::ext::OnInformationalCallback for OnInformational {\n    fn on_informational(&self, res: http::Response<()>) {\n        let res = res.map(|()| IncomingBody::empty());\n        let mut res = hyper_response::wrap(res);\n        (self.func)(self.data.0, &mut res);\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_headers_foreach_cases_preserved() {\n        let mut headers = hyper_headers::default();\n\n        let name1 = b\"Set-CookiE\";\n        let value1 = b\"a=b\";\n        hyper_headers_add(\n            &mut headers,\n            name1.as_ptr(),\n            name1.len(),\n            value1.as_ptr(),\n            value1.len(),\n        );\n\n        let name2 = b\"SET-COOKIE\";\n        let value2 = b\"c=d\";\n        hyper_headers_add(\n            &mut headers,\n            name2.as_ptr(),\n            name2.len(),\n            value2.as_ptr(),\n            value2.len(),\n        );\n\n        let mut vec = Vec::<u8>::new();\n        hyper_headers_foreach(&headers, concat, &mut vec as *mut _ as *mut c_void);\n\n        assert_eq!(vec, b\"Set-CookiE: a=b\\r\\nSET-COOKIE: c=d\\r\\n\");\n\n        extern \"C\" fn concat(\n            vec: *mut c_void,\n            name: *const u8,\n            name_len: usize,\n            value: *const u8,\n            value_len: usize,\n        ) -> c_int {\n            unsafe {\n                let vec = &mut *(vec as *mut Vec<u8>);\n                let name = std::slice::from_raw_parts(name, name_len);\n                let value = std::slice::from_raw_parts(value, value_len);\n                vec.extend(name);\n                vec.extend(b\": \");\n                vec.extend(value);\n                vec.extend(b\"\\r\\n\");\n            }\n            HYPER_ITER_CONTINUE\n        }\n    }\n\n    #[cfg(all(feature = \"http1\", feature = \"ffi\"))]\n    #[test]\n    fn test_headers_foreach_order_preserved() {\n        let mut headers = hyper_headers::default();\n\n        let name1 = b\"Set-CookiE\";\n        let value1 = b\"a=b\";\n        hyper_headers_add(\n            &mut headers,\n            name1.as_ptr(),\n            name1.len(),\n            value1.as_ptr(),\n            value1.len(),\n        );\n\n        let name2 = b\"Content-Encoding\";\n        let value2 = b\"gzip\";\n        hyper_headers_add(\n            &mut headers,\n            name2.as_ptr(),\n            name2.len(),\n            value2.as_ptr(),\n            value2.len(),\n        );\n\n        let name3 = b\"SET-COOKIE\";\n        let value3 = b\"c=d\";\n        hyper_headers_add(\n            &mut headers,\n            name3.as_ptr(),\n            name3.len(),\n            value3.as_ptr(),\n            value3.len(),\n        );\n\n        let mut vec = Vec::<u8>::new();\n        hyper_headers_foreach(&headers, concat, &mut vec as *mut _ as *mut c_void);\n\n        println!(\"{}\", std::str::from_utf8(&vec).unwrap());\n        assert_eq!(\n            vec,\n            b\"Set-CookiE: a=b\\r\\nContent-Encoding: gzip\\r\\nSET-COOKIE: c=d\\r\\n\"\n        );\n\n        extern \"C\" fn concat(\n            vec: *mut c_void,\n            name: *const u8,\n            name_len: usize,\n            value: *const u8,\n            value_len: usize,\n        ) -> c_int {\n            unsafe {\n                let vec = &mut *(vec as *mut Vec<u8>);\n                let name = std::slice::from_raw_parts(name, name_len);\n                let value = std::slice::from_raw_parts(value, value_len);\n                vec.extend(name);\n                vec.extend(b\": \");\n                vec.extend(value);\n                vec.extend(b\"\\r\\n\");\n            }\n            HYPER_ITER_CONTINUE\n        }\n    }\n}\n"
  },
  {
    "path": "src/ffi/io.rs",
    "content": "use std::ffi::c_void;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse super::task::hyper_context;\nuse crate::ffi::size_t;\nuse crate::rt::{Read, Write};\n\n/// Sentinel value to return from a read or write callback that the operation\n/// is pending.\npub const HYPER_IO_PENDING: size_t = 0xFFFFFFFF;\n/// Sentinel value to return from a read or write callback that the operation\n/// has errored.\npub const HYPER_IO_ERROR: size_t = 0xFFFFFFFE;\n\ntype hyper_io_read_callback =\n    extern \"C\" fn(*mut c_void, *mut hyper_context<'_>, *mut u8, size_t) -> size_t;\ntype hyper_io_write_callback =\n    extern \"C\" fn(*mut c_void, *mut hyper_context<'_>, *const u8, size_t) -> size_t;\n\n/// A read/write handle for a specific connection.\n///\n/// This owns a specific TCP or TLS connection for the lifetime of\n/// that connection. It contains a read and write callback, as well as a\n/// void *userdata. Typically the userdata will point to a struct\n/// containing a file descriptor and a TLS context.\n///\n/// Methods:\n///\n/// - hyper_io_new:          Create a new IO type used to represent a transport.\n/// - hyper_io_set_read:     Set the read function for this IO transport.\n/// - hyper_io_set_write:    Set the write function for this IO transport.\n/// - hyper_io_set_userdata: Set the user data pointer for this IO to some value.\n/// - hyper_io_free:         Free an IO handle.\npub struct hyper_io {\n    read: hyper_io_read_callback,\n    write: hyper_io_write_callback,\n    userdata: *mut c_void,\n}\n\nffi_fn! {\n    /// Create a new IO type used to represent a transport.\n    ///\n    /// The read and write functions of this transport should be set with\n    /// `hyper_io_set_read` and `hyper_io_set_write`.\n    ///\n    /// It is expected that the underlying transport is non-blocking. When\n    /// a read or write callback can't make progress because there is no\n    /// data available yet, it should use the `hyper_waker` mechanism to\n    /// arrange to be called again when data is available.\n    ///\n    /// To avoid a memory leak, the IO handle must eventually be consumed by\n    /// `hyper_io_free` or `hyper_clientconn_handshake`.\n    fn hyper_io_new() -> *mut hyper_io {\n        Box::into_raw(Box::new(hyper_io {\n            read: read_noop,\n            write: write_noop,\n            userdata: std::ptr::null_mut(),\n        }))\n    } ?= std::ptr::null_mut()\n}\n\nffi_fn! {\n    /// Free an IO handle.\n    ///\n    /// This should only be used if the request isn't consumed by\n    /// `hyper_clientconn_handshake`.\n    fn hyper_io_free(io: *mut hyper_io) {\n        drop(non_null!(Box::from_raw(io) ?= ()));\n    }\n}\n\nffi_fn! {\n    /// Set the user data pointer for this IO to some value.\n    ///\n    /// This value is passed as an argument to the read and write callbacks.\n    fn hyper_io_set_userdata(io: *mut hyper_io, data: *mut c_void) {\n        non_null!(&mut *io ?= ()).userdata = data;\n    }\n}\n\nffi_fn! {\n    /// Set the read function for this IO transport.\n    ///\n    /// Data that is read from the transport should be put in the `buf` pointer,\n    /// up to `buf_len` bytes. The number of bytes read should be the return value.\n    ///\n    /// It is undefined behavior to try to access the bytes in the `buf` pointer,\n    /// unless you have already written them yourself. It is also undefined behavior\n    /// to return that more bytes have been written than actually set on the `buf`.\n    ///\n    /// If there is no data currently available, the callback should create a\n    /// `hyper_waker` from its `hyper_context` argument and register the waker\n    /// with whatever polling mechanism is used to signal when data is available\n    /// later on. The return value should be `HYPER_IO_PENDING`. See the\n    /// documentation for `hyper_waker`.\n    ///\n    /// If there is an irrecoverable error reading data, then `HYPER_IO_ERROR`\n    /// should be the return value.\n    fn hyper_io_set_read(io: *mut hyper_io, func: hyper_io_read_callback) {\n        non_null!(&mut *io ?= ()).read = func;\n    }\n}\n\nffi_fn! {\n    /// Set the write function for this IO transport.\n    ///\n    /// Data from the `buf` pointer should be written to the transport, up to\n    /// `buf_len` bytes. The number of bytes written should be the return value.\n    ///\n    /// If there is no data currently available, the callback should create a\n    /// `hyper_waker` from its `hyper_context` argument and register the waker\n    /// with whatever polling mechanism is used to signal when data is available\n    /// later on. The return value should be `HYPER_IO_PENDING`. See the documentation\n    /// for `hyper_waker`.\n    ///\n    /// If there is an irrecoverable error reading data, then `HYPER_IO_ERROR`\n    /// should be the return value.\n    fn hyper_io_set_write(io: *mut hyper_io, func: hyper_io_write_callback) {\n        non_null!(&mut *io ?= ()).write = func;\n    }\n}\n\n/// cbindgen:ignore\nextern \"C\" fn read_noop(\n    _userdata: *mut c_void,\n    _: *mut hyper_context<'_>,\n    _buf: *mut u8,\n    _buf_len: size_t,\n) -> size_t {\n    0\n}\n\n/// cbindgen:ignore\nextern \"C\" fn write_noop(\n    _userdata: *mut c_void,\n    _: *mut hyper_context<'_>,\n    _buf: *const u8,\n    _buf_len: size_t,\n) -> size_t {\n    0\n}\n\nimpl Read for hyper_io {\n    fn poll_read(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        mut buf: crate::rt::ReadBufCursor<'_>,\n    ) -> Poll<std::io::Result<()>> {\n        let buf_ptr = unsafe { buf.as_mut() }.as_mut_ptr() as *mut u8;\n        let buf_len = buf.remaining();\n\n        match (self.read)(self.userdata, hyper_context::wrap(cx), buf_ptr, buf_len) {\n            HYPER_IO_PENDING => Poll::Pending,\n            HYPER_IO_ERROR => Poll::Ready(Err(std::io::Error::new(\n                std::io::ErrorKind::Other,\n                \"io error\",\n            ))),\n            ok => {\n                // We have to trust that the user's read callback actually\n                // filled in that many bytes... :(\n                unsafe { buf.advance(ok) };\n                Poll::Ready(Ok(()))\n            }\n        }\n    }\n}\n\nimpl Write for hyper_io {\n    fn poll_write(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<std::io::Result<usize>> {\n        let buf_ptr = buf.as_ptr();\n        let buf_len = buf.len();\n\n        match (self.write)(self.userdata, hyper_context::wrap(cx), buf_ptr, buf_len) {\n            HYPER_IO_PENDING => Poll::Pending,\n            HYPER_IO_ERROR => Poll::Ready(Err(std::io::Error::new(\n                std::io::ErrorKind::Other,\n                \"io error\",\n            ))),\n            ok => Poll::Ready(Ok(ok)),\n        }\n    }\n\n    fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<std::io::Result<()>> {\n        Poll::Ready(Ok(()))\n    }\n\n    fn poll_shutdown(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<std::io::Result<()>> {\n        Poll::Ready(Ok(()))\n    }\n}\n\nunsafe impl Send for hyper_io {}\nunsafe impl Sync for hyper_io {}\n"
  },
  {
    "path": "src/ffi/macros.rs",
    "content": "macro_rules! ffi_fn {\n    ($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) -> $ret:ty $body:block ?= $default:expr) => {\n        $(#[$doc])*\n        #[no_mangle]\n        pub extern \"C\" fn $name($($arg: $arg_ty),*) -> $ret {\n            use std::panic::{self, AssertUnwindSafe};\n\n            match panic::catch_unwind(AssertUnwindSafe(move || $body)) {\n                Ok(v) => v,\n                Err(_) => {\n                    $default\n                }\n            }\n        }\n    };\n\n    ($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) -> $ret:ty $body:block) => {\n        ffi_fn!($(#[$doc])* fn $name($($arg: $arg_ty),*) -> $ret $body ?= {\n            eprintln!(\"panic unwind caught, aborting\");\n            std::process::abort()\n        });\n    };\n\n    ($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) $body:block ?= $default:expr) => {\n        ffi_fn!($(#[$doc])* fn $name($($arg: $arg_ty),*) -> () $body ?= $default);\n    };\n\n    ($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) $body:block) => {\n        ffi_fn!($(#[$doc])* fn $name($($arg: $arg_ty),*) -> () $body);\n    };\n}\n\nmacro_rules! non_null {\n    ($ptr:ident, $eval:expr, $err:expr) => {{\n        debug_assert!(!$ptr.is_null(), \"{:?} must not be null\", stringify!($ptr));\n        if $ptr.is_null() {\n            return $err;\n        }\n        unsafe { $eval }\n    }};\n    (&*$ptr:ident ?= $err:expr) => {{\n        non_null!($ptr, &*$ptr, $err)\n    }};\n    (&mut *$ptr:ident ?= $err:expr) => {{\n        non_null!($ptr, &mut *$ptr, $err)\n    }};\n    (Box::from_raw($ptr:ident) ?= $err:expr) => {{\n        non_null!($ptr, Box::from_raw($ptr), $err)\n    }};\n    (Arc::from_raw($ptr:ident) ?= $err:expr) => {{\n        non_null!($ptr, Arc::from_raw($ptr), $err)\n    }};\n}\n"
  },
  {
    "path": "src/ffi/mod.rs",
    "content": "// We have a lot of c-types in here, stop warning about their names!\n#![allow(non_camel_case_types)]\n// fmt::Debug isn't helpful on FFI types\n#![allow(missing_debug_implementations)]\n// unreachable_pub warns `#[no_mangle] pub extern fn` in private mod.\n#![allow(unreachable_pub)]\n\n//! # hyper C API\n//!\n//! This part of the documentation describes the C API for hyper. That is, how\n//! to *use* the hyper library in C code. This is **not** a regular Rust\n//! module, and thus it is not accessible in Rust.\n//!\n//! ## Unstable\n//!\n//! The C API of hyper is currently **unstable**, which means it's not part of\n//! the semver contract as the rest of the Rust API is. Because of that, it's\n//! only accessible if `--cfg hyper_unstable_ffi` is passed to `rustc` when\n//! compiling. The easiest way to do that is setting the `RUSTFLAGS`\n//! environment variable.\n//!\n//! ## Building\n//!\n//! The C API is part of the Rust library, but isn't compiled by default. Using\n//! `cargo`, staring with `1.64.0`, it can be compiled with the following command:\n//!\n//! ```notrust\n//! RUSTFLAGS=\"--cfg hyper_unstable_ffi\" cargo rustc --crate-type cdylib --features client,http1,http2,ffi\n//! ```\n\n// We may eventually allow the FFI to be enabled without `client` or `http1`,\n// that is why we don't auto enable them as `ffi = [\"client\", \"http1\"]` in\n// the `Cargo.toml`.\n//\n// But for now, give a clear message that this compile error is expected.\n#[cfg(not(all(feature = \"client\", feature = \"http1\")))]\ncompile_error!(\"The `ffi` feature currently requires the `client` and `http1` features.\");\n\n#[cfg(not(hyper_unstable_ffi))]\ncompile_error!(\n    \"\\\n    The `ffi` feature is unstable, and requires the \\\n    `RUSTFLAGS='--cfg hyper_unstable_ffi'` environment variable to be set.\\\n\"\n);\n\n#[macro_use]\nmod macros;\n\nmod body;\nmod client;\nmod error;\nmod http_types;\nmod io;\nmod task;\n\npub use self::body::*;\npub use self::client::*;\npub use self::error::*;\npub use self::http_types::*;\npub use self::io::*;\npub use self::task::*;\n\n/// Return in iter functions to continue iterating.\npub const HYPER_ITER_CONTINUE: std::ffi::c_int = 0;\n/// Return in iter functions to stop iterating.\n#[allow(unused)]\npub const HYPER_ITER_BREAK: std::ffi::c_int = 1;\n\n/// An HTTP Version that is unspecified.\npub const HYPER_HTTP_VERSION_NONE: std::ffi::c_int = 0;\n/// The HTTP/1.0 version.\npub const HYPER_HTTP_VERSION_1_0: std::ffi::c_int = 10;\n/// The HTTP/1.1 version.\npub const HYPER_HTTP_VERSION_1_1: std::ffi::c_int = 11;\n/// The HTTP/2 version.\npub const HYPER_HTTP_VERSION_2: std::ffi::c_int = 20;\n\n#[derive(Clone)]\nstruct UserDataPointer(*mut std::ffi::c_void);\n\n// We don't actually know anything about this pointer, it's up to the user\n// to do the right thing.\nunsafe impl Send for UserDataPointer {}\nunsafe impl Sync for UserDataPointer {}\n\n/// cbindgen:ignore\nstatic VERSION_CSTR: &str = concat!(env!(\"CARGO_PKG_VERSION\"), \"\\0\");\n\n// `core::ffi::c_size_t` is a nightly-only experimental API.\n// https://github.com/rust-lang/rust/issues/88345\ntype size_t = usize;\n\nffi_fn! {\n    /// Returns a static ASCII (null terminated) string of the hyper version.\n    fn hyper_version() -> *const std::ffi::c_char {\n        VERSION_CSTR.as_ptr() as _\n    } ?= std::ptr::null()\n}\n"
  },
  {
    "path": "src/ffi/task.rs",
    "content": "use std::ffi::{c_int, c_void};\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::ptr;\nuse std::sync::{\n    atomic::{AtomicBool, Ordering},\n    Arc, Mutex, Weak,\n};\nuse std::task::{Context, Poll};\n\nuse futures_util::stream::{FuturesUnordered, Stream};\n\nuse super::error::hyper_code;\nuse super::UserDataPointer;\n\ntype BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send>>;\ntype BoxAny = Box<dyn AsTaskType + Send + Sync>;\n\n/// Return in a poll function to indicate it was ready.\npub const HYPER_POLL_READY: c_int = 0;\n/// Return in a poll function to indicate it is still pending.\n///\n/// The passed in `hyper_waker` should be registered to wake up the task at\n/// some later point.\npub const HYPER_POLL_PENDING: c_int = 1;\n/// Return in a poll function indicate an error.\npub const HYPER_POLL_ERROR: c_int = 3;\n\n/// A task executor for `hyper_task`s.\n///\n/// A task is a unit of work that may be blocked on IO, and can be polled to\n/// make progress on that work.\n///\n/// An executor can hold many tasks, included from unrelated HTTP connections.\n/// An executor is single threaded. Typically you might have one executor per\n/// thread. Or, for simplicity, you may choose one executor per connection.\n///\n/// Progress on tasks happens only when `hyper_executor_poll` is called, and only\n/// on tasks whose corresponding `hyper_waker` has been called to indicate they\n/// are ready to make progress (for instance, because the OS has indicated there\n/// is more data to read or more buffer space available to write).\n///\n/// Deadlock potential: `hyper_executor_poll` must not be called from within a task's\n/// callback. Doing so will result in a deadlock.\n///\n/// Methods:\n///\n/// - hyper_executor_new:  Creates a new task executor.\n/// - hyper_executor_push: Push a task onto the executor.\n/// - hyper_executor_poll: Polls the executor, trying to make progress on any tasks that have notified that they are ready again.\n/// - hyper_executor_free: Frees an executor and any incomplete tasks still part of it.\npub struct hyper_executor {\n    /// The executor of all task futures.\n    ///\n    /// There should never be contention on the mutex, as it is only locked\n    /// to drive the futures. However, we cannot guarantee proper usage from\n    /// `hyper_executor_poll()`, which in C could potentially be called inside\n    /// one of the stored futures. The mutex isn't re-entrant, so doing so\n    /// would result in a deadlock, but that's better than data corruption.\n    driver: Mutex<FuturesUnordered<TaskFuture>>,\n\n    /// The queue of futures that need to be pushed into the `driver`.\n    ///\n    /// This is has a separate mutex since `spawn` could be called from inside\n    /// a future, which would mean the driver's mutex is already locked.\n    spawn_queue: Mutex<Vec<TaskFuture>>,\n\n    /// This is used to track when a future calls `wake` while we are within\n    /// `hyper_executor::poll_next`.\n    is_woken: Arc<ExecWaker>,\n}\n\n#[derive(Clone)]\npub(crate) struct WeakExec(Weak<hyper_executor>);\n\nstruct ExecWaker(AtomicBool);\n\n/// An async task.\n///\n/// A task represents a chunk of work that will eventually yield exactly one\n/// `hyper_task_value`. Tasks are pushed onto an executor, and that executor is\n/// responsible for calling the necessary private functions on the task to make\n/// progress. In most cases those private functions will eventually cause read\n/// or write callbacks on a `hyper_io` object to be called.\n///\n/// Tasks are created by various functions:\n///\n/// - hyper_clientconn_handshake: Creates an HTTP client handshake task.\n/// - hyper_clientconn_send:      Creates a task to send a request on the client connection.\n/// - hyper_body_data:            Creates a task that will poll a response body for the next buffer of data.\n/// - hyper_body_foreach:         Creates a task to execute the callback with each body chunk received.\n///\n/// Tasks then have a userdata associated with them using `hyper_task_set_userdata`. This\n/// is important, for instance, to associate a request id with a given request. When multiple\n/// tasks are running on the same executor, this allows distinguishing tasks for different\n/// requests.\n///\n/// Tasks are then pushed onto an executor, and eventually yielded from hyper_executor_poll:\n///\n/// - hyper_executor_push:        Push a task onto the executor.\n/// - hyper_executor_poll:        Polls the executor, trying to make progress on any tasks that have notified that they are ready again.\n///\n/// Once a task is yielded from poll, retrieve its userdata, check its type,\n/// and extract its value. This will require a case from void* to the appropriate type.\n///\n/// Methods on hyper_task:\n///\n/// - hyper_task_type:            Query the return type of this task.\n/// - hyper_task_value:           Takes the output value of this task.\n/// - hyper_task_set_userdata:    Set a user data pointer to be associated with this task.\n/// - hyper_task_userdata:        Retrieve the userdata that has been set via hyper_task_set_userdata.\n/// - hyper_task_free:            Free a task.\npub struct hyper_task {\n    future: BoxFuture<BoxAny>,\n    output: Option<BoxAny>,\n    userdata: UserDataPointer,\n}\n\nstruct TaskFuture {\n    task: Option<Box<hyper_task>>,\n}\n\n/// An async context for a task that contains the related waker.\n///\n/// This is provided to `hyper_io`'s read and write callbacks. Currently\n/// its only purpose is to provide access to the waker. See `hyper_waker`.\n///\n/// Corresponding Rust type: <https://doc.rust-lang.org/std/task/struct.Context.html>\npub struct hyper_context<'a>(Context<'a>);\n\n/// A waker that is saved and used to waken a pending task.\n///\n/// This is provided to `hyper_io`'s read and write callbacks via `hyper_context`\n/// and `hyper_context_waker`.\n///\n/// When nonblocking I/O in one of those callbacks can't make progress (returns\n/// `EAGAIN` or `EWOULDBLOCK`), the callback has to return to avoid blocking the\n/// executor. But it also has to arrange to get called in the future when more\n/// data is available. That's the role of the async context and the waker. The\n/// waker can be used to tell the executor \"this task is ready to make progress.\"\n///\n/// The read or write callback, upon finding it can't make progress, must get a\n/// waker from the context (`hyper_context_waker`), arrange for that waker to be\n/// called in the future, and then return `HYPER_POLL_PENDING`.\n///\n/// The arrangements for the waker to be called in the future are up to the\n/// application, but usually it will involve one big `select(2)` loop that checks which\n/// FDs are ready, and a correspondence between FDs and waker objects. For each\n/// FD that is ready, the corresponding waker must be called. Then `hyper_executor_poll`\n/// must be called. That will cause the executor to attempt to make progress on each\n/// woken task.\n///\n/// Corresponding Rust type: <https://doc.rust-lang.org/std/task/struct.Waker.html>\npub struct hyper_waker {\n    waker: std::task::Waker,\n}\n\n/// A descriptor for what type a `hyper_task` value is.\n#[repr(C)]\npub enum hyper_task_return_type {\n    /// The value of this task is null (does not imply an error).\n    HYPER_TASK_EMPTY,\n    /// The value of this task is `hyper_error *`.\n    HYPER_TASK_ERROR,\n    /// The value of this task is `hyper_clientconn *`.\n    HYPER_TASK_CLIENTCONN,\n    /// The value of this task is `hyper_response *`.\n    HYPER_TASK_RESPONSE,\n    /// The value of this task is `hyper_buf *`.\n    HYPER_TASK_BUF,\n}\n\npub(crate) unsafe trait AsTaskType {\n    fn as_task_type(&self) -> hyper_task_return_type;\n}\n\npub(crate) trait IntoDynTaskType {\n    fn into_dyn_task_type(self) -> BoxAny;\n}\n\n// ===== impl hyper_executor =====\n\nimpl hyper_executor {\n    fn new() -> Arc<hyper_executor> {\n        Arc::new(hyper_executor {\n            driver: Mutex::new(FuturesUnordered::new()),\n            spawn_queue: Mutex::new(Vec::new()),\n            is_woken: Arc::new(ExecWaker(AtomicBool::new(false))),\n        })\n    }\n\n    pub(crate) fn downgrade(exec: &Arc<hyper_executor>) -> WeakExec {\n        WeakExec(Arc::downgrade(exec))\n    }\n\n    fn spawn(&self, task: Box<hyper_task>) {\n        self.spawn_queue\n            .lock()\n            .unwrap()\n            .push(TaskFuture { task: Some(task) });\n    }\n\n    fn poll_next(&self) -> Option<Box<hyper_task>> {\n        // Drain the queue first.\n        self.drain_queue();\n\n        let waker = futures_util::task::waker_ref(&self.is_woken);\n        let mut cx = Context::from_waker(&waker);\n\n        loop {\n            {\n                // Scope the lock on the driver to ensure it is dropped before\n                // calling drain_queue below.\n                let mut driver = self.driver.lock().unwrap();\n                match Pin::new(&mut *driver).poll_next(&mut cx) {\n                    Poll::Ready(val) => return val,\n                    Poll::Pending => {}\n                };\n            }\n\n            // poll_next returned Pending.\n            // Check if any of the pending tasks tried to spawn\n            // some new tasks. If so, drain into the driver and loop.\n            if self.drain_queue() {\n                continue;\n            }\n\n            // If the driver called `wake` while we were polling,\n            // we should poll again immediately!\n            if self.is_woken.0.swap(false, Ordering::SeqCst) {\n                continue;\n            }\n\n            return None;\n        }\n    }\n\n    /// drain_queue locks both self.spawn_queue and self.driver, so it requires\n    /// that neither of them be locked already.\n    fn drain_queue(&self) -> bool {\n        let mut queue = self.spawn_queue.lock().unwrap();\n        if queue.is_empty() {\n            return false;\n        }\n\n        let driver = self.driver.lock().unwrap();\n\n        for task in queue.drain(..) {\n            driver.push(task);\n        }\n\n        true\n    }\n}\n\nimpl futures_util::task::ArcWake for ExecWaker {\n    fn wake_by_ref(me: &Arc<ExecWaker>) {\n        me.0.store(true, Ordering::SeqCst);\n    }\n}\n\n// ===== impl WeakExec =====\n\nimpl WeakExec {\n    pub(crate) fn new() -> Self {\n        WeakExec(Weak::new())\n    }\n}\n\nimpl<F> crate::rt::Executor<F> for WeakExec\nwhere\n    F: Future + Send + 'static,\n    F::Output: Send + Sync + AsTaskType,\n{\n    fn execute(&self, fut: F) {\n        if let Some(exec) = self.0.upgrade() {\n            exec.spawn(hyper_task::boxed(fut));\n        }\n    }\n}\n\nffi_fn! {\n    /// Creates a new task executor.\n    ///\n    /// To avoid a memory leak, the executor must eventually be consumed by\n    /// `hyper_executor_free`.\n    fn hyper_executor_new() -> *const hyper_executor {\n        Arc::into_raw(hyper_executor::new())\n    } ?= ptr::null()\n}\n\nffi_fn! {\n    /// Frees an executor and any incomplete tasks still part of it.\n    ///\n    /// This should be used for any executor once it is no longer needed.\n    fn hyper_executor_free(exec: *const hyper_executor) {\n        drop(non_null!(Arc::from_raw(exec) ?= ()));\n    }\n}\n\nffi_fn! {\n    /// Push a task onto the executor.\n    ///\n    /// The executor takes ownership of the task, which must not be accessed\n    /// again.\n    ///\n    /// Ownership of the task will eventually be returned to the user from\n    /// `hyper_executor_poll`.\n    ///\n    /// To distinguish multiple tasks running on the same executor, use\n    /// hyper_task_set_userdata.\n    fn hyper_executor_push(exec: *const hyper_executor, task: *mut hyper_task) -> hyper_code {\n        let exec = non_null!(&*exec ?= hyper_code::HYPERE_INVALID_ARG);\n        let task = non_null!(Box::from_raw(task) ?= hyper_code::HYPERE_INVALID_ARG);\n        exec.spawn(task);\n        hyper_code::HYPERE_OK\n    }\n}\n\nffi_fn! {\n    /// Polls the executor, trying to make progress on any tasks that can do so.\n    ///\n    /// If any task from the executor is ready, returns one of them. The way\n    /// tasks signal being finished is internal to Hyper. The order in which tasks\n    /// are returned is not guaranteed. Use userdata to distinguish between tasks.\n    ///\n    /// To avoid a memory leak, the task must eventually be consumed by\n    /// `hyper_task_free`.\n    ///\n    /// If there are no ready tasks, this returns `NULL`.\n    fn hyper_executor_poll(exec: *const hyper_executor) -> *mut hyper_task {\n        let exec = non_null!(&*exec ?= ptr::null_mut());\n        match exec.poll_next() {\n            Some(task) => Box::into_raw(task),\n            None => ptr::null_mut(),\n        }\n    } ?= ptr::null_mut()\n}\n\n// ===== impl hyper_task =====\n\nimpl hyper_task {\n    pub(crate) fn boxed<F>(fut: F) -> Box<hyper_task>\n    where\n        F: Future + Send + 'static,\n        F::Output: IntoDynTaskType + Send + Sync + 'static,\n    {\n        Box::new(hyper_task {\n            future: Box::pin(async move { fut.await.into_dyn_task_type() }),\n            output: None,\n            userdata: UserDataPointer(ptr::null_mut()),\n        })\n    }\n\n    fn output_type(&self) -> hyper_task_return_type {\n        match self.output {\n            None => hyper_task_return_type::HYPER_TASK_EMPTY,\n            Some(ref val) => val.as_task_type(),\n        }\n    }\n}\n\nimpl Future for TaskFuture {\n    type Output = Box<hyper_task>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        match Pin::new(&mut self.task.as_mut().unwrap().future).poll(cx) {\n            Poll::Ready(val) => {\n                let mut task = self.task.take().unwrap();\n                task.output = Some(val);\n                Poll::Ready(task)\n            }\n            Poll::Pending => Poll::Pending,\n        }\n    }\n}\n\nffi_fn! {\n    /// Free a task.\n    ///\n    /// This should only be used if the task isn't consumed by\n    /// `hyper_clientconn_handshake` or taken ownership of by\n    /// `hyper_executor_push`.\n    fn hyper_task_free(task: *mut hyper_task) {\n        drop(non_null!(Box::from_raw(task) ?= ()));\n    }\n}\n\nffi_fn! {\n    /// Takes the output value of this task.\n    ///\n    /// This must only be called once polling the task on an executor has finished\n    /// this task.\n    ///\n    /// Use `hyper_task_type` to determine the type of the `void *` return value.\n    ///\n    /// To avoid a memory leak, a non-empty return value must eventually be\n    /// consumed by a function appropriate for its type, one of\n    /// `hyper_error_free`, `hyper_clientconn_free`, `hyper_response_free`, or\n    /// `hyper_buf_free`.\n    fn hyper_task_value(task: *mut hyper_task) -> *mut c_void {\n        let task = non_null!(&mut *task ?= ptr::null_mut());\n\n        if let Some(val) = task.output.take() {\n            let p = Box::into_raw(val) as *mut c_void;\n            // protect from returning fake pointers to empty types\n            if p == std::ptr::NonNull::<c_void>::dangling().as_ptr() {\n                ptr::null_mut()\n            } else {\n                p\n            }\n        } else {\n            ptr::null_mut()\n        }\n    } ?= ptr::null_mut()\n}\n\nffi_fn! {\n    /// Query the return type of this task.\n    fn hyper_task_type(task: *mut hyper_task) -> hyper_task_return_type {\n        // instead of blowing up spectacularly, just say this null task\n        // doesn't have a value to retrieve.\n        non_null!(&*task ?= hyper_task_return_type::HYPER_TASK_EMPTY).output_type()\n    }\n}\n\nffi_fn! {\n    /// Set a user data pointer to be associated with this task.\n    ///\n    /// This value will be passed to task callbacks, and can be checked later\n    /// with `hyper_task_userdata`.\n    ///\n    /// This is useful for telling apart tasks for different requests that are\n    /// running on the same executor.\n    fn hyper_task_set_userdata(task: *mut hyper_task, userdata: *mut c_void) {\n        if task.is_null() {\n            return;\n        }\n\n        unsafe { (*task).userdata = UserDataPointer(userdata) };\n    }\n}\n\nffi_fn! {\n    /// Retrieve the userdata that has been set via `hyper_task_set_userdata`.\n    fn hyper_task_userdata(task: *mut hyper_task) -> *mut c_void {\n        non_null!(&*task ?= ptr::null_mut()).userdata.0\n    } ?= ptr::null_mut()\n}\n\n// ===== impl AsTaskType =====\n\nunsafe impl AsTaskType for () {\n    fn as_task_type(&self) -> hyper_task_return_type {\n        hyper_task_return_type::HYPER_TASK_EMPTY\n    }\n}\n\nunsafe impl AsTaskType for crate::Error {\n    fn as_task_type(&self) -> hyper_task_return_type {\n        hyper_task_return_type::HYPER_TASK_ERROR\n    }\n}\n\nimpl<T> IntoDynTaskType for T\nwhere\n    T: AsTaskType + Send + Sync + 'static,\n{\n    fn into_dyn_task_type(self) -> BoxAny {\n        Box::new(self)\n    }\n}\n\nimpl<T> IntoDynTaskType for crate::Result<T>\nwhere\n    T: IntoDynTaskType + Send + Sync + 'static,\n{\n    fn into_dyn_task_type(self) -> BoxAny {\n        match self {\n            Ok(val) => val.into_dyn_task_type(),\n            Err(err) => Box::new(err),\n        }\n    }\n}\n\nimpl<T> IntoDynTaskType for Option<T>\nwhere\n    T: IntoDynTaskType + Send + Sync + 'static,\n{\n    fn into_dyn_task_type(self) -> BoxAny {\n        match self {\n            Some(val) => val.into_dyn_task_type(),\n            None => ().into_dyn_task_type(),\n        }\n    }\n}\n\n// ===== impl hyper_context =====\n\nimpl hyper_context<'_> {\n    pub(crate) fn wrap<'a, 'b>(cx: &'a mut Context<'b>) -> &'a mut hyper_context<'b> {\n        // A struct with only one field has the same layout as that field.\n        unsafe { std::mem::transmute::<&mut Context<'_>, &mut hyper_context<'_>>(cx) }\n    }\n}\n\nffi_fn! {\n    /// Creates a waker associated with the task context.\n    ///\n    /// The waker can be used to inform the task's executor that the task is\n    /// ready to make progress (using `hyper_waker_wake`).\n    ///\n    /// Typically this only needs to be called once, but it can be called\n    /// multiple times, returning a new waker each time.\n    ///\n    /// To avoid a memory leak, the waker must eventually be consumed by\n    /// `hyper_waker_free` or `hyper_waker_wake`.\n    fn hyper_context_waker(cx: *mut hyper_context<'_>) -> *mut hyper_waker {\n        let waker = non_null!(&mut *cx ?= ptr::null_mut()).0.waker().clone();\n        Box::into_raw(Box::new(hyper_waker { waker }))\n    } ?= ptr::null_mut()\n}\n\n// ===== impl hyper_waker =====\n\nffi_fn! {\n    /// Free a waker.\n    ///\n    /// This should only be used if the request isn't consumed by\n    /// `hyper_waker_wake`.\n    fn hyper_waker_free(waker: *mut hyper_waker) {\n        drop(non_null!(Box::from_raw(waker) ?= ()));\n    }\n}\n\nffi_fn! {\n    /// Wake up the task associated with a waker.\n    ///\n    /// This does not do work towards associated task. Instead, it signals\n    /// to the task's executor that the task is ready to make progress. The\n    /// application is responsible for calling hyper_executor_poll, which\n    /// will in turn do work on all tasks that are ready to make progress.\n    ///\n    /// NOTE: This consumes the waker. You should not use or free the waker afterwards.\n    fn hyper_waker_wake(waker: *mut hyper_waker) {\n        let waker = non_null!(Box::from_raw(waker) ?= ());\n        waker.waker.wake();\n    }\n}\n"
  },
  {
    "path": "src/headers.rs",
    "content": "#[cfg(all(feature = \"client\", feature = \"http1\"))]\nuse bytes::BytesMut;\nuse http::header::HeaderValue;\n#[cfg(all(feature = \"http2\", feature = \"client\"))]\nuse http::Method;\n#[cfg(any(feature = \"client\", all(feature = \"server\", feature = \"http2\")))]\nuse http::{\n    header::{ValueIter, CONTENT_LENGTH},\n    HeaderMap,\n};\n\n#[cfg(feature = \"http1\")]\npub(super) fn connection_keep_alive(value: &HeaderValue) -> bool {\n    connection_has(value, \"keep-alive\")\n}\n\n#[cfg(feature = \"http1\")]\npub(super) fn connection_close(value: &HeaderValue) -> bool {\n    connection_has(value, \"close\")\n}\n\n#[cfg(feature = \"http1\")]\nfn connection_has(value: &HeaderValue, needle: &str) -> bool {\n    if let Ok(s) = value.to_str() {\n        for val in s.split(',') {\n            if val.trim().eq_ignore_ascii_case(needle) {\n                return true;\n            }\n        }\n    }\n    false\n}\n\n#[cfg(all(feature = \"http1\", feature = \"server\"))]\npub(super) fn content_length_parse(value: &HeaderValue) -> Option<u64> {\n    from_digits(value.as_bytes())\n}\n\n#[cfg(any(feature = \"client\", all(feature = \"server\", feature = \"http2\")))]\npub(super) fn content_length_parse_all(headers: &HeaderMap) -> Option<u64> {\n    content_length_parse_all_values(headers.get_all(CONTENT_LENGTH).into_iter())\n}\n\n#[cfg(any(feature = \"client\", all(feature = \"server\", feature = \"http2\")))]\npub(super) fn content_length_parse_all_values(values: ValueIter<'_, HeaderValue>) -> Option<u64> {\n    // If multiple Content-Length headers were sent, everything can still\n    // be alright if they all contain the same value, and all parse\n    // correctly. If not, then it's an error.\n\n    let mut content_length: Option<u64> = None;\n    for h in values {\n        if let Ok(line) = h.to_str() {\n            for v in line.split(',') {\n                if let Some(n) = from_digits(v.trim().as_bytes()) {\n                    if content_length.is_none() {\n                        content_length = Some(n)\n                    } else if content_length != Some(n) {\n                        return None;\n                    }\n                } else {\n                    return None;\n                }\n            }\n        } else {\n            return None;\n        }\n    }\n\n    content_length\n}\n\nfn from_digits(bytes: &[u8]) -> Option<u64> {\n    // cannot use FromStr for u64, since it allows a signed prefix\n    let mut result = 0u64;\n    const RADIX: u64 = 10;\n\n    if bytes.is_empty() {\n        return None;\n    }\n\n    for &b in bytes {\n        // can't use char::to_digit, since we haven't verified these bytes\n        // are utf-8.\n        match b {\n            b'0'..=b'9' => {\n                result = result.checked_mul(RADIX)?;\n                result = result.checked_add((b - b'0') as u64)?;\n            }\n            _ => {\n                // not a DIGIT, get outta here!\n                return None;\n            }\n        }\n    }\n\n    Some(result)\n}\n\n#[cfg(all(feature = \"http2\", feature = \"client\"))]\npub(super) fn method_has_defined_payload_semantics(method: &Method) -> bool {\n    !matches!(\n        *method,\n        Method::GET | Method::HEAD | Method::DELETE | Method::CONNECT\n    )\n}\n\n#[cfg(feature = \"http2\")]\npub(super) fn set_content_length_if_missing(headers: &mut HeaderMap, len: u64) {\n    headers\n        .entry(CONTENT_LENGTH)\n        .or_insert_with(|| HeaderValue::from(len));\n}\n\n#[cfg(all(feature = \"client\", feature = \"http1\"))]\npub(super) fn transfer_encoding_is_chunked(headers: &HeaderMap) -> bool {\n    is_chunked(headers.get_all(http::header::TRANSFER_ENCODING).into_iter())\n}\n\n#[cfg(all(feature = \"client\", feature = \"http1\"))]\npub(super) fn is_chunked(mut encodings: ValueIter<'_, HeaderValue>) -> bool {\n    // chunked must always be the last encoding, according to spec\n    if let Some(line) = encodings.next_back() {\n        return is_chunked_(line);\n    }\n\n    false\n}\n\n#[cfg(feature = \"http1\")]\npub(super) fn is_chunked_(value: &HeaderValue) -> bool {\n    // chunked must always be the last encoding, according to spec\n    if let Ok(s) = value.to_str() {\n        if let Some(encoding) = s.rsplit(',').next() {\n            return encoding.trim().eq_ignore_ascii_case(\"chunked\");\n        }\n    }\n\n    false\n}\n\n#[cfg(all(feature = \"client\", feature = \"http1\"))]\npub(super) fn add_chunked(mut entry: http::header::OccupiedEntry<'_, HeaderValue>) {\n    const CHUNKED: &str = \"chunked\";\n\n    if let Some(line) = entry.iter_mut().next_back() {\n        // + 2 for \", \"\n        let new_cap = line.as_bytes().len() + CHUNKED.len() + 2;\n        let mut buf = BytesMut::with_capacity(new_cap);\n        buf.extend_from_slice(line.as_bytes());\n        buf.extend_from_slice(b\", \");\n        buf.extend_from_slice(CHUNKED.as_bytes());\n\n        *line = HeaderValue::from_maybe_shared(buf.freeze())\n            .expect(\"original header value plus ascii is valid\");\n        return;\n    }\n\n    entry.insert(HeaderValue::from_static(CHUNKED));\n}\n"
  },
  {
    "path": "src/lib.rs",
    "content": "#![deny(missing_docs)]\n#![deny(missing_debug_implementations)]\n#![cfg_attr(test, deny(rust_2018_idioms))]\n#![cfg_attr(all(test, feature = \"full\"), deny(unreachable_pub))]\n#![cfg_attr(all(test, feature = \"full\"), deny(warnings))]\n#![cfg_attr(all(test, feature = \"nightly\"), feature(test))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n//! # hyper\n//!\n//! hyper is a **fast** and **correct** HTTP implementation written in and for Rust.\n//!\n//! ## Features\n//!\n//! - HTTP/1 and HTTP/2\n//! - Asynchronous design\n//! - Leading in performance\n//! - Tested and **correct**\n//! - Extensive production use\n//! - [Client](client/index.html) and [Server](server/index.html) APIs\n//!\n//! If just starting out, **check out the [Guides](https://hyper.rs/guides/1/)\n//! first.**\n//!\n//! ## \"Low-level\"\n//!\n//! hyper is a lower-level HTTP library, meant to be a building block\n//! for libraries and applications.\n//!\n//! If looking for just a convenient HTTP client, consider the\n//! [reqwest](https://crates.io/crates/reqwest) crate.\n//!\n//! # Optional Features\n//!\n//! hyper uses a set of [feature flags] to reduce the amount of compiled code.\n//! It is possible to just enable certain features over others. By default,\n//! hyper does not enable any features but allows one to enable a subset for\n//! their use case. Below is a list of the available feature flags. You may\n//! also notice above each function, struct and trait there is listed one or\n//! more feature flags that are required for that item to be used.\n//!\n//! If you are new to hyper it is possible to enable the `full` feature flag\n//! which will enable all public APIs. Beware though that this will pull in\n//! many extra dependencies that you may not need.\n//!\n//! The following optional features are available:\n//!\n//! - `http1`: Enables HTTP/1 support.\n//! - `http2`: Enables HTTP/2 support.\n//! - `client`: Enables the HTTP `client`.\n//! - `server`: Enables the HTTP `server`.\n//!\n//! [feature flags]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section\n//!\n//! ## Unstable Features\n//!\n//! hyper includes a set of unstable optional features that can be enabled through the use of a\n//! feature flag and a [configuration flag].\n//!\n//! The following is a list of feature flags and their corresponding `RUSTFLAG`:\n//!\n//! - `ffi`: Enables C API for hyper `hyper_unstable_ffi`.\n//! - `tracing`: Enables debug logging with `hyper_unstable_tracing`.\n//!\n//! For example:\n//!\n//! ```notrust\n//! RUSTFLAGS=\"--cfg hyper_unstable_tracing\" cargo build\n//! ```\n//!\n//! [configuration flag]: https://doc.rust-lang.org/reference/conditional-compilation.html\n//!\n//! # Stability\n//!\n//! It's worth talking a bit about the stability of hyper. hyper's API follows\n//! [SemVer](https://semver.org). Breaking changes will only be introduced in\n//! major versions, if ever. New additions to the API, such as new types,\n//! methods, or traits will only be added in minor versions.\n//!\n//! Some parts of hyper are documented as NOT being part of the stable API. The\n//! following is a brief list, you can read more about each one in the relevant\n//! part of the documentation.\n//!\n//! - Downcasting error types from `Error::source()` is not considered stable.\n//! - Private dependencies use of global variables is not considered stable.\n//!   So, if a dependency uses `log` or `tracing`, hyper doesn't promise it\n//!   will continue to do so.\n//! - Behavior from default options is not stable. hyper reserves the right to\n//!   add new options that are enabled by default which might alter the\n//!   behavior, for the purposes of protection. It is also possible to _change_\n//!   what the default options are set to, also in efforts to protect the\n//!   most people possible.\n#[doc(hidden)]\npub use http;\n\n#[cfg(all(test, feature = \"nightly\"))]\nextern crate test;\n\n#[doc(no_inline)]\npub use http::{header, HeaderMap, Method, Request, Response, StatusCode, Uri, Version};\n\npub use crate::error::{Error, Result};\n\n#[macro_use]\nmod cfg;\n\n#[macro_use]\nmod trace;\n\npub mod body;\nmod common;\nmod error;\npub mod ext;\n#[cfg(test)]\nmod mock;\npub mod rt;\npub mod service;\npub mod upgrade;\n\n#[cfg(feature = \"ffi\")]\n#[cfg_attr(docsrs, doc(cfg(all(feature = \"ffi\", hyper_unstable_ffi))))]\npub mod ffi;\n\ncfg_proto! {\n    mod headers;\n    mod proto;\n}\n\ncfg_feature! {\n    #![feature = \"client\"]\n\n    pub mod client;\n}\n\ncfg_feature! {\n    #![feature = \"server\"]\n\n    pub mod server;\n}\n"
  },
  {
    "path": "src/mock.rs",
    "content": "// FIXME: re-implement tests with `async/await`\n/*\n#[cfg(feature = \"runtime\")]\nuse std::collections::HashMap;\nuse std::cmp;\nuse std::io::{self, Read, Write};\n#[cfg(feature = \"runtime\")]\nuse std::sync::{Arc, Mutex};\n\nuse bytes::Buf;\nuse futures::{Async, Poll};\n#[cfg(feature = \"runtime\")]\nuse futures::Future;\nuse futures::task::{self, Task};\nuse tokio_io::{AsyncRead, AsyncWrite};\n\n#[cfg(feature = \"runtime\")]\nuse crate::client::connect::{Connect, Connected, Destination};\n\n\n\n#[cfg(feature = \"runtime\")]\npub struct Duplex {\n    inner: Arc<Mutex<DuplexInner>>,\n}\n\n#[cfg(feature = \"runtime\")]\nstruct DuplexInner {\n    handle_read_task: Option<Task>,\n    read: AsyncIo<MockCursor>,\n    write: AsyncIo<MockCursor>,\n}\n\n#[cfg(feature = \"runtime\")]\nimpl Duplex {\n    pub(crate) fn channel() -> (Duplex, DuplexHandle) {\n        let mut inner = DuplexInner {\n            handle_read_task: None,\n            read: AsyncIo::new_buf(Vec::new(), 0),\n            write: AsyncIo::new_buf(Vec::new(), std::usize::MAX),\n        };\n\n        inner.read.park_tasks(true);\n        inner.write.park_tasks(true);\n\n        let inner = Arc::new(Mutex::new(inner));\n\n        let duplex = Duplex {\n            inner: inner.clone(),\n        };\n        let handle = DuplexHandle {\n            inner: inner,\n        };\n\n        (duplex, handle)\n    }\n}\n\n#[cfg(feature = \"runtime\")]\nimpl Read for Duplex {\n    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {\n        self.inner.lock().unwrap().read.read(buf)\n    }\n}\n\n#[cfg(feature = \"runtime\")]\nimpl Write for Duplex {\n    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {\n        let mut inner = self.inner.lock().unwrap();\n        let ret = inner.write.write(buf);\n        if let Some(task) = inner.handle_read_task.take() {\n            trace!(\"waking DuplexHandle read\");\n            task.notify();\n        }\n        ret\n    }\n\n    fn flush(&mut self) -> io::Result<()> {\n        self.inner.lock().unwrap().write.flush()\n    }\n}\n\n#[cfg(feature = \"runtime\")]\nimpl AsyncRead for Duplex {\n}\n\n#[cfg(feature = \"runtime\")]\nimpl AsyncWrite for Duplex {\n    fn shutdown(&mut self) -> Poll<(), io::Error> {\n        Ok(().into())\n    }\n\n    fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Poll<usize, io::Error> {\n        let mut inner = self.inner.lock().unwrap();\n        if let Some(task) = inner.handle_read_task.take() {\n            task.notify();\n        }\n        inner.write.write_buf(buf)\n    }\n}\n\n#[cfg(feature = \"runtime\")]\npub struct DuplexHandle {\n    inner: Arc<Mutex<DuplexInner>>,\n}\n\n#[cfg(feature = \"runtime\")]\nimpl DuplexHandle {\n    pub fn read(&self, buf: &mut [u8]) -> Poll<usize, io::Error> {\n        let mut inner = self.inner.lock().unwrap();\n        assert!(buf.len() >= inner.write.inner.len());\n        if inner.write.inner.is_empty() {\n            trace!(\"DuplexHandle read parking\");\n            inner.handle_read_task = Some(task::current());\n            return Ok(Async::NotReady);\n        }\n        inner.write.read(buf).map(Async::Ready)\n    }\n\n    pub fn write(&self, bytes: &[u8]) -> Poll<usize, io::Error> {\n        let mut inner = self.inner.lock().unwrap();\n        assert_eq!(inner.read.inner.pos, 0);\n        assert_eq!(inner.read.inner.vec.len(), 0, \"write but read isn't empty\");\n        inner\n            .read\n            .inner\n            .vec\n            .extend(bytes);\n        inner.read.block_in(bytes.len());\n        Ok(Async::Ready(bytes.len()))\n    }\n}\n\n#[cfg(feature = \"runtime\")]\nimpl Drop for DuplexHandle {\n    fn drop(&mut self) {\n        trace!(\"mock duplex handle drop\");\n        if !::std::thread::panicking() {\n            let mut inner = self.inner.lock().unwrap();\n            inner.read.close();\n            inner.write.close();\n        }\n    }\n}\n\n#[cfg(feature = \"runtime\")]\ntype BoxedConnectFut = Box<dyn Future<Item=(Duplex, Connected), Error=io::Error> + Send>;\n\n#[cfg(feature = \"runtime\")]\n#[derive(Clone)]\npub struct MockConnector {\n    mocks: Arc<Mutex<MockedConnections>>,\n}\n\n#[cfg(feature = \"runtime\")]\nstruct MockedConnections(HashMap<String, Vec<BoxedConnectFut>>);\n\n#[cfg(feature = \"runtime\")]\nimpl MockConnector {\n    pub fn new() -> MockConnector {\n        MockConnector {\n            mocks: Arc::new(Mutex::new(MockedConnections(HashMap::new()))),\n        }\n    }\n\n    pub fn mock(&mut self, key: &str) -> DuplexHandle {\n        use futures::future;\n        self.mock_fut(key, future::ok::<_, ()>(()))\n    }\n\n    pub fn mock_fut<F>(&mut self, key: &str, fut: F) -> DuplexHandle\n    where\n        F: Future + Send + 'static,\n    {\n        self.mock_opts(key, Connected::new(), fut)\n    }\n\n    pub fn mock_opts<F>(&mut self, key: &str, connected: Connected, fut: F) -> DuplexHandle\n    where\n        F: Future + Send + 'static,\n    {\n        let key = key.to_owned();\n\n        let (duplex, handle) = Duplex::channel();\n\n        let fut = Box::new(fut.then(move |_| {\n            trace!(\"MockConnector mocked fut ready\");\n            Ok((duplex, connected))\n        }));\n        self.mocks.lock().unwrap().0.entry(key)\n            .or_insert(Vec::new())\n            .push(fut);\n\n        handle\n    }\n}\n\n#[cfg(feature = \"runtime\")]\nimpl Connect for MockConnector {\n    type Transport = Duplex;\n    type Error = io::Error;\n    type Future = BoxedConnectFut;\n\n    fn connect(&self, dst: Destination) -> Self::Future {\n        trace!(\"mock connect: {:?}\", dst);\n        let key = format!(\"{}://{}{}\", dst.scheme(), dst.host(), if let Some(port) = dst.port() {\n            format!(\":{}\", port)\n        } else {\n            \"\".to_owned()\n        });\n        let mut mocks = self.mocks.lock().unwrap();\n        let mocks = mocks.0.get_mut(&key)\n            .expect(&format!(\"unknown mocks uri: {}\", key));\n        assert!(!mocks.is_empty(), \"no additional mocks for {}\", key);\n        mocks.remove(0)\n    }\n}\n\n\n#[cfg(feature = \"runtime\")]\nimpl Drop for MockedConnections {\n    fn drop(&mut self) {\n        if !::std::thread::panicking() {\n            for (key, mocks) in self.0.iter() {\n                assert_eq!(\n                    mocks.len(),\n                    0,\n                    \"not all mocked connects for {:?} were used\",\n                    key,\n                );\n            }\n        }\n    }\n}\n*/\n"
  },
  {
    "path": "src/proto/h1/conn.rs",
    "content": "use std::fmt;\n#[cfg(feature = \"server\")]\nuse std::future::Future;\nuse std::io;\nuse std::marker::{PhantomData, Unpin};\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n#[cfg(feature = \"server\")]\nuse std::time::Duration;\n\nuse crate::rt::{Read, Write};\nuse bytes::{Buf, Bytes};\nuse futures_core::ready;\nuse http::header::{HeaderValue, CONNECTION, TE};\nuse http::{HeaderMap, Method, Version};\nuse http_body::Frame;\nuse httparse::ParserConfig;\n\nuse super::io::Buffered;\nuse super::{Decoder, Encode, EncodedBuf, Encoder, Http1Transaction, ParseContext, Wants};\nuse crate::body::DecodedLength;\n#[cfg(feature = \"server\")]\nuse crate::common::time::Time;\nuse crate::headers;\nuse crate::proto::{BodyLength, MessageHead};\n#[cfg(feature = \"server\")]\nuse crate::rt::Sleep;\n\nconst H2_PREFACE: &[u8] = b\"PRI * HTTP/2.0\\r\\n\\r\\nSM\\r\\n\\r\\n\";\n\n/// This handles a connection, which will have been established over an\n/// `Read + Write` (like a socket), and will likely include multiple\n/// `Transaction`s over HTTP.\n///\n/// The connection will determine when a message begins and ends as well as\n/// determine if this connection can be kept alive after the message,\n/// or if it is complete.\npub(crate) struct Conn<I, B, T> {\n    io: Buffered<I, EncodedBuf<B>>,\n    state: State,\n    _marker: PhantomData<fn(T)>,\n}\n\nimpl<I, B, T> Conn<I, B, T>\nwhere\n    I: Read + Write + Unpin,\n    B: Buf,\n    T: Http1Transaction,\n{\n    pub(crate) fn new(io: I) -> Conn<I, B, T> {\n        Conn {\n            io: Buffered::new(io),\n            state: State {\n                allow_half_close: false,\n                cached_headers: None,\n                error: None,\n                keep_alive: KA::Busy,\n                method: None,\n                h1_parser_config: ParserConfig::default(),\n                h1_max_headers: None,\n                #[cfg(feature = \"server\")]\n                h1_header_read_timeout: None,\n                #[cfg(feature = \"server\")]\n                h1_header_read_timeout_fut: None,\n                #[cfg(feature = \"server\")]\n                h1_header_read_timeout_running: false,\n                #[cfg(feature = \"server\")]\n                date_header: true,\n                #[cfg(feature = \"server\")]\n                timer: Time::Empty,\n                preserve_header_case: false,\n                #[cfg(feature = \"ffi\")]\n                preserve_header_order: false,\n                title_case_headers: false,\n                h09_responses: false,\n                #[cfg(feature = \"client\")]\n                on_informational: None,\n                notify_read: false,\n                reading: Reading::Init,\n                writing: Writing::Init,\n                upgrade: None,\n                // We assume a modern world where the remote speaks HTTP/1.1.\n                // If they tell us otherwise, we'll downgrade in `read_head`.\n                version: Version::HTTP_11,\n                allow_trailer_fields: false,\n            },\n            _marker: PhantomData,\n        }\n    }\n\n    #[cfg(feature = \"server\")]\n    pub(crate) fn set_timer(&mut self, timer: Time) {\n        self.state.timer = timer;\n    }\n\n    #[cfg(feature = \"server\")]\n    pub(crate) fn set_flush_pipeline(&mut self, enabled: bool) {\n        self.io.set_flush_pipeline(enabled);\n    }\n\n    pub(crate) fn set_write_strategy_queue(&mut self) {\n        self.io.set_write_strategy_queue();\n    }\n\n    pub(crate) fn set_max_buf_size(&mut self, max: usize) {\n        self.io.set_max_buf_size(max);\n    }\n\n    #[cfg(feature = \"client\")]\n    pub(crate) fn set_read_buf_exact_size(&mut self, sz: usize) {\n        self.io.set_read_buf_exact_size(sz);\n    }\n\n    pub(crate) fn set_write_strategy_flatten(&mut self) {\n        self.io.set_write_strategy_flatten();\n    }\n\n    pub(crate) fn set_h1_parser_config(&mut self, parser_config: ParserConfig) {\n        self.state.h1_parser_config = parser_config;\n    }\n\n    pub(crate) fn set_title_case_headers(&mut self) {\n        self.state.title_case_headers = true;\n    }\n\n    pub(crate) fn set_preserve_header_case(&mut self) {\n        self.state.preserve_header_case = true;\n    }\n\n    #[cfg(feature = \"ffi\")]\n    pub(crate) fn set_preserve_header_order(&mut self) {\n        self.state.preserve_header_order = true;\n    }\n\n    #[cfg(feature = \"client\")]\n    pub(crate) fn set_h09_responses(&mut self) {\n        self.state.h09_responses = true;\n    }\n\n    pub(crate) fn set_http1_max_headers(&mut self, val: usize) {\n        self.state.h1_max_headers = Some(val);\n    }\n\n    #[cfg(feature = \"server\")]\n    pub(crate) fn set_http1_header_read_timeout(&mut self, val: Duration) {\n        self.state.h1_header_read_timeout = Some(val);\n    }\n\n    #[cfg(feature = \"server\")]\n    pub(crate) fn set_allow_half_close(&mut self) {\n        self.state.allow_half_close = true;\n    }\n\n    #[cfg(feature = \"server\")]\n    pub(crate) fn disable_date_header(&mut self) {\n        self.state.date_header = false;\n    }\n\n    pub(crate) fn into_inner(self) -> (I, Bytes) {\n        self.io.into_inner()\n    }\n\n    pub(crate) fn pending_upgrade(&mut self) -> Option<crate::upgrade::Pending> {\n        self.state.upgrade.take()\n    }\n\n    pub(crate) fn is_read_closed(&self) -> bool {\n        self.state.is_read_closed()\n    }\n\n    pub(crate) fn is_write_closed(&self) -> bool {\n        self.state.is_write_closed()\n    }\n\n    pub(crate) fn can_read_head(&self) -> bool {\n        if !matches!(self.state.reading, Reading::Init) {\n            return false;\n        }\n\n        if T::should_read_first() {\n            return true;\n        }\n\n        !matches!(self.state.writing, Writing::Init)\n    }\n\n    pub(crate) fn can_read_body(&self) -> bool {\n        matches!(\n            self.state.reading,\n            Reading::Body(..) | Reading::Continue(..)\n        )\n    }\n\n    #[cfg(feature = \"server\")]\n    pub(crate) fn has_initial_read_write_state(&self) -> bool {\n        matches!(self.state.reading, Reading::Init)\n            && matches!(self.state.writing, Writing::Init)\n            && self.io.read_buf().is_empty()\n    }\n\n    fn should_error_on_eof(&self) -> bool {\n        // If we're idle, it's probably just the connection closing gracefully.\n        T::should_error_on_parse_eof() && !self.state.is_idle()\n    }\n\n    fn has_h2_prefix(&self) -> bool {\n        let read_buf = self.io.read_buf();\n        read_buf.len() >= 24 && read_buf[..24] == *H2_PREFACE\n    }\n\n    pub(super) fn poll_read_head(\n        &mut self,\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<crate::Result<(MessageHead<T::Incoming>, DecodedLength, Wants)>>> {\n        debug_assert!(self.can_read_head());\n        trace!(\"Conn::read_head\");\n\n        #[cfg(feature = \"server\")]\n        if !self.state.h1_header_read_timeout_running {\n            if let Some(h1_header_read_timeout) = self.state.h1_header_read_timeout {\n                let deadline = self.state.timer.now() + h1_header_read_timeout;\n                self.state.h1_header_read_timeout_running = true;\n                match self.state.h1_header_read_timeout_fut {\n                    Some(ref mut h1_header_read_timeout_fut) => {\n                        trace!(\"resetting h1 header read timeout timer\");\n                        self.state.timer.reset(h1_header_read_timeout_fut, deadline);\n                    }\n                    None => {\n                        trace!(\"setting h1 header read timeout timer\");\n                        self.state.h1_header_read_timeout_fut =\n                            Some(self.state.timer.sleep_until(deadline));\n                    }\n                }\n            }\n        }\n\n        let msg = match self.io.parse::<T>(\n            cx,\n            ParseContext {\n                cached_headers: &mut self.state.cached_headers,\n                req_method: &mut self.state.method,\n                h1_parser_config: self.state.h1_parser_config.clone(),\n                h1_max_headers: self.state.h1_max_headers,\n                preserve_header_case: self.state.preserve_header_case,\n                #[cfg(feature = \"ffi\")]\n                preserve_header_order: self.state.preserve_header_order,\n                h09_responses: self.state.h09_responses,\n                #[cfg(feature = \"client\")]\n                on_informational: &mut self.state.on_informational,\n            },\n        ) {\n            Poll::Ready(Ok(msg)) => msg,\n            Poll::Ready(Err(e)) => return self.on_read_head_error(e),\n            Poll::Pending => {\n                #[cfg(feature = \"server\")]\n                if self.state.h1_header_read_timeout_running {\n                    if let Some(ref mut h1_header_read_timeout_fut) =\n                        self.state.h1_header_read_timeout_fut\n                    {\n                        if Pin::new(h1_header_read_timeout_fut).poll(cx).is_ready() {\n                            self.state.h1_header_read_timeout_running = false;\n\n                            warn!(\"read header from client timeout\");\n                            return Poll::Ready(Some(Err(crate::Error::new_header_timeout())));\n                        }\n                    }\n                }\n\n                return Poll::Pending;\n            }\n        };\n\n        #[cfg(feature = \"server\")]\n        {\n            self.state.h1_header_read_timeout_running = false;\n            self.state.h1_header_read_timeout_fut = None;\n        }\n\n        // Note: don't deconstruct `msg` into local variables, it appears\n        // the optimizer doesn't remove the extra copies.\n\n        debug!(\"incoming body is {}\", msg.decode);\n\n        // Prevent accepting HTTP/0.9 responses after the initial one, if any.\n        self.state.h09_responses = false;\n\n        // Drop any OnInformational callbacks, we're done there!\n        #[cfg(feature = \"client\")]\n        {\n            self.state.on_informational = None;\n        }\n\n        self.state.busy();\n        self.state.keep_alive &= msg.keep_alive;\n        self.state.version = msg.head.version;\n\n        let mut wants = if msg.wants_upgrade {\n            Wants::UPGRADE\n        } else {\n            Wants::EMPTY\n        };\n\n        if msg.decode == DecodedLength::ZERO {\n            if msg.expect_continue {\n                debug!(\"ignoring expect-continue since body is empty\");\n            }\n            self.state.reading = Reading::KeepAlive;\n            if !T::should_read_first() {\n                self.try_keep_alive(cx);\n            }\n        } else if msg.expect_continue && msg.head.version.gt(&Version::HTTP_10) {\n            let h1_max_header_size = None; // TODO: remove this when we land h1_max_header_size support\n            self.state.reading = Reading::Continue(Decoder::new(\n                msg.decode,\n                self.state.h1_max_headers,\n                h1_max_header_size,\n            ));\n            wants = wants.add(Wants::EXPECT);\n        } else {\n            let h1_max_header_size = None; // TODO: remove this when we land h1_max_header_size support\n            self.state.reading = Reading::Body(Decoder::new(\n                msg.decode,\n                self.state.h1_max_headers,\n                h1_max_header_size,\n            ));\n        }\n\n        self.state.allow_trailer_fields = msg\n            .head\n            .headers\n            .get(TE)\n            .map_or(false, |te_header| te_header == \"trailers\");\n\n        Poll::Ready(Some(Ok((msg.head, msg.decode, wants))))\n    }\n\n    fn on_read_head_error<Z>(&mut self, e: crate::Error) -> Poll<Option<crate::Result<Z>>> {\n        // If we are currently waiting on a message, then an empty\n        // message should be reported as an error. If not, it is just\n        // the connection closing gracefully.\n        let must_error = self.should_error_on_eof();\n        self.close_read();\n        self.io.consume_leading_lines();\n        let was_mid_parse = e.is_parse() || !self.io.read_buf().is_empty();\n        if was_mid_parse || must_error {\n            // We check if the buf contains the h2 Preface\n            debug!(\n                \"parse error ({}) with {} bytes\",\n                e,\n                self.io.read_buf().len()\n            );\n            match self.on_parse_error(e) {\n                Ok(()) => Poll::Pending, // XXX: wat?\n                Err(e) => Poll::Ready(Some(Err(e))),\n            }\n        } else {\n            debug!(\"read eof\");\n            self.close_write();\n            Poll::Ready(None)\n        }\n    }\n\n    pub(crate) fn poll_read_body(\n        &mut self,\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<io::Result<Frame<Bytes>>>> {\n        debug_assert!(self.can_read_body());\n\n        let (reading, ret) = match self.state.reading {\n            Reading::Body(ref mut decoder) => {\n                match ready!(decoder.decode(cx, &mut self.io)) {\n                    Ok(frame) => {\n                        if frame.is_data() {\n                            let slice = frame.data_ref().unwrap_or_else(|| unreachable!());\n                            let (reading, maybe_frame) = if decoder.is_eof() {\n                                debug!(\"incoming body completed\");\n                                (\n                                    Reading::KeepAlive,\n                                    if !slice.is_empty() {\n                                        Some(Ok(frame))\n                                    } else {\n                                        None\n                                    },\n                                )\n                            } else if slice.is_empty() {\n                                error!(\"incoming body unexpectedly ended\");\n                                // This should be unreachable, since all 3 decoders\n                                // either set eof=true or return an Err when reading\n                                // an empty slice...\n                                (Reading::Closed, None)\n                            } else {\n                                return Poll::Ready(Some(Ok(frame)));\n                            };\n                            (reading, Poll::Ready(maybe_frame))\n                        } else if frame.is_trailers() {\n                            (Reading::Closed, Poll::Ready(Some(Ok(frame))))\n                        } else {\n                            trace!(\"discarding unknown frame\");\n                            (Reading::Closed, Poll::Ready(None))\n                        }\n                    }\n                    Err(e) => {\n                        debug!(\"incoming body decode error: {}\", e);\n                        (Reading::Closed, Poll::Ready(Some(Err(e))))\n                    }\n                }\n            }\n            Reading::Continue(ref decoder) => {\n                // Write the 100 Continue if not already responded...\n                if let Writing::Init = self.state.writing {\n                    trace!(\"automatically sending 100 Continue\");\n                    let cont = b\"HTTP/1.1 100 Continue\\r\\n\\r\\n\";\n                    self.io.headers_buf().extend_from_slice(cont);\n                }\n\n                // And now recurse once in the Reading::Body state...\n                self.state.reading = Reading::Body(decoder.clone());\n                return self.poll_read_body(cx);\n            }\n            _ => unreachable!(\"poll_read_body invalid state: {:?}\", self.state.reading),\n        };\n\n        self.state.reading = reading;\n        self.try_keep_alive(cx);\n        ret\n    }\n\n    pub(crate) fn wants_read_again(&mut self) -> bool {\n        let ret = self.state.notify_read;\n        self.state.notify_read = false;\n        ret\n    }\n\n    pub(crate) fn poll_read_keep_alive(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {\n        debug_assert!(!self.can_read_head() && !self.can_read_body());\n\n        if self.is_read_closed() {\n            Poll::Pending\n        } else if self.is_mid_message() {\n            self.mid_message_detect_eof(cx)\n        } else {\n            self.require_empty_read(cx)\n        }\n    }\n\n    fn is_mid_message(&self) -> bool {\n        !matches!(\n            (&self.state.reading, &self.state.writing),\n            (&Reading::Init, &Writing::Init)\n        )\n    }\n\n    // This will check to make sure the io object read is empty.\n    //\n    // This should only be called for Clients wanting to enter the idle\n    // state.\n    fn require_empty_read(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {\n        debug_assert!(!self.can_read_head() && !self.can_read_body() && !self.is_read_closed());\n        debug_assert!(!self.is_mid_message());\n        debug_assert!(T::is_client());\n\n        if !self.io.read_buf().is_empty() {\n            debug!(\"received an unexpected {} bytes\", self.io.read_buf().len());\n            return Poll::Ready(Err(crate::Error::new_unexpected_message()));\n        }\n\n        let num_read = ready!(self.force_io_read(cx)).map_err(crate::Error::new_io)?;\n\n        if num_read == 0 {\n            let ret = if self.should_error_on_eof() {\n                trace!(\"found unexpected EOF on busy connection: {:?}\", self.state);\n                Poll::Ready(Err(crate::Error::new_incomplete()))\n            } else {\n                trace!(\"found EOF on idle connection, closing\");\n                Poll::Ready(Ok(()))\n            };\n\n            // order is important: should_error needs state BEFORE close_read\n            self.state.close_read();\n            return ret;\n        }\n\n        debug!(\n            \"received unexpected {} bytes on an idle connection\",\n            num_read\n        );\n        Poll::Ready(Err(crate::Error::new_unexpected_message()))\n    }\n\n    fn mid_message_detect_eof(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {\n        debug_assert!(!self.can_read_head() && !self.can_read_body() && !self.is_read_closed());\n        debug_assert!(self.is_mid_message());\n\n        if self.state.allow_half_close || !self.io.read_buf().is_empty() {\n            return Poll::Pending;\n        }\n\n        let num_read = ready!(self.force_io_read(cx)).map_err(crate::Error::new_io)?;\n\n        if num_read == 0 {\n            trace!(\"found unexpected EOF on busy connection: {:?}\", self.state);\n            self.state.close_read();\n            Poll::Ready(Err(crate::Error::new_incomplete()))\n        } else {\n            Poll::Ready(Ok(()))\n        }\n    }\n\n    fn force_io_read(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<usize>> {\n        debug_assert!(!self.state.is_read_closed());\n\n        let result = ready!(self.io.poll_read_from_io(cx));\n        Poll::Ready(result.map_err(|e| {\n            trace!(error = %e, \"force_io_read; io error\");\n            self.state.close();\n            e\n        }))\n    }\n\n    fn maybe_notify(&mut self, cx: &mut Context<'_>) {\n        // its possible that we returned NotReady from poll() without having\n        // exhausted the underlying Io. We would have done this when we\n        // determined we couldn't keep reading until we knew how writing\n        // would finish.\n\n        match self.state.reading {\n            Reading::Continue(..) | Reading::Body(..) | Reading::KeepAlive | Reading::Closed => {\n                return\n            }\n            Reading::Init => (),\n        };\n\n        match self.state.writing {\n            Writing::Body(..) => return,\n            Writing::Init | Writing::KeepAlive | Writing::Closed => (),\n        }\n\n        if !self.io.is_read_blocked() {\n            if self.io.read_buf().is_empty() {\n                match self.io.poll_read_from_io(cx) {\n                    Poll::Ready(Ok(n)) => {\n                        if n == 0 {\n                            trace!(\"maybe_notify; read eof\");\n                            if self.state.is_idle() {\n                                self.state.close();\n                            } else {\n                                self.close_read()\n                            }\n                            return;\n                        }\n                    }\n                    Poll::Pending => {\n                        trace!(\"maybe_notify; read_from_io blocked\");\n                        return;\n                    }\n                    Poll::Ready(Err(e)) => {\n                        trace!(\"maybe_notify; read_from_io error: {}\", e);\n                        self.state.close();\n                        self.state.error = Some(crate::Error::new_io(e));\n                    }\n                }\n            }\n            self.state.notify_read = true;\n        }\n    }\n\n    fn try_keep_alive(&mut self, cx: &mut Context<'_>) {\n        self.state.try_keep_alive::<T>();\n        self.maybe_notify(cx);\n    }\n\n    pub(crate) fn can_write_head(&self) -> bool {\n        if !T::should_read_first() && matches!(self.state.reading, Reading::Closed) {\n            return false;\n        }\n\n        match self.state.writing {\n            Writing::Init => self.io.can_headers_buf(),\n            _ => false,\n        }\n    }\n\n    pub(crate) fn can_write_body(&self) -> bool {\n        match self.state.writing {\n            Writing::Body(..) => true,\n            Writing::Init | Writing::KeepAlive | Writing::Closed => false,\n        }\n    }\n\n    pub(crate) fn can_buffer_body(&self) -> bool {\n        self.io.can_buffer()\n    }\n\n    pub(crate) fn write_head(&mut self, head: MessageHead<T::Outgoing>, body: Option<BodyLength>) {\n        if let Some(encoder) = self.encode_head(head, body) {\n            self.state.writing = if !encoder.is_eof() {\n                Writing::Body(encoder)\n            } else if encoder.is_last() {\n                Writing::Closed\n            } else {\n                Writing::KeepAlive\n            };\n        }\n    }\n\n    fn encode_head(\n        &mut self,\n        mut head: MessageHead<T::Outgoing>,\n        body: Option<BodyLength>,\n    ) -> Option<Encoder> {\n        debug_assert!(self.can_write_head());\n\n        if !T::should_read_first() {\n            self.state.busy();\n        }\n\n        self.enforce_version(&mut head);\n\n        let buf = self.io.headers_buf();\n        match super::role::encode_headers::<T>(\n            Encode {\n                head: &mut head,\n                body,\n                #[cfg(feature = \"server\")]\n                keep_alive: self.state.wants_keep_alive(),\n                req_method: &mut self.state.method,\n                title_case_headers: self.state.title_case_headers,\n                #[cfg(feature = \"server\")]\n                date_header: self.state.date_header,\n            },\n            buf,\n        ) {\n            Ok(encoder) => {\n                debug_assert!(self.state.cached_headers.is_none());\n                debug_assert!(head.headers.is_empty());\n                self.state.cached_headers = Some(head.headers);\n\n                #[cfg(feature = \"client\")]\n                {\n                    self.state.on_informational =\n                        head.extensions.remove::<crate::ext::OnInformational>();\n                }\n\n                Some(encoder)\n            }\n            Err(err) => {\n                self.state.error = Some(err);\n                self.state.writing = Writing::Closed;\n                None\n            }\n        }\n    }\n\n    // Fix keep-alive when Connection: keep-alive header is not present\n    fn fix_keep_alive(&mut self, head: &mut MessageHead<T::Outgoing>) {\n        let outgoing_is_keep_alive = head\n            .headers\n            .get(CONNECTION)\n            .map_or(false, headers::connection_keep_alive);\n\n        if !outgoing_is_keep_alive {\n            match head.version {\n                // If response is version 1.0 and keep-alive is not present in the response,\n                // disable keep-alive so the server closes the connection\n                Version::HTTP_10 => self.state.disable_keep_alive(),\n                // If response is version 1.1 and keep-alive is wanted, add\n                // Connection: keep-alive header when not present\n                Version::HTTP_11 => {\n                    if self.state.wants_keep_alive() {\n                        head.headers\n                            .insert(CONNECTION, HeaderValue::from_static(\"keep-alive\"));\n                    }\n                }\n                _ => (),\n            }\n        }\n    }\n\n    // If we know the remote speaks an older version, we try to fix up any messages\n    // to work with our older peer.\n    fn enforce_version(&mut self, head: &mut MessageHead<T::Outgoing>) {\n        match self.state.version {\n            Version::HTTP_10 => {\n                // Fixes response or connection when keep-alive header is not present\n                self.fix_keep_alive(head);\n                // If the remote only knows HTTP/1.0, we should force ourselves\n                // to do only speak HTTP/1.0 as well.\n                head.version = Version::HTTP_10;\n            }\n            Version::HTTP_11 => {\n                if let KA::Disabled = self.state.keep_alive.status() {\n                    head.headers\n                        .insert(CONNECTION, HeaderValue::from_static(\"close\"));\n                }\n            }\n            _ => (),\n        }\n        // If the remote speaks HTTP/1.1, then it *should* be fine with\n        // both HTTP/1.0 and HTTP/1.1 from us. So again, we just let\n        // the user's headers be.\n    }\n\n    pub(crate) fn write_body(&mut self, chunk: B) {\n        debug_assert!(self.can_write_body() && self.can_buffer_body());\n        // empty chunks should be discarded at Dispatcher level\n        debug_assert!(chunk.remaining() != 0);\n\n        let state = match self.state.writing {\n            Writing::Body(ref mut encoder) => {\n                self.io.buffer(encoder.encode(chunk));\n\n                if !encoder.is_eof() {\n                    return;\n                }\n\n                if encoder.is_last() {\n                    Writing::Closed\n                } else {\n                    Writing::KeepAlive\n                }\n            }\n            _ => unreachable!(\"write_body invalid state: {:?}\", self.state.writing),\n        };\n\n        self.state.writing = state;\n    }\n\n    pub(crate) fn write_trailers(&mut self, trailers: HeaderMap) {\n        if T::is_server() && !self.state.allow_trailer_fields {\n            debug!(\"trailers not allowed to be sent\");\n            return;\n        }\n        debug_assert!(self.can_write_body() && self.can_buffer_body());\n\n        match self.state.writing {\n            Writing::Body(ref encoder) => {\n                if let Some(enc_buf) =\n                    encoder.encode_trailers(trailers, self.state.title_case_headers)\n                {\n                    self.io.buffer(enc_buf);\n\n                    self.state.writing = if encoder.is_last() || encoder.is_close_delimited() {\n                        Writing::Closed\n                    } else {\n                        Writing::KeepAlive\n                    };\n                }\n            }\n            _ => unreachable!(\"write_trailers invalid state: {:?}\", self.state.writing),\n        }\n    }\n\n    pub(crate) fn write_body_and_end(&mut self, chunk: B) {\n        debug_assert!(self.can_write_body() && self.can_buffer_body());\n        // empty chunks should be discarded at Dispatcher level\n        debug_assert!(chunk.remaining() != 0);\n\n        let state = match self.state.writing {\n            Writing::Body(ref encoder) => {\n                let can_keep_alive = encoder.encode_and_end(chunk, self.io.write_buf());\n                if can_keep_alive {\n                    Writing::KeepAlive\n                } else {\n                    Writing::Closed\n                }\n            }\n            _ => unreachable!(\"write_body invalid state: {:?}\", self.state.writing),\n        };\n\n        self.state.writing = state;\n    }\n\n    pub(crate) fn end_body(&mut self) -> crate::Result<()> {\n        debug_assert!(self.can_write_body());\n\n        let encoder = match self.state.writing {\n            Writing::Body(ref mut enc) => enc,\n            _ => return Ok(()),\n        };\n\n        // end of stream, that means we should try to eof\n        match encoder.end() {\n            Ok(end) => {\n                if let Some(end) = end {\n                    self.io.buffer(end);\n                }\n\n                self.state.writing = if encoder.is_last() || encoder.is_close_delimited() {\n                    Writing::Closed\n                } else {\n                    Writing::KeepAlive\n                };\n\n                Ok(())\n            }\n            Err(not_eof) => {\n                self.state.writing = Writing::Closed;\n                Err(crate::Error::new_body_write_aborted().with(not_eof))\n            }\n        }\n    }\n\n    // When we get a parse error, depending on what side we are, we might be able\n    // to write a response before closing the connection.\n    //\n    // - Client: there is nothing we can do\n    // - Server: if Response hasn't been written yet, we can send a 4xx response\n    fn on_parse_error(&mut self, err: crate::Error) -> crate::Result<()> {\n        if let Writing::Init = self.state.writing {\n            if self.has_h2_prefix() {\n                return Err(crate::Error::new_version_h2());\n            }\n            if let Some(msg) = T::on_error(&err) {\n                // Drop the cached headers so as to not trigger a debug\n                // assert in `write_head`...\n                self.state.cached_headers.take();\n                self.write_head(msg, None);\n                self.state.error = Some(err);\n                return Ok(());\n            }\n        }\n\n        // fallback is pass the error back up\n        Err(err)\n    }\n\n    pub(crate) fn poll_flush(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        ready!(Pin::new(&mut self.io).poll_flush(cx))?;\n        self.try_keep_alive(cx);\n        trace!(\"flushed({}): {:?}\", T::LOG, self.state);\n        Poll::Ready(Ok(()))\n    }\n\n    pub(crate) fn poll_shutdown(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        match ready!(Pin::new(self.io.io_mut()).poll_shutdown(cx)) {\n            Ok(()) => {\n                trace!(\"shut down IO complete\");\n                Poll::Ready(Ok(()))\n            }\n            Err(e) => {\n                debug!(\"error shutting down IO: {}\", e);\n                Poll::Ready(Err(e))\n            }\n        }\n    }\n\n    /// If the read side can be cheaply drained, do so. Otherwise, close.\n    pub(super) fn poll_drain_or_close_read(&mut self, cx: &mut Context<'_>) {\n        if let Reading::Continue(ref decoder) = self.state.reading {\n            // skip sending the 100-continue\n            // just move forward to a read, in case a tiny body was included\n            self.state.reading = Reading::Body(decoder.clone());\n        }\n\n        let _ = self.poll_read_body(cx);\n\n        // If still in Reading::Body, just give up\n        match self.state.reading {\n            Reading::Init | Reading::KeepAlive => {\n                trace!(\"body drained\")\n            }\n            _ => self.close_read(),\n        }\n    }\n\n    pub(crate) fn close_read(&mut self) {\n        self.state.close_read();\n    }\n\n    pub(crate) fn close_write(&mut self) {\n        self.state.close_write();\n    }\n\n    #[cfg(feature = \"server\")]\n    pub(crate) fn disable_keep_alive(&mut self) {\n        if self.state.is_idle() {\n            trace!(\"disable_keep_alive; closing idle connection\");\n            self.state.close();\n        } else {\n            trace!(\"disable_keep_alive; in-progress connection\");\n            self.state.disable_keep_alive();\n        }\n    }\n\n    pub(crate) fn take_error(&mut self) -> crate::Result<()> {\n        if let Some(err) = self.state.error.take() {\n            Err(err)\n        } else {\n            Ok(())\n        }\n    }\n\n    pub(super) fn on_upgrade(&mut self) -> crate::upgrade::OnUpgrade {\n        trace!(\"{}: prepare possible HTTP upgrade\", T::LOG);\n        self.state.prepare_upgrade()\n    }\n}\n\nimpl<I, B: Buf, T> fmt::Debug for Conn<I, B, T> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Conn\")\n            .field(\"state\", &self.state)\n            .field(\"io\", &self.io)\n            .finish()\n    }\n}\n\n// B and T are never pinned\nimpl<I: Unpin, B, T> Unpin for Conn<I, B, T> {}\n\nstruct State {\n    allow_half_close: bool,\n    /// Re-usable HeaderMap to reduce allocating new ones.\n    cached_headers: Option<HeaderMap>,\n    /// If an error occurs when there wasn't a direct way to return it\n    /// back to the user, this is set.\n    error: Option<crate::Error>,\n    /// Current keep-alive status.\n    keep_alive: KA,\n    /// If mid-message, the HTTP Method that started it.\n    ///\n    /// This is used to know things such as if the message can include\n    /// a body or not.\n    method: Option<Method>,\n    h1_parser_config: ParserConfig,\n    h1_max_headers: Option<usize>,\n    #[cfg(feature = \"server\")]\n    h1_header_read_timeout: Option<Duration>,\n    #[cfg(feature = \"server\")]\n    h1_header_read_timeout_fut: Option<Pin<Box<dyn Sleep>>>,\n    #[cfg(feature = \"server\")]\n    h1_header_read_timeout_running: bool,\n    #[cfg(feature = \"server\")]\n    date_header: bool,\n    #[cfg(feature = \"server\")]\n    timer: Time,\n    preserve_header_case: bool,\n    #[cfg(feature = \"ffi\")]\n    preserve_header_order: bool,\n    title_case_headers: bool,\n    h09_responses: bool,\n    /// If set, called with each 1xx informational response received for\n    /// the current request. MUST be unset after a non-1xx response is\n    /// received.\n    #[cfg(feature = \"client\")]\n    on_informational: Option<crate::ext::OnInformational>,\n    /// Set to true when the Dispatcher should poll read operations\n    /// again. See the `maybe_notify` method for more.\n    notify_read: bool,\n    /// State of allowed reads\n    reading: Reading,\n    /// State of allowed writes\n    writing: Writing,\n    /// An expected pending HTTP upgrade.\n    upgrade: Option<crate::upgrade::Pending>,\n    /// Either HTTP/1.0 or 1.1 connection\n    version: Version,\n    /// Flag to track if trailer fields are allowed to be sent\n    allow_trailer_fields: bool,\n}\n\n#[derive(Debug)]\nenum Reading {\n    Init,\n    Continue(Decoder),\n    Body(Decoder),\n    KeepAlive,\n    Closed,\n}\n\nenum Writing {\n    Init,\n    Body(Encoder),\n    KeepAlive,\n    Closed,\n}\n\nimpl fmt::Debug for State {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let mut builder = f.debug_struct(\"State\");\n        builder\n            .field(\"reading\", &self.reading)\n            .field(\"writing\", &self.writing)\n            .field(\"keep_alive\", &self.keep_alive);\n\n        // Only show error field if it's interesting...\n        if let Some(ref error) = self.error {\n            builder.field(\"error\", error);\n        }\n\n        if self.allow_half_close {\n            builder.field(\"allow_half_close\", &true);\n        }\n\n        // Purposefully leaving off other fields..\n\n        builder.finish()\n    }\n}\n\nimpl fmt::Debug for Writing {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match *self {\n            Writing::Init => f.write_str(\"Init\"),\n            Writing::Body(ref enc) => f.debug_tuple(\"Body\").field(enc).finish(),\n            Writing::KeepAlive => f.write_str(\"KeepAlive\"),\n            Writing::Closed => f.write_str(\"Closed\"),\n        }\n    }\n}\n\nimpl std::ops::BitAndAssign<bool> for KA {\n    fn bitand_assign(&mut self, enabled: bool) {\n        if !enabled {\n            trace!(\"remote disabling keep-alive\");\n            *self = KA::Disabled;\n        }\n    }\n}\n\n#[derive(Clone, Copy, Debug, Default)]\nenum KA {\n    Idle,\n    #[default]\n    Busy,\n    Disabled,\n}\n\nimpl KA {\n    fn idle(&mut self) {\n        *self = KA::Idle;\n    }\n\n    fn busy(&mut self) {\n        *self = KA::Busy;\n    }\n\n    fn disable(&mut self) {\n        *self = KA::Disabled;\n    }\n\n    fn status(&self) -> KA {\n        *self\n    }\n}\n\nimpl State {\n    fn close(&mut self) {\n        trace!(\"State::close()\");\n        self.reading = Reading::Closed;\n        self.writing = Writing::Closed;\n        self.keep_alive.disable();\n    }\n\n    fn close_read(&mut self) {\n        trace!(\"State::close_read()\");\n        self.reading = Reading::Closed;\n        self.keep_alive.disable();\n    }\n\n    fn close_write(&mut self) {\n        trace!(\"State::close_write()\");\n        self.writing = Writing::Closed;\n        self.keep_alive.disable();\n    }\n\n    fn wants_keep_alive(&self) -> bool {\n        !matches!(self.keep_alive.status(), KA::Disabled)\n    }\n\n    fn try_keep_alive<T: Http1Transaction>(&mut self) {\n        match (&self.reading, &self.writing) {\n            (&Reading::KeepAlive, &Writing::KeepAlive) => {\n                if let KA::Busy = self.keep_alive.status() {\n                    self.idle::<T>();\n                } else {\n                    trace!(\n                        \"try_keep_alive({}): could keep-alive, but status = {:?}\",\n                        T::LOG,\n                        self.keep_alive\n                    );\n                    self.close();\n                }\n            }\n            (&Reading::Closed, &Writing::KeepAlive) | (&Reading::KeepAlive, &Writing::Closed) => {\n                self.close()\n            }\n            _ => (),\n        }\n    }\n\n    fn disable_keep_alive(&mut self) {\n        self.keep_alive.disable()\n    }\n\n    fn busy(&mut self) {\n        if let KA::Disabled = self.keep_alive.status() {\n            return;\n        }\n        self.keep_alive.busy();\n    }\n\n    fn idle<T: Http1Transaction>(&mut self) {\n        debug_assert!(!self.is_idle(), \"State::idle() called while idle\");\n\n        self.method = None;\n        self.keep_alive.idle();\n\n        if !self.is_idle() {\n            self.close();\n            return;\n        }\n\n        self.reading = Reading::Init;\n        self.writing = Writing::Init;\n\n        // !T::should_read_first() means Client.\n        //\n        // If Client connection has just gone idle, the Dispatcher\n        // should try the poll loop one more time, so as to poll the\n        // pending requests stream.\n        if !T::should_read_first() {\n            self.notify_read = true;\n        }\n\n        #[cfg(feature = \"server\")]\n        if self.h1_header_read_timeout.is_some() {\n            // Next read will start and poll the header read timeout,\n            // so we can close the connection if another header isn't\n            // received in a timely manner.\n            self.notify_read = true;\n        }\n    }\n\n    fn is_idle(&self) -> bool {\n        matches!(self.keep_alive.status(), KA::Idle)\n    }\n\n    fn is_read_closed(&self) -> bool {\n        matches!(self.reading, Reading::Closed)\n    }\n\n    fn is_write_closed(&self) -> bool {\n        matches!(self.writing, Writing::Closed)\n    }\n\n    fn prepare_upgrade(&mut self) -> crate::upgrade::OnUpgrade {\n        let (tx, rx) = crate::upgrade::pending();\n        self.upgrade = Some(tx);\n        rx\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    #[cfg(all(feature = \"nightly\", not(miri)))]\n    #[bench]\n    fn bench_read_head_short(b: &mut ::test::Bencher) {\n        use super::*;\n        use crate::common::io::Compat;\n        let s = b\"GET / HTTP/1.1\\r\\nHost: localhost:8080\\r\\n\\r\\n\";\n        let len = s.len();\n        b.bytes = len as u64;\n\n        // an empty IO, we'll be skipping and using the read buffer anyways\n        let io = Compat(tokio_test::io::Builder::new().build());\n        let mut conn = Conn::<_, bytes::Bytes, crate::proto::h1::ServerTransaction>::new(io);\n        *conn.io.read_buf_mut() = ::bytes::BytesMut::from(&s[..]);\n        conn.state.cached_headers = Some(HeaderMap::with_capacity(2));\n\n        let rt = tokio::runtime::Builder::new_current_thread()\n            .enable_all()\n            .build()\n            .unwrap();\n\n        b.iter(|| {\n            rt.block_on(futures_util::future::poll_fn(|cx| {\n                match conn.poll_read_head(cx) {\n                    Poll::Ready(Some(Ok(x))) => {\n                        ::test::black_box(&x);\n                        let mut headers = x.0.headers;\n                        headers.clear();\n                        conn.state.cached_headers = Some(headers);\n                    }\n                    f => panic!(\"expected Ready(Some(Ok(..))): {:?}\", f),\n                }\n\n                conn.io.read_buf_mut().reserve(1);\n                unsafe {\n                    conn.io.read_buf_mut().set_len(len);\n                }\n                conn.state.reading = Reading::Init;\n                Poll::Ready(())\n            }));\n        });\n    }\n\n    /*\n    //TODO: rewrite these using dispatch... someday...\n    use futures::{Async, Future, Stream, Sink};\n    use futures::future;\n\n    use proto::{self, ClientTransaction, MessageHead, ServerTransaction};\n    use super::super::Encoder;\n    use mock::AsyncIo;\n\n    use super::{Conn, Decoder, Reading, Writing};\n    use ::uri::Uri;\n\n    use std::str::FromStr;\n\n    #[test]\n    fn test_conn_init_read() {\n        let good_message = b\"GET / HTTP/1.1\\r\\n\\r\\n\".to_vec();\n        let len = good_message.len();\n        let io = AsyncIo::new_buf(good_message, len);\n        let mut conn = Conn::<_, proto::Bytes, ServerTransaction>::new(io);\n\n        match conn.poll().unwrap() {\n            Async::Ready(Some(Frame::Message { message, body: false })) => {\n                assert_eq!(message, MessageHead {\n                    subject: ::proto::RequestLine(::Get, Uri::from_str(\"/\").unwrap()),\n                    .. MessageHead::default()\n                })\n            },\n            f => panic!(\"frame is not Frame::Message: {:?}\", f)\n        }\n    }\n\n    #[test]\n    fn test_conn_parse_partial() {\n        let _: Result<(), ()> = future::lazy(|| {\n            let good_message = b\"GET / HTTP/1.1\\r\\nHost: foo.bar\\r\\n\\r\\n\".to_vec();\n            let io = AsyncIo::new_buf(good_message, 10);\n            let mut conn = Conn::<_, proto::Bytes, ServerTransaction>::new(io);\n            assert!(conn.poll().unwrap().is_not_ready());\n            conn.io.io_mut().block_in(50);\n            let async = conn.poll().unwrap();\n            assert!(async.is_ready());\n            match async {\n                Async::Ready(Some(Frame::Message { .. })) => (),\n                f => panic!(\"frame is not Message: {:?}\", f),\n            }\n            Ok(())\n        }).wait();\n    }\n\n    #[test]\n    fn test_conn_init_read_eof_idle() {\n        let io = AsyncIo::new_buf(vec![], 1);\n        let mut conn = Conn::<_, proto::Bytes, ServerTransaction>::new(io);\n        conn.state.idle();\n\n        match conn.poll().unwrap() {\n            Async::Ready(None) => {},\n            other => panic!(\"frame is not None: {:?}\", other)\n        }\n    }\n\n    #[test]\n    fn test_conn_init_read_eof_idle_partial_parse() {\n        let io = AsyncIo::new_buf(b\"GET / HTTP/1.1\".to_vec(), 100);\n        let mut conn = Conn::<_, proto::Bytes, ServerTransaction>::new(io);\n        conn.state.idle();\n\n        match conn.poll() {\n            Err(ref err) if err.kind() == std::io::ErrorKind::UnexpectedEof => {},\n            other => panic!(\"unexpected frame: {:?}\", other)\n        }\n    }\n\n    #[test]\n    fn test_conn_init_read_eof_busy() {\n        let _: Result<(), ()> = future::lazy(|| {\n            // server ignores\n            let io = AsyncIo::new_eof();\n            let mut conn = Conn::<_, proto::Bytes, ServerTransaction>::new(io);\n            conn.state.busy();\n\n            match conn.poll().unwrap() {\n                Async::Ready(None) => {},\n                other => panic!(\"unexpected frame: {:?}\", other)\n            }\n\n            // client\n            let io = AsyncIo::new_eof();\n            let mut conn = Conn::<_, proto::Bytes, ClientTransaction>::new(io);\n            conn.state.busy();\n\n            match conn.poll() {\n                Err(ref err) if err.kind() == std::io::ErrorKind::UnexpectedEof => {},\n                other => panic!(\"unexpected frame: {:?}\", other)\n            }\n            Ok(())\n        }).wait();\n    }\n\n    #[test]\n    fn test_conn_body_finish_read_eof() {\n        let _: Result<(), ()> = future::lazy(|| {\n            let io = AsyncIo::new_eof();\n            let mut conn = Conn::<_, proto::Bytes, ClientTransaction>::new(io);\n            conn.state.busy();\n            conn.state.writing = Writing::KeepAlive;\n            conn.state.reading = Reading::Body(Decoder::length(0));\n\n            match conn.poll() {\n                Ok(Async::Ready(Some(Frame::Body { chunk: None }))) => (),\n                other => panic!(\"unexpected frame: {:?}\", other)\n            }\n\n            // conn eofs, but tokio-proto will call poll() again, before calling flush()\n            // the conn eof in this case is perfectly fine\n\n            match conn.poll() {\n                Ok(Async::Ready(None)) => (),\n                other => panic!(\"unexpected frame: {:?}\", other)\n            }\n            Ok(())\n        }).wait();\n    }\n\n    #[test]\n    fn test_conn_message_empty_body_read_eof() {\n        let _: Result<(), ()> = future::lazy(|| {\n            let io = AsyncIo::new_buf(b\"HTTP/1.1 200 OK\\r\\nContent-Length: 0\\r\\n\\r\\n\".to_vec(), 1024);\n            let mut conn = Conn::<_, proto::Bytes, ClientTransaction>::new(io);\n            conn.state.busy();\n            conn.state.writing = Writing::KeepAlive;\n\n            match conn.poll() {\n                Ok(Async::Ready(Some(Frame::Message { body: false, .. }))) => (),\n                other => panic!(\"unexpected frame: {:?}\", other)\n            }\n\n            // conn eofs, but tokio-proto will call poll() again, before calling flush()\n            // the conn eof in this case is perfectly fine\n\n            match conn.poll() {\n                Ok(Async::Ready(None)) => (),\n                other => panic!(\"unexpected frame: {:?}\", other)\n            }\n            Ok(())\n        }).wait();\n    }\n\n    #[test]\n    fn test_conn_read_body_end() {\n        let _: Result<(), ()> = future::lazy(|| {\n            let io = AsyncIo::new_buf(b\"POST / HTTP/1.1\\r\\nContent-Length: 5\\r\\n\\r\\n12345\".to_vec(), 1024);\n            let mut conn = Conn::<_, proto::Bytes, ServerTransaction>::new(io);\n            conn.state.busy();\n\n            match conn.poll() {\n                Ok(Async::Ready(Some(Frame::Message { body: true, .. }))) => (),\n                other => panic!(\"unexpected frame: {:?}\", other)\n            }\n\n            match conn.poll() {\n                Ok(Async::Ready(Some(Frame::Body { chunk: Some(_) }))) => (),\n                other => panic!(\"unexpected frame: {:?}\", other)\n            }\n\n            // When the body is done, `poll` MUST return a `Body` frame with chunk set to `None`\n            match conn.poll() {\n                Ok(Async::Ready(Some(Frame::Body { chunk: None }))) => (),\n                other => panic!(\"unexpected frame: {:?}\", other)\n            }\n\n            match conn.poll() {\n                Ok(Async::NotReady) => (),\n                other => panic!(\"unexpected frame: {:?}\", other)\n            }\n            Ok(())\n        }).wait();\n    }\n\n    #[test]\n    fn test_conn_closed_read() {\n        let io = AsyncIo::new_buf(vec![], 0);\n        let mut conn = Conn::<_, proto::Bytes, ServerTransaction>::new(io);\n        conn.state.close();\n\n        match conn.poll().unwrap() {\n            Async::Ready(None) => {},\n            other => panic!(\"frame is not None: {:?}\", other)\n        }\n    }\n\n    #[test]\n    fn test_conn_body_write_length() {\n        let _ = pretty_env_logger::try_init();\n        let _: Result<(), ()> = future::lazy(|| {\n            let io = AsyncIo::new_buf(vec![], 0);\n            let mut conn = Conn::<_, proto::Bytes, ServerTransaction>::new(io);\n            let max = super::super::io::DEFAULT_MAX_BUFFER_SIZE + 4096;\n            conn.state.writing = Writing::Body(Encoder::length((max * 2) as u64));\n\n            assert!(conn.start_send(Frame::Body { chunk: Some(vec![b'a'; max].into()) }).unwrap().is_ready());\n            assert!(!conn.can_buffer_body());\n\n            assert!(conn.start_send(Frame::Body { chunk: Some(vec![b'b'; 1024 * 8].into()) }).unwrap().is_not_ready());\n\n            conn.io.io_mut().block_in(1024 * 3);\n            assert!(conn.poll_complete().unwrap().is_not_ready());\n            conn.io.io_mut().block_in(1024 * 3);\n            assert!(conn.poll_complete().unwrap().is_not_ready());\n            conn.io.io_mut().block_in(max * 2);\n            assert!(conn.poll_complete().unwrap().is_ready());\n\n            assert!(conn.start_send(Frame::Body { chunk: Some(vec![b'c'; 1024 * 8].into()) }).unwrap().is_ready());\n            Ok(())\n        }).wait();\n    }\n\n    #[test]\n    fn test_conn_body_write_chunked() {\n        let _: Result<(), ()> = future::lazy(|| {\n            let io = AsyncIo::new_buf(vec![], 4096);\n            let mut conn = Conn::<_, proto::Bytes, ServerTransaction>::new(io);\n            conn.state.writing = Writing::Body(Encoder::chunked());\n\n            assert!(conn.start_send(Frame::Body { chunk: Some(\"headers\".into()) }).unwrap().is_ready());\n            assert!(conn.start_send(Frame::Body { chunk: Some(vec![b'x'; 8192].into()) }).unwrap().is_ready());\n            Ok(())\n        }).wait();\n    }\n\n    #[test]\n    fn test_conn_body_flush() {\n        let _: Result<(), ()> = future::lazy(|| {\n            let io = AsyncIo::new_buf(vec![], 1024 * 1024 * 5);\n            let mut conn = Conn::<_, proto::Bytes, ServerTransaction>::new(io);\n            conn.state.writing = Writing::Body(Encoder::length(1024 * 1024));\n            assert!(conn.start_send(Frame::Body { chunk: Some(vec![b'a'; 1024 * 1024].into()) }).unwrap().is_ready());\n            assert!(!conn.can_buffer_body());\n            conn.io.io_mut().block_in(1024 * 1024 * 5);\n            assert!(conn.poll_complete().unwrap().is_ready());\n            assert!(conn.can_buffer_body());\n            assert!(conn.io.io_mut().flushed());\n\n            Ok(())\n        }).wait();\n    }\n\n    #[test]\n    fn test_conn_parking() {\n        use std::sync::Arc;\n        use futures::executor::Notify;\n        use futures::executor::NotifyHandle;\n\n        struct Car {\n            permit: bool,\n        }\n        impl Notify for Car {\n            fn notify(&self, _id: usize) {\n                assert!(self.permit, \"unparked without permit\");\n            }\n        }\n\n        fn car(permit: bool) -> NotifyHandle {\n            Arc::new(Car {\n                permit: permit,\n            }).into()\n        }\n\n        // test that once writing is done, unparks\n        let f = future::lazy(|| {\n            let io = AsyncIo::new_buf(vec![], 4096);\n            let mut conn = Conn::<_, proto::Bytes, ServerTransaction>::new(io);\n            conn.state.reading = Reading::KeepAlive;\n            assert!(conn.poll().unwrap().is_not_ready());\n\n            conn.state.writing = Writing::KeepAlive;\n            assert!(conn.poll_complete().unwrap().is_ready());\n            Ok::<(), ()>(())\n        });\n        ::futures::executor::spawn(f).poll_future_notify(&car(true), 0).unwrap();\n\n\n        // test that flushing when not waiting on read doesn't unpark\n        let f = future::lazy(|| {\n            let io = AsyncIo::new_buf(vec![], 4096);\n            let mut conn = Conn::<_, proto::Bytes, ServerTransaction>::new(io);\n            conn.state.writing = Writing::KeepAlive;\n            assert!(conn.poll_complete().unwrap().is_ready());\n            Ok::<(), ()>(())\n        });\n        ::futures::executor::spawn(f).poll_future_notify(&car(false), 0).unwrap();\n\n\n        // test that flushing and writing isn't done doesn't unpark\n        let f = future::lazy(|| {\n            let io = AsyncIo::new_buf(vec![], 4096);\n            let mut conn = Conn::<_, proto::Bytes, ServerTransaction>::new(io);\n            conn.state.reading = Reading::KeepAlive;\n            assert!(conn.poll().unwrap().is_not_ready());\n            conn.state.writing = Writing::Body(Encoder::length(5_000));\n            assert!(conn.poll_complete().unwrap().is_ready());\n            Ok::<(), ()>(())\n        });\n        ::futures::executor::spawn(f).poll_future_notify(&car(false), 0).unwrap();\n    }\n\n    #[test]\n    fn test_conn_closed_write() {\n        let io = AsyncIo::new_buf(vec![], 0);\n        let mut conn = Conn::<_, proto::Bytes, ServerTransaction>::new(io);\n        conn.state.close();\n\n        match conn.start_send(Frame::Body { chunk: Some(b\"foobar\".to_vec().into()) }) {\n            Err(_e) => {},\n            other => panic!(\"did not return Err: {:?}\", other)\n        }\n\n        assert!(conn.state.is_write_closed());\n    }\n\n    #[test]\n    fn test_conn_write_empty_chunk() {\n        let io = AsyncIo::new_buf(vec![], 0);\n        let mut conn = Conn::<_, proto::Bytes, ServerTransaction>::new(io);\n        conn.state.writing = Writing::KeepAlive;\n\n        assert!(conn.start_send(Frame::Body { chunk: None }).unwrap().is_ready());\n        assert!(conn.start_send(Frame::Body { chunk: Some(Vec::new().into()) }).unwrap().is_ready());\n        conn.start_send(Frame::Body { chunk: Some(vec![b'a'].into()) }).unwrap_err();\n    }\n    */\n}\n"
  },
  {
    "path": "src/proto/h1/decode.rs",
    "content": "use std::error::Error as StdError;\nuse std::fmt;\nuse std::io;\nuse std::task::{Context, Poll};\n\nuse bytes::{BufMut, Bytes, BytesMut};\nuse futures_core::ready;\nuse http::{HeaderMap, HeaderName, HeaderValue};\nuse http_body::Frame;\n\nuse super::io::MemRead;\nuse super::role::DEFAULT_MAX_HEADERS;\nuse super::DecodedLength;\n\nuse self::Kind::{Chunked, Eof, Length};\n\n/// Maximum amount of bytes allowed in chunked extensions.\n///\n/// This limit is currentlty applied for the entire body, not per chunk.\nconst CHUNKED_EXTENSIONS_LIMIT: u64 = 1024 * 16;\n\n/// Maximum number of bytes allowed for all trailer fields.\n///\n/// TODO: remove this when we land h1_max_header_size support\nconst TRAILER_LIMIT: usize = 1024 * 16;\n\n/// Decoders to handle different Transfer-Encodings.\n///\n/// If a message body does not include a Transfer-Encoding, it *should*\n/// include a Content-Length header.\n#[derive(Clone, PartialEq)]\npub(crate) struct Decoder {\n    kind: Kind,\n}\n\n#[derive(Debug, Clone, PartialEq)]\nenum Kind {\n    /// A Reader used when a Content-Length header is passed with a positive integer.\n    Length(u64),\n    /// A Reader used when Transfer-Encoding is `chunked`.\n    Chunked {\n        state: ChunkedState,\n        chunk_len: u64,\n        extensions_cnt: u64,\n        trailers_buf: Option<BytesMut>,\n        trailers_cnt: usize,\n        h1_max_headers: Option<usize>,\n        h1_max_header_size: Option<usize>,\n    },\n    /// A Reader used for responses that don't indicate a length or chunked.\n    ///\n    /// The bool tracks when EOF is seen on the transport.\n    ///\n    /// Note: This should only used for `Response`s. It is illegal for a\n    /// `Request` to be made with both `Content-Length` and\n    /// `Transfer-Encoding: chunked` missing, as explained from the spec:\n    ///\n    /// > If a Transfer-Encoding header field is present in a response and\n    /// > the chunked transfer coding is not the final encoding, the\n    /// > message body length is determined by reading the connection until\n    /// > it is closed by the server.  If a Transfer-Encoding header field\n    /// > is present in a request and the chunked transfer coding is not\n    /// > the final encoding, the message body length cannot be determined\n    /// > reliably; the server MUST respond with the 400 (Bad Request)\n    /// > status code and then close the connection.\n    Eof(bool),\n}\n\n#[derive(Debug, PartialEq, Clone, Copy)]\nenum ChunkedState {\n    Start,\n    Size,\n    SizeLws,\n    Extension,\n    SizeLf,\n    Body,\n    BodyCr,\n    BodyLf,\n    Trailer,\n    TrailerLf,\n    EndCr,\n    EndLf,\n    End,\n}\n\nimpl Decoder {\n    // constructors\n\n    pub(crate) fn length(x: u64) -> Decoder {\n        Decoder {\n            kind: Kind::Length(x),\n        }\n    }\n\n    pub(crate) fn chunked(\n        h1_max_headers: Option<usize>,\n        h1_max_header_size: Option<usize>,\n    ) -> Decoder {\n        Decoder {\n            kind: Kind::Chunked {\n                state: ChunkedState::new(),\n                chunk_len: 0,\n                extensions_cnt: 0,\n                trailers_buf: None,\n                trailers_cnt: 0,\n                h1_max_headers,\n                h1_max_header_size,\n            },\n        }\n    }\n\n    pub(crate) fn eof() -> Decoder {\n        Decoder {\n            kind: Kind::Eof(false),\n        }\n    }\n\n    pub(super) fn new(\n        len: DecodedLength,\n        h1_max_headers: Option<usize>,\n        h1_max_header_size: Option<usize>,\n    ) -> Self {\n        match len {\n            DecodedLength::CHUNKED => Decoder::chunked(h1_max_headers, h1_max_header_size),\n            DecodedLength::CLOSE_DELIMITED => Decoder::eof(),\n            length => Decoder::length(length.danger_len()),\n        }\n    }\n\n    // methods\n\n    pub(crate) fn is_eof(&self) -> bool {\n        matches!(\n            self.kind,\n            Length(0)\n                | Chunked {\n                    state: ChunkedState::End,\n                    ..\n                }\n                | Eof(true)\n        )\n    }\n\n    pub(crate) fn decode<R: MemRead>(\n        &mut self,\n        cx: &mut Context<'_>,\n        body: &mut R,\n    ) -> Poll<Result<Frame<Bytes>, io::Error>> {\n        trace!(\"decode; state={:?}\", self.kind);\n        match self.kind {\n            Length(ref mut remaining) => {\n                if *remaining == 0 {\n                    Poll::Ready(Ok(Frame::data(Bytes::new())))\n                } else {\n                    let to_read = *remaining as usize;\n                    let buf = ready!(body.read_mem(cx, to_read))?;\n                    let num = buf.as_ref().len() as u64;\n                    if num > *remaining {\n                        *remaining = 0;\n                    } else if num == 0 {\n                        return Poll::Ready(Err(io::Error::new(\n                            io::ErrorKind::UnexpectedEof,\n                            IncompleteBody,\n                        )));\n                    } else {\n                        *remaining -= num;\n                    }\n                    Poll::Ready(Ok(Frame::data(buf)))\n                }\n            }\n            Chunked {\n                ref mut state,\n                ref mut chunk_len,\n                ref mut extensions_cnt,\n                ref mut trailers_buf,\n                ref mut trailers_cnt,\n                ref h1_max_headers,\n                ref h1_max_header_size,\n            } => {\n                let h1_max_headers = h1_max_headers.unwrap_or(DEFAULT_MAX_HEADERS);\n                let h1_max_header_size = h1_max_header_size.unwrap_or(TRAILER_LIMIT);\n                loop {\n                    let mut buf = None;\n                    // advances the chunked state\n                    *state = ready!(state.step(\n                        cx,\n                        body,\n                        StepArgs {\n                            chunk_size: chunk_len,\n                            extensions_cnt,\n                            chunk_buf: &mut buf,\n                            trailers_buf,\n                            trailers_cnt,\n                            max_headers_cnt: h1_max_headers,\n                            max_headers_bytes: h1_max_header_size,\n                        }\n                    ))?;\n                    if *state == ChunkedState::End {\n                        trace!(\"end of chunked\");\n\n                        if trailers_buf.is_some() {\n                            trace!(\"found possible trailers\");\n\n                            // decoder enforces that trailers count will not exceed h1_max_headers\n                            if *trailers_cnt >= h1_max_headers {\n                                return Poll::Ready(Err(io::Error::new(\n                                    io::ErrorKind::InvalidData,\n                                    \"chunk trailers count overflow\",\n                                )));\n                            }\n                            match decode_trailers(\n                                &mut trailers_buf.take().expect(\"Trailer is None\"),\n                                *trailers_cnt,\n                            ) {\n                                Ok(headers) => {\n                                    return Poll::Ready(Ok(Frame::trailers(headers)));\n                                }\n                                Err(e) => {\n                                    return Poll::Ready(Err(e));\n                                }\n                            }\n                        }\n\n                        return Poll::Ready(Ok(Frame::data(Bytes::new())));\n                    }\n                    if let Some(buf) = buf {\n                        return Poll::Ready(Ok(Frame::data(buf)));\n                    }\n                }\n            }\n            Eof(ref mut is_eof) => {\n                if *is_eof {\n                    Poll::Ready(Ok(Frame::data(Bytes::new())))\n                } else {\n                    // 8192 chosen because its about 2 packets, there probably\n                    // won't be that much available, so don't have MemReaders\n                    // allocate buffers to big\n                    body.read_mem(cx, 8192).map_ok(|slice| {\n                        *is_eof = slice.is_empty();\n                        Frame::data(slice)\n                    })\n                }\n            }\n        }\n    }\n\n    #[cfg(test)]\n    async fn decode_fut<R: MemRead>(&mut self, body: &mut R) -> Result<Frame<Bytes>, io::Error> {\n        futures_util::future::poll_fn(move |cx| self.decode(cx, body)).await\n    }\n}\n\nimpl fmt::Debug for Decoder {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        fmt::Debug::fmt(&self.kind, f)\n    }\n}\n\nmacro_rules! byte (\n    ($rdr:ident, $cx:expr) => ({\n        let buf = ready!($rdr.read_mem($cx, 1))?;\n        if !buf.is_empty() {\n            buf[0]\n        } else {\n            return Poll::Ready(Err(io::Error::new(io::ErrorKind::UnexpectedEof,\n                                      \"unexpected EOF during chunk size line\")));\n        }\n    })\n);\n\nmacro_rules! or_overflow {\n    ($e:expr) => (\n        match $e {\n            Some(val) => val,\n            None => return Poll::Ready(Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"invalid chunk size: overflow\",\n            ))),\n        }\n    )\n}\n\nmacro_rules! put_u8 {\n    ($trailers_buf:expr, $byte:expr, $limit:expr) => {\n        $trailers_buf.put_u8($byte);\n\n        if $trailers_buf.len() >= $limit {\n            return Poll::Ready(Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"chunk trailers bytes over limit\",\n            )));\n        }\n    };\n}\n\nstruct StepArgs<'a> {\n    chunk_size: &'a mut u64,\n    chunk_buf: &'a mut Option<Bytes>,\n    extensions_cnt: &'a mut u64,\n    trailers_buf: &'a mut Option<BytesMut>,\n    trailers_cnt: &'a mut usize,\n    max_headers_cnt: usize,\n    max_headers_bytes: usize,\n}\n\nimpl ChunkedState {\n    fn new() -> ChunkedState {\n        ChunkedState::Start\n    }\n    fn step<R: MemRead>(\n        &self,\n        cx: &mut Context<'_>,\n        body: &mut R,\n        StepArgs {\n            chunk_size,\n            chunk_buf,\n            extensions_cnt,\n            trailers_buf,\n            trailers_cnt,\n            max_headers_cnt,\n            max_headers_bytes,\n        }: StepArgs<'_>,\n    ) -> Poll<Result<ChunkedState, io::Error>> {\n        use self::ChunkedState::*;\n        match *self {\n            Start => ChunkedState::read_start(cx, body, chunk_size),\n            Size => ChunkedState::read_size(cx, body, chunk_size),\n            SizeLws => ChunkedState::read_size_lws(cx, body),\n            Extension => ChunkedState::read_extension(cx, body, extensions_cnt),\n            SizeLf => ChunkedState::read_size_lf(cx, body, *chunk_size),\n            Body => ChunkedState::read_body(cx, body, chunk_size, chunk_buf),\n            BodyCr => ChunkedState::read_body_cr(cx, body),\n            BodyLf => ChunkedState::read_body_lf(cx, body),\n            Trailer => ChunkedState::read_trailer(cx, body, trailers_buf, max_headers_bytes),\n            TrailerLf => ChunkedState::read_trailer_lf(\n                cx,\n                body,\n                trailers_buf,\n                trailers_cnt,\n                max_headers_cnt,\n                max_headers_bytes,\n            ),\n            EndCr => ChunkedState::read_end_cr(cx, body, trailers_buf, max_headers_bytes),\n            EndLf => ChunkedState::read_end_lf(cx, body, trailers_buf, max_headers_bytes),\n            End => Poll::Ready(Ok(ChunkedState::End)),\n        }\n    }\n\n    fn read_start<R: MemRead>(\n        cx: &mut Context<'_>,\n        rdr: &mut R,\n        size: &mut u64,\n    ) -> Poll<Result<ChunkedState, io::Error>> {\n        trace!(\"Read chunk start\");\n\n        let radix = 16;\n        match byte!(rdr, cx) {\n            b @ b'0'..=b'9' => {\n                *size = or_overflow!(size.checked_mul(radix));\n                *size = or_overflow!(size.checked_add((b - b'0') as u64));\n            }\n            b @ b'a'..=b'f' => {\n                *size = or_overflow!(size.checked_mul(radix));\n                *size = or_overflow!(size.checked_add((b + 10 - b'a') as u64));\n            }\n            b @ b'A'..=b'F' => {\n                *size = or_overflow!(size.checked_mul(radix));\n                *size = or_overflow!(size.checked_add((b + 10 - b'A') as u64));\n            }\n            _ => {\n                return Poll::Ready(Err(io::Error::new(\n                    io::ErrorKind::InvalidInput,\n                    \"Invalid chunk size line: missing size digit\",\n                )));\n            }\n        }\n\n        Poll::Ready(Ok(ChunkedState::Size))\n    }\n\n    fn read_size<R: MemRead>(\n        cx: &mut Context<'_>,\n        rdr: &mut R,\n        size: &mut u64,\n    ) -> Poll<Result<ChunkedState, io::Error>> {\n        trace!(\"Read chunk hex size\");\n\n        let radix = 16;\n        match byte!(rdr, cx) {\n            b @ b'0'..=b'9' => {\n                *size = or_overflow!(size.checked_mul(radix));\n                *size = or_overflow!(size.checked_add((b - b'0') as u64));\n            }\n            b @ b'a'..=b'f' => {\n                *size = or_overflow!(size.checked_mul(radix));\n                *size = or_overflow!(size.checked_add((b + 10 - b'a') as u64));\n            }\n            b @ b'A'..=b'F' => {\n                *size = or_overflow!(size.checked_mul(radix));\n                *size = or_overflow!(size.checked_add((b + 10 - b'A') as u64));\n            }\n            b'\\t' | b' ' => return Poll::Ready(Ok(ChunkedState::SizeLws)),\n            b';' => return Poll::Ready(Ok(ChunkedState::Extension)),\n            b'\\r' => return Poll::Ready(Ok(ChunkedState::SizeLf)),\n            _ => {\n                return Poll::Ready(Err(io::Error::new(\n                    io::ErrorKind::InvalidInput,\n                    \"Invalid chunk size line: Invalid Size\",\n                )));\n            }\n        }\n        Poll::Ready(Ok(ChunkedState::Size))\n    }\n    fn read_size_lws<R: MemRead>(\n        cx: &mut Context<'_>,\n        rdr: &mut R,\n    ) -> Poll<Result<ChunkedState, io::Error>> {\n        trace!(\"read_size_lws\");\n        match byte!(rdr, cx) {\n            // LWS can follow the chunk size, but no more digits can come\n            b'\\t' | b' ' => Poll::Ready(Ok(ChunkedState::SizeLws)),\n            b';' => Poll::Ready(Ok(ChunkedState::Extension)),\n            b'\\r' => Poll::Ready(Ok(ChunkedState::SizeLf)),\n            _ => Poll::Ready(Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                \"Invalid chunk size linear white space\",\n            ))),\n        }\n    }\n    fn read_extension<R: MemRead>(\n        cx: &mut Context<'_>,\n        rdr: &mut R,\n        extensions_cnt: &mut u64,\n    ) -> Poll<Result<ChunkedState, io::Error>> {\n        trace!(\"read_extension\");\n        // We don't care about extensions really at all. Just ignore them.\n        // They \"end\" at the next CRLF.\n        //\n        // However, some implementations may not check for the CR, so to save\n        // them from themselves, we reject extensions containing plain LF as\n        // well.\n        match byte!(rdr, cx) {\n            b'\\r' => Poll::Ready(Ok(ChunkedState::SizeLf)),\n            b'\\n' => Poll::Ready(Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"invalid chunk extension contains newline\",\n            ))),\n            _ => {\n                *extensions_cnt += 1;\n                if *extensions_cnt >= CHUNKED_EXTENSIONS_LIMIT {\n                    Poll::Ready(Err(io::Error::new(\n                        io::ErrorKind::InvalidData,\n                        \"chunk extensions over limit\",\n                    )))\n                } else {\n                    Poll::Ready(Ok(ChunkedState::Extension))\n                }\n            } // no supported extensions\n        }\n    }\n    fn read_size_lf<R: MemRead>(\n        cx: &mut Context<'_>,\n        rdr: &mut R,\n        size: u64,\n    ) -> Poll<Result<ChunkedState, io::Error>> {\n        trace!(\"Chunk size is {:?}\", size);\n        match byte!(rdr, cx) {\n            b'\\n' => {\n                if size == 0 {\n                    Poll::Ready(Ok(ChunkedState::EndCr))\n                } else {\n                    debug!(\"incoming chunked header: {0:#X} ({0} bytes)\", size);\n                    Poll::Ready(Ok(ChunkedState::Body))\n                }\n            }\n            _ => Poll::Ready(Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                \"Invalid chunk size LF\",\n            ))),\n        }\n    }\n\n    fn read_body<R: MemRead>(\n        cx: &mut Context<'_>,\n        rdr: &mut R,\n        rem: &mut u64,\n        buf: &mut Option<Bytes>,\n    ) -> Poll<Result<ChunkedState, io::Error>> {\n        trace!(\"Chunked read, remaining={:?}\", rem);\n\n        // cap remaining bytes at the max capacity of usize\n        let rem_cap = match *rem {\n            r if r > usize::MAX as u64 => usize::MAX,\n            r => r as usize,\n        };\n\n        let to_read = rem_cap;\n        let slice = ready!(rdr.read_mem(cx, to_read))?;\n        let count = slice.len();\n\n        if count == 0 {\n            *rem = 0;\n            return Poll::Ready(Err(io::Error::new(\n                io::ErrorKind::UnexpectedEof,\n                IncompleteBody,\n            )));\n        }\n        *buf = Some(slice);\n        *rem -= count as u64;\n\n        if *rem > 0 {\n            Poll::Ready(Ok(ChunkedState::Body))\n        } else {\n            Poll::Ready(Ok(ChunkedState::BodyCr))\n        }\n    }\n    fn read_body_cr<R: MemRead>(\n        cx: &mut Context<'_>,\n        rdr: &mut R,\n    ) -> Poll<Result<ChunkedState, io::Error>> {\n        match byte!(rdr, cx) {\n            b'\\r' => Poll::Ready(Ok(ChunkedState::BodyLf)),\n            _ => Poll::Ready(Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                \"Invalid chunk body CR\",\n            ))),\n        }\n    }\n    fn read_body_lf<R: MemRead>(\n        cx: &mut Context<'_>,\n        rdr: &mut R,\n    ) -> Poll<Result<ChunkedState, io::Error>> {\n        match byte!(rdr, cx) {\n            b'\\n' => Poll::Ready(Ok(ChunkedState::Start)),\n            _ => Poll::Ready(Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                \"Invalid chunk body LF\",\n            ))),\n        }\n    }\n\n    fn read_trailer<R: MemRead>(\n        cx: &mut Context<'_>,\n        rdr: &mut R,\n        trailers_buf: &mut Option<BytesMut>,\n        h1_max_header_size: usize,\n    ) -> Poll<Result<ChunkedState, io::Error>> {\n        trace!(\"read_trailer\");\n        let byte = byte!(rdr, cx);\n\n        put_u8!(\n            trailers_buf.as_mut().expect(\"trailers_buf is None\"),\n            byte,\n            h1_max_header_size\n        );\n\n        match byte {\n            b'\\r' => Poll::Ready(Ok(ChunkedState::TrailerLf)),\n            _ => Poll::Ready(Ok(ChunkedState::Trailer)),\n        }\n    }\n\n    fn read_trailer_lf<R: MemRead>(\n        cx: &mut Context<'_>,\n        rdr: &mut R,\n        trailers_buf: &mut Option<BytesMut>,\n        trailers_cnt: &mut usize,\n        h1_max_headers: usize,\n        h1_max_header_size: usize,\n    ) -> Poll<Result<ChunkedState, io::Error>> {\n        let byte = byte!(rdr, cx);\n        match byte {\n            b'\\n' => {\n                if *trailers_cnt >= h1_max_headers {\n                    return Poll::Ready(Err(io::Error::new(\n                        io::ErrorKind::InvalidData,\n                        \"chunk trailers count overflow\",\n                    )));\n                }\n                *trailers_cnt += 1;\n\n                put_u8!(\n                    trailers_buf.as_mut().expect(\"trailers_buf is None\"),\n                    byte,\n                    h1_max_header_size\n                );\n\n                Poll::Ready(Ok(ChunkedState::EndCr))\n            }\n            _ => Poll::Ready(Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                \"Invalid trailer end LF\",\n            ))),\n        }\n    }\n\n    fn read_end_cr<R: MemRead>(\n        cx: &mut Context<'_>,\n        rdr: &mut R,\n        trailers_buf: &mut Option<BytesMut>,\n        h1_max_header_size: usize,\n    ) -> Poll<Result<ChunkedState, io::Error>> {\n        let byte = byte!(rdr, cx);\n        match byte {\n            b'\\r' => {\n                if let Some(trailers_buf) = trailers_buf {\n                    put_u8!(trailers_buf, byte, h1_max_header_size);\n                }\n                Poll::Ready(Ok(ChunkedState::EndLf))\n            }\n            byte => {\n                match trailers_buf {\n                    None => {\n                        // 64 will fit a single Expires header without reallocating\n                        let mut buf = BytesMut::with_capacity(64);\n                        buf.put_u8(byte);\n                        *trailers_buf = Some(buf);\n                    }\n                    Some(ref mut trailers_buf) => {\n                        put_u8!(trailers_buf, byte, h1_max_header_size);\n                    }\n                }\n\n                Poll::Ready(Ok(ChunkedState::Trailer))\n            }\n        }\n    }\n    fn read_end_lf<R: MemRead>(\n        cx: &mut Context<'_>,\n        rdr: &mut R,\n        trailers_buf: &mut Option<BytesMut>,\n        h1_max_header_size: usize,\n    ) -> Poll<Result<ChunkedState, io::Error>> {\n        let byte = byte!(rdr, cx);\n        match byte {\n            b'\\n' => {\n                if let Some(trailers_buf) = trailers_buf {\n                    put_u8!(trailers_buf, byte, h1_max_header_size);\n                }\n                Poll::Ready(Ok(ChunkedState::End))\n            }\n            _ => Poll::Ready(Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                \"Invalid chunk end LF\",\n            ))),\n        }\n    }\n}\n\n// TODO: disallow Transfer-Encoding, Content-Length, Trailer, etc in trailers ??\nfn decode_trailers(buf: &mut BytesMut, count: usize) -> Result<HeaderMap, io::Error> {\n    let mut trailers = HeaderMap::new();\n    let mut headers = vec![httparse::EMPTY_HEADER; count];\n    let res = httparse::parse_headers(buf, &mut headers);\n    match res {\n        Ok(httparse::Status::Complete((_, headers))) => {\n            for header in headers.iter() {\n                use std::convert::TryFrom;\n                let name = match HeaderName::try_from(header.name) {\n                    Ok(name) => name,\n                    Err(_) => {\n                        return Err(io::Error::new(\n                            io::ErrorKind::InvalidInput,\n                            format!(\"Invalid header name: {:?}\", &header),\n                        ));\n                    }\n                };\n\n                let value = match HeaderValue::from_bytes(header.value) {\n                    Ok(value) => value,\n                    Err(_) => {\n                        return Err(io::Error::new(\n                            io::ErrorKind::InvalidInput,\n                            format!(\"Invalid header value: {:?}\", &header),\n                        ));\n                    }\n                };\n\n                trailers.insert(name, value);\n            }\n\n            Ok(trailers)\n        }\n        Ok(httparse::Status::Partial) => Err(io::Error::new(\n            io::ErrorKind::InvalidInput,\n            \"Partial header\",\n        )),\n        Err(e) => Err(io::Error::new(io::ErrorKind::InvalidInput, e)),\n    }\n}\n\n#[derive(Debug)]\nstruct IncompleteBody;\n\nimpl fmt::Display for IncompleteBody {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"end of file before message length reached\")\n    }\n}\n\nimpl StdError for IncompleteBody {}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::rt::{Read, ReadBuf};\n    use std::pin::Pin;\n    use std::time::Duration;\n\n    impl MemRead for &[u8] {\n        fn read_mem(&mut self, _: &mut Context<'_>, len: usize) -> Poll<io::Result<Bytes>> {\n            let n = std::cmp::min(len, self.len());\n            if n > 0 {\n                let (a, b) = self.split_at(n);\n                let buf = Bytes::copy_from_slice(a);\n                *self = b;\n                Poll::Ready(Ok(buf))\n            } else {\n                Poll::Ready(Ok(Bytes::new()))\n            }\n        }\n    }\n\n    impl MemRead for &mut (dyn Read + Unpin) {\n        fn read_mem(&mut self, cx: &mut Context<'_>, len: usize) -> Poll<io::Result<Bytes>> {\n            let mut v = vec![0; len];\n            let mut buf = ReadBuf::new(&mut v);\n            ready!(Pin::new(self).poll_read(cx, buf.unfilled())?);\n            Poll::Ready(Ok(Bytes::copy_from_slice(buf.filled())))\n        }\n    }\n\n    impl MemRead for Bytes {\n        fn read_mem(&mut self, _: &mut Context<'_>, len: usize) -> Poll<io::Result<Bytes>> {\n            let n = std::cmp::min(len, self.len());\n            let ret = self.split_to(n);\n            Poll::Ready(Ok(ret))\n        }\n    }\n\n    /*\n    use std::io;\n    use std::io::Write;\n    use super::Decoder;\n    use super::ChunkedState;\n    use futures::{Async, Poll};\n    use bytes::{BytesMut, Bytes};\n    use crate::mock::AsyncIo;\n    */\n\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn test_read_chunk_size() {\n        use std::io::ErrorKind::{InvalidData, InvalidInput, UnexpectedEof};\n\n        async fn read(s: &str) -> u64 {\n            let mut state = ChunkedState::new();\n            let rdr = &mut s.as_bytes();\n            let mut size = 0;\n            let mut ext_cnt = 0;\n            let mut trailers_cnt = 0;\n            loop {\n                let result = futures_util::future::poll_fn(|cx| {\n                    state.step(\n                        cx,\n                        rdr,\n                        StepArgs {\n                            chunk_size: &mut size,\n                            extensions_cnt: &mut ext_cnt,\n                            chunk_buf: &mut None,\n                            trailers_buf: &mut None,\n                            trailers_cnt: &mut trailers_cnt,\n                            max_headers_cnt: DEFAULT_MAX_HEADERS,\n                            max_headers_bytes: TRAILER_LIMIT,\n                        },\n                    )\n                })\n                .await;\n                let desc = format!(\"read_size failed for {:?}\", s);\n                state = result.expect(&desc);\n                if state == ChunkedState::Body || state == ChunkedState::EndCr {\n                    break;\n                }\n            }\n            size\n        }\n\n        async fn read_err(s: &str, expected_err: io::ErrorKind) {\n            let mut state = ChunkedState::new();\n            let rdr = &mut s.as_bytes();\n            let mut size = 0;\n            let mut ext_cnt = 0;\n            let mut trailers_cnt = 0;\n            loop {\n                let result = futures_util::future::poll_fn(|cx| {\n                    state.step(\n                        cx,\n                        rdr,\n                        StepArgs {\n                            chunk_size: &mut size,\n                            extensions_cnt: &mut ext_cnt,\n                            chunk_buf: &mut None,\n                            trailers_buf: &mut None,\n                            trailers_cnt: &mut trailers_cnt,\n                            max_headers_cnt: DEFAULT_MAX_HEADERS,\n                            max_headers_bytes: TRAILER_LIMIT,\n                        },\n                    )\n                })\n                .await;\n                state = match result {\n                    Ok(s) => s,\n                    Err(e) => {\n                        assert!(\n                            expected_err == e.kind(),\n                            \"Reading {:?}, expected {:?}, but got {:?}\",\n                            s,\n                            expected_err,\n                            e.kind()\n                        );\n                        return;\n                    }\n                };\n                if state == ChunkedState::Body || state == ChunkedState::End {\n                    panic!(\"Was Ok. Expected Err for {:?}\", s);\n                }\n            }\n        }\n\n        assert_eq!(1, read(\"1\\r\\n\").await);\n        assert_eq!(1, read(\"01\\r\\n\").await);\n        assert_eq!(0, read(\"0\\r\\n\").await);\n        assert_eq!(0, read(\"00\\r\\n\").await);\n        assert_eq!(10, read(\"A\\r\\n\").await);\n        assert_eq!(10, read(\"a\\r\\n\").await);\n        assert_eq!(255, read(\"Ff\\r\\n\").await);\n        assert_eq!(255, read(\"Ff   \\r\\n\").await);\n        // Missing LF or CRLF\n        read_err(\"F\\rF\", InvalidInput).await;\n        read_err(\"F\", UnexpectedEof).await;\n        // Missing digit\n        read_err(\"\\r\\n\\r\\n\", InvalidInput).await;\n        read_err(\"\\r\\n\", InvalidInput).await;\n        // Invalid hex digit\n        read_err(\"X\\r\\n\", InvalidInput).await;\n        read_err(\"1X\\r\\n\", InvalidInput).await;\n        read_err(\"-\\r\\n\", InvalidInput).await;\n        read_err(\"-1\\r\\n\", InvalidInput).await;\n        // Acceptable (if not fully valid) extensions do not influence the size\n        assert_eq!(1, read(\"1;extension\\r\\n\").await);\n        assert_eq!(10, read(\"a;ext name=value\\r\\n\").await);\n        assert_eq!(1, read(\"1;extension;extension2\\r\\n\").await);\n        assert_eq!(1, read(\"1;;;  ;\\r\\n\").await);\n        assert_eq!(2, read(\"2; extension...\\r\\n\").await);\n        assert_eq!(3, read(\"3   ; extension=123\\r\\n\").await);\n        assert_eq!(3, read(\"3   ;\\r\\n\").await);\n        assert_eq!(3, read(\"3   ;   \\r\\n\").await);\n        // Invalid extensions cause an error\n        read_err(\"1 invalid extension\\r\\n\", InvalidInput).await;\n        read_err(\"1 A\\r\\n\", InvalidInput).await;\n        read_err(\"1;no CRLF\", UnexpectedEof).await;\n        read_err(\"1;reject\\nnewlines\\r\\n\", InvalidData).await;\n        // Overflow\n        read_err(\"f0000000000000003\\r\\n\", InvalidData).await;\n    }\n\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn test_read_sized_early_eof() {\n        let mut bytes = &b\"foo bar\"[..];\n        let mut decoder = Decoder::length(10);\n        assert_eq!(\n            decoder\n                .decode_fut(&mut bytes)\n                .await\n                .unwrap()\n                .data_ref()\n                .unwrap()\n                .len(),\n            7\n        );\n        let e = decoder.decode_fut(&mut bytes).await.unwrap_err();\n        assert_eq!(e.kind(), io::ErrorKind::UnexpectedEof);\n    }\n\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn test_read_chunked_early_eof() {\n        let mut bytes = &b\"\\\n            9\\r\\n\\\n            foo bar\\\n        \"[..];\n        let mut decoder = Decoder::chunked(None, None);\n        assert_eq!(\n            decoder\n                .decode_fut(&mut bytes)\n                .await\n                .unwrap()\n                .data_ref()\n                .unwrap()\n                .len(),\n            7\n        );\n        let e = decoder.decode_fut(&mut bytes).await.unwrap_err();\n        assert_eq!(e.kind(), io::ErrorKind::UnexpectedEof);\n    }\n\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn test_read_chunked_single_read() {\n        let mut mock_buf = &b\"10\\r\\n1234567890abcdef\\r\\n0\\r\\n\"[..];\n        let buf = Decoder::chunked(None, None)\n            .decode_fut(&mut mock_buf)\n            .await\n            .expect(\"decode\")\n            .into_data()\n            .expect(\"unknown frame type\");\n        assert_eq!(16, buf.len());\n        let result = String::from_utf8(buf.as_ref().to_vec()).expect(\"decode String\");\n        assert_eq!(\"1234567890abcdef\", &result);\n    }\n\n    #[tokio::test]\n    async fn test_read_chunked_with_missing_zero_digit() {\n        // After reading a valid chunk, the ending is missing a zero.\n        let mut mock_buf = &b\"1\\r\\nZ\\r\\n\\r\\n\\r\\n\"[..];\n        let mut decoder = Decoder::chunked(None, None);\n        let buf = decoder\n            .decode_fut(&mut mock_buf)\n            .await\n            .expect(\"decode\")\n            .into_data()\n            .expect(\"unknown frame type\");\n        assert_eq!(\"Z\", buf);\n\n        let err = decoder\n            .decode_fut(&mut mock_buf)\n            .await\n            .expect_err(\"decode 2\");\n        assert_eq!(err.kind(), io::ErrorKind::InvalidInput);\n    }\n\n    #[tokio::test]\n    async fn test_read_chunked_extensions_over_limit() {\n        // construct a chunked body where each individual chunked extension\n        // is totally fine, but combined is over the limit.\n        let per_chunk = super::CHUNKED_EXTENSIONS_LIMIT * 2 / 3;\n        let mut scratch = vec![];\n        for _ in 0..2 {\n            scratch.extend(b\"1;\");\n            scratch.extend(b\"x\".repeat(per_chunk as usize));\n            scratch.extend(b\"\\r\\nA\\r\\n\");\n        }\n        scratch.extend(b\"0\\r\\n\\r\\n\");\n        let mut mock_buf = Bytes::from(scratch);\n\n        let mut decoder = Decoder::chunked(None, None);\n        let buf1 = decoder\n            .decode_fut(&mut mock_buf)\n            .await\n            .expect(\"decode1\")\n            .into_data()\n            .expect(\"unknown frame type\");\n        assert_eq!(&buf1[..], b\"A\");\n\n        let err = decoder\n            .decode_fut(&mut mock_buf)\n            .await\n            .expect_err(\"decode2\");\n        assert_eq!(err.kind(), io::ErrorKind::InvalidData);\n        assert_eq!(err.to_string(), \"chunk extensions over limit\");\n    }\n\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn test_read_chunked_trailer_with_missing_lf() {\n        let mut mock_buf = &b\"10\\r\\n1234567890abcdef\\r\\n0\\r\\nbad\\r\\r\\n\"[..];\n        let mut decoder = Decoder::chunked(None, None);\n        decoder.decode_fut(&mut mock_buf).await.expect(\"decode\");\n        let e = decoder.decode_fut(&mut mock_buf).await.unwrap_err();\n        assert_eq!(e.kind(), io::ErrorKind::InvalidInput);\n    }\n\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn test_read_chunked_after_eof() {\n        let mut mock_buf = &b\"10\\r\\n1234567890abcdef\\r\\n0\\r\\n\\r\\n\"[..];\n        let mut decoder = Decoder::chunked(None, None);\n\n        // normal read\n        let buf = decoder\n            .decode_fut(&mut mock_buf)\n            .await\n            .unwrap()\n            .into_data()\n            .expect(\"unknown frame type\");\n        assert_eq!(16, buf.len());\n        let result = String::from_utf8(buf.as_ref().to_vec()).expect(\"decode String\");\n        assert_eq!(\"1234567890abcdef\", &result);\n\n        // eof read\n        let buf = decoder\n            .decode_fut(&mut mock_buf)\n            .await\n            .expect(\"decode\")\n            .into_data()\n            .expect(\"unknown frame type\");\n        assert_eq!(0, buf.len());\n\n        // ensure read after eof also returns eof\n        let buf = decoder\n            .decode_fut(&mut mock_buf)\n            .await\n            .expect(\"decode\")\n            .into_data()\n            .expect(\"unknown frame type\");\n        assert_eq!(0, buf.len());\n    }\n\n    // perform an async read using a custom buffer size and causing a blocking\n    // read at the specified byte\n    async fn read_async(mut decoder: Decoder, content: &[u8], block_at: usize) -> String {\n        let mut outs = Vec::new();\n\n        let mut ins = crate::common::io::Compat::new(if block_at == 0 {\n            tokio_test::io::Builder::new()\n                .wait(Duration::from_millis(10))\n                .read(content)\n                .build()\n        } else {\n            tokio_test::io::Builder::new()\n                .read(&content[..block_at])\n                .wait(Duration::from_millis(10))\n                .read(&content[block_at..])\n                .build()\n        });\n\n        let mut ins = &mut ins as &mut (dyn Read + Unpin);\n\n        loop {\n            let buf = decoder\n                .decode_fut(&mut ins)\n                .await\n                .expect(\"unexpected decode error\")\n                .into_data()\n                .expect(\"unexpected frame type\");\n            if buf.is_empty() {\n                break; // eof\n            }\n            outs.extend(buf.as_ref());\n        }\n\n        String::from_utf8(outs).expect(\"decode String\")\n    }\n\n    // iterate over the different ways that this async read could go.\n    // tests blocking a read at each byte along the content - The shotgun approach\n    async fn all_async_cases(content: &str, expected: &str, decoder: Decoder) {\n        let content_len = content.len();\n        for block_at in 0..content_len {\n            let actual = read_async(decoder.clone(), content.as_bytes(), block_at).await;\n            assert_eq!(expected, &actual) //, \"Failed async. Blocking at {}\", block_at);\n        }\n    }\n\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn test_read_length_async() {\n        let content = \"foobar\";\n        all_async_cases(content, content, Decoder::length(content.len() as u64)).await;\n    }\n\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn test_read_chunked_async() {\n        let content = \"3\\r\\nfoo\\r\\n3\\r\\nbar\\r\\n0\\r\\n\\r\\n\";\n        let expected = \"foobar\";\n        all_async_cases(content, expected, Decoder::chunked(None, None)).await;\n    }\n\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn test_read_eof_async() {\n        let content = \"foobar\";\n        all_async_cases(content, content, Decoder::eof()).await;\n    }\n\n    #[cfg(all(feature = \"nightly\", not(miri)))]\n    #[bench]\n    fn bench_decode_chunked_1kb(b: &mut test::Bencher) {\n        let rt = new_runtime();\n\n        const LEN: usize = 1024;\n        let mut vec = Vec::new();\n        vec.extend(format!(\"{:x}\\r\\n\", LEN).as_bytes());\n        vec.extend(&[0; LEN][..]);\n        vec.extend(b\"\\r\\n\");\n        let content = Bytes::from(vec);\n\n        b.bytes = LEN as u64;\n\n        b.iter(|| {\n            let mut decoder = Decoder::chunked(None, None);\n            rt.block_on(async {\n                let mut raw = content.clone();\n                let chunk = decoder\n                    .decode_fut(&mut raw)\n                    .await\n                    .unwrap()\n                    .into_data()\n                    .unwrap();\n                assert_eq!(chunk.len(), LEN);\n            });\n        });\n    }\n\n    #[cfg(all(feature = \"nightly\", not(miri)))]\n    #[bench]\n    fn bench_decode_length_1kb(b: &mut test::Bencher) {\n        let rt = new_runtime();\n\n        const LEN: usize = 1024;\n        let content = Bytes::from(&[0; LEN][..]);\n        b.bytes = LEN as u64;\n\n        b.iter(|| {\n            let mut decoder = Decoder::length(LEN as u64);\n            rt.block_on(async {\n                let mut raw = content.clone();\n                let chunk = decoder\n                    .decode_fut(&mut raw)\n                    .await\n                    .unwrap()\n                    .into_data()\n                    .unwrap();\n                assert_eq!(chunk.len(), LEN);\n            });\n        });\n    }\n\n    #[cfg(feature = \"nightly\")]\n    fn new_runtime() -> tokio::runtime::Runtime {\n        tokio::runtime::Builder::new_current_thread()\n            .enable_all()\n            .build()\n            .expect(\"rt build\")\n    }\n\n    #[test]\n    fn test_decode_trailers() {\n        let mut buf = BytesMut::new();\n        buf.extend_from_slice(\n            b\"Expires: Wed, 21 Oct 2015 07:28:00 GMT\\r\\nX-Stream-Error: failed to decode\\r\\n\\r\\n\",\n        );\n        let headers = decode_trailers(&mut buf, 2).expect(\"decode_trailers\");\n        assert_eq!(headers.len(), 2);\n        assert_eq!(\n            headers.get(\"Expires\").unwrap(),\n            \"Wed, 21 Oct 2015 07:28:00 GMT\"\n        );\n        assert_eq!(headers.get(\"X-Stream-Error\").unwrap(), \"failed to decode\");\n    }\n\n    #[tokio::test]\n    async fn test_trailer_max_headers_enforced() {\n        let h1_max_headers = 10;\n        let mut scratch = vec![];\n        scratch.extend(b\"10\\r\\n1234567890abcdef\\r\\n0\\r\\n\");\n        for i in 0..h1_max_headers {\n            scratch.extend(format!(\"trailer{}: {}\\r\\n\", i, i).as_bytes());\n        }\n        scratch.extend(b\"\\r\\n\");\n        let mut mock_buf = Bytes::from(scratch);\n\n        let mut decoder = Decoder::chunked(Some(h1_max_headers), None);\n\n        // ready chunked body\n        let buf = decoder\n            .decode_fut(&mut mock_buf)\n            .await\n            .unwrap()\n            .into_data()\n            .expect(\"unknown frame type\");\n        assert_eq!(16, buf.len());\n\n        // eof read\n        let err = decoder\n            .decode_fut(&mut mock_buf)\n            .await\n            .expect_err(\"trailer fields over limit\");\n        assert_eq!(err.kind(), io::ErrorKind::InvalidData);\n    }\n\n    #[tokio::test]\n    async fn test_trailer_max_header_size_huge_trailer() {\n        let max_header_size = 1024;\n        let mut scratch = vec![];\n        scratch.extend(b\"10\\r\\n1234567890abcdef\\r\\n0\\r\\n\");\n        scratch.extend(format!(\"huge_trailer: {}\\r\\n\", \"x\".repeat(max_header_size)).as_bytes());\n        scratch.extend(b\"\\r\\n\");\n        let mut mock_buf = Bytes::from(scratch);\n\n        let mut decoder = Decoder::chunked(None, Some(max_header_size));\n\n        // ready chunked body\n        let buf = decoder\n            .decode_fut(&mut mock_buf)\n            .await\n            .unwrap()\n            .into_data()\n            .expect(\"unknown frame type\");\n        assert_eq!(16, buf.len());\n\n        // eof read\n        let err = decoder\n            .decode_fut(&mut mock_buf)\n            .await\n            .expect_err(\"trailers over limit\");\n        assert_eq!(err.kind(), io::ErrorKind::InvalidData);\n    }\n\n    #[tokio::test]\n    async fn test_trailer_max_header_size_many_small_trailers() {\n        let max_headers = 10;\n        let header_size = 64;\n        let mut scratch = vec![];\n        scratch.extend(b\"10\\r\\n1234567890abcdef\\r\\n0\\r\\n\");\n\n        for i in 0..max_headers {\n            scratch.extend(format!(\"trailer{}: {}\\r\\n\", i, \"x\".repeat(header_size)).as_bytes());\n        }\n\n        scratch.extend(b\"\\r\\n\");\n        let mut mock_buf = Bytes::from(scratch);\n\n        let mut decoder = Decoder::chunked(None, Some(max_headers * header_size));\n\n        // ready chunked body\n        let buf = decoder\n            .decode_fut(&mut mock_buf)\n            .await\n            .unwrap()\n            .into_data()\n            .expect(\"unknown frame type\");\n        assert_eq!(16, buf.len());\n\n        // eof read\n        let err = decoder\n            .decode_fut(&mut mock_buf)\n            .await\n            .expect_err(\"trailers over limit\");\n        assert_eq!(err.kind(), io::ErrorKind::InvalidData);\n    }\n}\n"
  },
  {
    "path": "src/proto/h1/dispatch.rs",
    "content": "use std::{\n    error::Error as StdError,\n    future::Future,\n    marker::Unpin,\n    pin::Pin,\n    task::{Context, Poll},\n};\n\nuse crate::rt::{Read, Write};\nuse bytes::{Buf, Bytes};\nuse futures_core::ready;\nuse http::Request;\n\nuse super::{Http1Transaction, Wants};\nuse crate::body::{Body, DecodedLength, Incoming as IncomingBody};\n#[cfg(feature = \"client\")]\nuse crate::client::dispatch::TrySendError;\nuse crate::common::task;\nuse crate::proto::{BodyLength, Conn, Dispatched, MessageHead, RequestHead};\nuse crate::upgrade::OnUpgrade;\n\npub(crate) struct Dispatcher<D, Bs: Body, I, T> {\n    conn: Conn<I, Bs::Data, T>,\n    dispatch: D,\n    body_tx: Option<crate::body::Sender>,\n    body_rx: Pin<Box<Option<Bs>>>,\n    is_closing: bool,\n}\n\npub(crate) trait Dispatch {\n    type PollItem;\n    type PollBody;\n    type PollError;\n    type RecvItem;\n    fn poll_msg(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Self::PollError>>>;\n    fn recv_msg(&mut self, msg: crate::Result<(Self::RecvItem, IncomingBody)>)\n        -> crate::Result<()>;\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), ()>>;\n    fn should_poll(&self) -> bool;\n}\n\ncfg_server! {\n    use crate::service::HttpService;\n\n    pub(crate) struct Server<S: HttpService<B>, B> {\n        in_flight: Pin<Box<Option<S::Future>>>,\n        pub(crate) service: S,\n    }\n}\n\ncfg_client! {\n    pin_project_lite::pin_project! {\n        pub(crate) struct Client<B> {\n            callback: Option<crate::client::dispatch::Callback<Request<B>, http::Response<IncomingBody>>>,\n            #[pin]\n            rx: ClientRx<B>,\n            rx_closed: bool,\n        }\n    }\n\n    type ClientRx<B> = crate::client::dispatch::Receiver<Request<B>, http::Response<IncomingBody>>;\n}\n\nimpl<D, Bs, I, T> Dispatcher<D, Bs, I, T>\nwhere\n    D: Dispatch<\n            PollItem = MessageHead<T::Outgoing>,\n            PollBody = Bs,\n            RecvItem = MessageHead<T::Incoming>,\n        > + Unpin,\n    D::PollError: Into<Box<dyn StdError + Send + Sync>>,\n    I: Read + Write + Unpin,\n    T: Http1Transaction + Unpin,\n    Bs: Body + 'static,\n    Bs::Error: Into<Box<dyn StdError + Send + Sync>>,\n{\n    pub(crate) fn new(dispatch: D, conn: Conn<I, Bs::Data, T>) -> Self {\n        Dispatcher {\n            conn,\n            dispatch,\n            body_tx: None,\n            body_rx: Box::pin(None),\n            is_closing: false,\n        }\n    }\n\n    #[cfg(feature = \"server\")]\n    pub(crate) fn disable_keep_alive(&mut self) {\n        self.conn.disable_keep_alive();\n\n        // If keep alive has been disabled and no read or write has been seen on\n        // the connection yet, we must be in a state where the server is being asked to\n        // shut down before any data has been seen on the connection\n        if self.conn.is_write_closed() || self.conn.has_initial_read_write_state() {\n            self.close();\n        }\n    }\n\n    pub(crate) fn into_inner(self) -> (I, Bytes, D) {\n        let (io, buf) = self.conn.into_inner();\n        (io, buf, self.dispatch)\n    }\n\n    /// Run this dispatcher until HTTP says this connection is done,\n    /// but don't call `Write::shutdown` on the underlying IO.\n    ///\n    /// This is useful for old-style HTTP upgrades, but ignores\n    /// newer-style upgrade API.\n    pub(crate) fn poll_without_shutdown(\n        &mut self,\n        cx: &mut Context<'_>,\n    ) -> Poll<crate::Result<()>> {\n        Pin::new(self).poll_catch(cx, false).map_ok(|ds| {\n            if let Dispatched::Upgrade(pending) = ds {\n                pending.manual();\n            }\n        })\n    }\n\n    fn poll_catch(\n        &mut self,\n        cx: &mut Context<'_>,\n        should_shutdown: bool,\n    ) -> Poll<crate::Result<Dispatched>> {\n        Poll::Ready(ready!(self.poll_inner(cx, should_shutdown)).or_else(|e| {\n            // Be sure to alert a streaming body of the failure.\n            if let Some(mut body) = self.body_tx.take() {\n                body.send_error(crate::Error::new_body(\"connection error\"));\n            }\n            // An error means we're shutting down either way.\n            // We just try to give the error to the user,\n            // and close the connection with an Ok. If we\n            // cannot give it to the user, then return the Err.\n            self.dispatch.recv_msg(Err(e))?;\n            Ok(Dispatched::Shutdown)\n        }))\n    }\n\n    fn poll_inner(\n        &mut self,\n        cx: &mut Context<'_>,\n        should_shutdown: bool,\n    ) -> Poll<crate::Result<Dispatched>> {\n        T::update_date();\n\n        ready!(self.poll_loop(cx))?;\n\n        if self.is_done() {\n            if let Some(pending) = self.conn.pending_upgrade() {\n                self.conn.take_error()?;\n                return Poll::Ready(Ok(Dispatched::Upgrade(pending)));\n            } else if should_shutdown {\n                ready!(self.conn.poll_shutdown(cx)).map_err(crate::Error::new_shutdown)?;\n            }\n            self.conn.take_error()?;\n            Poll::Ready(Ok(Dispatched::Shutdown))\n        } else {\n            Poll::Pending\n        }\n    }\n\n    fn poll_loop(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {\n        // Limit the looping on this connection, in case it is ready far too\n        // often, so that other futures don't starve.\n        //\n        // 16 was chosen arbitrarily, as that is number of pipelined requests\n        // benchmarks often use. Perhaps it should be a config option instead.\n        for _ in 0..16 {\n            let _ = self.poll_read(cx)?;\n            let _ = self.poll_write(cx)?;\n            let _ = self.poll_flush(cx)?;\n\n            // This could happen if reading paused before blocking on IO,\n            // such as getting to the end of a framed message, but then\n            // writing/flushing set the state back to Init. In that case,\n            // if the read buffer still had bytes, we'd want to try poll_read\n            // again, or else we wouldn't ever be woken up again.\n            //\n            // Using this instead of task::current() and notify() inside\n            // the Conn is noticeably faster in pipelined benchmarks.\n            if !self.conn.wants_read_again() {\n                //break;\n                return Poll::Ready(Ok(()));\n            }\n        }\n\n        trace!(\"poll_loop yielding (self = {:p})\", self);\n\n        task::yield_now(cx).map(|never| match never {})\n    }\n\n    fn poll_read(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {\n        loop {\n            if self.is_closing {\n                return Poll::Ready(Ok(()));\n            } else if self.conn.can_read_head() {\n                ready!(self.poll_read_head(cx))?;\n            } else if let Some(mut body) = self.body_tx.take() {\n                if self.conn.can_read_body() {\n                    match body.poll_ready(cx) {\n                        Poll::Ready(Ok(())) => (),\n                        Poll::Pending => {\n                            self.body_tx = Some(body);\n                            return Poll::Pending;\n                        }\n                        Poll::Ready(Err(_canceled)) => {\n                            // user doesn't care about the body\n                            // so we should stop reading\n                            trace!(\"body receiver dropped before eof, draining or closing\");\n                            self.conn.poll_drain_or_close_read(cx);\n                            continue;\n                        }\n                    }\n                    match self.conn.poll_read_body(cx) {\n                        Poll::Ready(Some(Ok(frame))) => {\n                            if frame.is_data() {\n                                let chunk = frame.into_data().unwrap_or_else(|_| unreachable!());\n                                match body.try_send_data(chunk) {\n                                    Ok(()) => {\n                                        self.body_tx = Some(body);\n                                    }\n                                    Err(_canceled) => {\n                                        if self.conn.can_read_body() {\n                                            trace!(\"body receiver dropped before eof, closing\");\n                                            self.conn.close_read();\n                                        }\n                                    }\n                                }\n                            } else if frame.is_trailers() {\n                                let trailers =\n                                    frame.into_trailers().unwrap_or_else(|_| unreachable!());\n                                match body.try_send_trailers(trailers) {\n                                    Ok(()) => {\n                                        self.body_tx = Some(body);\n                                    }\n                                    Err(_canceled) => {\n                                        if self.conn.can_read_body() {\n                                            trace!(\"body receiver dropped before eof, closing\");\n                                            self.conn.close_read();\n                                        }\n                                    }\n                                }\n                            } else {\n                                // we should have dropped all unknown frames in poll_read_body\n                                error!(\"unexpected frame\");\n                            }\n                        }\n                        Poll::Ready(None) => {\n                            // just drop, the body will close automatically\n                        }\n                        Poll::Pending => {\n                            self.body_tx = Some(body);\n                            return Poll::Pending;\n                        }\n                        Poll::Ready(Some(Err(e))) => {\n                            body.send_error(crate::Error::new_body(e));\n                        }\n                    }\n                } else {\n                    // just drop, the body will close automatically\n                }\n            } else {\n                return self.conn.poll_read_keep_alive(cx);\n            }\n        }\n    }\n\n    fn poll_read_head(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {\n        // can dispatch receive, or does it still care about other incoming message?\n        match ready!(self.dispatch.poll_ready(cx)) {\n            Ok(()) => (),\n            Err(()) => {\n                trace!(\"dispatch no longer receiving messages\");\n                self.close();\n                return Poll::Ready(Ok(()));\n            }\n        }\n\n        // dispatch is ready for a message, try to read one\n        match ready!(self.conn.poll_read_head(cx)) {\n            Some(Ok((mut head, body_len, wants))) => {\n                let body = match body_len {\n                    DecodedLength::ZERO => IncomingBody::empty(),\n                    other => {\n                        let (tx, rx) =\n                            IncomingBody::new_channel(other, wants.contains(Wants::EXPECT));\n                        self.body_tx = Some(tx);\n                        rx\n                    }\n                };\n                if wants.contains(Wants::UPGRADE) {\n                    let upgrade = self.conn.on_upgrade();\n                    debug_assert!(!upgrade.is_none(), \"empty upgrade\");\n                    debug_assert!(\n                        head.extensions.get::<OnUpgrade>().is_none(),\n                        \"OnUpgrade already set\"\n                    );\n                    head.extensions.insert(upgrade);\n                }\n                self.dispatch.recv_msg(Ok((head, body)))?;\n                Poll::Ready(Ok(()))\n            }\n            Some(Err(err)) => {\n                debug!(\"read_head error: {}\", err);\n                self.dispatch.recv_msg(Err(err))?;\n                // if here, the dispatcher gave the user the error\n                // somewhere else. we still need to shutdown, but\n                // not as a second error.\n                self.close();\n                Poll::Ready(Ok(()))\n            }\n            None => {\n                // read eof, the write side will have been closed too unless\n                // allow_read_close was set to true, in which case just do\n                // nothing...\n                debug_assert!(self.conn.is_read_closed());\n                if self.conn.is_write_closed() {\n                    self.close();\n                }\n                Poll::Ready(Ok(()))\n            }\n        }\n    }\n\n    fn poll_write(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {\n        loop {\n            if self.is_closing {\n                return Poll::Ready(Ok(()));\n            } else if self.body_rx.is_none()\n                && self.conn.can_write_head()\n                && self.dispatch.should_poll()\n            {\n                if let Some(msg) = ready!(Pin::new(&mut self.dispatch).poll_msg(cx)) {\n                    let (head, body) = msg.map_err(crate::Error::new_user_service)?;\n\n                    let body_type = if body.is_end_stream() {\n                        self.body_rx.set(None);\n                        None\n                    } else {\n                        let btype = body\n                            .size_hint()\n                            .exact()\n                            .map(BodyLength::Known)\n                            .or(Some(BodyLength::Unknown));\n                        self.body_rx.set(Some(body));\n                        btype\n                    };\n                    self.conn.write_head(head, body_type);\n                } else {\n                    self.close();\n                    return Poll::Ready(Ok(()));\n                }\n            } else if !self.conn.can_buffer_body() {\n                ready!(self.poll_flush(cx))?;\n            } else {\n                // A new scope is needed :(\n                if let (Some(mut body), clear_body) =\n                    OptGuard::new(self.body_rx.as_mut()).guard_mut()\n                {\n                    debug_assert!(!*clear_body, \"opt guard defaults to keeping body\");\n                    if !self.conn.can_write_body() {\n                        trace!(\n                            \"no more write body allowed, user body is_end_stream = {}\",\n                            body.is_end_stream(),\n                        );\n                        *clear_body = true;\n                        continue;\n                    }\n\n                    let item = ready!(body.as_mut().poll_frame(cx));\n                    if let Some(item) = item {\n                        let frame = item.map_err(|e| {\n                            *clear_body = true;\n                            crate::Error::new_user_body(e)\n                        })?;\n\n                        if frame.is_data() {\n                            let chunk = frame.into_data().unwrap_or_else(|_| unreachable!());\n                            let eos = body.is_end_stream();\n                            if eos {\n                                *clear_body = true;\n                                if chunk.remaining() == 0 {\n                                    trace!(\"discarding empty chunk\");\n                                    self.conn.end_body()?;\n                                } else {\n                                    self.conn.write_body_and_end(chunk);\n                                }\n                            } else {\n                                if chunk.remaining() == 0 {\n                                    trace!(\"discarding empty chunk\");\n                                    continue;\n                                }\n                                self.conn.write_body(chunk);\n                            }\n                        } else if frame.is_trailers() {\n                            *clear_body = true;\n                            self.conn.write_trailers(\n                                frame.into_trailers().unwrap_or_else(|_| unreachable!()),\n                            );\n                        } else {\n                            trace!(\"discarding unknown frame\");\n                            continue;\n                        }\n                    } else {\n                        *clear_body = true;\n                        self.conn.end_body()?;\n                    }\n                } else {\n                    // If there's no body_rx, end the body\n                    if self.conn.can_write_body() {\n                        self.conn.end_body()?;\n                    } else {\n                        return Poll::Pending;\n                    }\n                }\n            }\n        }\n    }\n\n    fn poll_flush(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {\n        self.conn.poll_flush(cx).map_err(|err| {\n            debug!(\"error writing: {}\", err);\n            crate::Error::new_body_write(err)\n        })\n    }\n\n    fn close(&mut self) {\n        self.is_closing = true;\n        self.conn.close_read();\n        self.conn.close_write();\n    }\n\n    fn is_done(&self) -> bool {\n        if self.is_closing {\n            return true;\n        }\n\n        let read_done = self.conn.is_read_closed();\n\n        if !T::should_read_first() && read_done {\n            // a client that cannot read may was well be done.\n            true\n        } else {\n            let write_done = self.conn.is_write_closed()\n                || (!self.dispatch.should_poll() && self.body_rx.is_none());\n            read_done && write_done\n        }\n    }\n}\n\nimpl<D, Bs, I, T> Future for Dispatcher<D, Bs, I, T>\nwhere\n    D: Dispatch<\n            PollItem = MessageHead<T::Outgoing>,\n            PollBody = Bs,\n            RecvItem = MessageHead<T::Incoming>,\n        > + Unpin,\n    D::PollError: Into<Box<dyn StdError + Send + Sync>>,\n    I: Read + Write + Unpin,\n    T: Http1Transaction + Unpin,\n    Bs: Body + 'static,\n    Bs::Error: Into<Box<dyn StdError + Send + Sync>>,\n{\n    type Output = crate::Result<Dispatched>;\n\n    #[inline]\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        self.poll_catch(cx, true)\n    }\n}\n\n// ===== impl OptGuard =====\n\n/// A drop guard to allow a mutable borrow of an Option while being able to\n/// set whether the `Option` should be cleared on drop.\nstruct OptGuard<'a, T>(Pin<&'a mut Option<T>>, bool);\n\nimpl<'a, T> OptGuard<'a, T> {\n    fn new(pin: Pin<&'a mut Option<T>>) -> Self {\n        OptGuard(pin, false)\n    }\n\n    fn guard_mut(&mut self) -> (Option<Pin<&mut T>>, &mut bool) {\n        (self.0.as_mut().as_pin_mut(), &mut self.1)\n    }\n}\n\nimpl<T> Drop for OptGuard<'_, T> {\n    fn drop(&mut self) {\n        if self.1 {\n            self.0.set(None);\n        }\n    }\n}\n\n// ===== impl Server =====\n\ncfg_server! {\n    impl<S, B> Server<S, B>\n    where\n        S: HttpService<B>,\n    {\n        pub(crate) fn new(service: S) -> Server<S, B> {\n            Server {\n                in_flight: Box::pin(None),\n                service,\n            }\n        }\n\n        pub(crate) fn into_service(self) -> S {\n            self.service\n        }\n    }\n\n    // Service is never pinned\n    impl<S: HttpService<B>, B> Unpin for Server<S, B> {}\n\n    impl<S, Bs> Dispatch for Server<S, IncomingBody>\n    where\n        S: HttpService<IncomingBody, ResBody = Bs>,\n        S::Error: Into<Box<dyn StdError + Send + Sync>>,\n        Bs: Body,\n    {\n        type PollItem = MessageHead<http::StatusCode>;\n        type PollBody = Bs;\n        type PollError = S::Error;\n        type RecvItem = RequestHead;\n\n        fn poll_msg(\n            mut self: Pin<&mut Self>,\n            cx: &mut Context<'_>,\n        ) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Self::PollError>>> {\n            let mut this = self.as_mut();\n            let ret = if let Some(ref mut fut) = this.in_flight.as_mut().as_pin_mut() {\n                let resp = ready!(fut.as_mut().poll(cx)?);\n                let (parts, body) = resp.into_parts();\n                let head = MessageHead {\n                    version: parts.version,\n                    subject: parts.status,\n                    headers: parts.headers,\n                    extensions: parts.extensions,\n                };\n                Poll::Ready(Some(Ok((head, body))))\n            } else {\n                unreachable!(\"poll_msg shouldn't be called if no inflight\");\n            };\n\n            // Since in_flight finished, remove it\n            this.in_flight.set(None);\n            ret\n        }\n\n        fn recv_msg(&mut self, msg: crate::Result<(Self::RecvItem, IncomingBody)>) -> crate::Result<()> {\n            let (msg, body) = msg?;\n            let mut req = Request::new(body);\n            *req.method_mut() = msg.subject.0;\n            *req.uri_mut() = msg.subject.1;\n            *req.headers_mut() = msg.headers;\n            *req.version_mut() = msg.version;\n            *req.extensions_mut() = msg.extensions;\n            let fut = self.service.call(req);\n            self.in_flight.set(Some(fut));\n            Ok(())\n        }\n\n        fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), ()>> {\n            if self.in_flight.is_some() {\n                Poll::Pending\n            } else {\n                Poll::Ready(Ok(()))\n            }\n        }\n\n        fn should_poll(&self) -> bool {\n            self.in_flight.is_some()\n        }\n    }\n}\n\n// ===== impl Client =====\n\ncfg_client! {\n    use std::convert::Infallible;\n\n    impl<B> Client<B> {\n        pub(crate) fn new(rx: ClientRx<B>) -> Client<B> {\n            Client {\n                callback: None,\n                rx,\n                rx_closed: false,\n            }\n        }\n    }\n\n    impl<B> Dispatch for Client<B>\n    where\n        B: Body,\n    {\n        type PollItem = RequestHead;\n        type PollBody = B;\n        type PollError = Infallible;\n        type RecvItem = crate::proto::ResponseHead;\n\n        fn poll_msg(\n            mut self: Pin<&mut Self>,\n            cx: &mut Context<'_>,\n        ) -> Poll<Option<Result<(Self::PollItem, Self::PollBody), Infallible>>> {\n            let mut this = self.as_mut();\n            debug_assert!(!this.rx_closed);\n            match this.rx.poll_recv(cx) {\n                Poll::Ready(Some((req, mut cb))) => {\n                    // check that future hasn't been canceled already\n                    match cb.poll_canceled(cx) {\n                        Poll::Ready(()) => {\n                            trace!(\"request canceled\");\n                            Poll::Ready(None)\n                        }\n                        Poll::Pending => {\n                            let (parts, body) = req.into_parts();\n                            let head = RequestHead {\n                                version: parts.version,\n                                subject: crate::proto::RequestLine(parts.method, parts.uri),\n                                headers: parts.headers,\n                                extensions: parts.extensions,\n                            };\n                            this.callback = Some(cb);\n                            Poll::Ready(Some(Ok((head, body))))\n                        }\n                    }\n                }\n                Poll::Ready(None) => {\n                    // user has dropped sender handle\n                    trace!(\"client tx closed\");\n                    this.rx_closed = true;\n                    Poll::Ready(None)\n                }\n                Poll::Pending => Poll::Pending,\n            }\n        }\n\n        fn recv_msg(&mut self, msg: crate::Result<(Self::RecvItem, IncomingBody)>) -> crate::Result<()> {\n            match msg {\n                Ok((msg, body)) => {\n                    if let Some(cb) = self.callback.take() {\n                        let res = msg.into_response(body);\n                        cb.send(Ok(res));\n                        Ok(())\n                    } else {\n                        // Getting here is likely a bug! An error should have happened\n                        // in Conn::require_empty_read() before ever parsing a\n                        // full message!\n                        Err(crate::Error::new_unexpected_message())\n                    }\n                }\n                Err(err) => {\n                    if let Some(cb) = self.callback.take() {\n                        cb.send(Err(TrySendError {\n                            error: err,\n                            message: None,\n                        }));\n                        Ok(())\n                    } else if !self.rx_closed {\n                        self.rx.close();\n                        if let Some((req, cb)) = self.rx.try_recv() {\n                            trace!(\"canceling queued request with connection error: {}\", err);\n                            // in this case, the message was never even started, so it's safe to tell\n                            // the user that the request was completely canceled\n                            cb.send(Err(TrySendError {\n                                error: crate::Error::new_canceled().with(err),\n                                message: Some(req),\n                            }));\n                            Ok(())\n                        } else {\n                            Err(err)\n                        }\n                    } else {\n                        Err(err)\n                    }\n                }\n            }\n        }\n\n        fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), ()>> {\n            match self.callback {\n                Some(ref mut cb) => match cb.poll_canceled(cx) {\n                    Poll::Ready(()) => {\n                        trace!(\"callback receiver has dropped\");\n                        Poll::Ready(Err(()))\n                    }\n                    Poll::Pending => Poll::Ready(Ok(())),\n                },\n                None => Poll::Ready(Err(())),\n            }\n        }\n\n        fn should_poll(&self) -> bool {\n            self.callback.is_none()\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::common::io::Compat;\n    use crate::proto::h1::ClientTransaction;\n    use std::time::Duration;\n\n    #[test]\n    fn client_read_bytes_before_writing_request() {\n        let _ = pretty_env_logger::try_init();\n\n        tokio_test::task::spawn(()).enter(|cx, _| {\n            let (io, mut handle) = tokio_test::io::Builder::new().build_with_handle();\n\n            // Block at 0 for now, but we will release this response before\n            // the request is ready to write later...\n            let (mut tx, rx) = crate::client::dispatch::channel();\n            let conn = Conn::<_, bytes::Bytes, ClientTransaction>::new(Compat::new(io));\n            let mut dispatcher = Dispatcher::new(Client::new(rx), conn);\n\n            // First poll is needed to allow tx to send...\n            assert!(Pin::new(&mut dispatcher).poll(cx).is_pending());\n\n            // Unblock our IO, which has a response before we've sent request!\n            //\n            handle.read(b\"HTTP/1.1 200 OK\\r\\n\\r\\n\");\n\n            let mut res_rx = tx\n                .try_send(crate::Request::new(IncomingBody::empty()))\n                .unwrap();\n\n            tokio_test::assert_ready_ok!(Pin::new(&mut dispatcher).poll(cx));\n            let err = tokio_test::assert_ready_ok!(Pin::new(&mut res_rx).poll(cx))\n                .expect_err(\"callback should send error\");\n\n            match (err.error.is_canceled(), err.message.as_ref()) {\n                (true, Some(_)) => (),\n                _ => panic!(\"expected Canceled, got {:?}\", err),\n            }\n        });\n    }\n\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn client_flushing_is_not_ready_for_next_request() {\n        let _ = pretty_env_logger::try_init();\n\n        let (io, _handle) = tokio_test::io::Builder::new()\n            .write(b\"POST / HTTP/1.1\\r\\ncontent-length: 4\\r\\n\\r\\n\")\n            .read(b\"HTTP/1.1 200 OK\\r\\ncontent-length: 0\\r\\n\\r\\n\")\n            .wait(std::time::Duration::from_secs(2))\n            .build_with_handle();\n\n        let (mut tx, rx) = crate::client::dispatch::channel();\n        let mut conn = Conn::<_, bytes::Bytes, ClientTransaction>::new(Compat::new(io));\n        conn.set_write_strategy_queue();\n\n        let dispatcher = Dispatcher::new(Client::new(rx), conn);\n        let _dispatcher = tokio::spawn(async move { dispatcher.await });\n\n        let body = {\n            let (mut tx, body) = IncomingBody::new_channel(DecodedLength::new(4), false);\n            tx.try_send_data(\"reee\".into()).unwrap();\n            body\n        };\n\n        let req = crate::Request::builder().method(\"POST\").body(body).unwrap();\n\n        let res = tx.try_send(req).unwrap().await.expect(\"response\");\n        drop(res);\n\n        assert!(!tx.is_ready());\n    }\n\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn body_empty_chunks_ignored() {\n        let _ = pretty_env_logger::try_init();\n\n        let io = tokio_test::io::Builder::new()\n            // no reading or writing, just be blocked for the test...\n            .wait(Duration::from_secs(5))\n            .build();\n\n        let (mut tx, rx) = crate::client::dispatch::channel();\n        let conn = Conn::<_, bytes::Bytes, ClientTransaction>::new(Compat::new(io));\n        let mut dispatcher = tokio_test::task::spawn(Dispatcher::new(Client::new(rx), conn));\n\n        // First poll is needed to allow tx to send...\n        assert!(dispatcher.poll().is_pending());\n\n        let body = {\n            let (mut tx, body) = IncomingBody::channel();\n            tx.try_send_data(\"\".into()).unwrap();\n            body\n        };\n\n        let _res_rx = tx.try_send(crate::Request::new(body)).unwrap();\n\n        // Ensure conn.write_body wasn't called with the empty chunk.\n        // If it is, it will trigger an assertion.\n        assert!(dispatcher.poll().is_pending());\n    }\n}\n"
  },
  {
    "path": "src/proto/h1/encode.rs",
    "content": "use std::collections::HashSet;\nuse std::fmt;\nuse std::io::IoSlice;\n\nuse bytes::buf::{Chain, Take};\nuse bytes::{Buf, Bytes};\nuse http::{\n    header::{\n        AUTHORIZATION, CACHE_CONTROL, CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_RANGE,\n        CONTENT_TYPE, HOST, MAX_FORWARDS, SET_COOKIE, TE, TRAILER, TRANSFER_ENCODING,\n    },\n    HeaderMap, HeaderName,\n};\n\nuse super::io::WriteBuf;\nuse super::role::{write_headers, write_headers_title_case};\n\ntype StaticBuf = &'static [u8];\n\n/// Encoders to handle different Transfer-Encodings.\n#[derive(Debug, Clone, PartialEq)]\npub(crate) struct Encoder {\n    kind: Kind,\n    is_last: bool,\n}\n\n#[derive(Debug)]\npub(crate) struct EncodedBuf<B> {\n    kind: BufKind<B>,\n}\n\n#[derive(Debug)]\npub(crate) struct NotEof(u64);\n\n#[derive(Debug, PartialEq, Clone)]\nenum Kind {\n    /// An Encoder for when Transfer-Encoding includes `chunked`.\n    Chunked(Option<Vec<HeaderName>>),\n    /// An Encoder for when Content-Length is set.\n    ///\n    /// Enforces that the body is not longer than the Content-Length header.\n    Length(u64),\n    /// An Encoder for when neither Content-Length nor Chunked encoding is set.\n    ///\n    /// This is mostly only used with HTTP/1.0 with a length. This kind requires\n    /// the connection to be closed when the body is finished.\n    #[cfg(feature = \"server\")]\n    CloseDelimited,\n}\n\n#[derive(Debug)]\nenum BufKind<B> {\n    Exact(B),\n    Limited(Take<B>),\n    Chunked(Chain<Chain<ChunkSize, B>, StaticBuf>),\n    ChunkedEnd(StaticBuf),\n    Trailers(Chain<Chain<StaticBuf, Bytes>, StaticBuf>),\n}\n\nimpl Encoder {\n    fn new(kind: Kind) -> Encoder {\n        Encoder {\n            kind,\n            is_last: false,\n        }\n    }\n    pub(crate) fn chunked() -> Encoder {\n        Encoder::new(Kind::Chunked(None))\n    }\n\n    pub(crate) fn length(len: u64) -> Encoder {\n        Encoder::new(Kind::Length(len))\n    }\n\n    #[cfg(feature = \"server\")]\n    pub(crate) fn close_delimited() -> Encoder {\n        Encoder::new(Kind::CloseDelimited)\n    }\n\n    pub(crate) fn into_chunked_with_trailing_fields(self, trailers: Vec<HeaderName>) -> Encoder {\n        match self.kind {\n            Kind::Chunked(_) => Encoder {\n                kind: Kind::Chunked(Some(trailers)),\n                is_last: self.is_last,\n            },\n            _ => self,\n        }\n    }\n\n    pub(crate) fn is_eof(&self) -> bool {\n        matches!(self.kind, Kind::Length(0))\n    }\n\n    #[cfg(feature = \"server\")]\n    pub(crate) fn set_last(mut self, is_last: bool) -> Self {\n        self.is_last = is_last;\n        self\n    }\n\n    pub(crate) fn is_last(&self) -> bool {\n        self.is_last\n    }\n\n    pub(crate) fn is_close_delimited(&self) -> bool {\n        match self.kind {\n            #[cfg(feature = \"server\")]\n            Kind::CloseDelimited => true,\n            _ => false,\n        }\n    }\n\n    pub(crate) fn is_chunked(&self) -> bool {\n        matches!(self.kind, Kind::Chunked(_))\n    }\n\n    pub(crate) fn end<B>(&self) -> Result<Option<EncodedBuf<B>>, NotEof> {\n        match self.kind {\n            Kind::Length(0) => Ok(None),\n            Kind::Chunked(_) => Ok(Some(EncodedBuf {\n                kind: BufKind::ChunkedEnd(b\"0\\r\\n\\r\\n\"),\n            })),\n            #[cfg(feature = \"server\")]\n            Kind::CloseDelimited => Ok(None),\n            Kind::Length(n) => Err(NotEof(n)),\n        }\n    }\n\n    pub(crate) fn encode<B>(&mut self, msg: B) -> EncodedBuf<B>\n    where\n        B: Buf,\n    {\n        let len = msg.remaining();\n        debug_assert!(len > 0, \"encode() called with empty buf\");\n\n        let kind = match self.kind {\n            Kind::Chunked(_) => {\n                trace!(\"encoding chunked {}B\", len);\n                let buf = ChunkSize::new(len)\n                    .chain(msg)\n                    .chain(b\"\\r\\n\" as &'static [u8]);\n                BufKind::Chunked(buf)\n            }\n            Kind::Length(ref mut remaining) => {\n                trace!(\"sized write, len = {}\", len);\n                if len as u64 > *remaining {\n                    let limit = *remaining as usize;\n                    *remaining = 0;\n                    BufKind::Limited(msg.take(limit))\n                } else {\n                    *remaining -= len as u64;\n                    BufKind::Exact(msg)\n                }\n            }\n            #[cfg(feature = \"server\")]\n            Kind::CloseDelimited => {\n                trace!(\"close delimited write {}B\", len);\n                BufKind::Exact(msg)\n            }\n        };\n        EncodedBuf { kind }\n    }\n\n    pub(crate) fn encode_trailers<B>(\n        &self,\n        trailers: HeaderMap,\n        title_case_headers: bool,\n    ) -> Option<EncodedBuf<B>> {\n        trace!(\"encoding trailers\");\n        match &self.kind {\n            Kind::Chunked(Some(allowed_trailer_fields)) => {\n                let allowed_set: HashSet<&HeaderName> = allowed_trailer_fields.iter().collect();\n\n                let mut cur_name = None;\n                let mut allowed_trailers = HeaderMap::new();\n\n                for (opt_name, value) in trailers {\n                    if let Some(n) = opt_name {\n                        cur_name = Some(n);\n                    }\n                    let name = cur_name.as_ref().expect(\"current header name\");\n\n                    if allowed_set.contains(name) {\n                        if is_valid_trailer_field(name) {\n                            allowed_trailers.insert(name, value);\n                        } else {\n                            debug!(\"trailer field is not valid: {}\", &name);\n                        }\n                    } else {\n                        debug!(\"trailer header name not found in trailer header: {}\", &name);\n                    }\n                }\n\n                let mut buf = Vec::new();\n                if title_case_headers {\n                    write_headers_title_case(&allowed_trailers, &mut buf);\n                } else {\n                    write_headers(&allowed_trailers, &mut buf);\n                }\n\n                if buf.is_empty() {\n                    return None;\n                }\n\n                Some(EncodedBuf {\n                    kind: BufKind::Trailers(b\"0\\r\\n\".chain(Bytes::from(buf)).chain(b\"\\r\\n\")),\n                })\n            }\n            Kind::Chunked(None) => {\n                debug!(\"attempted to encode trailers, but the trailer header is not set\");\n                None\n            }\n            _ => {\n                debug!(\"attempted to encode trailers for non-chunked response\");\n                None\n            }\n        }\n    }\n\n    pub(super) fn encode_and_end<B>(&self, msg: B, dst: &mut WriteBuf<EncodedBuf<B>>) -> bool\n    where\n        B: Buf,\n    {\n        let len = msg.remaining();\n        debug_assert!(len > 0, \"encode() called with empty buf\");\n\n        match self.kind {\n            Kind::Chunked(_) => {\n                trace!(\"encoding chunked {}B\", len);\n                let buf = ChunkSize::new(len)\n                    .chain(msg)\n                    .chain(b\"\\r\\n0\\r\\n\\r\\n\" as &'static [u8]);\n                dst.buffer(buf);\n                !self.is_last\n            }\n            Kind::Length(remaining) => {\n                use std::cmp::Ordering;\n\n                trace!(\"sized write, len = {}\", len);\n                match (len as u64).cmp(&remaining) {\n                    Ordering::Equal => {\n                        dst.buffer(msg);\n                        !self.is_last\n                    }\n                    Ordering::Greater => {\n                        dst.buffer(msg.take(remaining as usize));\n                        !self.is_last\n                    }\n                    Ordering::Less => {\n                        dst.buffer(msg);\n                        false\n                    }\n                }\n            }\n            #[cfg(feature = \"server\")]\n            Kind::CloseDelimited => {\n                trace!(\"close delimited write {}B\", len);\n                dst.buffer(msg);\n                false\n            }\n        }\n    }\n}\n\nfn is_valid_trailer_field(name: &HeaderName) -> bool {\n    !matches!(\n        *name,\n        AUTHORIZATION\n            | CACHE_CONTROL\n            | CONTENT_ENCODING\n            | CONTENT_LENGTH\n            | CONTENT_RANGE\n            | CONTENT_TYPE\n            | HOST\n            | MAX_FORWARDS\n            | SET_COOKIE\n            | TRAILER\n            | TRANSFER_ENCODING\n            | TE\n    )\n}\n\nimpl<B> Buf for EncodedBuf<B>\nwhere\n    B: Buf,\n{\n    #[inline]\n    fn remaining(&self) -> usize {\n        match self.kind {\n            BufKind::Exact(ref b) => b.remaining(),\n            BufKind::Limited(ref b) => b.remaining(),\n            BufKind::Chunked(ref b) => b.remaining(),\n            BufKind::ChunkedEnd(ref b) => b.remaining(),\n            BufKind::Trailers(ref b) => b.remaining(),\n        }\n    }\n\n    #[inline]\n    fn chunk(&self) -> &[u8] {\n        match self.kind {\n            BufKind::Exact(ref b) => b.chunk(),\n            BufKind::Limited(ref b) => b.chunk(),\n            BufKind::Chunked(ref b) => b.chunk(),\n            BufKind::ChunkedEnd(ref b) => b.chunk(),\n            BufKind::Trailers(ref b) => b.chunk(),\n        }\n    }\n\n    #[inline]\n    fn advance(&mut self, cnt: usize) {\n        match self.kind {\n            BufKind::Exact(ref mut b) => b.advance(cnt),\n            BufKind::Limited(ref mut b) => b.advance(cnt),\n            BufKind::Chunked(ref mut b) => b.advance(cnt),\n            BufKind::ChunkedEnd(ref mut b) => b.advance(cnt),\n            BufKind::Trailers(ref mut b) => b.advance(cnt),\n        }\n    }\n\n    #[inline]\n    fn chunks_vectored<'t>(&'t self, dst: &mut [IoSlice<'t>]) -> usize {\n        match self.kind {\n            BufKind::Exact(ref b) => b.chunks_vectored(dst),\n            BufKind::Limited(ref b) => b.chunks_vectored(dst),\n            BufKind::Chunked(ref b) => b.chunks_vectored(dst),\n            BufKind::ChunkedEnd(ref b) => b.chunks_vectored(dst),\n            BufKind::Trailers(ref b) => b.chunks_vectored(dst),\n        }\n    }\n}\n\n#[cfg(target_pointer_width = \"32\")]\nconst USIZE_BYTES: usize = 4;\n\n#[cfg(target_pointer_width = \"64\")]\nconst USIZE_BYTES: usize = 8;\n\n// each byte will become 2 hex\nconst CHUNK_SIZE_MAX_BYTES: usize = USIZE_BYTES * 2;\n\n#[derive(Clone, Copy)]\nstruct ChunkSize {\n    bytes: [u8; CHUNK_SIZE_MAX_BYTES + 2],\n    pos: u8,\n    len: u8,\n}\n\nimpl ChunkSize {\n    fn new(len: usize) -> ChunkSize {\n        use std::fmt::Write;\n        let mut size = ChunkSize {\n            bytes: [0; CHUNK_SIZE_MAX_BYTES + 2],\n            pos: 0,\n            len: 0,\n        };\n        write!(&mut size, \"{:X}\\r\\n\", len).expect(\"CHUNK_SIZE_MAX_BYTES should fit any usize\");\n        size\n    }\n}\n\nimpl Buf for ChunkSize {\n    #[inline]\n    fn remaining(&self) -> usize {\n        (self.len - self.pos).into()\n    }\n\n    #[inline]\n    fn chunk(&self) -> &[u8] {\n        &self.bytes[self.pos.into()..self.len.into()]\n    }\n\n    #[inline]\n    fn advance(&mut self, cnt: usize) {\n        assert!(cnt <= self.remaining());\n        self.pos += cnt as u8; // just asserted cnt fits in u8\n    }\n}\n\nimpl fmt::Debug for ChunkSize {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"ChunkSize\")\n            .field(\"bytes\", &&self.bytes[..self.len.into()])\n            .field(\"pos\", &self.pos)\n            .finish()\n    }\n}\n\nimpl fmt::Write for ChunkSize {\n    fn write_str(&mut self, num: &str) -> fmt::Result {\n        use std::io::Write;\n        (&mut self.bytes[self.len.into()..])\n            .write_all(num.as_bytes())\n            .expect(\"&mut [u8].write() cannot error\");\n        self.len += num.len() as u8; // safe because bytes is never bigger than 256\n        Ok(())\n    }\n}\n\nimpl<B: Buf> From<B> for EncodedBuf<B> {\n    fn from(buf: B) -> Self {\n        EncodedBuf {\n            kind: BufKind::Exact(buf),\n        }\n    }\n}\n\nimpl<B: Buf> From<Take<B>> for EncodedBuf<B> {\n    fn from(buf: Take<B>) -> Self {\n        EncodedBuf {\n            kind: BufKind::Limited(buf),\n        }\n    }\n}\n\nimpl<B: Buf> From<Chain<Chain<ChunkSize, B>, StaticBuf>> for EncodedBuf<B> {\n    fn from(buf: Chain<Chain<ChunkSize, B>, StaticBuf>) -> Self {\n        EncodedBuf {\n            kind: BufKind::Chunked(buf),\n        }\n    }\n}\n\nimpl fmt::Display for NotEof {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"early end, expected {} more bytes\", self.0)\n    }\n}\n\nimpl std::error::Error for NotEof {}\n\n#[cfg(test)]\nmod tests {\n    use bytes::BufMut;\n    use http::{\n        header::{\n            AUTHORIZATION, CACHE_CONTROL, CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_RANGE,\n            CONTENT_TYPE, HOST, MAX_FORWARDS, SET_COOKIE, TE, TRAILER, TRANSFER_ENCODING,\n        },\n        HeaderMap, HeaderName, HeaderValue,\n    };\n\n    use super::super::io::Cursor;\n    use super::Encoder;\n\n    #[test]\n    fn chunked() {\n        let mut encoder = Encoder::chunked();\n        let mut dst = Vec::new();\n\n        let msg1 = b\"foo bar\".as_ref();\n        let buf1 = encoder.encode(msg1);\n        dst.put(buf1);\n        assert_eq!(dst, b\"7\\r\\nfoo bar\\r\\n\");\n\n        let msg2 = b\"baz quux herp\".as_ref();\n        let buf2 = encoder.encode(msg2);\n        dst.put(buf2);\n\n        assert_eq!(dst, b\"7\\r\\nfoo bar\\r\\nD\\r\\nbaz quux herp\\r\\n\");\n\n        let end = encoder.end::<Cursor<Vec<u8>>>().unwrap().unwrap();\n        dst.put(end);\n\n        assert_eq!(\n            dst,\n            b\"7\\r\\nfoo bar\\r\\nD\\r\\nbaz quux herp\\r\\n0\\r\\n\\r\\n\".as_ref()\n        );\n    }\n\n    #[test]\n    fn length() {\n        let max_len = 8;\n        let mut encoder = Encoder::length(max_len as u64);\n        let mut dst = Vec::new();\n\n        let msg1 = b\"foo bar\".as_ref();\n        let buf1 = encoder.encode(msg1);\n        dst.put(buf1);\n\n        assert_eq!(dst, b\"foo bar\");\n        assert!(!encoder.is_eof());\n        encoder.end::<()>().unwrap_err();\n\n        let msg2 = b\"baz\".as_ref();\n        let buf2 = encoder.encode(msg2);\n        dst.put(buf2);\n\n        assert_eq!(dst.len(), max_len);\n        assert_eq!(dst, b\"foo barb\");\n        assert!(encoder.is_eof());\n        assert!(encoder.end::<()>().unwrap().is_none());\n    }\n\n    #[cfg(feature = \"server\")]\n    #[test]\n    fn eof() {\n        let mut encoder = Encoder::close_delimited();\n        let mut dst = Vec::new();\n\n        let msg1 = b\"foo bar\".as_ref();\n        let buf1 = encoder.encode(msg1);\n        dst.put(buf1);\n\n        assert_eq!(dst, b\"foo bar\");\n        assert!(!encoder.is_eof());\n        encoder.end::<()>().unwrap();\n\n        let msg2 = b\"baz\".as_ref();\n        let buf2 = encoder.encode(msg2);\n        dst.put(buf2);\n\n        assert_eq!(dst, b\"foo barbaz\");\n        assert!(!encoder.is_eof());\n        encoder.end::<()>().unwrap();\n    }\n\n    #[test]\n    fn chunked_with_valid_trailers() {\n        let encoder = Encoder::chunked();\n        let trailers = vec![HeaderName::from_static(\"chunky-trailer\")];\n        let encoder = encoder.into_chunked_with_trailing_fields(trailers);\n\n        let headers = HeaderMap::from_iter(vec![\n            (\n                HeaderName::from_static(\"chunky-trailer\"),\n                HeaderValue::from_static(\"header data\"),\n            ),\n            (\n                HeaderName::from_static(\"should-not-be-included\"),\n                HeaderValue::from_static(\"oops\"),\n            ),\n        ]);\n\n        let buf1 = encoder.encode_trailers::<&[u8]>(headers, false).unwrap();\n\n        let mut dst = Vec::new();\n        dst.put(buf1);\n        assert_eq!(dst, b\"0\\r\\nchunky-trailer: header data\\r\\n\\r\\n\");\n    }\n\n    #[test]\n    fn chunked_with_multiple_trailer_headers() {\n        let encoder = Encoder::chunked();\n        let trailers = vec![\n            HeaderName::from_static(\"chunky-trailer\"),\n            HeaderName::from_static(\"chunky-trailer-2\"),\n        ];\n        let encoder = encoder.into_chunked_with_trailing_fields(trailers);\n\n        let headers = HeaderMap::from_iter(vec![\n            (\n                HeaderName::from_static(\"chunky-trailer\"),\n                HeaderValue::from_static(\"header data\"),\n            ),\n            (\n                HeaderName::from_static(\"chunky-trailer-2\"),\n                HeaderValue::from_static(\"more header data\"),\n            ),\n        ]);\n\n        let buf1 = encoder.encode_trailers::<&[u8]>(headers, false).unwrap();\n\n        let mut dst = Vec::new();\n        dst.put(buf1);\n        assert_eq!(\n            dst,\n            b\"0\\r\\nchunky-trailer: header data\\r\\nchunky-trailer-2: more header data\\r\\n\\r\\n\"\n        );\n    }\n\n    #[test]\n    fn chunked_with_no_trailer_header() {\n        let encoder = Encoder::chunked();\n\n        let headers = HeaderMap::from_iter(vec![(\n            HeaderName::from_static(\"chunky-trailer\"),\n            HeaderValue::from_static(\"header data\"),\n        )]);\n\n        assert!(encoder\n            .encode_trailers::<&[u8]>(headers.clone(), false)\n            .is_none());\n\n        let trailers = vec![];\n        let encoder = encoder.into_chunked_with_trailing_fields(trailers);\n\n        assert!(encoder.encode_trailers::<&[u8]>(headers, false).is_none());\n    }\n\n    #[test]\n    fn chunked_with_invalid_trailers() {\n        let encoder = Encoder::chunked();\n\n        let trailers = vec![\n            AUTHORIZATION,\n            CACHE_CONTROL,\n            CONTENT_ENCODING,\n            CONTENT_LENGTH,\n            CONTENT_RANGE,\n            CONTENT_TYPE,\n            HOST,\n            MAX_FORWARDS,\n            SET_COOKIE,\n            TRAILER,\n            TRANSFER_ENCODING,\n            TE,\n        ];\n        let encoder = encoder.into_chunked_with_trailing_fields(trailers);\n\n        let mut headers = HeaderMap::new();\n        headers.insert(AUTHORIZATION, HeaderValue::from_static(\"header data\"));\n        headers.insert(CACHE_CONTROL, HeaderValue::from_static(\"header data\"));\n        headers.insert(CONTENT_ENCODING, HeaderValue::from_static(\"header data\"));\n        headers.insert(CONTENT_LENGTH, HeaderValue::from_static(\"header data\"));\n        headers.insert(CONTENT_RANGE, HeaderValue::from_static(\"header data\"));\n        headers.insert(CONTENT_TYPE, HeaderValue::from_static(\"header data\"));\n        headers.insert(HOST, HeaderValue::from_static(\"header data\"));\n        headers.insert(MAX_FORWARDS, HeaderValue::from_static(\"header data\"));\n        headers.insert(SET_COOKIE, HeaderValue::from_static(\"header data\"));\n        headers.insert(TRAILER, HeaderValue::from_static(\"header data\"));\n        headers.insert(TRANSFER_ENCODING, HeaderValue::from_static(\"header data\"));\n        headers.insert(TE, HeaderValue::from_static(\"header data\"));\n\n        assert!(encoder.encode_trailers::<&[u8]>(headers, true).is_none());\n    }\n\n    #[test]\n    fn chunked_with_title_case_headers() {\n        let encoder = Encoder::chunked();\n        let trailers = vec![HeaderName::from_static(\"chunky-trailer\")];\n        let encoder = encoder.into_chunked_with_trailing_fields(trailers);\n\n        let headers = HeaderMap::from_iter(vec![(\n            HeaderName::from_static(\"chunky-trailer\"),\n            HeaderValue::from_static(\"header data\"),\n        )]);\n        let buf1 = encoder.encode_trailers::<&[u8]>(headers, true).unwrap();\n\n        let mut dst = Vec::new();\n        dst.put(buf1);\n        assert_eq!(dst, b\"0\\r\\nChunky-Trailer: header data\\r\\n\\r\\n\");\n    }\n\n    #[test]\n    fn chunked_trailers_case_insensitive_matching() {\n        // Regression test for issue #4010: HTTP/1.1 trailers are case-sensitive\n        //\n        // Previously, the Trailer header values were stored as HeaderValue (preserving case)\n        // and compared against HeaderName (which is always lowercase). This caused trailers\n        // declared as \"Chunky-Trailer\" to not match actual trailers sent as \"chunky-trailer\".\n        //\n        // The fix converts Trailer header values to HeaderName during parsing, which\n        // normalizes the case and enables proper case-insensitive matching.\n        //\n        // Note: HeaderName::from_static() requires lowercase input. In real usage,\n        // HeaderName::from_bytes() is used to parse the Trailer header value, which\n        // normalizes mixed-case input like \"Chunky-Trailer\" to \"chunky-trailer\".\n        let encoder = Encoder::chunked();\n        let trailers = vec![HeaderName::from_static(\"chunky-trailer\")];\n        let encoder = encoder.into_chunked_with_trailing_fields(trailers);\n\n        // The actual trailer being sent\n        let headers = HeaderMap::from_iter(vec![(\n            HeaderName::from_static(\"chunky-trailer\"),\n            HeaderValue::from_static(\"trailer value\"),\n        )]);\n\n        let buf = encoder.encode_trailers::<&[u8]>(headers, false).unwrap();\n        let mut dst = Vec::new();\n        dst.put(buf);\n        assert_eq!(dst, b\"0\\r\\nchunky-trailer: trailer value\\r\\n\\r\\n\");\n    }\n}\n"
  },
  {
    "path": "src/proto/h1/io.rs",
    "content": "use std::cmp;\nuse std::fmt;\nuse std::io::{self, IoSlice};\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse crate::rt::{Read, ReadBuf, Write};\nuse bytes::{Buf, BufMut, Bytes, BytesMut};\nuse futures_core::ready;\n\nuse super::{Http1Transaction, ParseContext, ParsedMessage};\nuse crate::common::buf::BufList;\n\n/// The initial buffer size allocated before trying to read from IO.\npub(crate) const INIT_BUFFER_SIZE: usize = 8192;\n\n/// The minimum value that can be set to max buffer size.\npub(crate) const MINIMUM_MAX_BUFFER_SIZE: usize = INIT_BUFFER_SIZE;\n\n/// The default maximum read buffer size. If the buffer gets this big and\n/// a message is still not complete, a `TooLarge` error is triggered.\n// Note: if this changes, update server::conn::Http::max_buf_size docs.\npub(crate) const DEFAULT_MAX_BUFFER_SIZE: usize = 8192 + 4096 * 100;\n\n/// The maximum number of distinct `Buf`s to hold in a list before requiring\n/// a flush. Only affects when the buffer strategy is to queue buffers.\n///\n/// Note that a flush can happen before reaching the maximum. This simply\n/// forces a flush if the queue gets this big.\nconst MAX_BUF_LIST_BUFFERS: usize = 16;\n\npub(crate) struct Buffered<T, B> {\n    flush_pipeline: bool,\n    io: T,\n    partial_len: Option<usize>,\n    read_blocked: bool,\n    read_buf: BytesMut,\n    read_buf_strategy: ReadStrategy,\n    write_buf: WriteBuf<B>,\n}\n\nimpl<T, B> fmt::Debug for Buffered<T, B>\nwhere\n    B: Buf,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Buffered\")\n            .field(\"read_buf\", &self.read_buf)\n            .field(\"write_buf\", &self.write_buf)\n            .finish()\n    }\n}\n\nimpl<T, B> Buffered<T, B>\nwhere\n    T: Read + Write + Unpin,\n    B: Buf,\n{\n    pub(crate) fn new(io: T) -> Buffered<T, B> {\n        let strategy = if io.is_write_vectored() {\n            WriteStrategy::Queue\n        } else {\n            WriteStrategy::Flatten\n        };\n        let write_buf = WriteBuf::new(strategy);\n        Buffered {\n            flush_pipeline: false,\n            io,\n            partial_len: None,\n            read_blocked: false,\n            read_buf: BytesMut::with_capacity(0),\n            read_buf_strategy: ReadStrategy::default(),\n            write_buf,\n        }\n    }\n\n    #[cfg(feature = \"server\")]\n    pub(crate) fn set_flush_pipeline(&mut self, enabled: bool) {\n        debug_assert!(!self.write_buf.has_remaining());\n        self.flush_pipeline = enabled;\n        if enabled {\n            self.set_write_strategy_flatten();\n        }\n    }\n\n    pub(crate) fn set_max_buf_size(&mut self, max: usize) {\n        assert!(\n            max >= MINIMUM_MAX_BUFFER_SIZE,\n            \"The max_buf_size cannot be smaller than {}.\",\n            MINIMUM_MAX_BUFFER_SIZE,\n        );\n        self.read_buf_strategy = ReadStrategy::with_max(max);\n        self.write_buf.max_buf_size = max;\n    }\n\n    #[cfg(feature = \"client\")]\n    pub(crate) fn set_read_buf_exact_size(&mut self, sz: usize) {\n        self.read_buf_strategy = ReadStrategy::Exact(sz);\n    }\n\n    pub(crate) fn set_write_strategy_flatten(&mut self) {\n        // this should always be called only at construction time,\n        // so this assert is here to catch myself\n        debug_assert!(self.write_buf.queue.bufs_cnt() == 0);\n        self.write_buf.set_strategy(WriteStrategy::Flatten);\n    }\n\n    pub(crate) fn set_write_strategy_queue(&mut self) {\n        // this should always be called only at construction time,\n        // so this assert is here to catch myself\n        debug_assert!(self.write_buf.queue.bufs_cnt() == 0);\n        self.write_buf.set_strategy(WriteStrategy::Queue);\n    }\n\n    pub(crate) fn read_buf(&self) -> &[u8] {\n        self.read_buf.as_ref()\n    }\n\n    #[cfg(test)]\n    #[cfg(feature = \"nightly\")]\n    pub(super) fn read_buf_mut(&mut self) -> &mut BytesMut {\n        &mut self.read_buf\n    }\n\n    /// Return the \"allocated\" available space, not the potential space\n    /// that could be allocated in the future.\n    fn read_buf_remaining_mut(&self) -> usize {\n        self.read_buf.capacity() - self.read_buf.len()\n    }\n\n    /// Return whether we can append to the headers buffer.\n    ///\n    /// Reasons we can't:\n    /// - The write buf is in queue mode, and some of the past body is still\n    ///   needing to be flushed.\n    pub(crate) fn can_headers_buf(&self) -> bool {\n        !self.write_buf.queue.has_remaining()\n    }\n\n    pub(crate) fn headers_buf(&mut self) -> &mut Vec<u8> {\n        let buf = self.write_buf.headers_mut();\n        &mut buf.bytes\n    }\n\n    pub(super) fn write_buf(&mut self) -> &mut WriteBuf<B> {\n        &mut self.write_buf\n    }\n\n    pub(crate) fn buffer<BB: Buf + Into<B>>(&mut self, buf: BB) {\n        self.write_buf.buffer(buf)\n    }\n\n    pub(crate) fn can_buffer(&self) -> bool {\n        self.flush_pipeline || self.write_buf.can_buffer()\n    }\n\n    pub(crate) fn consume_leading_lines(&mut self) {\n        if !self.read_buf.is_empty() {\n            let mut i = 0;\n            while i < self.read_buf.len() {\n                match self.read_buf[i] {\n                    b'\\r' | b'\\n' => i += 1,\n                    _ => break,\n                }\n            }\n            self.read_buf.advance(i);\n        }\n    }\n\n    pub(super) fn parse<S>(\n        &mut self,\n        cx: &mut Context<'_>,\n        parse_ctx: ParseContext<'_>,\n    ) -> Poll<crate::Result<ParsedMessage<S::Incoming>>>\n    where\n        S: Http1Transaction,\n    {\n        loop {\n            match super::role::parse_headers::<S>(\n                &mut self.read_buf,\n                self.partial_len,\n                ParseContext {\n                    cached_headers: parse_ctx.cached_headers,\n                    req_method: parse_ctx.req_method,\n                    h1_parser_config: parse_ctx.h1_parser_config.clone(),\n                    h1_max_headers: parse_ctx.h1_max_headers,\n                    preserve_header_case: parse_ctx.preserve_header_case,\n                    #[cfg(feature = \"ffi\")]\n                    preserve_header_order: parse_ctx.preserve_header_order,\n                    h09_responses: parse_ctx.h09_responses,\n                    #[cfg(feature = \"client\")]\n                    on_informational: parse_ctx.on_informational,\n                },\n            )? {\n                Some(msg) => {\n                    debug!(\"parsed {} headers\", msg.head.headers.len());\n                    self.partial_len = None;\n                    return Poll::Ready(Ok(msg));\n                }\n                None => {\n                    let max = self.read_buf_strategy.max();\n                    let curr_len = self.read_buf.len();\n                    if curr_len >= max {\n                        debug!(\"max_buf_size ({}) reached, closing\", max);\n                        return Poll::Ready(Err(crate::Error::new_too_large()));\n                    }\n                    if curr_len > 0 {\n                        trace!(\"partial headers; {} bytes so far\", curr_len);\n                        self.partial_len = Some(curr_len);\n                    } else {\n                        // 1xx gobled some bytes\n                        self.partial_len = None;\n                    }\n                }\n            }\n            if ready!(self.poll_read_from_io(cx)).map_err(crate::Error::new_io)? == 0 {\n                trace!(\"parse eof\");\n                return Poll::Ready(Err(crate::Error::new_incomplete()));\n            }\n        }\n    }\n\n    pub(crate) fn poll_read_from_io(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<usize>> {\n        self.read_blocked = false;\n        let next = self.read_buf_strategy.next();\n        if self.read_buf_remaining_mut() < next {\n            self.read_buf.reserve(next);\n        }\n\n        // SAFETY: ReadBuf and poll_read promise not to set any uninitialized\n        // bytes onto `dst`.\n        let dst = unsafe { self.read_buf.chunk_mut().as_uninit_slice_mut() };\n        let mut buf = ReadBuf::uninit(dst);\n        match Pin::new(&mut self.io).poll_read(cx, buf.unfilled()) {\n            Poll::Ready(Ok(_)) => {\n                let n = buf.filled().len();\n                trace!(\"received {} bytes\", n);\n                unsafe {\n                    // Safety: we just read that many bytes into the\n                    // uninitialized part of the buffer, so this is okay.\n                    // @tokio pls give me back `poll_read_buf` thanks\n                    self.read_buf.advance_mut(n);\n                }\n                self.read_buf_strategy.record(n);\n                Poll::Ready(Ok(n))\n            }\n            Poll::Pending => {\n                self.read_blocked = true;\n                Poll::Pending\n            }\n            Poll::Ready(Err(e)) => Poll::Ready(Err(e)),\n        }\n    }\n\n    pub(crate) fn into_inner(self) -> (T, Bytes) {\n        (self.io, self.read_buf.freeze())\n    }\n\n    pub(crate) fn io_mut(&mut self) -> &mut T {\n        &mut self.io\n    }\n\n    pub(crate) fn is_read_blocked(&self) -> bool {\n        self.read_blocked\n    }\n\n    pub(crate) fn poll_flush(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        if self.flush_pipeline && !self.read_buf.is_empty() {\n            Poll::Ready(Ok(()))\n        } else if self.write_buf.remaining() == 0 {\n            Pin::new(&mut self.io).poll_flush(cx)\n        } else {\n            if let WriteStrategy::Flatten = self.write_buf.strategy {\n                return self.poll_flush_flattened(cx);\n            }\n\n            const MAX_WRITEV_BUFS: usize = 64;\n            loop {\n                let n = {\n                    let mut iovs = [IoSlice::new(&[]); MAX_WRITEV_BUFS];\n                    let len = self.write_buf.chunks_vectored(&mut iovs);\n                    ready!(Pin::new(&mut self.io).poll_write_vectored(cx, &iovs[..len]))?\n                };\n                // TODO(eliza): we have to do this manually because\n                // `poll_write_buf` doesn't exist in Tokio 0.3 yet...when\n                // `poll_write_buf` comes back, the manual advance will need to leave!\n                self.write_buf.advance(n);\n                debug!(\"flushed {} bytes\", n);\n                if self.write_buf.remaining() == 0 {\n                    break;\n                } else if n == 0 {\n                    trace!(\n                        \"write returned zero, but {} bytes remaining\",\n                        self.write_buf.remaining()\n                    );\n                    return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));\n                }\n            }\n            Pin::new(&mut self.io).poll_flush(cx)\n        }\n    }\n\n    /// Specialized version of `flush` when strategy is Flatten.\n    ///\n    /// Since all buffered bytes are flattened into the single headers buffer,\n    /// that skips some bookkeeping around using multiple buffers.\n    fn poll_flush_flattened(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        loop {\n            let n = ready!(Pin::new(&mut self.io).poll_write(cx, self.write_buf.headers.chunk()))?;\n            debug!(\"flushed {} bytes\", n);\n            self.write_buf.headers.advance(n);\n            if self.write_buf.headers.remaining() == 0 {\n                self.write_buf.headers.reset();\n                break;\n            } else if n == 0 {\n                trace!(\n                    \"write returned zero, but {} bytes remaining\",\n                    self.write_buf.remaining()\n                );\n                return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));\n            }\n        }\n        Pin::new(&mut self.io).poll_flush(cx)\n    }\n\n    #[cfg(test)]\n    fn flush(&mut self) -> impl std::future::Future<Output = io::Result<()>> + '_ {\n        futures_util::future::poll_fn(move |cx| self.poll_flush(cx))\n    }\n}\n\n// The `B` is a `Buf`, we never project a pin to it\nimpl<T: Unpin, B> Unpin for Buffered<T, B> {}\n\n// TODO: This trait is old... at least rename to PollBytes or something...\npub(crate) trait MemRead {\n    fn read_mem(&mut self, cx: &mut Context<'_>, len: usize) -> Poll<io::Result<Bytes>>;\n}\n\nimpl<T, B> MemRead for Buffered<T, B>\nwhere\n    T: Read + Write + Unpin,\n    B: Buf,\n{\n    fn read_mem(&mut self, cx: &mut Context<'_>, len: usize) -> Poll<io::Result<Bytes>> {\n        if !self.read_buf.is_empty() {\n            let n = std::cmp::min(len, self.read_buf.len());\n            Poll::Ready(Ok(self.read_buf.split_to(n).freeze()))\n        } else {\n            let n = ready!(self.poll_read_from_io(cx))?;\n            Poll::Ready(Ok(self.read_buf.split_to(::std::cmp::min(len, n)).freeze()))\n        }\n    }\n}\n\n#[derive(Clone, Copy, Debug)]\nenum ReadStrategy {\n    Adaptive {\n        decrease_now: bool,\n        next: usize,\n        max: usize,\n    },\n    #[cfg(feature = \"client\")]\n    Exact(usize),\n}\n\nimpl ReadStrategy {\n    fn with_max(max: usize) -> ReadStrategy {\n        ReadStrategy::Adaptive {\n            decrease_now: false,\n            next: INIT_BUFFER_SIZE,\n            max,\n        }\n    }\n\n    fn next(&self) -> usize {\n        match *self {\n            ReadStrategy::Adaptive { next, .. } => next,\n            #[cfg(feature = \"client\")]\n            ReadStrategy::Exact(exact) => exact,\n        }\n    }\n\n    fn max(&self) -> usize {\n        match *self {\n            ReadStrategy::Adaptive { max, .. } => max,\n            #[cfg(feature = \"client\")]\n            ReadStrategy::Exact(exact) => exact,\n        }\n    }\n\n    fn record(&mut self, bytes_read: usize) {\n        match *self {\n            ReadStrategy::Adaptive {\n                ref mut decrease_now,\n                ref mut next,\n                max,\n                ..\n            } => {\n                if bytes_read >= *next {\n                    *next = cmp::min(incr_power_of_two(*next), max);\n                    *decrease_now = false;\n                } else {\n                    let decr_to = prev_power_of_two(*next);\n                    if bytes_read < decr_to {\n                        if *decrease_now {\n                            *next = cmp::max(decr_to, INIT_BUFFER_SIZE);\n                            *decrease_now = false;\n                        } else {\n                            // Decreasing is a two \"record\" process.\n                            *decrease_now = true;\n                        }\n                    } else {\n                        // A read within the current range should cancel\n                        // a potential decrease, since we just saw proof\n                        // that we still need this size.\n                        *decrease_now = false;\n                    }\n                }\n            }\n            #[cfg(feature = \"client\")]\n            ReadStrategy::Exact(_) => (),\n        }\n    }\n}\n\nfn incr_power_of_two(n: usize) -> usize {\n    n.saturating_mul(2)\n}\n\nfn prev_power_of_two(n: usize) -> usize {\n    // Only way this shift can underflow is if n is less than 4.\n    // (Which would means `usize::MAX >> 64` and underflowed!)\n    debug_assert!(n >= 4);\n    (usize::MAX >> (n.leading_zeros() + 2)) + 1\n}\n\nimpl Default for ReadStrategy {\n    fn default() -> ReadStrategy {\n        ReadStrategy::with_max(DEFAULT_MAX_BUFFER_SIZE)\n    }\n}\n\n#[derive(Clone)]\npub(crate) struct Cursor<T> {\n    bytes: T,\n    pos: usize,\n}\n\nimpl<T: AsRef<[u8]>> Cursor<T> {\n    #[inline]\n    pub(crate) fn new(bytes: T) -> Cursor<T> {\n        Cursor { bytes, pos: 0 }\n    }\n}\n\nimpl Cursor<Vec<u8>> {\n    /// If we've advanced the position a bit in this cursor, and wish to\n    /// extend the underlying vector, we may wish to unshift the \"read\" bytes\n    /// off, and move everything else over.\n    fn maybe_unshift(&mut self, additional: usize) {\n        if self.pos == 0 {\n            // nothing to do\n            return;\n        }\n\n        if self.bytes.capacity() - self.bytes.len() >= additional {\n            // there's room!\n            return;\n        }\n\n        self.bytes.drain(0..self.pos);\n        self.pos = 0;\n    }\n\n    fn reset(&mut self) {\n        self.pos = 0;\n        self.bytes.clear();\n    }\n}\n\nimpl<T: AsRef<[u8]>> fmt::Debug for Cursor<T> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Cursor\")\n            .field(\"pos\", &self.pos)\n            .field(\"len\", &self.bytes.as_ref().len())\n            .finish()\n    }\n}\n\nimpl<T: AsRef<[u8]>> Buf for Cursor<T> {\n    #[inline]\n    fn remaining(&self) -> usize {\n        self.bytes.as_ref().len() - self.pos\n    }\n\n    #[inline]\n    fn chunk(&self) -> &[u8] {\n        &self.bytes.as_ref()[self.pos..]\n    }\n\n    #[inline]\n    fn advance(&mut self, cnt: usize) {\n        debug_assert!(self.pos + cnt <= self.bytes.as_ref().len());\n        self.pos += cnt;\n    }\n}\n\n// an internal buffer to collect writes before flushes\npub(super) struct WriteBuf<B> {\n    /// Re-usable buffer that holds message headers\n    headers: Cursor<Vec<u8>>,\n    max_buf_size: usize,\n    /// Deque of user buffers if strategy is Queue\n    queue: BufList<B>,\n    strategy: WriteStrategy,\n}\n\nimpl<B: Buf> WriteBuf<B> {\n    fn new(strategy: WriteStrategy) -> WriteBuf<B> {\n        WriteBuf {\n            headers: Cursor::new(Vec::with_capacity(INIT_BUFFER_SIZE)),\n            max_buf_size: DEFAULT_MAX_BUFFER_SIZE,\n            queue: BufList::new(),\n            strategy,\n        }\n    }\n}\n\nimpl<B> WriteBuf<B>\nwhere\n    B: Buf,\n{\n    fn set_strategy(&mut self, strategy: WriteStrategy) {\n        self.strategy = strategy;\n    }\n\n    pub(super) fn buffer<BB: Buf + Into<B>>(&mut self, mut buf: BB) {\n        debug_assert!(buf.has_remaining());\n        match self.strategy {\n            WriteStrategy::Flatten => {\n                let head = self.headers_mut();\n\n                head.maybe_unshift(buf.remaining());\n                trace!(\n                    self.len = head.remaining(),\n                    buf.len = buf.remaining(),\n                    \"buffer.flatten\"\n                );\n                //perf: This is a little faster than <Vec as BufMut>>::put,\n                //but accomplishes the same result.\n                loop {\n                    let adv = {\n                        let slice = buf.chunk();\n                        if slice.is_empty() {\n                            return;\n                        }\n                        head.bytes.extend_from_slice(slice);\n                        slice.len()\n                    };\n                    buf.advance(adv);\n                }\n            }\n            WriteStrategy::Queue => {\n                trace!(\n                    self.len = self.remaining(),\n                    buf.len = buf.remaining(),\n                    \"buffer.queue\"\n                );\n                self.queue.push(buf.into());\n            }\n        }\n    }\n\n    fn can_buffer(&self) -> bool {\n        match self.strategy {\n            WriteStrategy::Flatten => self.remaining() < self.max_buf_size,\n            WriteStrategy::Queue => {\n                self.queue.bufs_cnt() < MAX_BUF_LIST_BUFFERS && self.remaining() < self.max_buf_size\n            }\n        }\n    }\n\n    fn headers_mut(&mut self) -> &mut Cursor<Vec<u8>> {\n        debug_assert!(!self.queue.has_remaining());\n        &mut self.headers\n    }\n}\n\nimpl<B: Buf> fmt::Debug for WriteBuf<B> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"WriteBuf\")\n            .field(\"remaining\", &self.remaining())\n            .field(\"strategy\", &self.strategy)\n            .finish()\n    }\n}\n\nimpl<B: Buf> Buf for WriteBuf<B> {\n    #[inline]\n    fn remaining(&self) -> usize {\n        self.headers.remaining() + self.queue.remaining()\n    }\n\n    #[inline]\n    fn chunk(&self) -> &[u8] {\n        let headers = self.headers.chunk();\n        if !headers.is_empty() {\n            headers\n        } else {\n            self.queue.chunk()\n        }\n    }\n\n    #[inline]\n    fn advance(&mut self, cnt: usize) {\n        let hrem = self.headers.remaining();\n\n        match hrem.cmp(&cnt) {\n            cmp::Ordering::Equal => self.headers.reset(),\n            cmp::Ordering::Greater => self.headers.advance(cnt),\n            cmp::Ordering::Less => {\n                let qcnt = cnt - hrem;\n                self.headers.reset();\n                self.queue.advance(qcnt);\n            }\n        }\n    }\n\n    #[inline]\n    fn chunks_vectored<'t>(&'t self, dst: &mut [IoSlice<'t>]) -> usize {\n        let n = self.headers.chunks_vectored(dst);\n        self.queue.chunks_vectored(&mut dst[n..]) + n\n    }\n}\n\n#[derive(Debug)]\nenum WriteStrategy {\n    Flatten,\n    Queue,\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::common::io::Compat;\n    use std::time::Duration;\n\n    use tokio_test::io::Builder as Mock;\n\n    // #[cfg(feature = \"nightly\")]\n    // use test::Bencher;\n\n    /*\n    impl<T: Read> MemRead for AsyncIo<T> {\n        fn read_mem(&mut self, len: usize) -> Poll<Bytes, io::Error> {\n            let mut v = vec![0; len];\n            let n = try_nb!(self.read(v.as_mut_slice()));\n            Ok(Async::Ready(BytesMut::from(&v[..n]).freeze()))\n        }\n    }\n    */\n\n    #[tokio::test]\n    #[ignore]\n    async fn iobuf_write_empty_slice() {\n        // TODO(eliza): can i have writev back pls T_T\n        // // First, let's just check that the Mock would normally return an\n        // // error on an unexpected write, even if the buffer is empty...\n        // let mut mock = Mock::new().build();\n        // futures_util::future::poll_fn(|cx| {\n        //     Pin::new(&mut mock).poll_write_buf(cx, &mut Cursor::new(&[]))\n        // })\n        // .await\n        // .expect_err(\"should be a broken pipe\");\n\n        // // underlying io will return the logic error upon write,\n        // // so we are testing that the io_buf does not trigger a write\n        // // when there is nothing to flush\n        // let mock = Mock::new().build();\n        // let mut io_buf = Buffered::<_, Cursor<Vec<u8>>>::new(mock);\n        // io_buf.flush().await.expect(\"should short-circuit flush\");\n    }\n\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn parse_reads_until_blocked() {\n        use crate::proto::h1::ClientTransaction;\n\n        let _ = pretty_env_logger::try_init();\n        let mock = Mock::new()\n            // Split over multiple reads will read all of it\n            .read(b\"HTTP/1.1 200 OK\\r\\n\")\n            .read(b\"Server: hyper\\r\\n\")\n            // missing last line ending\n            .wait(Duration::from_secs(1))\n            .build();\n\n        let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(Compat::new(mock));\n\n        // We expect a `parse` to be not ready, and so can't await it directly.\n        // Rather, this `poll_fn` will wrap the `Poll` result.\n        futures_util::future::poll_fn(|cx| {\n            let parse_ctx = ParseContext {\n                cached_headers: &mut None,\n                req_method: &mut None,\n                h1_parser_config: Default::default(),\n                h1_max_headers: None,\n                preserve_header_case: false,\n                #[cfg(feature = \"ffi\")]\n                preserve_header_order: false,\n                h09_responses: false,\n                #[cfg(feature = \"client\")]\n                on_informational: &mut None,\n            };\n            assert!(buffered\n                .parse::<ClientTransaction>(cx, parse_ctx)\n                .is_pending());\n            Poll::Ready(())\n        })\n        .await;\n\n        assert_eq!(\n            buffered.read_buf,\n            b\"HTTP/1.1 200 OK\\r\\nServer: hyper\\r\\n\"[..]\n        );\n    }\n\n    #[test]\n    fn read_strategy_adaptive_increments() {\n        let mut strategy = ReadStrategy::default();\n        assert_eq!(strategy.next(), 8192);\n\n        // Grows if record == next\n        strategy.record(8192);\n        assert_eq!(strategy.next(), 16384);\n\n        strategy.record(16384);\n        assert_eq!(strategy.next(), 32768);\n\n        // Enormous records still increment at same rate\n        strategy.record(usize::MAX);\n        assert_eq!(strategy.next(), 65536);\n\n        let max = strategy.max();\n        while strategy.next() < max {\n            strategy.record(max);\n        }\n\n        assert_eq!(strategy.next(), max, \"never goes over max\");\n        strategy.record(max + 1);\n        assert_eq!(strategy.next(), max, \"never goes over max\");\n    }\n\n    #[test]\n    fn read_strategy_adaptive_decrements() {\n        let mut strategy = ReadStrategy::default();\n        strategy.record(8192);\n        assert_eq!(strategy.next(), 16384);\n\n        strategy.record(1);\n        assert_eq!(\n            strategy.next(),\n            16384,\n            \"first smaller record doesn't decrement yet\"\n        );\n        strategy.record(8192);\n        assert_eq!(strategy.next(), 16384, \"record was with range\");\n\n        strategy.record(1);\n        assert_eq!(\n            strategy.next(),\n            16384,\n            \"in-range record should make this the 'first' again\"\n        );\n\n        strategy.record(1);\n        assert_eq!(strategy.next(), 8192, \"second smaller record decrements\");\n\n        strategy.record(1);\n        assert_eq!(strategy.next(), 8192, \"first doesn't decrement\");\n        strategy.record(1);\n        assert_eq!(strategy.next(), 8192, \"doesn't decrement under minimum\");\n    }\n\n    #[test]\n    fn read_strategy_adaptive_stays_the_same() {\n        let mut strategy = ReadStrategy::default();\n        strategy.record(8192);\n        assert_eq!(strategy.next(), 16384);\n\n        strategy.record(8193);\n        assert_eq!(\n            strategy.next(),\n            16384,\n            \"first smaller record doesn't decrement yet\"\n        );\n\n        strategy.record(8193);\n        assert_eq!(\n            strategy.next(),\n            16384,\n            \"with current step does not decrement\"\n        );\n    }\n\n    #[test]\n    fn read_strategy_adaptive_max_fuzz() {\n        fn fuzz(max: usize) {\n            let mut strategy = ReadStrategy::with_max(max);\n            while strategy.next() < max {\n                strategy.record(usize::MAX);\n            }\n            let mut next = strategy.next();\n            while next > 8192 {\n                strategy.record(1);\n                strategy.record(1);\n                next = strategy.next();\n                assert!(\n                    next.is_power_of_two(),\n                    \"decrement should be powers of two: {} (max = {})\",\n                    next,\n                    max,\n                );\n            }\n        }\n\n        let mut max = 8192;\n        while max < std::usize::MAX {\n            fuzz(max);\n            max = (max / 2).saturating_mul(3);\n        }\n        fuzz(usize::MAX);\n    }\n\n    #[test]\n    #[should_panic]\n    #[cfg(debug_assertions)] // needs to trigger a debug_assert\n    fn write_buf_requires_non_empty_bufs() {\n        let mock = Mock::new().build();\n        let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(Compat::new(mock));\n\n        buffered.buffer(Cursor::new(Vec::new()));\n    }\n\n    /*\n    TODO: needs tokio_test::io to allow configure write_buf calls\n    #[test]\n    fn write_buf_queue() {\n        let _ = pretty_env_logger::try_init();\n\n        let mock = AsyncIo::new_buf(vec![], 1024);\n        let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(mock);\n\n\n        buffered.headers_buf().extend(b\"hello \");\n        buffered.buffer(Cursor::new(b\"world, \".to_vec()));\n        buffered.buffer(Cursor::new(b\"it's \".to_vec()));\n        buffered.buffer(Cursor::new(b\"hyper!\".to_vec()));\n        assert_eq!(buffered.write_buf.queue.bufs_cnt(), 3);\n        buffered.flush().unwrap();\n\n        assert_eq!(buffered.io, b\"hello world, it's hyper!\");\n        assert_eq!(buffered.io.num_writes(), 1);\n        assert_eq!(buffered.write_buf.queue.bufs_cnt(), 0);\n    }\n    */\n\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn write_buf_flatten() {\n        let _ = pretty_env_logger::try_init();\n\n        let mock = Mock::new().write(b\"hello world, it's hyper!\").build();\n\n        let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(Compat::new(mock));\n        buffered.write_buf.set_strategy(WriteStrategy::Flatten);\n\n        buffered.headers_buf().extend(b\"hello \");\n        buffered.buffer(Cursor::new(b\"world, \".to_vec()));\n        buffered.buffer(Cursor::new(b\"it's \".to_vec()));\n        buffered.buffer(Cursor::new(b\"hyper!\".to_vec()));\n        assert_eq!(buffered.write_buf.queue.bufs_cnt(), 0);\n\n        buffered.flush().await.expect(\"flush\");\n    }\n\n    #[test]\n    fn write_buf_flatten_partially_flushed() {\n        let _ = pretty_env_logger::try_init();\n\n        let b = |s: &str| Cursor::new(s.as_bytes().to_vec());\n\n        let mut write_buf = WriteBuf::<Cursor<Vec<u8>>>::new(WriteStrategy::Flatten);\n\n        write_buf.buffer(b(\"hello \"));\n        write_buf.buffer(b(\"world, \"));\n\n        assert_eq!(write_buf.chunk(), b\"hello world, \");\n\n        // advance most of the way, but not all\n        write_buf.advance(11);\n\n        assert_eq!(write_buf.chunk(), b\", \");\n        assert_eq!(write_buf.headers.pos, 11);\n        assert_eq!(write_buf.headers.bytes.capacity(), INIT_BUFFER_SIZE);\n\n        // there's still room in the headers buffer, so just push on the end\n        write_buf.buffer(b(\"it's hyper!\"));\n\n        assert_eq!(write_buf.chunk(), b\", it's hyper!\");\n        assert_eq!(write_buf.headers.pos, 11);\n\n        let rem1 = write_buf.remaining();\n        let cap = write_buf.headers.bytes.capacity();\n\n        // but when this would go over capacity, don't copy the old bytes\n        write_buf.buffer(Cursor::new(vec![b'X'; cap]));\n        assert_eq!(write_buf.remaining(), cap + rem1);\n        assert_eq!(write_buf.headers.pos, 0);\n    }\n\n    #[cfg(not(miri))]\n    #[tokio::test]\n    async fn write_buf_queue_disable_auto() {\n        let _ = pretty_env_logger::try_init();\n\n        let mock = Mock::new()\n            .write(b\"hello \")\n            .write(b\"world, \")\n            .write(b\"it's \")\n            .write(b\"hyper!\")\n            .build();\n\n        let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(Compat::new(mock));\n        buffered.write_buf.set_strategy(WriteStrategy::Queue);\n\n        // we have 4 buffers, and vec IO disabled, but explicitly said\n        // don't try to auto detect (via setting strategy above)\n\n        buffered.headers_buf().extend(b\"hello \");\n        buffered.buffer(Cursor::new(b\"world, \".to_vec()));\n        buffered.buffer(Cursor::new(b\"it's \".to_vec()));\n        buffered.buffer(Cursor::new(b\"hyper!\".to_vec()));\n        assert_eq!(buffered.write_buf.queue.bufs_cnt(), 3);\n\n        buffered.flush().await.expect(\"flush\");\n\n        assert_eq!(buffered.write_buf.queue.bufs_cnt(), 0);\n    }\n\n    // #[cfg(feature = \"nightly\")]\n    // #[bench]\n    // fn bench_write_buf_flatten_buffer_chunk(b: &mut Bencher) {\n    //     let s = \"Hello, World!\";\n    //     b.bytes = s.len() as u64;\n\n    //     let mut write_buf = WriteBuf::<bytes::Bytes>::new();\n    //     write_buf.set_strategy(WriteStrategy::Flatten);\n    //     b.iter(|| {\n    //         let chunk = bytes::Bytes::from(s);\n    //         write_buf.buffer(chunk);\n    //         ::test::black_box(&write_buf);\n    //         write_buf.headers.bytes.clear();\n    //     })\n    // }\n}\n"
  },
  {
    "path": "src/proto/h1/mod.rs",
    "content": "use bytes::BytesMut;\nuse http::{HeaderMap, Method};\nuse httparse::ParserConfig;\n\nuse crate::body::DecodedLength;\nuse crate::proto::{BodyLength, MessageHead};\n\npub(crate) use self::conn::Conn;\npub(crate) use self::decode::Decoder;\npub(crate) use self::dispatch::Dispatcher;\npub(crate) use self::encode::{EncodedBuf, Encoder};\n//TODO: move out of h1::io\npub(crate) use self::io::MINIMUM_MAX_BUFFER_SIZE;\n\nmod conn;\nmod decode;\npub(crate) mod dispatch;\nmod encode;\nmod io;\nmod role;\n\ncfg_client! {\n    pub(crate) type ClientTransaction = role::Client;\n}\n\ncfg_server! {\n    pub(crate) type ServerTransaction = role::Server;\n}\n\npub(crate) trait Http1Transaction {\n    type Incoming;\n    type Outgoing: Default;\n    #[cfg(feature = \"tracing\")]\n    const LOG: &'static str;\n    fn parse(bytes: &mut BytesMut, ctx: ParseContext<'_>) -> ParseResult<Self::Incoming>;\n    fn encode(enc: Encode<'_, Self::Outgoing>, dst: &mut Vec<u8>) -> crate::Result<Encoder>;\n\n    fn on_error(err: &crate::Error) -> Option<MessageHead<Self::Outgoing>>;\n\n    fn is_client() -> bool {\n        !Self::is_server()\n    }\n\n    fn is_server() -> bool {\n        !Self::is_client()\n    }\n\n    fn should_error_on_parse_eof() -> bool {\n        Self::is_client()\n    }\n\n    fn should_read_first() -> bool {\n        Self::is_server()\n    }\n\n    fn update_date() {}\n}\n\n/// Result newtype for Http1Transaction::parse.\npub(crate) type ParseResult<T> = Result<Option<ParsedMessage<T>>, crate::error::Parse>;\n\n#[derive(Debug)]\npub(crate) struct ParsedMessage<T> {\n    head: MessageHead<T>,\n    decode: DecodedLength,\n    expect_continue: bool,\n    keep_alive: bool,\n    wants_upgrade: bool,\n}\n\npub(crate) struct ParseContext<'a> {\n    cached_headers: &'a mut Option<HeaderMap>,\n    req_method: &'a mut Option<Method>,\n    h1_parser_config: ParserConfig,\n    h1_max_headers: Option<usize>,\n    preserve_header_case: bool,\n    #[cfg(feature = \"ffi\")]\n    preserve_header_order: bool,\n    h09_responses: bool,\n    #[cfg(feature = \"client\")]\n    on_informational: &'a mut Option<crate::ext::OnInformational>,\n}\n\n/// Passed to Http1Transaction::encode\npub(crate) struct Encode<'a, T> {\n    head: &'a mut MessageHead<T>,\n    body: Option<BodyLength>,\n    #[cfg(feature = \"server\")]\n    keep_alive: bool,\n    req_method: &'a mut Option<Method>,\n    title_case_headers: bool,\n    #[cfg(feature = \"server\")]\n    date_header: bool,\n}\n\n/// Extra flags that a request \"wants\", like expect-continue or upgrades.\n#[derive(Clone, Copy, Debug)]\nstruct Wants(u8);\n\nimpl Wants {\n    const EMPTY: Wants = Wants(0b00);\n    const EXPECT: Wants = Wants(0b01);\n    const UPGRADE: Wants = Wants(0b10);\n\n    #[must_use]\n    fn add(self, other: Wants) -> Wants {\n        Wants(self.0 | other.0)\n    }\n\n    fn contains(&self, other: Wants) -> bool {\n        (self.0 & other.0) == other.0\n    }\n}\n"
  },
  {
    "path": "src/proto/h1/role.rs",
    "content": "use std::mem::MaybeUninit;\n\n#[cfg(feature = \"client\")]\nuse std::fmt::{self, Write as _};\n\nuse bytes::Bytes;\nuse bytes::BytesMut;\n#[cfg(feature = \"client\")]\nuse http::header::Entry;\n#[cfg(feature = \"server\")]\nuse http::header::ValueIter;\nuse http::header::{self, HeaderMap, HeaderName, HeaderValue};\nuse http::{Method, StatusCode, Version};\nuse smallvec::{smallvec, smallvec_inline, SmallVec};\n\nuse crate::body::DecodedLength;\n#[cfg(feature = \"server\")]\nuse crate::common::date;\nuse crate::error::Parse;\nuse crate::ext::HeaderCaseMap;\n#[cfg(feature = \"ffi\")]\nuse crate::ext::OriginalHeaderOrder;\nuse crate::headers;\nuse crate::proto::h1::{\n    Encode, Encoder, Http1Transaction, ParseContext, ParseResult, ParsedMessage,\n};\n#[cfg(feature = \"client\")]\nuse crate::proto::RequestHead;\nuse crate::proto::{BodyLength, MessageHead, RequestLine};\n\npub(crate) const DEFAULT_MAX_HEADERS: usize = 100;\nconst AVERAGE_HEADER_SIZE: usize = 30; // totally scientific\n#[cfg(feature = \"server\")]\nconst MAX_URI_LEN: usize = (u16::MAX - 1) as usize;\n\nmacro_rules! header_name {\n    ($bytes:expr) => {{\n        {\n            match HeaderName::from_bytes($bytes) {\n                Ok(name) => name,\n                Err(e) => maybe_panic!(e),\n            }\n        }\n    }};\n}\n\nmacro_rules! header_value {\n    ($bytes:expr) => {{\n        {\n            unsafe { HeaderValue::from_maybe_shared_unchecked($bytes) }\n        }\n    }};\n}\n\nmacro_rules! maybe_panic {\n    ($($arg:tt)*) => ({\n        let _err = ($($arg)*);\n        if cfg!(debug_assertions) {\n            panic!(\"{:?}\", _err);\n        } else {\n            error!(\"Internal Hyper error, please report {:?}\", _err);\n            return Err(Parse::Internal)\n        }\n    })\n}\n\npub(super) fn parse_headers<T>(\n    bytes: &mut BytesMut,\n    prev_len: Option<usize>,\n    ctx: ParseContext<'_>,\n) -> ParseResult<T::Incoming>\nwhere\n    T: Http1Transaction,\n{\n    // If the buffer is empty, don't bother entering the span, it's just noise.\n    if bytes.is_empty() {\n        return Ok(None);\n    }\n\n    let _entered = trace_span!(\"parse_headers\");\n\n    if let Some(prev_len) = prev_len {\n        if !is_complete_fast(bytes, prev_len) {\n            return Ok(None);\n        }\n    }\n\n    T::parse(bytes, ctx)\n}\n\n/// A fast scan for the end of a message.\n/// Used when there was a partial read, to skip full parsing on a\n/// a slow connection.\nfn is_complete_fast(bytes: &[u8], prev_len: usize) -> bool {\n    let start = prev_len.saturating_sub(3);\n    let bytes = &bytes[start..];\n\n    for (i, b) in bytes.iter().copied().enumerate() {\n        if b == b'\\r' {\n            if bytes[i + 1..].chunks(3).next() == Some(&b\"\\n\\r\\n\"[..]) {\n                return true;\n            }\n        } else if b == b'\\n' && bytes.get(i + 1) == Some(&b'\\n') {\n            return true;\n        }\n    }\n\n    false\n}\n\npub(super) fn encode_headers<T>(\n    enc: Encode<'_, T::Outgoing>,\n    dst: &mut Vec<u8>,\n) -> crate::Result<Encoder>\nwhere\n    T: Http1Transaction,\n{\n    let _entered = trace_span!(\"encode_headers\");\n    T::encode(enc, dst)\n}\n\n// There are 2 main roles, Client and Server.\n\n#[cfg(feature = \"client\")]\npub(crate) enum Client {}\n\n#[cfg(feature = \"server\")]\npub(crate) enum Server {}\n\n#[cfg(feature = \"server\")]\nimpl Http1Transaction for Server {\n    type Incoming = RequestLine;\n    type Outgoing = StatusCode;\n    #[cfg(feature = \"tracing\")]\n    const LOG: &'static str = \"{role=server}\";\n\n    fn parse(buf: &mut BytesMut, ctx: ParseContext<'_>) -> ParseResult<RequestLine> {\n        debug_assert!(!buf.is_empty(), \"parse called with empty buf\");\n\n        let mut keep_alive;\n        let is_http_11;\n        let subject;\n        let version;\n        let len;\n        let headers_len;\n        let method;\n        let path_range;\n\n        // Both headers_indices and headers are using uninitialized memory,\n        // but we *never* read any of it until after httparse has assigned\n        // values into it. By not zeroing out the stack memory, this saves\n        // a good ~5% on pipeline benchmarks.\n        let mut headers_indices: SmallVec<[MaybeUninit<HeaderIndices>; DEFAULT_MAX_HEADERS]> =\n            match ctx.h1_max_headers {\n                Some(cap) => smallvec![MaybeUninit::uninit(); cap],\n                None => smallvec_inline![MaybeUninit::uninit(); DEFAULT_MAX_HEADERS],\n            };\n        {\n            let mut headers: SmallVec<[MaybeUninit<httparse::Header<'_>>; DEFAULT_MAX_HEADERS]> =\n                match ctx.h1_max_headers {\n                    Some(cap) => smallvec![MaybeUninit::uninit(); cap],\n                    None => smallvec_inline![MaybeUninit::uninit(); DEFAULT_MAX_HEADERS],\n                };\n            trace!(bytes = buf.len(), \"Request.parse\");\n            let mut req = httparse::Request::new(&mut []);\n            let bytes = buf.as_ref();\n            match ctx.h1_parser_config.parse_request_with_uninit_headers(\n                &mut req,\n                bytes,\n                &mut headers,\n            ) {\n                Ok(httparse::Status::Complete(parsed_len)) => {\n                    trace!(\"Request.parse Complete({})\", parsed_len);\n                    len = parsed_len;\n                    let uri = req.path.unwrap();\n                    if uri.len() > MAX_URI_LEN {\n                        return Err(Parse::UriTooLong);\n                    }\n                    method = Method::from_bytes(req.method.unwrap().as_bytes())?;\n                    path_range = Server::record_path_range(bytes, uri);\n                    version = if req.version.unwrap() == 1 {\n                        keep_alive = true;\n                        is_http_11 = true;\n                        Version::HTTP_11\n                    } else {\n                        keep_alive = false;\n                        is_http_11 = false;\n                        Version::HTTP_10\n                    };\n\n                    record_header_indices(bytes, req.headers, &mut headers_indices)?;\n                    headers_len = req.headers.len();\n                }\n                Ok(httparse::Status::Partial) => return Ok(None),\n                // if invalid Token, try to determine if for method or path\n                Err(httparse::Error::Token) => {\n                    return Err({\n                        if req.method.is_none() {\n                            Parse::Method\n                        } else {\n                            debug_assert!(req.path.is_none());\n                            Parse::Uri\n                        }\n                    })\n                }\n                Err(err) => return Err(err.into()),\n            }\n        };\n\n        let slice = buf.split_to(len).freeze();\n        let uri = {\n            let uri_bytes = slice.slice_ref(&slice[path_range]);\n            // TODO(lucab): switch to `Uri::from_shared()` once public.\n            http::Uri::from_maybe_shared(uri_bytes)?\n        };\n        subject = RequestLine(method, uri);\n\n        // According to https://tools.ietf.org/html/rfc7230#section-3.3.3\n        // 1. (irrelevant to Request)\n        // 2. (irrelevant to Request)\n        // 3. Transfer-Encoding: chunked has a chunked body.\n        // 4. If multiple differing Content-Length headers or invalid, close connection.\n        // 5. Content-Length header has a sized body.\n        // 6. Length 0.\n        // 7. (irrelevant to Request)\n\n        let mut decoder = DecodedLength::ZERO;\n        let mut expect_continue = false;\n        let mut con_len = None;\n        let mut is_te = false;\n        let mut is_te_chunked = false;\n        let mut wants_upgrade = subject.0 == Method::CONNECT;\n\n        let mut header_case_map = if ctx.preserve_header_case {\n            Some(HeaderCaseMap::default())\n        } else {\n            None\n        };\n\n        #[cfg(feature = \"ffi\")]\n        let mut header_order = if ctx.preserve_header_order {\n            Some(OriginalHeaderOrder::default())\n        } else {\n            None\n        };\n\n        let mut headers = ctx.cached_headers.take().unwrap_or_default();\n\n        headers.reserve(headers_len);\n\n        for header in &headers_indices[..headers_len] {\n            // SAFETY: array is valid up to `headers_len`\n            let header = unsafe { header.assume_init_ref() };\n            let name = header_name!(&slice[header.name.0..header.name.1]);\n            let value = header_value!(slice.slice(header.value.0..header.value.1));\n\n            match name {\n                header::TRANSFER_ENCODING => {\n                    // https://tools.ietf.org/html/rfc7230#section-3.3.3\n                    // If Transfer-Encoding header is present, and 'chunked' is\n                    // not the final encoding, and this is a Request, then it is\n                    // malformed. A server should respond with 400 Bad Request.\n                    if !is_http_11 {\n                        debug!(\"HTTP/1.0 cannot have Transfer-Encoding header\");\n                        return Err(Parse::transfer_encoding_unexpected());\n                    }\n                    is_te = true;\n                    if headers::is_chunked_(&value) {\n                        is_te_chunked = true;\n                        decoder = DecodedLength::CHUNKED;\n                    } else {\n                        is_te_chunked = false;\n                    }\n                }\n                header::CONTENT_LENGTH => {\n                    if is_te {\n                        continue;\n                    }\n                    let len = headers::content_length_parse(&value)\n                        .ok_or_else(Parse::content_length_invalid)?;\n                    if let Some(prev) = con_len {\n                        if prev != len {\n                            debug!(\n                                \"multiple Content-Length headers with different values: [{}, {}]\",\n                                prev, len,\n                            );\n                            return Err(Parse::content_length_invalid());\n                        }\n                        // we don't need to append this secondary length\n                        continue;\n                    }\n                    decoder = DecodedLength::checked_new(len)?;\n                    con_len = Some(len);\n                }\n                header::CONNECTION => {\n                    // keep_alive was previously set to default for Version\n                    if keep_alive {\n                        // HTTP/1.1\n                        keep_alive = !headers::connection_close(&value);\n                    } else {\n                        // HTTP/1.0\n                        keep_alive = headers::connection_keep_alive(&value);\n                    }\n                }\n                header::EXPECT => {\n                    // According to https://datatracker.ietf.org/doc/html/rfc2616#section-14.20\n                    // Comparison of expectation values is case-insensitive for unquoted tokens\n                    // (including the 100-continue token)\n                    expect_continue = value.as_bytes().eq_ignore_ascii_case(b\"100-continue\");\n                }\n                header::UPGRADE => {\n                    // Upgrades are only allowed with HTTP/1.1\n                    wants_upgrade = is_http_11;\n                }\n\n                _ => (),\n            }\n\n            if let Some(ref mut header_case_map) = header_case_map {\n                header_case_map.append(&name, slice.slice(header.name.0..header.name.1));\n            }\n\n            #[cfg(feature = \"ffi\")]\n            if let Some(ref mut header_order) = header_order {\n                header_order.append(&name);\n            }\n\n            headers.append(name, value);\n        }\n\n        if is_te && !is_te_chunked {\n            debug!(\"request with transfer-encoding header, but not chunked, bad request\");\n            return Err(Parse::transfer_encoding_invalid());\n        }\n\n        let mut extensions = http::Extensions::default();\n\n        if let Some(header_case_map) = header_case_map {\n            extensions.insert(header_case_map);\n        }\n\n        #[cfg(feature = \"ffi\")]\n        if let Some(header_order) = header_order {\n            extensions.insert(header_order);\n        }\n\n        *ctx.req_method = Some(subject.0.clone());\n\n        Ok(Some(ParsedMessage {\n            head: MessageHead {\n                version,\n                subject,\n                headers,\n                extensions,\n            },\n            decode: decoder,\n            expect_continue,\n            keep_alive,\n            wants_upgrade,\n        }))\n    }\n\n    fn encode(mut msg: Encode<'_, Self::Outgoing>, dst: &mut Vec<u8>) -> crate::Result<Encoder> {\n        trace!(\n            \"Server::encode status={:?}, body={:?}, req_method={:?}\",\n            msg.head.subject,\n            msg.body,\n            msg.req_method\n        );\n\n        let mut wrote_len = false;\n\n        // hyper currently doesn't support returning 1xx status codes as a Response\n        // This is because Service only allows returning a single Response, and\n        // so if you try to reply with a e.g. 100 Continue, you have no way of\n        // replying with the latter status code response.\n        let (ret, is_last) = if msg.head.subject == StatusCode::SWITCHING_PROTOCOLS {\n            (Ok(()), true)\n        } else if msg.req_method == &Some(Method::CONNECT) && msg.head.subject.is_success() {\n            // Sending content-length or transfer-encoding header on 2xx response\n            // to CONNECT is forbidden in RFC 7231.\n            wrote_len = true;\n            (Ok(()), true)\n        } else if msg.head.subject.is_informational() {\n            warn!(\"response with 1xx status code not supported\");\n            *msg.head = MessageHead::default();\n            msg.head.subject = StatusCode::INTERNAL_SERVER_ERROR;\n            msg.body = None;\n            (Err(crate::Error::new_user_unsupported_status_code()), true)\n        } else {\n            (Ok(()), !msg.keep_alive)\n        };\n\n        // In some error cases, we don't know about the invalid message until already\n        // pushing some bytes onto the `dst`. In those cases, we don't want to send\n        // the half-pushed message, so rewind to before.\n        let orig_len = dst.len();\n\n        let init_cap = 30 + msg.head.headers.len() * AVERAGE_HEADER_SIZE;\n        dst.reserve(init_cap);\n\n        let custom_reason_phrase = msg.head.extensions.get::<crate::ext::ReasonPhrase>();\n\n        if msg.head.version == Version::HTTP_11\n            && msg.head.subject == StatusCode::OK\n            && custom_reason_phrase.is_none()\n        {\n            extend(dst, b\"HTTP/1.1 200 OK\\r\\n\");\n        } else {\n            match msg.head.version {\n                Version::HTTP_10 => extend(dst, b\"HTTP/1.0 \"),\n                Version::HTTP_11 => extend(dst, b\"HTTP/1.1 \"),\n                Version::HTTP_2 => {\n                    debug!(\"response with HTTP2 version coerced to HTTP/1.1\");\n                    extend(dst, b\"HTTP/1.1 \");\n                }\n                other => panic!(\"unexpected response version: {:?}\", other),\n            }\n\n            extend(dst, msg.head.subject.as_str().as_bytes());\n            extend(dst, b\" \");\n\n            if let Some(reason) = custom_reason_phrase {\n                extend(dst, reason.as_bytes());\n            } else {\n                // a reason MUST be written, as many parsers will expect it.\n                extend(\n                    dst,\n                    msg.head\n                        .subject\n                        .canonical_reason()\n                        .unwrap_or(\"<none>\")\n                        .as_bytes(),\n                );\n            }\n\n            extend(dst, b\"\\r\\n\");\n        }\n\n        let orig_headers;\n        let extensions = std::mem::take(&mut msg.head.extensions);\n        let orig_headers = match extensions.get::<HeaderCaseMap>() {\n            None if msg.title_case_headers => {\n                orig_headers = HeaderCaseMap::default();\n                Some(&orig_headers)\n            }\n            orig_headers => orig_headers,\n        };\n        let encoder = if let Some(orig_headers) = orig_headers {\n            Self::encode_headers_with_original_case(\n                msg,\n                dst,\n                is_last,\n                orig_len,\n                wrote_len,\n                orig_headers,\n            )?\n        } else {\n            Self::encode_headers_with_lower_case(msg, dst, is_last, orig_len, wrote_len)?\n        };\n\n        ret.map(|()| encoder)\n    }\n\n    fn on_error(err: &crate::Error) -> Option<MessageHead<Self::Outgoing>> {\n        use crate::error::Kind;\n        let status = match *err.kind() {\n            Kind::Parse(Parse::Method)\n            | Kind::Parse(Parse::Header(_))\n            | Kind::Parse(Parse::Uri)\n            | Kind::Parse(Parse::Version) => StatusCode::BAD_REQUEST,\n            Kind::Parse(Parse::TooLarge) => StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE,\n            Kind::Parse(Parse::UriTooLong) => StatusCode::URI_TOO_LONG,\n            _ => return None,\n        };\n\n        debug!(\"sending automatic response ({}) for parse error\", status);\n        let msg = MessageHead {\n            subject: status,\n            ..Default::default()\n        };\n        Some(msg)\n    }\n\n    fn is_server() -> bool {\n        true\n    }\n\n    fn update_date() {\n        date::update();\n    }\n}\n\n#[cfg(feature = \"server\")]\nimpl Server {\n    fn can_have_body(method: &Option<Method>, status: StatusCode) -> bool {\n        Server::can_chunked(method, status)\n    }\n\n    fn can_chunked(method: &Option<Method>, status: StatusCode) -> bool {\n        if method == &Some(Method::HEAD)\n            || method == &Some(Method::CONNECT) && status.is_success()\n            || status.is_informational()\n        {\n            false\n        } else {\n            !matches!(status, StatusCode::NO_CONTENT | StatusCode::NOT_MODIFIED)\n        }\n    }\n\n    fn can_have_content_length(method: &Option<Method>, status: StatusCode) -> bool {\n        if status.is_informational() || method == &Some(Method::CONNECT) && status.is_success() {\n            false\n        } else {\n            !matches!(status, StatusCode::NO_CONTENT | StatusCode::NOT_MODIFIED)\n        }\n    }\n\n    fn can_have_implicit_zero_content_length(method: &Option<Method>, status: StatusCode) -> bool {\n        Server::can_have_content_length(method, status) && method != &Some(Method::HEAD)\n    }\n\n    fn encode_headers_with_lower_case(\n        msg: Encode<'_, StatusCode>,\n        dst: &mut Vec<u8>,\n        is_last: bool,\n        orig_len: usize,\n        wrote_len: bool,\n    ) -> crate::Result<Encoder> {\n        struct LowercaseWriter;\n\n        impl HeaderNameWriter for LowercaseWriter {\n            #[inline]\n            fn write_full_header_line(\n                &mut self,\n                dst: &mut Vec<u8>,\n                line: &str,\n                _: (HeaderName, &str),\n            ) {\n                extend(dst, line.as_bytes())\n            }\n\n            #[inline]\n            fn write_header_name_with_colon(\n                &mut self,\n                dst: &mut Vec<u8>,\n                name_with_colon: &str,\n                _: HeaderName,\n            ) {\n                extend(dst, name_with_colon.as_bytes())\n            }\n\n            #[inline]\n            fn write_header_name(&mut self, dst: &mut Vec<u8>, name: &HeaderName) {\n                extend(dst, name.as_str().as_bytes())\n            }\n        }\n\n        Self::encode_headers(msg, dst, is_last, orig_len, wrote_len, LowercaseWriter)\n    }\n\n    #[cold]\n    #[inline(never)]\n    fn encode_headers_with_original_case(\n        msg: Encode<'_, StatusCode>,\n        dst: &mut Vec<u8>,\n        is_last: bool,\n        orig_len: usize,\n        wrote_len: bool,\n        orig_headers: &HeaderCaseMap,\n    ) -> crate::Result<Encoder> {\n        struct OrigCaseWriter<'map> {\n            map: &'map HeaderCaseMap,\n            current: Option<(HeaderName, ValueIter<'map, Bytes>)>,\n            title_case_headers: bool,\n        }\n\n        impl HeaderNameWriter for OrigCaseWriter<'_> {\n            #[inline]\n            fn write_full_header_line(\n                &mut self,\n                dst: &mut Vec<u8>,\n                _: &str,\n                (name, rest): (HeaderName, &str),\n            ) {\n                self.write_header_name(dst, &name);\n                extend(dst, rest.as_bytes());\n            }\n\n            #[inline]\n            fn write_header_name_with_colon(\n                &mut self,\n                dst: &mut Vec<u8>,\n                _: &str,\n                name: HeaderName,\n            ) {\n                self.write_header_name(dst, &name);\n                extend(dst, b\": \");\n            }\n\n            #[inline]\n            fn write_header_name(&mut self, dst: &mut Vec<u8>, name: &HeaderName) {\n                let Self {\n                    map,\n                    ref mut current,\n                    title_case_headers,\n                } = *self;\n                if current.as_ref().map_or(true, |(last, _)| last != name) {\n                    *current = None;\n                }\n                let (_, values) =\n                    current.get_or_insert_with(|| (name.clone(), map.get_all_internal(name)));\n\n                if let Some(orig_name) = values.next() {\n                    extend(dst, orig_name);\n                } else if title_case_headers {\n                    title_case(dst, name.as_str().as_bytes());\n                } else {\n                    extend(dst, name.as_str().as_bytes());\n                }\n            }\n        }\n\n        let header_name_writer = OrigCaseWriter {\n            map: orig_headers,\n            current: None,\n            title_case_headers: msg.title_case_headers,\n        };\n\n        Self::encode_headers(msg, dst, is_last, orig_len, wrote_len, header_name_writer)\n    }\n\n    #[inline]\n    fn encode_headers<W>(\n        msg: Encode<'_, StatusCode>,\n        dst: &mut Vec<u8>,\n        mut is_last: bool,\n        orig_len: usize,\n        mut wrote_len: bool,\n        mut header_name_writer: W,\n    ) -> crate::Result<Encoder>\n    where\n        W: HeaderNameWriter,\n    {\n        // In some error cases, we don't know about the invalid message until already\n        // pushing some bytes onto the `dst`. In those cases, we don't want to send\n        // the half-pushed message, so rewind to before.\n        let rewind = |dst: &mut Vec<u8>| {\n            dst.truncate(orig_len);\n        };\n\n        let mut encoder = Encoder::length(0);\n        let mut allowed_trailer_fields: Option<Vec<HeaderName>> = None;\n        let mut wrote_date = false;\n        let mut cur_name = None;\n        let mut is_name_written = false;\n        let mut must_write_chunked = false;\n        let mut prev_con_len = None;\n\n        macro_rules! handle_is_name_written {\n            () => {{\n                if is_name_written {\n                    // we need to clean up and write the newline\n                    debug_assert_ne!(\n                        &dst[dst.len() - 2..],\n                        b\"\\r\\n\",\n                        \"previous header wrote newline but set is_name_written\"\n                    );\n\n                    if must_write_chunked {\n                        extend(dst, b\", chunked\\r\\n\");\n                    } else {\n                        extend(dst, b\"\\r\\n\");\n                    }\n                }\n            }};\n        }\n\n        'headers: for (opt_name, value) in msg.head.headers.drain() {\n            if let Some(n) = opt_name {\n                cur_name = Some(n);\n                handle_is_name_written!();\n                is_name_written = false;\n            }\n            let name = cur_name.as_ref().expect(\"current header name\");\n            match *name {\n                header::CONTENT_LENGTH => {\n                    if wrote_len && !is_name_written {\n                        warn!(\"unexpected content-length found, canceling\");\n                        rewind(dst);\n                        return Err(crate::Error::new_user_header());\n                    }\n                    match msg.body {\n                        Some(BodyLength::Known(known_len)) => {\n                            // The Body claims to know a length, and\n                            // the headers are already set. For performance\n                            // reasons, we are just going to trust that\n                            // the values match.\n                            //\n                            // In debug builds, we'll assert they are the\n                            // same to help developers find bugs.\n                            #[cfg(debug_assertions)]\n                            {\n                                if let Some(len) = headers::content_length_parse(&value) {\n                                    if msg.req_method != &Some(Method::HEAD) || known_len != 0 {\n                                        assert!(\n                                        len == known_len,\n                                        \"payload claims content-length of {}, custom content-length header claims {}\",\n                                        known_len,\n                                        len,\n                                    );\n                                    }\n                                }\n                            }\n\n                            if !is_name_written {\n                                encoder = Encoder::length(known_len);\n                                header_name_writer.write_header_name_with_colon(\n                                    dst,\n                                    \"content-length: \",\n                                    header::CONTENT_LENGTH,\n                                );\n                                extend(dst, value.as_bytes());\n                                wrote_len = true;\n                                is_name_written = true;\n                            }\n                            continue 'headers;\n                        }\n                        Some(BodyLength::Unknown) => {\n                            // The Body impl didn't know how long the\n                            // body is, but a length header was included.\n                            // We have to parse the value to return our\n                            // Encoder...\n\n                            if let Some(len) = headers::content_length_parse(&value) {\n                                if let Some(prev) = prev_con_len {\n                                    if prev != len {\n                                        warn!(\n                                            \"multiple Content-Length values found: [{}, {}]\",\n                                            prev, len\n                                        );\n                                        rewind(dst);\n                                        return Err(crate::Error::new_user_header());\n                                    }\n                                    debug_assert!(is_name_written);\n                                    continue 'headers;\n                                } else {\n                                    // we haven't written content-length yet!\n                                    encoder = Encoder::length(len);\n                                    header_name_writer.write_header_name_with_colon(\n                                        dst,\n                                        \"content-length: \",\n                                        header::CONTENT_LENGTH,\n                                    );\n                                    extend(dst, value.as_bytes());\n                                    wrote_len = true;\n                                    is_name_written = true;\n                                    prev_con_len = Some(len);\n                                    continue 'headers;\n                                }\n                            } else {\n                                warn!(\"illegal Content-Length value: {:?}\", value);\n                                rewind(dst);\n                                return Err(crate::Error::new_user_header());\n                            }\n                        }\n                        None => {\n                            // We have no body to actually send,\n                            // but the headers claim a content-length.\n                            // There's only 2 ways this makes sense:\n                            //\n                            // - The header says the length is `0`.\n                            // - This is a response to a `HEAD` request.\n                            if msg.req_method == &Some(Method::HEAD) {\n                                debug_assert_eq!(encoder, Encoder::length(0));\n                            } else {\n                                if value.as_bytes() != b\"0\" {\n                                    warn!(\n                                        \"content-length value found, but empty body provided: {:?}\",\n                                        value\n                                    );\n                                }\n                                continue 'headers;\n                            }\n                        }\n                    }\n                    wrote_len = true;\n                }\n                header::TRANSFER_ENCODING => {\n                    if wrote_len && !is_name_written {\n                        warn!(\"unexpected transfer-encoding found, canceling\");\n                        rewind(dst);\n                        return Err(crate::Error::new_user_header());\n                    }\n                    // check that we actually can send a chunked body...\n                    if msg.head.version == Version::HTTP_10\n                        || !Server::can_chunked(msg.req_method, msg.head.subject)\n                    {\n                        continue;\n                    }\n                    wrote_len = true;\n                    // Must check each value, because `chunked` needs to be the\n                    // last encoding, or else we add it.\n                    must_write_chunked = !headers::is_chunked_(&value);\n\n                    if !is_name_written {\n                        encoder = Encoder::chunked();\n                        is_name_written = true;\n                        header_name_writer.write_header_name_with_colon(\n                            dst,\n                            \"transfer-encoding: \",\n                            header::TRANSFER_ENCODING,\n                        );\n                        extend(dst, value.as_bytes());\n                    } else {\n                        extend(dst, b\", \");\n                        extend(dst, value.as_bytes());\n                    }\n                    continue 'headers;\n                }\n                header::CONNECTION => {\n                    if !is_last && headers::connection_close(&value) {\n                        is_last = true;\n                    }\n                    if !is_name_written {\n                        is_name_written = true;\n                        header_name_writer.write_header_name_with_colon(\n                            dst,\n                            \"connection: \",\n                            header::CONNECTION,\n                        );\n                        extend(dst, value.as_bytes());\n                    } else {\n                        extend(dst, b\", \");\n                        extend(dst, value.as_bytes());\n                    }\n                    continue 'headers;\n                }\n                header::DATE => {\n                    wrote_date = true;\n                }\n                header::TRAILER => {\n                    // check that we actually can send a chunked body...\n                    if msg.head.version == Version::HTTP_10\n                        || !Server::can_chunked(msg.req_method, msg.head.subject)\n                    {\n                        continue;\n                    }\n\n                    if !is_name_written {\n                        is_name_written = true;\n                        header_name_writer.write_header_name_with_colon(\n                            dst,\n                            \"trailer: \",\n                            header::TRAILER,\n                        );\n                        extend(dst, value.as_bytes());\n                    } else {\n                        extend(dst, b\", \");\n                        extend(dst, value.as_bytes());\n                    }\n\n                    // Parse the Trailer header value into HeaderNames.\n                    // The value may contain comma-separated names.\n                    // HeaderName normalizes to lowercase for case-insensitive matching.\n                    if let Ok(value_str) = value.to_str() {\n                        let names: Vec<HeaderName> = value_str\n                            .split(',')\n                            .filter_map(|s| HeaderName::from_bytes(s.trim().as_bytes()).ok())\n                            .collect();\n\n                        match allowed_trailer_fields {\n                            Some(ref mut fields) => {\n                                fields.extend(names);\n                            }\n                            None => {\n                                allowed_trailer_fields = Some(names);\n                            }\n                        }\n                    }\n\n                    continue 'headers;\n                }\n                _ => (),\n            }\n            //TODO: this should perhaps instead combine them into\n            //single lines, as RFC7230 suggests is preferable.\n\n            // non-special write Name and Value\n            debug_assert!(\n                !is_name_written,\n                \"{:?} set is_name_written and didn't continue loop\",\n                name,\n            );\n            header_name_writer.write_header_name(dst, name);\n            extend(dst, b\": \");\n            extend(dst, value.as_bytes());\n            extend(dst, b\"\\r\\n\");\n        }\n\n        handle_is_name_written!();\n\n        if !wrote_len {\n            encoder = match msg.body {\n                Some(BodyLength::Unknown) => {\n                    if msg.head.version == Version::HTTP_10\n                        || !Server::can_chunked(msg.req_method, msg.head.subject)\n                    {\n                        Encoder::close_delimited()\n                    } else {\n                        header_name_writer.write_full_header_line(\n                            dst,\n                            \"transfer-encoding: chunked\\r\\n\",\n                            (header::TRANSFER_ENCODING, \": chunked\\r\\n\"),\n                        );\n                        Encoder::chunked()\n                    }\n                }\n                None | Some(BodyLength::Known(0)) => {\n                    if Server::can_have_implicit_zero_content_length(\n                        msg.req_method,\n                        msg.head.subject,\n                    ) {\n                        header_name_writer.write_full_header_line(\n                            dst,\n                            \"content-length: 0\\r\\n\",\n                            (header::CONTENT_LENGTH, \": 0\\r\\n\"),\n                        )\n                    }\n                    Encoder::length(0)\n                }\n                Some(BodyLength::Known(len)) => {\n                    if !Server::can_have_content_length(msg.req_method, msg.head.subject) {\n                        Encoder::length(0)\n                    } else {\n                        header_name_writer.write_header_name_with_colon(\n                            dst,\n                            \"content-length: \",\n                            header::CONTENT_LENGTH,\n                        );\n                        extend(dst, ::itoa::Buffer::new().format(len).as_bytes());\n                        extend(dst, b\"\\r\\n\");\n                        Encoder::length(len)\n                    }\n                }\n            };\n        }\n\n        if !Server::can_have_body(msg.req_method, msg.head.subject) {\n            trace!(\n                \"server body forced to 0; method={:?}, status={:?}\",\n                msg.req_method,\n                msg.head.subject\n            );\n            encoder = Encoder::length(0);\n        }\n\n        // cached date is much faster than formatting every request\n        // don't force the write if disabled\n        if !wrote_date && msg.date_header {\n            dst.reserve(date::DATE_VALUE_LENGTH + 8);\n            header_name_writer.write_header_name_with_colon(dst, \"date: \", header::DATE);\n            date::extend(dst);\n            extend(dst, b\"\\r\\n\\r\\n\");\n        } else {\n            extend(dst, b\"\\r\\n\");\n        }\n\n        if encoder.is_chunked() {\n            if let Some(allowed_trailer_fields) = allowed_trailer_fields {\n                encoder = encoder.into_chunked_with_trailing_fields(allowed_trailer_fields);\n            }\n        }\n\n        Ok(encoder.set_last(is_last))\n    }\n\n    /// Helper for zero-copy parsing of request path URI.\n    #[inline]\n    fn record_path_range(bytes: &[u8], req_path: &str) -> std::ops::Range<usize> {\n        let bytes_ptr = bytes.as_ptr() as usize;\n        let start = req_path.as_ptr() as usize - bytes_ptr;\n        let end = start + req_path.len();\n        std::ops::Range { start, end }\n    }\n}\n\n#[cfg(feature = \"server\")]\ntrait HeaderNameWriter {\n    fn write_full_header_line(\n        &mut self,\n        dst: &mut Vec<u8>,\n        line: &str,\n        name_value_pair: (HeaderName, &str),\n    );\n    fn write_header_name_with_colon(\n        &mut self,\n        dst: &mut Vec<u8>,\n        name_with_colon: &str,\n        name: HeaderName,\n    );\n    fn write_header_name(&mut self, dst: &mut Vec<u8>, name: &HeaderName);\n}\n\n#[cfg(feature = \"client\")]\nimpl Http1Transaction for Client {\n    type Incoming = StatusCode;\n    type Outgoing = RequestLine;\n    #[cfg(feature = \"tracing\")]\n    const LOG: &'static str = \"{role=client}\";\n\n    fn parse(buf: &mut BytesMut, ctx: ParseContext<'_>) -> ParseResult<StatusCode> {\n        debug_assert!(!buf.is_empty(), \"parse called with empty buf\");\n\n        // Loop to skip information status code headers (100 Continue, etc).\n        loop {\n            let mut headers_indices: SmallVec<[MaybeUninit<HeaderIndices>; DEFAULT_MAX_HEADERS]> =\n                match ctx.h1_max_headers {\n                    Some(cap) => smallvec![MaybeUninit::uninit(); cap],\n                    None => smallvec_inline![MaybeUninit::uninit(); DEFAULT_MAX_HEADERS],\n                };\n            let (len, status, reason, version, headers_len) = {\n                let mut headers: SmallVec<\n                    [MaybeUninit<httparse::Header<'_>>; DEFAULT_MAX_HEADERS],\n                > = match ctx.h1_max_headers {\n                    Some(cap) => smallvec![MaybeUninit::uninit(); cap],\n                    None => smallvec_inline![MaybeUninit::uninit(); DEFAULT_MAX_HEADERS],\n                };\n                trace!(bytes = buf.len(), \"Response.parse\");\n                let mut res = httparse::Response::new(&mut []);\n                let bytes = buf.as_ref();\n                match ctx.h1_parser_config.parse_response_with_uninit_headers(\n                    &mut res,\n                    bytes,\n                    &mut headers,\n                ) {\n                    Ok(httparse::Status::Complete(len)) => {\n                        trace!(\"Response.parse Complete({})\", len);\n                        let status = StatusCode::from_u16(res.code.unwrap())?;\n\n                        let reason = {\n                            let reason = res.reason.unwrap();\n                            // Only save the reason phrase if it isn't the canonical reason\n                            if Some(reason) != status.canonical_reason() {\n                                Some(Bytes::copy_from_slice(reason.as_bytes()))\n                            } else {\n                                None\n                            }\n                        };\n\n                        let version = if res.version.unwrap() == 1 {\n                            Version::HTTP_11\n                        } else {\n                            Version::HTTP_10\n                        };\n                        record_header_indices(bytes, res.headers, &mut headers_indices)?;\n                        let headers_len = res.headers.len();\n                        (len, status, reason, version, headers_len)\n                    }\n                    Ok(httparse::Status::Partial) => return Ok(None),\n                    Err(httparse::Error::Version) if ctx.h09_responses => {\n                        trace!(\"Response.parse accepted HTTP/0.9 response\");\n\n                        (0, StatusCode::OK, None, Version::HTTP_09, 0)\n                    }\n                    Err(e) => return Err(e.into()),\n                }\n            };\n\n            let mut slice = buf.split_to(len);\n\n            if ctx\n                .h1_parser_config\n                .obsolete_multiline_headers_in_responses_are_allowed()\n            {\n                for header in &mut headers_indices[..headers_len] {\n                    // SAFETY: array is valid up to `headers_len`\n                    let header = unsafe { header.assume_init_mut() };\n                    Client::obs_fold_line(&mut slice, header);\n                }\n            }\n\n            let slice = slice.freeze();\n\n            let mut headers = ctx.cached_headers.take().unwrap_or_default();\n\n            let mut keep_alive = version == Version::HTTP_11;\n\n            let mut header_case_map = if ctx.preserve_header_case {\n                Some(HeaderCaseMap::default())\n            } else {\n                None\n            };\n\n            #[cfg(feature = \"ffi\")]\n            let mut header_order = if ctx.preserve_header_order {\n                Some(OriginalHeaderOrder::default())\n            } else {\n                None\n            };\n\n            headers.reserve(headers_len);\n            for header in &headers_indices[..headers_len] {\n                // SAFETY: array is valid up to `headers_len`\n                let header = unsafe { header.assume_init_ref() };\n                let name = header_name!(&slice[header.name.0..header.name.1]);\n                let value = header_value!(slice.slice(header.value.0..header.value.1));\n\n                if let header::CONNECTION = name {\n                    // keep_alive was previously set to default for Version\n                    if keep_alive {\n                        // HTTP/1.1\n                        keep_alive = !headers::connection_close(&value);\n                    } else {\n                        // HTTP/1.0\n                        keep_alive = headers::connection_keep_alive(&value);\n                    }\n                }\n\n                if let Some(ref mut header_case_map) = header_case_map {\n                    header_case_map.append(&name, slice.slice(header.name.0..header.name.1));\n                }\n\n                #[cfg(feature = \"ffi\")]\n                if let Some(ref mut header_order) = header_order {\n                    header_order.append(&name);\n                }\n\n                headers.append(name, value);\n            }\n\n            let mut extensions = http::Extensions::default();\n\n            if let Some(header_case_map) = header_case_map {\n                extensions.insert(header_case_map);\n            }\n\n            #[cfg(feature = \"ffi\")]\n            if let Some(header_order) = header_order {\n                extensions.insert(header_order);\n            }\n\n            if let Some(reason) = reason {\n                // Safety: httparse ensures that only valid reason phrase bytes are present in this\n                // field.\n                let reason = crate::ext::ReasonPhrase::from_bytes_unchecked(reason);\n                extensions.insert(reason);\n            }\n\n            let head = MessageHead {\n                version,\n                subject: status,\n                headers,\n                extensions,\n            };\n            if let Some((decode, is_upgrade)) = Client::decoder(&head, ctx.req_method)? {\n                return Ok(Some(ParsedMessage {\n                    head,\n                    decode,\n                    expect_continue: false,\n                    // a client upgrade means the connection can't be used\n                    // again, as it is definitely upgrading.\n                    keep_alive: keep_alive && !is_upgrade,\n                    wants_upgrade: is_upgrade,\n                }));\n            }\n\n            if head.subject.is_informational() {\n                if let Some(callback) = ctx.on_informational {\n                    callback.call(head.into_response(()));\n                }\n            }\n\n            // Parsing a 1xx response could have consumed the buffer, check if\n            // it is empty now...\n            if buf.is_empty() {\n                return Ok(None);\n            }\n        }\n    }\n\n    fn encode(msg: Encode<'_, Self::Outgoing>, dst: &mut Vec<u8>) -> crate::Result<Encoder> {\n        trace!(\n            \"Client::encode method={:?}, body={:?}\",\n            msg.head.subject.0,\n            msg.body\n        );\n\n        *msg.req_method = Some(msg.head.subject.0.clone());\n\n        let body = Client::set_length(msg.head, msg.body);\n\n        let init_cap = 30 + msg.head.headers.len() * AVERAGE_HEADER_SIZE;\n        dst.reserve(init_cap);\n\n        extend(dst, msg.head.subject.0.as_str().as_bytes());\n        extend(dst, b\" \");\n        //TODO: add API to http::Uri to encode without std::fmt\n        let _ = write!(FastWrite(dst), \"{} \", msg.head.subject.1);\n\n        match msg.head.version {\n            Version::HTTP_10 => extend(dst, b\"HTTP/1.0\"),\n            Version::HTTP_11 => extend(dst, b\"HTTP/1.1\"),\n            Version::HTTP_2 => {\n                debug!(\"request with HTTP2 version coerced to HTTP/1.1\");\n                extend(dst, b\"HTTP/1.1\");\n            }\n            other => panic!(\"unexpected request version: {:?}\", other),\n        }\n        extend(dst, b\"\\r\\n\");\n\n        if let Some(orig_headers) = msg.head.extensions.get::<HeaderCaseMap>() {\n            write_headers_original_case(\n                &msg.head.headers,\n                orig_headers,\n                dst,\n                msg.title_case_headers,\n            );\n        } else if msg.title_case_headers {\n            write_headers_title_case(&msg.head.headers, dst);\n        } else {\n            write_headers(&msg.head.headers, dst);\n        }\n\n        extend(dst, b\"\\r\\n\");\n        msg.head.headers.clear(); //TODO: remove when switching to drain()\n\n        Ok(body)\n    }\n\n    fn on_error(_err: &crate::Error) -> Option<MessageHead<Self::Outgoing>> {\n        // we can't tell the server about any errors it creates\n        None\n    }\n\n    fn is_client() -> bool {\n        true\n    }\n}\n\n#[cfg(feature = \"client\")]\nimpl Client {\n    /// Returns Some(length, wants_upgrade) if successful.\n    ///\n    /// Returns None if this message head should be skipped (like a 100 status).\n    fn decoder(\n        inc: &MessageHead<StatusCode>,\n        method: &mut Option<Method>,\n    ) -> Result<Option<(DecodedLength, bool)>, Parse> {\n        // According to https://tools.ietf.org/html/rfc7230#section-3.3.3\n        // 1. HEAD responses, and Status 1xx, 204, and 304 cannot have a body.\n        // 2. Status 2xx to a CONNECT cannot have a body.\n        // 3. Transfer-Encoding: chunked has a chunked body.\n        // 4. If multiple differing Content-Length headers or invalid, close connection.\n        // 5. Content-Length header has a sized body.\n        // 6. (irrelevant to Response)\n        // 7. Read till EOF.\n\n        match inc.subject.as_u16() {\n            101 => {\n                return Ok(Some((DecodedLength::ZERO, true)));\n            }\n            100 | 102..=199 => {\n                trace!(\"ignoring informational response: {}\", inc.subject.as_u16());\n                return Ok(None);\n            }\n            204 | 304 => return Ok(Some((DecodedLength::ZERO, false))),\n            _ => (),\n        }\n        match *method {\n            Some(Method::HEAD) => {\n                return Ok(Some((DecodedLength::ZERO, false)));\n            }\n            Some(Method::CONNECT) => {\n                if let 200..=299 = inc.subject.as_u16() {\n                    return Ok(Some((DecodedLength::ZERO, true)));\n                }\n            }\n            Some(_) => {}\n            None => {\n                trace!(\"Client::decoder is missing the Method\");\n            }\n        }\n\n        if inc.headers.contains_key(header::TRANSFER_ENCODING) {\n            // https://tools.ietf.org/html/rfc7230#section-3.3.3\n            // If Transfer-Encoding header is present, and 'chunked' is\n            // not the final encoding, and this is a Request, then it is\n            // malformed. A server should respond with 400 Bad Request.\n            if inc.version == Version::HTTP_10 {\n                debug!(\"HTTP/1.0 cannot have Transfer-Encoding header\");\n                Err(Parse::transfer_encoding_unexpected())\n            } else if headers::transfer_encoding_is_chunked(&inc.headers) {\n                Ok(Some((DecodedLength::CHUNKED, false)))\n            } else {\n                trace!(\"not chunked, read till eof\");\n                Ok(Some((DecodedLength::CLOSE_DELIMITED, false)))\n            }\n        } else if let Some(len) = headers::content_length_parse_all(&inc.headers) {\n            Ok(Some((DecodedLength::checked_new(len)?, false)))\n        } else if inc.headers.contains_key(header::CONTENT_LENGTH) {\n            debug!(\"illegal Content-Length header\");\n            Err(Parse::content_length_invalid())\n        } else {\n            trace!(\"neither Transfer-Encoding nor Content-Length\");\n            Ok(Some((DecodedLength::CLOSE_DELIMITED, false)))\n        }\n    }\n    fn set_length(head: &mut RequestHead, body: Option<BodyLength>) -> Encoder {\n        let body = if let Some(body) = body {\n            body\n        } else {\n            head.headers.remove(header::TRANSFER_ENCODING);\n            return Encoder::length(0);\n        };\n\n        // HTTP/1.0 doesn't know about chunked\n        let can_chunked = head.version == Version::HTTP_11;\n        let headers = &mut head.headers;\n\n        // If the user already set specific headers, we should respect them, regardless\n        // of what the Body knows about itself. They set them for a reason.\n\n        // Because of the borrow checker, we can't check the for an existing\n        // Content-Length header while holding an `Entry` for the Transfer-Encoding\n        // header, so unfortunately, we must do the check here, first.\n\n        let existing_con_len = headers::content_length_parse_all(headers);\n        let mut should_remove_con_len = false;\n\n        if !can_chunked {\n            // Chunked isn't legal, so if it is set, we need to remove it.\n            if headers.remove(header::TRANSFER_ENCODING).is_some() {\n                trace!(\"removing illegal transfer-encoding header\");\n            }\n\n            return if let Some(len) = existing_con_len {\n                Encoder::length(len)\n            } else if let BodyLength::Known(len) = body {\n                set_content_length(headers, len)\n            } else {\n                // HTTP/1.0 client requests without a content-length\n                // cannot have any body at all.\n                Encoder::length(0)\n            };\n        }\n\n        // If the user set a transfer-encoding, respect that. Let's just\n        // make sure `chunked` is the final encoding.\n        let encoder = match headers.entry(header::TRANSFER_ENCODING) {\n            Entry::Occupied(te) => {\n                should_remove_con_len = true;\n                if headers::is_chunked(te.iter()) {\n                    Some(Encoder::chunked())\n                } else {\n                    warn!(\"user provided transfer-encoding does not end in 'chunked'\");\n\n                    // There's a Transfer-Encoding, but it doesn't end in 'chunked'!\n                    // An example that could trigger this:\n                    //\n                    //     Transfer-Encoding: gzip\n                    //\n                    // This can be bad, depending on if this is a request or a\n                    // response.\n                    //\n                    // - A request is illegal if there is a `Transfer-Encoding`\n                    //   but it doesn't end in `chunked`.\n                    // - A response that has `Transfer-Encoding` but doesn't\n                    //   end in `chunked` isn't illegal, it just forces this\n                    //   to be close-delimited.\n                    //\n                    // We can try to repair this, by adding `chunked` ourselves.\n\n                    headers::add_chunked(te);\n                    Some(Encoder::chunked())\n                }\n            }\n            Entry::Vacant(te) => {\n                if let Some(len) = existing_con_len {\n                    Some(Encoder::length(len))\n                } else if let BodyLength::Unknown = body {\n                    // GET, HEAD, and CONNECT almost never have bodies.\n                    //\n                    // So instead of sending a \"chunked\" body with a 0-chunk,\n                    // assume no body here. If you *must* send a body,\n                    // set the headers explicitly.\n                    match head.subject.0 {\n                        Method::GET | Method::HEAD | Method::CONNECT => Some(Encoder::length(0)),\n                        _ => {\n                            te.insert(HeaderValue::from_static(\"chunked\"));\n                            Some(Encoder::chunked())\n                        }\n                    }\n                } else {\n                    None\n                }\n            }\n        };\n\n        let encoder = encoder.map(|enc| {\n            if enc.is_chunked() {\n                // Parse Trailer header values into HeaderNames.\n                // Each Trailer header value may contain comma-separated names.\n                // HeaderName normalizes to lowercase, enabling case-insensitive matching.\n                let allowed_trailer_fields: Vec<HeaderName> = headers\n                    .get_all(header::TRAILER)\n                    .iter()\n                    .filter_map(|hv| hv.to_str().ok())\n                    .flat_map(|s| s.split(','))\n                    .filter_map(|s| HeaderName::from_bytes(s.trim().as_bytes()).ok())\n                    .collect();\n\n                if !allowed_trailer_fields.is_empty() {\n                    return enc.into_chunked_with_trailing_fields(allowed_trailer_fields);\n                }\n            }\n\n            enc\n        });\n\n        // This is because we need a second mutable borrow to remove\n        // content-length header.\n        if let Some(encoder) = encoder {\n            if should_remove_con_len && existing_con_len.is_some() {\n                headers.remove(header::CONTENT_LENGTH);\n            }\n            return encoder;\n        }\n\n        // User didn't set transfer-encoding, AND we know body length,\n        // so we can just set the Content-Length automatically.\n\n        let len = if let BodyLength::Known(len) = body {\n            len\n        } else {\n            unreachable!(\"BodyLength::Unknown would set chunked\");\n        };\n\n        set_content_length(headers, len)\n    }\n\n    fn obs_fold_line(all: &mut [u8], idx: &mut HeaderIndices) {\n        // If the value has obs-folded text, then in-place shift the bytes out\n        // of here.\n        //\n        // https://httpwg.org/specs/rfc9112.html#line.folding\n        //\n        // > A user agent that receives an obs-fold MUST replace each received\n        // > obs-fold with one or more SP octets prior to interpreting the\n        // > field value.\n        //\n        // This means strings like \"\\r\\n\\t foo\" must replace the \"\\r\\n\\t \" with\n        // a single space.\n\n        let buf = &mut all[idx.value.0..idx.value.1];\n\n        // look for a newline, otherwise bail out\n        let first_nl = match buf.iter().position(|b| *b == b'\\n') {\n            Some(i) => i,\n            None => return,\n        };\n\n        // not on standard slices because whatever, sigh\n        fn trim_start(mut s: &[u8]) -> &[u8] {\n            while let [first, rest @ ..] = s {\n                if first.is_ascii_whitespace() {\n                    s = rest;\n                } else {\n                    break;\n                }\n            }\n            s\n        }\n\n        fn trim_end(mut s: &[u8]) -> &[u8] {\n            while let [rest @ .., last] = s {\n                if last.is_ascii_whitespace() {\n                    s = rest;\n                } else {\n                    break;\n                }\n            }\n            s\n        }\n\n        fn trim(s: &[u8]) -> &[u8] {\n            trim_start(trim_end(s))\n        }\n\n        // TODO(perf): we could do the moves in-place, but this is so uncommon\n        // that it shouldn't matter.\n        let mut unfolded = trim_end(&buf[..first_nl]).to_vec();\n        for line in buf[first_nl + 1..].split(|b| *b == b'\\n') {\n            unfolded.push(b' ');\n            unfolded.extend_from_slice(trim(line));\n        }\n        buf[..unfolded.len()].copy_from_slice(&unfolded);\n        idx.value.1 = idx.value.0 + unfolded.len();\n    }\n}\n\n#[cfg(feature = \"client\")]\nfn set_content_length(headers: &mut HeaderMap, len: u64) -> Encoder {\n    // At this point, there should not be a valid Content-Length\n    // header. However, since we'll be indexing in anyways, we can\n    // warn the user if there was an existing illegal header.\n    //\n    // Or at least, we can in theory. It's actually a little bit slower,\n    // so perhaps only do that while the user is developing/testing.\n\n    if cfg!(debug_assertions) {\n        match headers.entry(header::CONTENT_LENGTH) {\n            Entry::Occupied(mut cl) => {\n                // Internal sanity check, we should have already determined\n                // that the header was illegal before calling this function.\n                debug_assert!(headers::content_length_parse_all_values(cl.iter()).is_none());\n                // Uh oh, the user set `Content-Length` headers, but set bad ones.\n                // This would be an illegal message anyways, so let's try to repair\n                // with our known good length.\n                error!(\"user provided content-length header was invalid\");\n\n                cl.insert(HeaderValue::from(len));\n                Encoder::length(len)\n            }\n            Entry::Vacant(cl) => {\n                cl.insert(HeaderValue::from(len));\n                Encoder::length(len)\n            }\n        }\n    } else {\n        headers.insert(header::CONTENT_LENGTH, HeaderValue::from(len));\n        Encoder::length(len)\n    }\n}\n\n#[derive(Clone, Copy)]\nstruct HeaderIndices {\n    name: (usize, usize),\n    value: (usize, usize),\n}\n\nfn record_header_indices(\n    bytes: &[u8],\n    headers: &[httparse::Header<'_>],\n    indices: &mut [MaybeUninit<HeaderIndices>],\n) -> Result<(), crate::error::Parse> {\n    let bytes_ptr = bytes.as_ptr() as usize;\n\n    for (header, indices) in headers.iter().zip(indices.iter_mut()) {\n        if header.name.len() >= (1 << 16) {\n            debug!(\"header name larger than 64kb: {:?}\", header.name);\n            return Err(crate::error::Parse::TooLarge);\n        }\n        let name_start = header.name.as_ptr() as usize - bytes_ptr;\n        let name_end = name_start + header.name.len();\n        let value_start = header.value.as_ptr() as usize - bytes_ptr;\n        let value_end = value_start + header.value.len();\n\n        indices.write(HeaderIndices {\n            name: (name_start, name_end),\n            value: (value_start, value_end),\n        });\n    }\n\n    Ok(())\n}\n\n// Write header names as title case. The header name is assumed to be ASCII.\nfn title_case(dst: &mut Vec<u8>, name: &[u8]) {\n    dst.reserve(name.len());\n\n    // Ensure first character is uppercased\n    let mut prev = b'-';\n    for &(mut c) in name {\n        if prev == b'-' {\n            c.make_ascii_uppercase();\n        }\n        dst.push(c);\n        prev = c;\n    }\n}\n\npub(crate) fn write_headers_title_case(headers: &HeaderMap, dst: &mut Vec<u8>) {\n    for (name, value) in headers {\n        title_case(dst, name.as_str().as_bytes());\n        extend(dst, b\": \");\n        extend(dst, value.as_bytes());\n        extend(dst, b\"\\r\\n\");\n    }\n}\n\npub(crate) fn write_headers(headers: &HeaderMap, dst: &mut Vec<u8>) {\n    for (name, value) in headers {\n        extend(dst, name.as_str().as_bytes());\n        extend(dst, b\": \");\n        extend(dst, value.as_bytes());\n        extend(dst, b\"\\r\\n\");\n    }\n}\n\n#[cold]\n#[cfg(feature = \"client\")]\nfn write_headers_original_case(\n    headers: &HeaderMap,\n    orig_case: &HeaderCaseMap,\n    dst: &mut Vec<u8>,\n    title_case_headers: bool,\n) {\n    // For each header name/value pair, there may be a value in the casemap\n    // that corresponds to the HeaderValue. So, we iterator all the keys,\n    // and for each one, try to pair the originally cased name with the value.\n    //\n    // TODO: consider adding http::HeaderMap::entries() iterator\n    for name in headers.keys() {\n        let mut names = orig_case.get_all(name);\n\n        for value in headers.get_all(name) {\n            if let Some(orig_name) = names.next() {\n                extend(dst, orig_name.as_ref());\n            } else if title_case_headers {\n                title_case(dst, name.as_str().as_bytes());\n            } else {\n                extend(dst, name.as_str().as_bytes());\n            }\n\n            // Wanted for curl test cases that send `X-Custom-Header:\\r\\n`\n            if value.is_empty() {\n                extend(dst, b\":\\r\\n\");\n            } else {\n                extend(dst, b\": \");\n                extend(dst, value.as_bytes());\n                extend(dst, b\"\\r\\n\");\n            }\n        }\n    }\n}\n\n#[cfg(feature = \"client\")]\nstruct FastWrite<'a>(&'a mut Vec<u8>);\n\n#[cfg(feature = \"client\")]\nimpl fmt::Write for FastWrite<'_> {\n    #[inline]\n    fn write_str(&mut self, s: &str) -> fmt::Result {\n        extend(self.0, s.as_bytes());\n        Ok(())\n    }\n\n    #[inline]\n    fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {\n        fmt::write(self, args)\n    }\n}\n\n#[inline]\nfn extend(dst: &mut Vec<u8>, data: &[u8]) {\n    dst.extend_from_slice(data);\n}\n\n#[cfg(test)]\nmod tests {\n    use bytes::BytesMut;\n\n    use super::*;\n\n    #[cfg(feature = \"server\")]\n    #[test]\n    fn test_parse_request() {\n        let _ = pretty_env_logger::try_init();\n        let mut raw = BytesMut::from(\"GET /echo HTTP/1.1\\r\\nHost: hyper.rs\\r\\n\\r\\n\");\n        let mut method = None;\n        let msg = Server::parse(\n            &mut raw,\n            ParseContext {\n                cached_headers: &mut None,\n                req_method: &mut method,\n                h1_parser_config: Default::default(),\n                h1_max_headers: None,\n                preserve_header_case: false,\n                #[cfg(feature = \"ffi\")]\n                preserve_header_order: false,\n                h09_responses: false,\n                #[cfg(feature = \"client\")]\n                on_informational: &mut None,\n            },\n        )\n        .unwrap()\n        .unwrap();\n        assert_eq!(raw.len(), 0);\n        assert_eq!(msg.head.subject.0, crate::Method::GET);\n        assert_eq!(msg.head.subject.1, \"/echo\");\n        assert_eq!(msg.head.version, crate::Version::HTTP_11);\n        assert_eq!(msg.head.headers.len(), 1);\n        assert_eq!(msg.head.headers[\"Host\"], \"hyper.rs\");\n        assert_eq!(method, Some(crate::Method::GET));\n    }\n\n    #[test]\n    fn test_parse_response() {\n        let _ = pretty_env_logger::try_init();\n        let mut raw = BytesMut::from(\"HTTP/1.1 200 OK\\r\\nContent-Length: 0\\r\\n\\r\\n\");\n        let ctx = ParseContext {\n            cached_headers: &mut None,\n            req_method: &mut Some(crate::Method::GET),\n            h1_parser_config: Default::default(),\n            h1_max_headers: None,\n            preserve_header_case: false,\n            #[cfg(feature = \"ffi\")]\n            preserve_header_order: false,\n            h09_responses: false,\n            #[cfg(feature = \"client\")]\n            on_informational: &mut None,\n        };\n        let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();\n        assert_eq!(raw.len(), 0);\n        assert_eq!(msg.head.subject, crate::StatusCode::OK);\n        assert_eq!(msg.head.version, crate::Version::HTTP_11);\n        assert_eq!(msg.head.headers.len(), 1);\n        assert_eq!(msg.head.headers[\"Content-Length\"], \"0\");\n    }\n\n    #[cfg(feature = \"server\")]\n    #[test]\n    fn test_parse_request_errors() {\n        let mut raw = BytesMut::from(\"GET htt:p// HTTP/1.1\\r\\nHost: hyper.rs\\r\\n\\r\\n\");\n        let ctx = ParseContext {\n            cached_headers: &mut None,\n            req_method: &mut None,\n            h1_parser_config: Default::default(),\n            h1_max_headers: None,\n            preserve_header_case: false,\n            #[cfg(feature = \"ffi\")]\n            preserve_header_order: false,\n            h09_responses: false,\n            #[cfg(feature = \"client\")]\n            on_informational: &mut None,\n        };\n        Server::parse(&mut raw, ctx).unwrap_err();\n    }\n\n    const H09_RESPONSE: &str = \"Baguettes are super delicious, don't you agree?\";\n\n    #[test]\n    fn test_parse_response_h09_allowed() {\n        let _ = pretty_env_logger::try_init();\n        let mut raw = BytesMut::from(H09_RESPONSE);\n        let ctx = ParseContext {\n            cached_headers: &mut None,\n            req_method: &mut Some(crate::Method::GET),\n            h1_parser_config: Default::default(),\n            h1_max_headers: None,\n            preserve_header_case: false,\n            #[cfg(feature = \"ffi\")]\n            preserve_header_order: false,\n            h09_responses: true,\n            #[cfg(feature = \"client\")]\n            on_informational: &mut None,\n        };\n        let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();\n        assert_eq!(raw, H09_RESPONSE);\n        assert_eq!(msg.head.subject, crate::StatusCode::OK);\n        assert_eq!(msg.head.version, crate::Version::HTTP_09);\n        assert_eq!(msg.head.headers.len(), 0);\n    }\n\n    #[test]\n    fn test_parse_response_h09_rejected() {\n        let _ = pretty_env_logger::try_init();\n        let mut raw = BytesMut::from(H09_RESPONSE);\n        let ctx = ParseContext {\n            cached_headers: &mut None,\n            req_method: &mut Some(crate::Method::GET),\n            h1_parser_config: Default::default(),\n            h1_max_headers: None,\n            preserve_header_case: false,\n            #[cfg(feature = \"ffi\")]\n            preserve_header_order: false,\n            h09_responses: false,\n            #[cfg(feature = \"client\")]\n            on_informational: &mut None,\n        };\n        Client::parse(&mut raw, ctx).unwrap_err();\n        assert_eq!(raw, H09_RESPONSE);\n    }\n\n    const RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON: &str =\n        \"HTTP/1.1 200 OK\\r\\nAccess-Control-Allow-Credentials : true\\r\\n\\r\\n\";\n\n    #[test]\n    fn test_parse_allow_response_with_spaces_before_colons() {\n        use httparse::ParserConfig;\n\n        let _ = pretty_env_logger::try_init();\n        let mut raw = BytesMut::from(RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON);\n        let mut h1_parser_config = ParserConfig::default();\n        h1_parser_config.allow_spaces_after_header_name_in_responses(true);\n        let ctx = ParseContext {\n            cached_headers: &mut None,\n            req_method: &mut Some(crate::Method::GET),\n            h1_parser_config,\n            h1_max_headers: None,\n            preserve_header_case: false,\n            #[cfg(feature = \"ffi\")]\n            preserve_header_order: false,\n            h09_responses: false,\n            #[cfg(feature = \"client\")]\n            on_informational: &mut None,\n        };\n        let msg = Client::parse(&mut raw, ctx).unwrap().unwrap();\n        assert_eq!(raw.len(), 0);\n        assert_eq!(msg.head.subject, crate::StatusCode::OK);\n        assert_eq!(msg.head.version, crate::Version::HTTP_11);\n        assert_eq!(msg.head.headers.len(), 1);\n        assert_eq!(msg.head.headers[\"Access-Control-Allow-Credentials\"], \"true\");\n    }\n\n    #[test]\n    fn test_parse_reject_response_with_spaces_before_colons() {\n        let _ = pretty_env_logger::try_init();\n        let mut raw = BytesMut::from(RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON);\n        let ctx = ParseContext {\n            cached_headers: &mut None,\n            req_method: &mut Some(crate::Method::GET),\n            h1_parser_config: Default::default(),\n            h1_max_headers: None,\n            preserve_header_case: false,\n            #[cfg(feature = \"ffi\")]\n            preserve_header_order: false,\n            h09_responses: false,\n            #[cfg(feature = \"client\")]\n            on_informational: &mut None,\n        };\n        Client::parse(&mut raw, ctx).unwrap_err();\n    }\n\n    const REQUEST_WITH_MULTIPLE_SPACES_IN_REQUEST_LINE: &str =\n        \"GET  /echo  HTTP/1.1\\r\\nHost: hyper.rs\\r\\n\\r\\n\";\n\n    #[cfg(feature = \"server\")]\n    #[test]\n    fn test_parse_allow_request_with_multiple_spaces_in_request_line() {\n        use httparse::ParserConfig;\n\n        let _ = pretty_env_logger::try_init();\n        let mut raw = BytesMut::from(REQUEST_WITH_MULTIPLE_SPACES_IN_REQUEST_LINE);\n        let mut h1_parser_config = ParserConfig::default();\n        h1_parser_config.allow_multiple_spaces_in_request_line_delimiters(true);\n        let mut method = None;\n        let ctx = ParseContext {\n            cached_headers: &mut None,\n            req_method: &mut method,\n            h1_parser_config,\n            h1_max_headers: None,\n            preserve_header_case: false,\n            #[cfg(feature = \"ffi\")]\n            preserve_header_order: false,\n            h09_responses: false,\n            #[cfg(feature = \"client\")]\n            on_informational: &mut None,\n        };\n        let msg = Server::parse(&mut raw, ctx).unwrap().unwrap();\n        assert_eq!(raw.len(), 0);\n        assert_eq!(msg.head.subject.0, crate::Method::GET);\n        assert_eq!(msg.head.subject.1, \"/echo\");\n        assert_eq!(msg.head.version, crate::Version::HTTP_11);\n        assert_eq!(msg.head.headers.len(), 1);\n        assert_eq!(msg.head.headers[\"Host\"], \"hyper.rs\");\n        assert_eq!(method, Some(crate::Method::GET));\n    }\n\n    #[cfg(feature = \"server\")]\n    #[test]\n    fn test_parse_reject_request_with_multiple_spaces_in_request_line() {\n        let _ = pretty_env_logger::try_init();\n        let mut raw = BytesMut::from(REQUEST_WITH_MULTIPLE_SPACES_IN_REQUEST_LINE);\n        let ctx = ParseContext {\n            cached_headers: &mut None,\n            req_method: &mut None,\n            h1_parser_config: Default::default(),\n            h1_max_headers: None,\n            preserve_header_case: false,\n            #[cfg(feature = \"ffi\")]\n            preserve_header_order: false,\n            h09_responses: false,\n            #[cfg(feature = \"client\")]\n            on_informational: &mut None,\n        };\n        Server::parse(&mut raw, ctx).unwrap_err();\n    }\n\n    #[cfg(feature = \"server\")]\n    #[test]\n    fn test_parse_preserve_header_case_in_request() {\n        let mut raw =\n            BytesMut::from(\"GET / HTTP/1.1\\r\\nHost: hyper.rs\\r\\nX-BREAD: baguette\\r\\n\\r\\n\");\n        let ctx = ParseContext {\n            cached_headers: &mut None,\n            req_method: &mut None,\n            h1_parser_config: Default::default(),\n            h1_max_headers: None,\n            preserve_header_case: true,\n            #[cfg(feature = \"ffi\")]\n            preserve_header_order: false,\n            h09_responses: false,\n            #[cfg(feature = \"client\")]\n            on_informational: &mut None,\n        };\n        let parsed_message = Server::parse(&mut raw, ctx).unwrap().unwrap();\n        let orig_headers = parsed_message\n            .head\n            .extensions\n            .get::<HeaderCaseMap>()\n            .unwrap();\n        assert_eq!(\n            orig_headers\n                .get_all_internal(&HeaderName::from_static(\"host\"))\n                .collect::<Vec<_>>(),\n            vec![&Bytes::from(\"Host\")]\n        );\n        assert_eq!(\n            orig_headers\n                .get_all_internal(&HeaderName::from_static(\"x-bread\"))\n                .collect::<Vec<_>>(),\n            vec![&Bytes::from(\"X-BREAD\")]\n        );\n    }\n\n    #[cfg(feature = \"server\")]\n    #[test]\n    fn test_decoder_request() {\n        fn parse(s: &str) -> ParsedMessage<RequestLine> {\n            let mut bytes = BytesMut::from(s);\n            Server::parse(\n                &mut bytes,\n                ParseContext {\n                    cached_headers: &mut None,\n                    req_method: &mut None,\n                    h1_parser_config: Default::default(),\n                    h1_max_headers: None,\n                    preserve_header_case: false,\n                    #[cfg(feature = \"ffi\")]\n                    preserve_header_order: false,\n                    h09_responses: false,\n                    #[cfg(feature = \"client\")]\n                    on_informational: &mut None,\n                },\n            )\n            .expect(\"parse ok\")\n            .expect(\"parse complete\")\n        }\n\n        fn parse_err(s: &str, comment: &str) -> crate::error::Parse {\n            let mut bytes = BytesMut::from(s);\n            Server::parse(\n                &mut bytes,\n                ParseContext {\n                    cached_headers: &mut None,\n                    req_method: &mut None,\n                    h1_parser_config: Default::default(),\n                    h1_max_headers: None,\n                    preserve_header_case: false,\n                    #[cfg(feature = \"ffi\")]\n                    preserve_header_order: false,\n                    h09_responses: false,\n                    #[cfg(feature = \"client\")]\n                    on_informational: &mut None,\n                },\n            )\n            .expect_err(comment)\n        }\n\n        // no length or transfer-encoding means 0-length body\n        assert_eq!(\n            parse(\n                \"\\\n                 GET / HTTP/1.1\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::ZERO\n        );\n\n        assert_eq!(\n            parse(\n                \"\\\n                 POST / HTTP/1.1\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::ZERO\n        );\n\n        // transfer-encoding: chunked\n        assert_eq!(\n            parse(\n                \"\\\n                 POST / HTTP/1.1\\r\\n\\\n                 transfer-encoding: chunked\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::CHUNKED\n        );\n\n        assert_eq!(\n            parse(\n                \"\\\n                 POST / HTTP/1.1\\r\\n\\\n                 transfer-encoding: gzip, chunked\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::CHUNKED\n        );\n\n        assert_eq!(\n            parse(\n                \"\\\n                 POST / HTTP/1.1\\r\\n\\\n                 transfer-encoding: gzip\\r\\n\\\n                 transfer-encoding: chunked\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::CHUNKED\n        );\n\n        // content-length\n        assert_eq!(\n            parse(\n                \"\\\n                 POST / HTTP/1.1\\r\\n\\\n                 content-length: 10\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::new(10)\n        );\n\n        // transfer-encoding and content-length = chunked\n        assert_eq!(\n            parse(\n                \"\\\n                 POST / HTTP/1.1\\r\\n\\\n                 content-length: 10\\r\\n\\\n                 transfer-encoding: chunked\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::CHUNKED\n        );\n\n        assert_eq!(\n            parse(\n                \"\\\n                 POST / HTTP/1.1\\r\\n\\\n                 transfer-encoding: chunked\\r\\n\\\n                 content-length: 10\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::CHUNKED\n        );\n\n        assert_eq!(\n            parse(\n                \"\\\n                 POST / HTTP/1.1\\r\\n\\\n                 transfer-encoding: gzip\\r\\n\\\n                 content-length: 10\\r\\n\\\n                 transfer-encoding: chunked\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::CHUNKED\n        );\n\n        // multiple content-lengths of same value are fine\n        assert_eq!(\n            parse(\n                \"\\\n                 POST / HTTP/1.1\\r\\n\\\n                 content-length: 10\\r\\n\\\n                 content-length: 10\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::new(10)\n        );\n\n        // multiple content-lengths with different values is an error\n        parse_err(\n            \"\\\n             POST / HTTP/1.1\\r\\n\\\n             content-length: 10\\r\\n\\\n             content-length: 11\\r\\n\\\n             \\r\\n\\\n             \",\n            \"multiple content-lengths\",\n        );\n\n        // content-length with prefix is not allowed\n        parse_err(\n            \"\\\n             POST / HTTP/1.1\\r\\n\\\n             content-length: +10\\r\\n\\\n             \\r\\n\\\n             \",\n            \"prefixed content-length\",\n        );\n\n        // transfer-encoding that isn't chunked is an error\n        parse_err(\n            \"\\\n             POST / HTTP/1.1\\r\\n\\\n             transfer-encoding: gzip\\r\\n\\\n             \\r\\n\\\n             \",\n            \"transfer-encoding but not chunked\",\n        );\n\n        parse_err(\n            \"\\\n             POST / HTTP/1.1\\r\\n\\\n             transfer-encoding: chunked, gzip\\r\\n\\\n             \\r\\n\\\n             \",\n            \"transfer-encoding doesn't end in chunked\",\n        );\n\n        parse_err(\n            \"\\\n             POST / HTTP/1.1\\r\\n\\\n             transfer-encoding: chunked\\r\\n\\\n             transfer-encoding: afterlol\\r\\n\\\n             \\r\\n\\\n             \",\n            \"transfer-encoding multiple lines doesn't end in chunked\",\n        );\n\n        // http/1.0\n\n        assert_eq!(\n            parse(\n                \"\\\n                 POST / HTTP/1.0\\r\\n\\\n                 content-length: 10\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::new(10)\n        );\n\n        // 1.0 doesn't understand chunked, so its an error\n        parse_err(\n            \"\\\n             POST / HTTP/1.0\\r\\n\\\n             transfer-encoding: chunked\\r\\n\\\n             \\r\\n\\\n             \",\n            \"1.0 chunked\",\n        );\n    }\n\n    #[test]\n    fn test_decoder_response() {\n        fn parse(s: &str) -> ParsedMessage<StatusCode> {\n            parse_with_method(s, Method::GET)\n        }\n\n        fn parse_ignores(s: &str) {\n            let mut bytes = BytesMut::from(s);\n            assert!(Client::parse(\n                &mut bytes,\n                ParseContext {\n                    cached_headers: &mut None,\n                    req_method: &mut Some(Method::GET),\n                    h1_parser_config: Default::default(),\n                    h1_max_headers: None,\n                    preserve_header_case: false,\n                    #[cfg(feature = \"ffi\")]\n                    preserve_header_order: false,\n                    h09_responses: false,\n                    #[cfg(feature = \"client\")]\n                    on_informational: &mut None,\n                }\n            )\n            .expect(\"parse ok\")\n            .is_none())\n        }\n\n        fn parse_with_method(s: &str, m: Method) -> ParsedMessage<StatusCode> {\n            let mut bytes = BytesMut::from(s);\n            Client::parse(\n                &mut bytes,\n                ParseContext {\n                    cached_headers: &mut None,\n                    req_method: &mut Some(m),\n                    h1_parser_config: Default::default(),\n                    h1_max_headers: None,\n                    preserve_header_case: false,\n                    #[cfg(feature = \"ffi\")]\n                    preserve_header_order: false,\n                    h09_responses: false,\n                    #[cfg(feature = \"client\")]\n                    on_informational: &mut None,\n                },\n            )\n            .expect(\"parse ok\")\n            .expect(\"parse complete\")\n        }\n\n        fn parse_err(s: &str) -> crate::error::Parse {\n            let mut bytes = BytesMut::from(s);\n            Client::parse(\n                &mut bytes,\n                ParseContext {\n                    cached_headers: &mut None,\n                    req_method: &mut Some(Method::GET),\n                    h1_parser_config: Default::default(),\n                    h1_max_headers: None,\n                    preserve_header_case: false,\n                    #[cfg(feature = \"ffi\")]\n                    preserve_header_order: false,\n                    h09_responses: false,\n                    #[cfg(feature = \"client\")]\n                    on_informational: &mut None,\n                },\n            )\n            .expect_err(\"parse should err\")\n        }\n\n        // no content-length or transfer-encoding means close-delimited\n        assert_eq!(\n            parse(\n                \"\\\n                 HTTP/1.1 200 OK\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::CLOSE_DELIMITED\n        );\n\n        // 204 and 304 never have a body\n        assert_eq!(\n            parse(\n                \"\\\n                 HTTP/1.1 204 No Content\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::ZERO\n        );\n\n        assert_eq!(\n            parse(\n                \"\\\n                 HTTP/1.1 304 Not Modified\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::ZERO\n        );\n\n        // content-length\n        assert_eq!(\n            parse(\n                \"\\\n                 HTTP/1.1 200 OK\\r\\n\\\n                 content-length: 8\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::new(8)\n        );\n\n        assert_eq!(\n            parse(\n                \"\\\n                 HTTP/1.1 200 OK\\r\\n\\\n                 content-length: 8\\r\\n\\\n                 content-length: 8\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::new(8)\n        );\n\n        parse_err(\n            \"\\\n             HTTP/1.1 200 OK\\r\\n\\\n             content-length: 8\\r\\n\\\n             content-length: 9\\r\\n\\\n             \\r\\n\\\n             \",\n        );\n\n        parse_err(\n            \"\\\n             HTTP/1.1 200 OK\\r\\n\\\n             content-length: +8\\r\\n\\\n             \\r\\n\\\n             \",\n        );\n\n        // transfer-encoding: chunked\n        assert_eq!(\n            parse(\n                \"\\\n                 HTTP/1.1 200 OK\\r\\n\\\n                 transfer-encoding: chunked\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::CHUNKED\n        );\n\n        // transfer-encoding not-chunked is close-delimited\n        assert_eq!(\n            parse(\n                \"\\\n                 HTTP/1.1 200 OK\\r\\n\\\n                 transfer-encoding: yolo\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::CLOSE_DELIMITED\n        );\n\n        // transfer-encoding and content-length = chunked\n        assert_eq!(\n            parse(\n                \"\\\n                 HTTP/1.1 200 OK\\r\\n\\\n                 content-length: 10\\r\\n\\\n                 transfer-encoding: chunked\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::CHUNKED\n        );\n\n        // HEAD can have content-length, but not body\n        assert_eq!(\n            parse_with_method(\n                \"\\\n                 HTTP/1.1 200 OK\\r\\n\\\n                 content-length: 8\\r\\n\\\n                 \\r\\n\\\n                 \",\n                Method::HEAD\n            )\n            .decode,\n            DecodedLength::ZERO\n        );\n\n        // CONNECT with 200 never has body\n        {\n            let msg = parse_with_method(\n                \"\\\n                 HTTP/1.1 200 OK\\r\\n\\\n                 \\r\\n\\\n                 \",\n                Method::CONNECT,\n            );\n            assert_eq!(msg.decode, DecodedLength::ZERO);\n            assert!(!msg.keep_alive, \"should be upgrade\");\n            assert!(msg.wants_upgrade, \"should be upgrade\");\n        }\n\n        // CONNECT receiving non 200 can have a body\n        assert_eq!(\n            parse_with_method(\n                \"\\\n                 HTTP/1.1 400 Bad Request\\r\\n\\\n                 \\r\\n\\\n                 \",\n                Method::CONNECT\n            )\n            .decode,\n            DecodedLength::CLOSE_DELIMITED\n        );\n\n        // 1xx status codes\n        parse_ignores(\n            \"\\\n             HTTP/1.1 100 Continue\\r\\n\\\n             \\r\\n\\\n             \",\n        );\n\n        parse_ignores(\n            \"\\\n             HTTP/1.1 103 Early Hints\\r\\n\\\n             \\r\\n\\\n             \",\n        );\n\n        // 101 upgrade not supported yet\n        {\n            let msg = parse(\n                \"\\\n                 HTTP/1.1 101 Switching Protocols\\r\\n\\\n                 \\r\\n\\\n                 \",\n            );\n            assert_eq!(msg.decode, DecodedLength::ZERO);\n            assert!(!msg.keep_alive, \"should be last\");\n            assert!(msg.wants_upgrade, \"should be upgrade\");\n        }\n\n        // http/1.0\n        assert_eq!(\n            parse(\n                \"\\\n                 HTTP/1.0 200 OK\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .decode,\n            DecodedLength::CLOSE_DELIMITED\n        );\n\n        // 1.0 doesn't understand chunked\n        parse_err(\n            \"\\\n             HTTP/1.0 200 OK\\r\\n\\\n             transfer-encoding: chunked\\r\\n\\\n             \\r\\n\\\n             \",\n        );\n\n        // keep-alive\n        assert!(\n            parse(\n                \"\\\n                 HTTP/1.1 200 OK\\r\\n\\\n                 content-length: 0\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .keep_alive,\n            \"HTTP/1.1 keep-alive is default\"\n        );\n\n        assert!(\n            !parse(\n                \"\\\n                 HTTP/1.1 200 OK\\r\\n\\\n                 content-length: 0\\r\\n\\\n                 connection: foo, close, bar\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .keep_alive,\n            \"connection close is always close\"\n        );\n\n        assert!(\n            !parse(\n                \"\\\n                 HTTP/1.0 200 OK\\r\\n\\\n                 content-length: 0\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .keep_alive,\n            \"HTTP/1.0 close is default\"\n        );\n\n        assert!(\n            parse(\n                \"\\\n                 HTTP/1.0 200 OK\\r\\n\\\n                 content-length: 0\\r\\n\\\n                 connection: foo, keep-alive, bar\\r\\n\\\n                 \\r\\n\\\n                 \"\n            )\n            .keep_alive,\n            \"connection keep-alive is always keep-alive\"\n        );\n    }\n\n    #[cfg(feature = \"client\")]\n    #[test]\n    fn test_client_obs_fold_line() {\n        fn unfold(src: &str) -> String {\n            let mut buf = src.as_bytes().to_vec();\n            let mut idx = HeaderIndices {\n                name: (0, 0),\n                value: (0, buf.len()),\n            };\n            Client::obs_fold_line(&mut buf, &mut idx);\n            String::from_utf8(buf[idx.value.0..idx.value.1].to_vec()).unwrap()\n        }\n\n        assert_eq!(unfold(\"a normal line\"), \"a normal line\",);\n\n        assert_eq!(unfold(\"obs\\r\\n fold\\r\\n\\t line\"), \"obs fold line\",);\n    }\n\n    #[test]\n    fn test_client_request_encode_title_case() {\n        use crate::proto::BodyLength;\n        use http::header::HeaderValue;\n\n        let mut head = MessageHead::default();\n        head.headers\n            .insert(\"content-length\", HeaderValue::from_static(\"10\"));\n        head.headers\n            .insert(\"content-type\", HeaderValue::from_static(\"application/json\"));\n        head.headers.insert(\"*-*\", HeaderValue::from_static(\"o_o\"));\n\n        let mut vec = Vec::new();\n        Client::encode(\n            Encode {\n                head: &mut head,\n                body: Some(BodyLength::Known(10)),\n                #[cfg(feature = \"server\")]\n                keep_alive: true,\n                req_method: &mut None,\n                title_case_headers: true,\n                #[cfg(feature = \"server\")]\n                date_header: true,\n            },\n            &mut vec,\n        )\n        .unwrap();\n\n        assert_eq!(vec, b\"GET / HTTP/1.1\\r\\nContent-Length: 10\\r\\nContent-Type: application/json\\r\\n*-*: o_o\\r\\n\\r\\n\".to_vec());\n    }\n\n    #[test]\n    fn test_client_request_encode_orig_case() {\n        use crate::proto::BodyLength;\n        use http::header::{HeaderValue, CONTENT_LENGTH};\n\n        let mut head = MessageHead::default();\n        head.headers\n            .insert(\"content-length\", HeaderValue::from_static(\"10\"));\n        head.headers\n            .insert(\"content-type\", HeaderValue::from_static(\"application/json\"));\n\n        let mut orig_headers = HeaderCaseMap::default();\n        orig_headers.insert(CONTENT_LENGTH, \"CONTENT-LENGTH\".into());\n        head.extensions.insert(orig_headers);\n\n        let mut vec = Vec::new();\n        Client::encode(\n            Encode {\n                head: &mut head,\n                body: Some(BodyLength::Known(10)),\n                #[cfg(feature = \"server\")]\n                keep_alive: true,\n                req_method: &mut None,\n                title_case_headers: false,\n                #[cfg(feature = \"server\")]\n                date_header: true,\n            },\n            &mut vec,\n        )\n        .unwrap();\n\n        assert_eq!(\n            &*vec,\n            b\"GET / HTTP/1.1\\r\\nCONTENT-LENGTH: 10\\r\\ncontent-type: application/json\\r\\n\\r\\n\"\n                .as_ref(),\n        );\n    }\n    #[test]\n    fn test_client_request_encode_orig_and_title_case() {\n        use crate::proto::BodyLength;\n        use http::header::{HeaderValue, CONTENT_LENGTH};\n\n        let mut head = MessageHead::default();\n        head.headers\n            .insert(\"content-length\", HeaderValue::from_static(\"10\"));\n        head.headers\n            .insert(\"content-type\", HeaderValue::from_static(\"application/json\"));\n\n        let mut orig_headers = HeaderCaseMap::default();\n        orig_headers.insert(CONTENT_LENGTH, \"CONTENT-LENGTH\".into());\n        head.extensions.insert(orig_headers);\n\n        let mut vec = Vec::new();\n        Client::encode(\n            Encode {\n                head: &mut head,\n                body: Some(BodyLength::Known(10)),\n                #[cfg(feature = \"server\")]\n                keep_alive: true,\n                req_method: &mut None,\n                title_case_headers: true,\n                #[cfg(feature = \"server\")]\n                date_header: true,\n            },\n            &mut vec,\n        )\n        .unwrap();\n\n        assert_eq!(\n            &*vec,\n            b\"GET / HTTP/1.1\\r\\nCONTENT-LENGTH: 10\\r\\nContent-Type: application/json\\r\\n\\r\\n\"\n                .as_ref(),\n        );\n    }\n\n    #[cfg(feature = \"server\")]\n    #[test]\n    fn test_server_encode_connect_method() {\n        let mut head = MessageHead::default();\n\n        let mut vec = Vec::new();\n        let encoder = Server::encode(\n            Encode {\n                head: &mut head,\n                body: None,\n                keep_alive: true,\n                req_method: &mut Some(Method::CONNECT),\n                title_case_headers: false,\n                date_header: true,\n            },\n            &mut vec,\n        )\n        .unwrap();\n\n        assert!(encoder.is_last());\n    }\n\n    #[cfg(feature = \"server\")]\n    #[test]\n    fn test_server_response_encode_title_case() {\n        use crate::proto::BodyLength;\n        use http::header::HeaderValue;\n\n        let mut head = MessageHead::default();\n        head.headers\n            .insert(\"content-length\", HeaderValue::from_static(\"10\"));\n        head.headers\n            .insert(\"content-type\", HeaderValue::from_static(\"application/json\"));\n        head.headers\n            .insert(\"weird--header\", HeaderValue::from_static(\"\"));\n\n        let mut vec = Vec::new();\n        Server::encode(\n            Encode {\n                head: &mut head,\n                body: Some(BodyLength::Known(10)),\n                keep_alive: true,\n                req_method: &mut None,\n                title_case_headers: true,\n                date_header: true,\n            },\n            &mut vec,\n        )\n        .unwrap();\n\n        let expected_response =\n            b\"HTTP/1.1 200 OK\\r\\nContent-Length: 10\\r\\nContent-Type: application/json\\r\\nWeird--Header: \\r\\n\";\n\n        assert_eq!(&vec[..expected_response.len()], &expected_response[..]);\n    }\n\n    #[cfg(feature = \"server\")]\n    #[test]\n    fn test_server_response_encode_orig_case() {\n        use crate::proto::BodyLength;\n        use http::header::{HeaderValue, CONTENT_LENGTH};\n\n        let mut head = MessageHead::default();\n        head.headers\n            .insert(\"content-length\", HeaderValue::from_static(\"10\"));\n        head.headers\n            .insert(\"content-type\", HeaderValue::from_static(\"application/json\"));\n\n        let mut orig_headers = HeaderCaseMap::default();\n        orig_headers.insert(CONTENT_LENGTH, \"CONTENT-LENGTH\".into());\n        head.extensions.insert(orig_headers);\n\n        let mut vec = Vec::new();\n        Server::encode(\n            Encode {\n                head: &mut head,\n                body: Some(BodyLength::Known(10)),\n                keep_alive: true,\n                req_method: &mut None,\n                title_case_headers: false,\n                date_header: true,\n            },\n            &mut vec,\n        )\n        .unwrap();\n\n        let expected_response =\n            b\"HTTP/1.1 200 OK\\r\\nCONTENT-LENGTH: 10\\r\\ncontent-type: application/json\\r\\ndate: \";\n\n        assert_eq!(&vec[..expected_response.len()], &expected_response[..]);\n    }\n\n    #[cfg(feature = \"server\")]\n    #[test]\n    fn test_server_response_encode_orig_and_title_case() {\n        use crate::proto::BodyLength;\n        use http::header::{HeaderValue, CONTENT_LENGTH};\n\n        let mut head = MessageHead::default();\n        head.headers\n            .insert(\"content-length\", HeaderValue::from_static(\"10\"));\n        head.headers\n            .insert(\"content-type\", HeaderValue::from_static(\"application/json\"));\n\n        let mut orig_headers = HeaderCaseMap::default();\n        orig_headers.insert(CONTENT_LENGTH, \"CONTENT-LENGTH\".into());\n        head.extensions.insert(orig_headers);\n\n        let mut vec = Vec::new();\n        Server::encode(\n            Encode {\n                head: &mut head,\n                body: Some(BodyLength::Known(10)),\n                keep_alive: true,\n                req_method: &mut None,\n                title_case_headers: true,\n                date_header: true,\n            },\n            &mut vec,\n        )\n        .unwrap();\n\n        // this will also test that the date does exist\n        let expected_response =\n            b\"HTTP/1.1 200 OK\\r\\nCONTENT-LENGTH: 10\\r\\nContent-Type: application/json\\r\\nDate: \";\n\n        assert_eq!(&vec[..expected_response.len()], &expected_response[..]);\n    }\n\n    #[cfg(feature = \"server\")]\n    #[test]\n    fn test_disabled_date_header() {\n        use crate::proto::BodyLength;\n        use http::header::{HeaderValue, CONTENT_LENGTH};\n\n        let mut head = MessageHead::default();\n        head.headers\n            .insert(\"content-length\", HeaderValue::from_static(\"10\"));\n        head.headers\n            .insert(\"content-type\", HeaderValue::from_static(\"application/json\"));\n\n        let mut orig_headers = HeaderCaseMap::default();\n        orig_headers.insert(CONTENT_LENGTH, \"CONTENT-LENGTH\".into());\n        head.extensions.insert(orig_headers);\n\n        let mut vec = Vec::new();\n        Server::encode(\n            Encode {\n                head: &mut head,\n                body: Some(BodyLength::Known(10)),\n                keep_alive: true,\n                req_method: &mut None,\n                title_case_headers: true,\n                date_header: false,\n            },\n            &mut vec,\n        )\n        .unwrap();\n\n        let expected_response =\n            b\"HTTP/1.1 200 OK\\r\\nCONTENT-LENGTH: 10\\r\\nContent-Type: application/json\\r\\n\\r\\n\";\n\n        assert_eq!(&vec, &expected_response);\n    }\n\n    #[test]\n    fn parse_header_htabs() {\n        let mut bytes = BytesMut::from(\"HTTP/1.1 200 OK\\r\\nserver: hello\\tworld\\r\\n\\r\\n\");\n        let parsed = Client::parse(\n            &mut bytes,\n            ParseContext {\n                cached_headers: &mut None,\n                req_method: &mut Some(Method::GET),\n                h1_parser_config: Default::default(),\n                h1_max_headers: None,\n                preserve_header_case: false,\n                #[cfg(feature = \"ffi\")]\n                preserve_header_order: false,\n                h09_responses: false,\n                #[cfg(feature = \"client\")]\n                on_informational: &mut None,\n            },\n        )\n        .expect(\"parse ok\")\n        .expect(\"parse complete\");\n\n        assert_eq!(parsed.head.headers[\"server\"], \"hello\\tworld\");\n    }\n\n    #[cfg(feature = \"server\")]\n    #[test]\n    fn parse_too_large_headers() {\n        fn gen_req_with_headers(num: usize) -> String {\n            let mut req = String::from(\"GET / HTTP/1.1\\r\\n\");\n            for i in 0..num {\n                req.push_str(&format!(\"key{i}: val{i}\\r\\n\"));\n            }\n            req.push_str(\"\\r\\n\");\n            req\n        }\n        fn gen_resp_with_headers(num: usize) -> String {\n            let mut req = String::from(\"HTTP/1.1 200 OK\\r\\n\");\n            for i in 0..num {\n                req.push_str(&format!(\"key{i}: val{i}\\r\\n\"));\n            }\n            req.push_str(\"\\r\\n\");\n            req\n        }\n        fn parse(max_headers: Option<usize>, gen_size: usize, should_success: bool) {\n            {\n                // server side\n                let mut bytes = BytesMut::from(gen_req_with_headers(gen_size).as_str());\n                let result = Server::parse(\n                    &mut bytes,\n                    ParseContext {\n                        cached_headers: &mut None,\n                        req_method: &mut None,\n                        h1_parser_config: Default::default(),\n                        h1_max_headers: max_headers,\n                        preserve_header_case: false,\n                        #[cfg(feature = \"ffi\")]\n                        preserve_header_order: false,\n                        h09_responses: false,\n                        #[cfg(feature = \"client\")]\n                        on_informational: &mut None,\n                    },\n                );\n                if should_success {\n                    result.expect(\"parse ok\").expect(\"parse complete\");\n                } else {\n                    result.expect_err(\"parse should err\");\n                }\n            }\n            {\n                // client side\n                let mut bytes = BytesMut::from(gen_resp_with_headers(gen_size).as_str());\n                let result = Client::parse(\n                    &mut bytes,\n                    ParseContext {\n                        cached_headers: &mut None,\n                        req_method: &mut None,\n                        h1_parser_config: Default::default(),\n                        h1_max_headers: max_headers,\n                        preserve_header_case: false,\n                        #[cfg(feature = \"ffi\")]\n                        preserve_header_order: false,\n                        h09_responses: false,\n                        #[cfg(feature = \"client\")]\n                        on_informational: &mut None,\n                    },\n                );\n                if should_success {\n                    result.expect(\"parse ok\").expect(\"parse complete\");\n                } else {\n                    result.expect_err(\"parse should err\");\n                }\n            }\n        }\n\n        // check generator\n        assert_eq!(\n            gen_req_with_headers(0),\n            String::from(\"GET / HTTP/1.1\\r\\n\\r\\n\")\n        );\n        assert_eq!(\n            gen_req_with_headers(1),\n            String::from(\"GET / HTTP/1.1\\r\\nkey0: val0\\r\\n\\r\\n\")\n        );\n        assert_eq!(\n            gen_req_with_headers(2),\n            String::from(\"GET / HTTP/1.1\\r\\nkey0: val0\\r\\nkey1: val1\\r\\n\\r\\n\")\n        );\n        assert_eq!(\n            gen_req_with_headers(3),\n            String::from(\"GET / HTTP/1.1\\r\\nkey0: val0\\r\\nkey1: val1\\r\\nkey2: val2\\r\\n\\r\\n\")\n        );\n\n        // default max_headers is 100, so\n        //\n        // - less than or equal to 100, accepted\n        //\n        parse(None, 0, true);\n        parse(None, 1, true);\n        parse(None, 50, true);\n        parse(None, 99, true);\n        parse(None, 100, true);\n        //\n        // - more than 100, rejected\n        //\n        parse(None, 101, false);\n        parse(None, 102, false);\n        parse(None, 200, false);\n\n        // max_headers is 0, parser will reject any headers\n        //\n        // - without header, accepted\n        //\n        parse(Some(0), 0, true);\n        //\n        // - with header(s), rejected\n        //\n        parse(Some(0), 1, false);\n        parse(Some(0), 100, false);\n\n        // max_headers is 200\n        //\n        // - less than or equal to 200, accepted\n        //\n        parse(Some(200), 0, true);\n        parse(Some(200), 1, true);\n        parse(Some(200), 100, true);\n        parse(Some(200), 200, true);\n        //\n        // - more than 200, rejected\n        //\n        parse(Some(200), 201, false);\n        parse(Some(200), 210, false);\n    }\n\n    #[test]\n    fn test_is_complete_fast() {\n        let s = b\"GET / HTTP/1.1\\r\\na: b\\r\\n\\r\\n\";\n        for n in 0..s.len() {\n            assert!(is_complete_fast(s, n), \"{:?}; {}\", s, n);\n        }\n        let s = b\"GET / HTTP/1.1\\na: b\\n\\n\";\n        for n in 0..s.len() {\n            assert!(is_complete_fast(s, n));\n        }\n\n        // Not\n        let s = b\"GET / HTTP/1.1\\r\\na: b\\r\\n\\r\";\n        for n in 0..s.len() {\n            assert!(!is_complete_fast(s, n));\n        }\n        let s = b\"GET / HTTP/1.1\\na: b\\n\";\n        for n in 0..s.len() {\n            assert!(!is_complete_fast(s, n));\n        }\n    }\n\n    #[test]\n    fn test_write_headers_orig_case_empty_value() {\n        let mut headers = HeaderMap::new();\n        let name = http::header::HeaderName::from_static(\"x-empty\");\n        headers.insert(&name, \"\".parse().expect(\"parse empty\"));\n        let mut orig_cases = HeaderCaseMap::default();\n        orig_cases.insert(name, Bytes::from_static(b\"X-EmptY\"));\n\n        let mut dst = Vec::new();\n        super::write_headers_original_case(&headers, &orig_cases, &mut dst, false);\n\n        assert_eq!(\n            dst, b\"X-EmptY:\\r\\n\",\n            \"there should be no space between the colon and CRLF\"\n        );\n    }\n\n    #[test]\n    fn test_write_headers_orig_case_multiple_entries() {\n        let mut headers = HeaderMap::new();\n        let name = http::header::HeaderName::from_static(\"x-empty\");\n        headers.insert(&name, \"a\".parse().unwrap());\n        headers.append(&name, \"b\".parse().unwrap());\n\n        let mut orig_cases = HeaderCaseMap::default();\n        orig_cases.insert(name.clone(), Bytes::from_static(b\"X-Empty\"));\n        orig_cases.append(name, Bytes::from_static(b\"X-EMPTY\"));\n\n        let mut dst = Vec::new();\n        super::write_headers_original_case(&headers, &orig_cases, &mut dst, false);\n\n        assert_eq!(dst, b\"X-Empty: a\\r\\nX-EMPTY: b\\r\\n\");\n    }\n\n    #[cfg(feature = \"nightly\")]\n    use test::Bencher;\n\n    #[cfg(feature = \"nightly\")]\n    #[bench]\n    fn bench_parse_incoming(b: &mut Bencher) {\n        let mut raw = BytesMut::from(\n            &b\"GET /super_long_uri/and_whatever?what_should_we_talk_about/\\\n            I_wonder/Hard_to_write_in_an_uri_after_all/you_have_to_make\\\n            _up_the_punctuation_yourself/how_fun_is_that?test=foo&test1=\\\n            foo1&test2=foo2&test3=foo3&test4=foo4 HTTP/1.1\\r\\nHost: \\\n            hyper.rs\\r\\nAccept: a lot of things\\r\\nAccept-Charset: \\\n            utf8\\r\\nAccept-Encoding: *\\r\\nAccess-Control-Allow-\\\n            Credentials: None\\r\\nAccess-Control-Allow-Origin: None\\r\\n\\\n            Access-Control-Allow-Methods: None\\r\\nAccess-Control-Allow-\\\n            Headers: None\\r\\nContent-Encoding: utf8\\r\\nContent-Security-\\\n            Policy: None\\r\\nContent-Type: text/html\\r\\nOrigin: hyper\\\n            \\r\\nSec-Websocket-Extensions: It looks super important!\\r\\n\\\n            Sec-Websocket-Origin: hyper\\r\\nSec-Websocket-Version: 4.3\\r\\\n            \\nStrict-Transport-Security: None\\r\\nUser-Agent: hyper\\r\\n\\\n            X-Content-Duration: None\\r\\nX-Content-Security-Policy: None\\\n            \\r\\nX-DNSPrefetch-Control: None\\r\\nX-Frame-Options: \\\n            Something important obviously\\r\\nX-Requested-With: Nothing\\\n            \\r\\n\\r\\n\"[..],\n        );\n        let len = raw.len();\n        let mut headers = Some(HeaderMap::new());\n\n        b.bytes = len as u64;\n        b.iter(|| {\n            let mut msg = Server::parse(\n                &mut raw,\n                ParseContext {\n                    cached_headers: &mut headers,\n                    req_method: &mut None,\n                    h1_parser_config: Default::default(),\n                    h1_max_headers: None,\n                    preserve_header_case: false,\n                    #[cfg(feature = \"ffi\")]\n                    preserve_header_order: false,\n                    h09_responses: false,\n                    #[cfg(feature = \"client\")]\n                    on_informational: &mut None,\n                },\n            )\n            .unwrap()\n            .unwrap();\n            ::test::black_box(&msg);\n\n            // Remove all references pointing into BytesMut.\n            msg.head.headers.clear();\n            headers = Some(msg.head.headers);\n            std::mem::take(&mut msg.head.subject);\n\n            restart(&mut raw, len);\n        });\n\n        fn restart(b: &mut BytesMut, len: usize) {\n            b.reserve(1);\n            unsafe {\n                b.set_len(len);\n            }\n        }\n    }\n\n    #[cfg(feature = \"nightly\")]\n    #[bench]\n    fn bench_parse_short(b: &mut Bencher) {\n        let s = &b\"GET / HTTP/1.1\\r\\nHost: localhost:8080\\r\\n\\r\\n\"[..];\n        let mut raw = BytesMut::from(s);\n        let len = raw.len();\n        let mut headers = Some(HeaderMap::new());\n\n        b.bytes = len as u64;\n        b.iter(|| {\n            let mut msg = Server::parse(\n                &mut raw,\n                ParseContext {\n                    cached_headers: &mut headers,\n                    req_method: &mut None,\n                    h1_parser_config: Default::default(),\n                    h1_max_headers: None,\n                    preserve_header_case: false,\n                    #[cfg(feature = \"ffi\")]\n                    preserve_header_order: false,\n                    h09_responses: false,\n                    #[cfg(feature = \"client\")]\n                    on_informational: &mut None,\n                },\n            )\n            .unwrap()\n            .unwrap();\n            ::test::black_box(&msg);\n            msg.head.headers.clear();\n            headers = Some(msg.head.headers);\n            restart(&mut raw, len);\n        });\n\n        fn restart(b: &mut BytesMut, len: usize) {\n            b.reserve(1);\n            unsafe {\n                b.set_len(len);\n            }\n        }\n    }\n\n    #[cfg(feature = \"nightly\")]\n    #[bench]\n    fn bench_server_encode_headers_preset(b: &mut Bencher) {\n        use crate::proto::BodyLength;\n        use http::header::HeaderValue;\n\n        let len = 108;\n        b.bytes = len as u64;\n\n        let mut head = MessageHead::default();\n        let mut headers = HeaderMap::new();\n        headers.insert(\"content-length\", HeaderValue::from_static(\"10\"));\n        headers.insert(\"content-type\", HeaderValue::from_static(\"application/json\"));\n\n        b.iter(|| {\n            let mut vec = Vec::new();\n            head.headers = headers.clone();\n            Server::encode(\n                Encode {\n                    head: &mut head,\n                    body: Some(BodyLength::Known(10)),\n                    keep_alive: true,\n                    req_method: &mut Some(Method::GET),\n                    title_case_headers: false,\n                    date_header: true,\n                },\n                &mut vec,\n            )\n            .unwrap();\n            assert_eq!(vec.len(), len);\n            ::test::black_box(vec);\n        })\n    }\n\n    #[cfg(feature = \"nightly\")]\n    #[bench]\n    fn bench_server_encode_no_headers(b: &mut Bencher) {\n        use crate::proto::BodyLength;\n\n        let len = 76;\n        b.bytes = len as u64;\n\n        let mut head = MessageHead::default();\n        let mut vec = Vec::with_capacity(128);\n\n        b.iter(|| {\n            Server::encode(\n                Encode {\n                    head: &mut head,\n                    body: Some(BodyLength::Known(10)),\n                    keep_alive: true,\n                    req_method: &mut Some(Method::GET),\n                    title_case_headers: false,\n                    date_header: true,\n                },\n                &mut vec,\n            )\n            .unwrap();\n            assert_eq!(vec.len(), len);\n            ::test::black_box(&vec);\n\n            vec.clear();\n        })\n    }\n}\n"
  },
  {
    "path": "src/proto/h2/client.rs",
    "content": "use std::{\n    convert::Infallible,\n    future::Future,\n    marker::PhantomData,\n    pin::Pin,\n    task::{Context, Poll},\n    time::Duration,\n};\n\nuse crate::rt::{Read, Write};\nuse bytes::Bytes;\nuse futures_channel::mpsc::{Receiver, Sender};\nuse futures_channel::{mpsc, oneshot};\nuse futures_core::{ready, FusedFuture, FusedStream, Stream};\nuse h2::client::{Builder, Connection, SendRequest};\nuse h2::SendStream;\nuse http::{Method, StatusCode};\nuse pin_project_lite::pin_project;\n\nuse super::ping::{Ponger, Recorder};\nuse super::{ping, PipeToSendStream, SendBuf};\nuse crate::body::{Body, Incoming as IncomingBody};\nuse crate::client::dispatch::{Callback, SendWhen, TrySendError};\nuse crate::common::either::Either;\nuse crate::common::io::Compat;\nuse crate::common::time::Time;\nuse crate::ext::Protocol;\nuse crate::headers;\nuse crate::proto::Dispatched;\nuse crate::rt::bounds::{Http2ClientConnExec, Http2UpgradedExec};\nuse crate::upgrade::Upgraded;\nuse crate::{Request, Response};\nuse h2::client::ResponseFuture;\n\ntype ClientRx<B> = crate::client::dispatch::Receiver<Request<B>, Response<IncomingBody>>;\n\n///// An mpsc channel is used to help notify the `Connection` task when *all*\n///// other handles to it have been dropped, so that it can shutdown.\ntype ConnDropRef = mpsc::Sender<Infallible>;\n\n///// A oneshot channel watches the `Connection` task, and when it completes,\n///// the \"dispatch\" task will be notified and can shutdown sooner.\ntype ConnEof = oneshot::Receiver<Infallible>;\n\n// Our defaults are chosen for the \"majority\" case, which usually are not\n// resource constrained, and so the spec default of 64kb can be too limiting\n// for performance.\nconst DEFAULT_CONN_WINDOW: u32 = 1024 * 1024 * 5; // 5mb\nconst DEFAULT_STREAM_WINDOW: u32 = 1024 * 1024 * 2; // 2mb\nconst DEFAULT_MAX_FRAME_SIZE: u32 = 1024 * 16; // 16kb\nconst DEFAULT_MAX_SEND_BUF_SIZE: usize = 1024 * 1024; // 1mb\nconst DEFAULT_MAX_HEADER_LIST_SIZE: u32 = 1024 * 16; // 16kb\n\n// The maximum number of concurrent streams that the client is allowed to open\n// before it receives the initial SETTINGS frame from the server.\n// This default value is derived from what the HTTP/2 spec recommends as the\n// minimum value that endpoints advertise to their peers. It means that using\n// this value will minimize the chance of the failure where the local endpoint\n// attempts to open too many streams and gets rejected by the remote peer with\n// the `REFUSED_STREAM` error.\nconst DEFAULT_INITIAL_MAX_SEND_STREAMS: usize = 100;\n\n#[derive(Clone, Debug)]\npub(crate) struct Config {\n    pub(crate) adaptive_window: bool,\n    pub(crate) initial_conn_window_size: u32,\n    pub(crate) initial_stream_window_size: u32,\n    pub(crate) initial_max_send_streams: usize,\n    pub(crate) max_frame_size: Option<u32>,\n    pub(crate) max_header_list_size: u32,\n    pub(crate) keep_alive_interval: Option<Duration>,\n    pub(crate) keep_alive_timeout: Duration,\n    pub(crate) keep_alive_while_idle: bool,\n    pub(crate) max_concurrent_reset_streams: Option<usize>,\n    pub(crate) max_send_buffer_size: usize,\n    pub(crate) max_pending_accept_reset_streams: Option<usize>,\n    pub(crate) max_local_error_reset_streams: Option<usize>,\n    pub(crate) header_table_size: Option<u32>,\n    pub(crate) max_concurrent_streams: Option<u32>,\n}\n\nimpl Default for Config {\n    fn default() -> Config {\n        Config {\n            adaptive_window: false,\n            initial_conn_window_size: DEFAULT_CONN_WINDOW,\n            initial_stream_window_size: DEFAULT_STREAM_WINDOW,\n            initial_max_send_streams: DEFAULT_INITIAL_MAX_SEND_STREAMS,\n            max_frame_size: Some(DEFAULT_MAX_FRAME_SIZE),\n            max_header_list_size: DEFAULT_MAX_HEADER_LIST_SIZE,\n            keep_alive_interval: None,\n            keep_alive_timeout: Duration::from_secs(20),\n            keep_alive_while_idle: false,\n            max_concurrent_reset_streams: None,\n            max_send_buffer_size: DEFAULT_MAX_SEND_BUF_SIZE,\n            max_pending_accept_reset_streams: None,\n            max_local_error_reset_streams: Some(1024),\n            header_table_size: None,\n            max_concurrent_streams: None,\n        }\n    }\n}\n\nfn new_builder(config: &Config) -> Builder {\n    let mut builder = Builder::default();\n    builder\n        .initial_max_send_streams(config.initial_max_send_streams)\n        .initial_window_size(config.initial_stream_window_size)\n        .initial_connection_window_size(config.initial_conn_window_size)\n        .max_header_list_size(config.max_header_list_size)\n        .max_send_buffer_size(config.max_send_buffer_size)\n        .max_local_error_reset_streams(config.max_local_error_reset_streams)\n        .enable_push(false);\n    if let Some(max) = config.max_frame_size {\n        builder.max_frame_size(max);\n    }\n    if let Some(max) = config.max_concurrent_reset_streams {\n        builder.max_concurrent_reset_streams(max);\n    }\n    if let Some(max) = config.max_pending_accept_reset_streams {\n        builder.max_pending_accept_reset_streams(max);\n    }\n    if let Some(size) = config.header_table_size {\n        builder.header_table_size(size);\n    }\n    if let Some(max) = config.max_concurrent_streams {\n        builder.max_concurrent_streams(max);\n    }\n    builder\n}\n\nfn new_ping_config(config: &Config) -> ping::Config {\n    ping::Config {\n        bdp_initial_window: if config.adaptive_window {\n            Some(config.initial_stream_window_size)\n        } else {\n            None\n        },\n        keep_alive_interval: config.keep_alive_interval,\n        keep_alive_timeout: config.keep_alive_timeout,\n        keep_alive_while_idle: config.keep_alive_while_idle,\n    }\n}\n\npub(crate) async fn handshake<T, B, E>(\n    io: T,\n    req_rx: ClientRx<B>,\n    config: &Config,\n    mut exec: E,\n    timer: Time,\n) -> crate::Result<ClientTask<B, E, T>>\nwhere\n    T: Read + Write + Unpin,\n    B: Body + 'static,\n    B::Data: Send + 'static,\n    E: Http2ClientConnExec<B, T> + Clone + Unpin,\n    B::Error: Into<Box<dyn std::error::Error + Send + Sync>>,\n{\n    let (h2_tx, mut conn) = new_builder(config)\n        .handshake::<_, SendBuf<B::Data>>(Compat::new(io))\n        .await\n        .map_err(crate::Error::new_h2)?;\n\n    // An mpsc channel is used entirely to detect when the\n    // 'Client' has been dropped. This is to get around a bug\n    // in h2 where dropping all SendRequests won't notify a\n    // parked Connection.\n    let (conn_drop_ref, conn_drop_rx) = mpsc::channel(1);\n    let (cancel_tx, conn_eof) = oneshot::channel();\n\n    let ping_config = new_ping_config(config);\n\n    let (conn, ping) = if ping_config.is_enabled() {\n        let pp = conn.ping_pong().expect(\"conn.ping_pong\");\n        let (recorder, ponger) = ping::channel(pp, ping_config, timer);\n\n        let conn: Conn<_, B> = Conn::new(ponger, conn);\n        (Either::left(conn), recorder)\n    } else {\n        (Either::right(conn), ping::disabled())\n    };\n    let conn: ConnMapErr<T, B> = ConnMapErr {\n        conn,\n        is_terminated: false,\n    };\n\n    exec.execute_h2_future(H2ClientFuture::Task {\n        task: ConnTask::new(conn, conn_drop_rx, cancel_tx),\n    });\n\n    Ok(ClientTask {\n        ping,\n        conn_drop_ref,\n        conn_eof,\n        executor: exec,\n        h2_tx,\n        req_rx,\n        fut_ctx: None,\n        marker: PhantomData,\n    })\n}\n\npin_project! {\n    struct Conn<T, B>\n    where\n        B: Body,\n    {\n        #[pin]\n        ponger: Ponger,\n        #[pin]\n        conn: Connection<Compat<T>, SendBuf<<B as Body>::Data>>,\n    }\n}\n\nimpl<T, B> Conn<T, B>\nwhere\n    B: Body,\n    T: Read + Write + Unpin,\n{\n    fn new(ponger: Ponger, conn: Connection<Compat<T>, SendBuf<<B as Body>::Data>>) -> Self {\n        Conn { ponger, conn }\n    }\n}\n\nimpl<T, B> Future for Conn<T, B>\nwhere\n    B: Body,\n    T: Read + Write + Unpin,\n{\n    type Output = Result<(), h2::Error>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let mut this = self.project();\n        match this.ponger.poll(cx) {\n            Poll::Ready(ping::Ponged::SizeUpdate(wnd)) => {\n                this.conn.set_target_window_size(wnd);\n                this.conn.set_initial_window_size(wnd)?;\n            }\n            Poll::Ready(ping::Ponged::KeepAliveTimedOut) => {\n                debug!(\"connection keep-alive timed out\");\n                return Poll::Ready(Ok(()));\n            }\n            Poll::Pending => {}\n        }\n\n        Pin::new(&mut this.conn).poll(cx)\n    }\n}\n\npin_project! {\n    struct ConnMapErr<T, B>\n    where\n        B: Body,\n        T: Read,\n        T: Write,\n        T: Unpin,\n    {\n        #[pin]\n        conn: Either<Conn<T, B>, Connection<Compat<T>, SendBuf<<B as Body>::Data>>>,\n        #[pin]\n        is_terminated: bool,\n    }\n}\n\nimpl<T, B> Future for ConnMapErr<T, B>\nwhere\n    B: Body,\n    T: Read + Write + Unpin,\n{\n    type Output = Result<(), ()>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let mut this = self.project();\n\n        if *this.is_terminated {\n            return Poll::Pending;\n        }\n        let polled = this.conn.poll(cx);\n        if polled.is_ready() {\n            *this.is_terminated = true;\n        }\n        polled.map_err(|_e| {\n            debug!(error = %_e, \"connection error\");\n        })\n    }\n}\n\nimpl<T, B> FusedFuture for ConnMapErr<T, B>\nwhere\n    B: Body,\n    T: Read + Write + Unpin,\n{\n    fn is_terminated(&self) -> bool {\n        self.is_terminated\n    }\n}\n\npin_project! {\n    pub struct ConnTask<T, B>\n    where\n        B: Body,\n        T: Read,\n        T: Write,\n        T: Unpin,\n    {\n        #[pin]\n        drop_rx: Receiver<Infallible>,\n        #[pin]\n        cancel_tx: Option<oneshot::Sender<Infallible>>,\n        #[pin]\n        conn: ConnMapErr<T, B>,\n    }\n}\n\nimpl<T, B> ConnTask<T, B>\nwhere\n    B: Body,\n    T: Read + Write + Unpin,\n{\n    fn new(\n        conn: ConnMapErr<T, B>,\n        drop_rx: Receiver<Infallible>,\n        cancel_tx: oneshot::Sender<Infallible>,\n    ) -> Self {\n        Self {\n            drop_rx,\n            cancel_tx: Some(cancel_tx),\n            conn,\n        }\n    }\n}\n\nimpl<T, B> Future for ConnTask<T, B>\nwhere\n    B: Body,\n    T: Read + Write + Unpin,\n{\n    type Output = ();\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let mut this = self.project();\n\n        if !this.conn.is_terminated() && Pin::new(&mut this.conn).poll(cx).is_ready() {\n            // ok or err, the `conn` has finished.\n            return Poll::Ready(());\n        }\n\n        if !this.drop_rx.is_terminated() && Pin::new(&mut this.drop_rx).poll_next(cx).is_ready() {\n            // mpsc has been dropped, hopefully polling\n            // the connection some more should start shutdown\n            // and then close.\n            trace!(\"send_request dropped, starting conn shutdown\");\n            drop(this.cancel_tx.take().expect(\"ConnTask Future polled twice\"));\n        }\n\n        Poll::Pending\n    }\n}\n\npin_project! {\n    #[project = H2ClientFutureProject]\n    pub enum H2ClientFuture<B, T, E>\n    where\n        B: http_body::Body,\n        B: 'static,\n        B::Error: Into<Box<dyn std::error::Error + Send + Sync>>,\n        T: Read,\n        T: Write,\n        T: Unpin,\n    {\n        Pipe {\n            #[pin]\n            pipe: PipeMap<B>,\n        },\n        Send {\n            #[pin]\n            send_when: SendWhen<B, E>,\n        },\n        Task {\n            #[pin]\n            task: ConnTask<T, B>,\n        },\n    }\n}\n\nimpl<B, T, E> Future for H2ClientFuture<B, T, E>\nwhere\n    B: http_body::Body + 'static,\n    B::Error: Into<Box<dyn std::error::Error + Send + Sync>>,\n    T: Read + Write + Unpin,\n    E: Http2UpgradedExec<B::Data>,\n{\n    type Output = ();\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> std::task::Poll<Self::Output> {\n        let this = self.project();\n\n        match this {\n            H2ClientFutureProject::Pipe { pipe } => pipe.poll(cx),\n            H2ClientFutureProject::Send { send_when } => send_when.poll(cx),\n            H2ClientFutureProject::Task { task } => task.poll(cx),\n        }\n    }\n}\n\nstruct FutCtx<B>\nwhere\n    B: Body,\n{\n    is_connect: bool,\n    eos: bool,\n    fut: ResponseFuture,\n    body_tx: SendStream<SendBuf<B::Data>>,\n    body: B,\n    cb: Callback<Request<B>, Response<IncomingBody>>,\n}\n\nimpl<B: Body> Unpin for FutCtx<B> {}\n\npub(crate) struct ClientTask<B, E, T>\nwhere\n    B: Body,\n    E: Unpin,\n{\n    ping: ping::Recorder,\n    conn_drop_ref: ConnDropRef,\n    conn_eof: ConnEof,\n    executor: E,\n    h2_tx: SendRequest<SendBuf<B::Data>>,\n    req_rx: ClientRx<B>,\n    fut_ctx: Option<FutCtx<B>>,\n    marker: PhantomData<T>,\n}\n\nimpl<B, E, T> ClientTask<B, E, T>\nwhere\n    B: Body + 'static,\n    E: Http2ClientConnExec<B, T> + Unpin,\n    B::Error: Into<Box<dyn std::error::Error + Send + Sync>>,\n    T: Read + Write + Unpin,\n{\n    pub(crate) fn is_extended_connect_protocol_enabled(&self) -> bool {\n        self.h2_tx.is_extended_connect_protocol_enabled()\n    }\n}\n\npin_project! {\n    pub struct PipeMap<S>\n    where\n        S: Body,\n    {\n        #[pin]\n        pipe: PipeToSendStream<S>,\n        #[pin]\n        conn_drop_ref: Option<Sender<Infallible>>,\n        #[pin]\n        ping: Option<Recorder>,\n    }\n}\n\nimpl<B> Future for PipeMap<B>\nwhere\n    B: http_body::Body,\n    B::Error: Into<Box<dyn std::error::Error + Send + Sync>>,\n{\n    type Output = ();\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> std::task::Poll<Self::Output> {\n        let mut this = self.project();\n\n        match Pin::new(&mut this.pipe).poll(cx) {\n            Poll::Ready(result) => {\n                if let Err(_e) = result {\n                    debug!(\"client request body error: {}\", _e);\n                }\n                drop(this.conn_drop_ref.take().expect(\"Future polled twice\"));\n                drop(this.ping.take().expect(\"Future polled twice\"));\n                return Poll::Ready(());\n            }\n            Poll::Pending => (),\n        };\n        Poll::Pending\n    }\n}\n\nimpl<B, E, T> ClientTask<B, E, T>\nwhere\n    B: Body + 'static + Unpin,\n    B::Data: Send,\n    E: Http2ClientConnExec<B, T> + Clone + Unpin,\n    B::Error: Into<Box<dyn std::error::Error + Send + Sync>>,\n    T: Read + Write + Unpin,\n{\n    fn poll_pipe(&mut self, f: FutCtx<B>, cx: &mut Context<'_>) {\n        let ping = self.ping.clone();\n\n        let send_stream = if !f.is_connect {\n            if !f.eos {\n                let mut pipe = PipeToSendStream::new(f.body, f.body_tx);\n\n                // eagerly see if the body pipe is ready and\n                // can thus skip allocating in the executor\n                match Pin::new(&mut pipe).poll(cx) {\n                    Poll::Ready(_) => (),\n                    Poll::Pending => {\n                        let conn_drop_ref = self.conn_drop_ref.clone();\n                        // keep the ping recorder's knowledge of an\n                        // \"open stream\" alive while this body is\n                        // still sending...\n                        let ping = ping.clone();\n\n                        let pipe = PipeMap {\n                            pipe,\n                            conn_drop_ref: Some(conn_drop_ref),\n                            ping: Some(ping),\n                        };\n                        // Clear send task\n                        self.executor\n                            .execute_h2_future(H2ClientFuture::Pipe { pipe });\n                    }\n                }\n            }\n\n            None\n        } else {\n            Some(f.body_tx)\n        };\n\n        self.executor.execute_h2_future(H2ClientFuture::Send {\n            send_when: SendWhen {\n                when: ResponseFutMap {\n                    fut: f.fut,\n                    ping: Some(ping),\n                    send_stream: Some(send_stream),\n                    exec: self.executor.clone(),\n                },\n                call_back: Some(f.cb),\n            },\n        });\n    }\n}\n\npin_project! {\n    pub(crate) struct ResponseFutMap<B, E>\n    where\n        B: Body,\n        B: 'static,\n    {\n        #[pin]\n        fut: ResponseFuture,\n        ping: Option<Recorder>,\n        #[pin]\n        send_stream: Option<Option<SendStream<SendBuf<<B as Body>::Data>>>>,\n        exec: E,\n    }\n}\n\nimpl<B, E> Future for ResponseFutMap<B, E>\nwhere\n    B: Body + 'static,\n    E: Http2UpgradedExec<B::Data>,\n{\n    type Output = Result<Response<crate::body::Incoming>, (crate::Error, Option<Request<B>>)>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let mut this = self.as_mut().project();\n\n        let result = ready!(this.fut.poll(cx));\n\n        let ping = this.ping.take().expect(\"Future polled twice\");\n        let send_stream = this.send_stream.take().expect(\"Future polled twice\");\n\n        match result {\n            Ok(res) => {\n                // record that we got the response headers\n                ping.record_non_data();\n\n                let content_length = headers::content_length_parse_all(res.headers());\n                if let (Some(mut send_stream), StatusCode::OK) = (send_stream, res.status()) {\n                    if content_length.map_or(false, |len| len != 0) {\n                        warn!(\"h2 connect response with non-zero body not supported\");\n\n                        send_stream.send_reset(h2::Reason::INTERNAL_ERROR);\n                        return Poll::Ready(Err((\n                            crate::Error::new_h2(h2::Reason::INTERNAL_ERROR.into()),\n                            None::<Request<B>>,\n                        )));\n                    }\n                    let (parts, recv_stream) = res.into_parts();\n                    let mut res = Response::from_parts(parts, IncomingBody::empty());\n\n                    let (pending, on_upgrade) = crate::upgrade::pending();\n\n                    let (h2_up, up_task) = super::upgrade::pair(send_stream, recv_stream, ping);\n                    self.exec.execute_upgrade(up_task);\n                    let upgraded = Upgraded::new(h2_up, Bytes::new());\n\n                    pending.fulfill(upgraded);\n                    res.extensions_mut().insert(on_upgrade);\n\n                    Poll::Ready(Ok(res))\n                } else {\n                    let res = res.map(|stream| {\n                        let ping = ping.for_stream(&stream);\n                        IncomingBody::h2(stream, content_length.into(), ping)\n                    });\n                    Poll::Ready(Ok(res))\n                }\n            }\n            Err(err) => {\n                ping.ensure_not_timed_out().map_err(|e| (e, None))?;\n\n                debug!(\"client response error: {}\", err);\n                Poll::Ready(Err((crate::Error::new_h2(err), None::<Request<B>>)))\n            }\n        }\n    }\n}\n\nimpl<B, E, T> Future for ClientTask<B, E, T>\nwhere\n    B: Body + 'static + Unpin,\n    B::Data: Send,\n    B::Error: Into<Box<dyn std::error::Error + Send + Sync>>,\n    E: Http2ClientConnExec<B, T> + Clone + Unpin,\n    T: Read + Write + Unpin,\n{\n    type Output = crate::Result<Dispatched>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        loop {\n            match ready!(self.h2_tx.poll_ready(cx)) {\n                Ok(()) => (),\n                Err(err) => {\n                    self.ping.ensure_not_timed_out()?;\n                    return if err.reason() == Some(::h2::Reason::NO_ERROR) {\n                        trace!(\"connection gracefully shutdown\");\n                        Poll::Ready(Ok(Dispatched::Shutdown))\n                    } else {\n                        Poll::Ready(Err(crate::Error::new_h2(err)))\n                    };\n                }\n            };\n\n            // If we were waiting on pending open\n            // continue where we left off.\n            if let Some(f) = self.fut_ctx.take() {\n                self.poll_pipe(f, cx);\n                continue;\n            }\n\n            match self.req_rx.poll_recv(cx) {\n                Poll::Ready(Some((req, cb))) => {\n                    // check that future hasn't been canceled already\n                    if cb.is_canceled() {\n                        trace!(\"request callback is canceled\");\n                        continue;\n                    }\n                    let (head, body) = req.into_parts();\n                    let mut req = ::http::Request::from_parts(head, ());\n                    super::strip_connection_headers(req.headers_mut(), true);\n                    if let Some(len) = body.size_hint().exact() {\n                        if len != 0 || headers::method_has_defined_payload_semantics(req.method()) {\n                            headers::set_content_length_if_missing(req.headers_mut(), len);\n                        }\n                    }\n\n                    let is_connect = req.method() == Method::CONNECT;\n                    let eos = body.is_end_stream();\n\n                    if is_connect\n                        && headers::content_length_parse_all(req.headers())\n                            .map_or(false, |len| len != 0)\n                    {\n                        debug!(\"h2 connect request with non-zero body not supported\");\n                        cb.send(Err(TrySendError {\n                            error: crate::Error::new_user_invalid_connect(),\n                            message: None,\n                        }));\n                        continue;\n                    }\n\n                    if let Some(protocol) = req.extensions_mut().remove::<Protocol>() {\n                        req.extensions_mut().insert(protocol.into_inner());\n                    }\n\n                    let (fut, body_tx) = match self.h2_tx.send_request(req, !is_connect && eos) {\n                        Ok(ok) => ok,\n                        Err(err) => {\n                            debug!(\"client send request error: {}\", err);\n                            cb.send(Err(TrySendError {\n                                error: crate::Error::new_h2(err),\n                                message: None,\n                            }));\n                            continue;\n                        }\n                    };\n\n                    let f = FutCtx {\n                        is_connect,\n                        eos,\n                        fut,\n                        body_tx,\n                        body,\n                        cb,\n                    };\n\n                    // Check poll_ready() again.\n                    // If the call to send_request() resulted in the new stream being pending open\n                    // we have to wait for the open to complete before accepting new requests.\n                    match self.h2_tx.poll_ready(cx) {\n                        Poll::Pending => {\n                            // Save Context\n                            self.fut_ctx = Some(f);\n                            return Poll::Pending;\n                        }\n                        Poll::Ready(Ok(())) => (),\n                        Poll::Ready(Err(err)) => {\n                            f.cb.send(Err(TrySendError {\n                                error: crate::Error::new_h2(err),\n                                message: None,\n                            }));\n                            continue;\n                        }\n                    }\n                    self.poll_pipe(f, cx);\n                    continue;\n                }\n\n                Poll::Ready(None) => {\n                    trace!(\"client::dispatch::Sender dropped\");\n                    return Poll::Ready(Ok(Dispatched::Shutdown));\n                }\n\n                Poll::Pending => match ready!(Pin::new(&mut self.conn_eof).poll(cx)) {\n                    // As of Rust 1.82, this pattern is no longer needed, and emits a warning.\n                    // But we cannot remove it as long as MSRV is less than that.\n                    #[allow(unused)]\n                    Ok(never) => match never {},\n                    Err(_conn_is_eof) => {\n                        trace!(\"connection task is closed, closing dispatch task\");\n                        return Poll::Ready(Ok(Dispatched::Shutdown));\n                    }\n                },\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/proto/h2/mod.rs",
    "content": "use std::error::Error as StdError;\nuse std::future::Future;\nuse std::io::{Cursor, IoSlice};\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse bytes::Buf;\nuse futures_core::ready;\nuse h2::SendStream;\nuse http::header::{HeaderName, CONNECTION, TE, TRANSFER_ENCODING, UPGRADE};\nuse http::HeaderMap;\nuse pin_project_lite::pin_project;\n\nuse crate::body::Body;\n\npub(crate) mod ping;\npub(crate) mod upgrade;\n\ncfg_client! {\n    pub(crate) mod client;\n    pub(crate) use self::client::ClientTask;\n}\n\ncfg_server! {\n    pub(crate) mod server;\n    pub(crate) use self::server::Server;\n}\n\n/// Default initial stream window size defined in HTTP2 spec.\npub(crate) const SPEC_WINDOW_SIZE: u32 = 65_535;\n\n// List of connection headers from RFC 9110 Section 7.6.1\n//\n// TE headers are allowed in HTTP/2 requests as long as the value is \"trailers\", so they're\n// tested separately.\nstatic CONNECTION_HEADERS: [HeaderName; 4] = [\n    HeaderName::from_static(\"keep-alive\"),\n    HeaderName::from_static(\"proxy-connection\"),\n    TRANSFER_ENCODING,\n    UPGRADE,\n];\n\nfn strip_connection_headers(headers: &mut HeaderMap, is_request: bool) {\n    for header in &CONNECTION_HEADERS {\n        if headers.remove(header).is_some() {\n            warn!(\"Connection header illegal in HTTP/2: {}\", header.as_str());\n        }\n    }\n\n    if is_request {\n        if headers\n            .get(TE)\n            .map_or(false, |te_header| te_header != \"trailers\")\n        {\n            warn!(\"TE headers not set to \\\"trailers\\\" are illegal in HTTP/2 requests\");\n            headers.remove(TE);\n        }\n    } else if headers.remove(TE).is_some() {\n        warn!(\"TE headers illegal in HTTP/2 responses\");\n    }\n\n    if let Some(header) = headers.remove(CONNECTION) {\n        warn!(\n            \"Connection header illegal in HTTP/2: {}\",\n            CONNECTION.as_str()\n        );\n        // A `Connection` header may have a comma-separated list of names of other headers that\n        // are meant for only this specific connection.\n        //\n        // Iterate these names and remove them as headers. Connection-specific headers are\n        // forbidden in HTTP2, as that information has been moved into frame types of the h2\n        // protocol.\n        if let Ok(header_contents) = header.to_str() {\n            for name in header_contents.split(',') {\n                let name = name.trim();\n                headers.remove(name);\n            }\n        }\n    }\n}\n\n// body adapters used by both Client and Server\n\npin_project! {\n    pub(crate) struct PipeToSendStream<S>\n    where\n        S: Body,\n    {\n        body_tx: SendStream<SendBuf<S::Data>>,\n        data_done: bool,\n        #[pin]\n        stream: S,\n    }\n}\n\nimpl<S> PipeToSendStream<S>\nwhere\n    S: Body,\n{\n    fn new(stream: S, tx: SendStream<SendBuf<S::Data>>) -> PipeToSendStream<S> {\n        PipeToSendStream {\n            body_tx: tx,\n            data_done: false,\n            stream,\n        }\n    }\n}\n\nimpl<S> Future for PipeToSendStream<S>\nwhere\n    S: Body,\n    S::Error: Into<Box<dyn StdError + Send + Sync>>,\n{\n    type Output = crate::Result<()>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let mut me = self.project();\n        loop {\n            // we don't have the next chunk of data yet, so just reserve 1 byte to make\n            // sure there's some capacity available. h2 will handle the capacity management\n            // for the actual body chunk.\n            me.body_tx.reserve_capacity(1);\n\n            if me.body_tx.capacity() == 0 {\n                loop {\n                    match ready!(me.body_tx.poll_capacity(cx)) {\n                        Some(Ok(0)) => {}\n                        Some(Ok(_)) => break,\n                        Some(Err(e)) => return Poll::Ready(Err(crate::Error::new_body_write(e))),\n                        None => {\n                            // None means the stream is no longer in a\n                            // streaming state, we either finished it\n                            // somehow, or the remote reset us.\n                            return Poll::Ready(Err(crate::Error::new_body_write(\n                                \"send stream capacity unexpectedly closed\",\n                            )));\n                        }\n                    }\n                }\n            } else if let Poll::Ready(reason) = me\n                .body_tx\n                .poll_reset(cx)\n                .map_err(crate::Error::new_body_write)?\n            {\n                debug!(\"stream received RST_STREAM: {:?}\", reason);\n                return Poll::Ready(Err(crate::Error::new_body_write(::h2::Error::from(reason))));\n            }\n\n            match ready!(me.stream.as_mut().poll_frame(cx)) {\n                Some(Ok(frame)) => {\n                    if frame.is_data() {\n                        let chunk = frame.into_data().unwrap_or_else(|_| unreachable!());\n                        let is_eos = me.stream.is_end_stream();\n                        trace!(\n                            \"send body chunk: {} bytes, eos={}\",\n                            chunk.remaining(),\n                            is_eos,\n                        );\n\n                        let buf = SendBuf::Buf(chunk);\n                        me.body_tx\n                            .send_data(buf, is_eos)\n                            .map_err(crate::Error::new_body_write)?;\n\n                        if is_eos {\n                            return Poll::Ready(Ok(()));\n                        }\n                    } else if frame.is_trailers() {\n                        // no more DATA, so give any capacity back\n                        me.body_tx.reserve_capacity(0);\n                        me.body_tx\n                            .send_trailers(frame.into_trailers().unwrap_or_else(|_| unreachable!()))\n                            .map_err(crate::Error::new_body_write)?;\n                        return Poll::Ready(Ok(()));\n                    } else {\n                        trace!(\"discarding unknown frame\");\n                        // loop again\n                    }\n                }\n                Some(Err(e)) => return Poll::Ready(Err(me.body_tx.on_user_err(e))),\n                None => {\n                    // no more frames means we're done here\n                    // but at this point, we haven't sent an EOS DATA, or\n                    // any trailers, so send an empty EOS DATA.\n                    return Poll::Ready(me.body_tx.send_eos_frame());\n                }\n            }\n        }\n    }\n}\n\ntrait SendStreamExt {\n    fn on_user_err<E>(&mut self, err: E) -> crate::Error\n    where\n        E: Into<Box<dyn std::error::Error + Send + Sync>>;\n    fn send_eos_frame(&mut self) -> crate::Result<()>;\n}\n\nimpl<B: Buf> SendStreamExt for SendStream<SendBuf<B>> {\n    fn on_user_err<E>(&mut self, err: E) -> crate::Error\n    where\n        E: Into<Box<dyn std::error::Error + Send + Sync>>,\n    {\n        let err = crate::Error::new_user_body(err);\n        debug!(\"send body user stream error: {}\", err);\n        self.send_reset(err.h2_reason());\n        err\n    }\n\n    fn send_eos_frame(&mut self) -> crate::Result<()> {\n        trace!(\"send body eos\");\n        self.send_data(SendBuf::None, true)\n            .map_err(crate::Error::new_body_write)\n    }\n}\n\n#[repr(usize)]\nenum SendBuf<B> {\n    Buf(B),\n    Cursor(Cursor<Box<[u8]>>),\n    None,\n}\n\nimpl<B: Buf> Buf for SendBuf<B> {\n    #[inline]\n    fn remaining(&self) -> usize {\n        match *self {\n            Self::Buf(ref b) => b.remaining(),\n            Self::Cursor(ref c) => Buf::remaining(c),\n            Self::None => 0,\n        }\n    }\n\n    #[inline]\n    fn chunk(&self) -> &[u8] {\n        match *self {\n            Self::Buf(ref b) => b.chunk(),\n            Self::Cursor(ref c) => c.chunk(),\n            Self::None => &[],\n        }\n    }\n\n    #[inline]\n    fn advance(&mut self, cnt: usize) {\n        match *self {\n            Self::Buf(ref mut b) => b.advance(cnt),\n            Self::Cursor(ref mut c) => c.advance(cnt),\n            Self::None => {}\n        }\n    }\n\n    fn chunks_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {\n        match *self {\n            Self::Buf(ref b) => b.chunks_vectored(dst),\n            Self::Cursor(ref c) => c.chunks_vectored(dst),\n            Self::None => 0,\n        }\n    }\n}\n"
  },
  {
    "path": "src/proto/h2/ping.rs",
    "content": "//! HTTP2 Ping usage\n//!\n//! hyper uses HTTP2 pings for two purposes:\n//!\n//! 1. Adaptive flow control using BDP\n//! 2. Connection keep-alive\n//!\n//! Both cases are optional.\n//!\n//! # BDP Algorithm\n//!\n//! 1. When receiving a DATA frame, if a BDP ping isn't outstanding:\n//!    1a. Record current time.\n//!    1b. Send a BDP ping.\n//! 2. Increment the number of received bytes.\n//! 3. When the BDP ping ack is received:\n//!    3a. Record duration from sent time.\n//!    3b. Merge RTT with a running average.\n//!    3c. Calculate bdp as bytes/rtt.\n//!    3d. If bdp is over 2/3 max, set new max to bdp and update windows.\n\nuse std::fmt;\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::sync::{Arc, Mutex};\nuse std::task::{self, Poll};\nuse std::time::{Duration, Instant};\n\nuse h2::{Ping, PingPong};\n\nuse crate::common::time::Time;\nuse crate::rt::Sleep;\n\ntype WindowSize = u32;\n\npub(super) fn disabled() -> Recorder {\n    Recorder { shared: None }\n}\n\npub(super) fn channel(ping_pong: PingPong, config: Config, timer: Time) -> (Recorder, Ponger) {\n    debug_assert!(\n        config.is_enabled(),\n        \"ping channel requires bdp or keep-alive config\",\n    );\n\n    let bdp = config.bdp_initial_window.map(|wnd| Bdp {\n        bdp: wnd,\n        max_bandwidth: 0.0,\n        rtt: 0.0,\n        ping_delay: Duration::from_millis(100),\n        stable_count: 0,\n    });\n\n    let now = timer.now();\n\n    let (bytes, next_bdp_at) = if bdp.is_some() {\n        (Some(0), Some(now))\n    } else {\n        (None, None)\n    };\n\n    let keep_alive = config.keep_alive_interval.map(|interval| KeepAlive {\n        interval,\n        timeout: config.keep_alive_timeout,\n        while_idle: config.keep_alive_while_idle,\n        sleep: timer.sleep(interval),\n        state: KeepAliveState::Init,\n        timer: timer.clone(),\n    });\n\n    let last_read_at = keep_alive.as_ref().map(|_| now);\n\n    let shared = Arc::new(Mutex::new(Shared {\n        bytes,\n        last_read_at,\n        is_keep_alive_timed_out: false,\n        ping_pong,\n        ping_sent_at: None,\n        next_bdp_at,\n        timer,\n    }));\n\n    (\n        Recorder {\n            shared: Some(shared.clone()),\n        },\n        Ponger {\n            bdp,\n            keep_alive,\n            shared,\n        },\n    )\n}\n\n#[derive(Clone)]\npub(super) struct Config {\n    pub(super) bdp_initial_window: Option<WindowSize>,\n    /// If no frames are received in this amount of time, a PING frame is sent.\n    pub(super) keep_alive_interval: Option<Duration>,\n    /// After sending a keepalive PING, the connection will be closed if\n    /// a pong is not received in this amount of time.\n    pub(super) keep_alive_timeout: Duration,\n    /// If true, sends pings even when there are no active streams.\n    pub(super) keep_alive_while_idle: bool,\n}\n\n#[derive(Clone)]\npub(crate) struct Recorder {\n    shared: Option<Arc<Mutex<Shared>>>,\n}\n\npub(super) struct Ponger {\n    bdp: Option<Bdp>,\n    keep_alive: Option<KeepAlive>,\n    shared: Arc<Mutex<Shared>>,\n}\n\nstruct Shared {\n    ping_pong: PingPong,\n    ping_sent_at: Option<Instant>,\n\n    // bdp\n    /// If `Some`, bdp is enabled, and this tracks how many bytes have been\n    /// read during the current sample.\n    bytes: Option<usize>,\n    /// We delay a variable amount of time between BDP pings. This allows us\n    /// to send less pings as the bandwidth stabilizes.\n    next_bdp_at: Option<Instant>,\n\n    // keep-alive\n    /// If `Some`, keep-alive is enabled, and the Instant is how long ago\n    /// the connection read the last frame.\n    last_read_at: Option<Instant>,\n\n    is_keep_alive_timed_out: bool,\n    timer: Time,\n}\n\nstruct Bdp {\n    /// Current BDP in bytes\n    bdp: u32,\n    /// Largest bandwidth we've seen so far.\n    max_bandwidth: f64,\n    /// Round trip time in seconds\n    rtt: f64,\n    /// Delay the next ping by this amount.\n    ///\n    /// This will change depending on how stable the current bandwidth is.\n    ping_delay: Duration,\n    /// The count of ping round trips where BDP has stayed the same.\n    stable_count: u32,\n}\n\nstruct KeepAlive {\n    /// If no frames are received in this amount of time, a PING frame is sent.\n    interval: Duration,\n    /// After sending a keepalive PING, the connection will be closed if\n    /// a pong is not received in this amount of time.\n    timeout: Duration,\n    /// If true, sends pings even when there are no active streams.\n    while_idle: bool,\n    state: KeepAliveState,\n    sleep: Pin<Box<dyn Sleep>>,\n    timer: Time,\n}\n\nenum KeepAliveState {\n    Init,\n    Scheduled(Instant),\n    PingSent,\n}\n\npub(super) enum Ponged {\n    SizeUpdate(WindowSize),\n    KeepAliveTimedOut,\n}\n\n#[derive(Debug)]\npub(super) struct KeepAliveTimedOut;\n\n// ===== impl Config =====\n\nimpl Config {\n    pub(super) fn is_enabled(&self) -> bool {\n        self.bdp_initial_window.is_some() || self.keep_alive_interval.is_some()\n    }\n}\n\n// ===== impl Recorder =====\n\nimpl Recorder {\n    pub(crate) fn record_data(&self, len: usize) {\n        let shared = if let Some(ref shared) = self.shared {\n            shared\n        } else {\n            return;\n        };\n\n        let mut locked = shared.lock().unwrap();\n\n        locked.update_last_read_at();\n\n        // are we ready to send another bdp ping?\n        // if not, we don't need to record bytes either\n\n        if let Some(ref next_bdp_at) = locked.next_bdp_at {\n            if locked.timer.now() < *next_bdp_at {\n                return;\n            } else {\n                locked.next_bdp_at = None;\n            }\n        }\n\n        if let Some(ref mut bytes) = locked.bytes {\n            *bytes += len;\n        } else {\n            // no need to send bdp ping if bdp is disabled\n            return;\n        }\n\n        if !locked.is_ping_sent() {\n            locked.send_ping();\n        }\n    }\n\n    pub(crate) fn record_non_data(&self) {\n        let shared = if let Some(ref shared) = self.shared {\n            shared\n        } else {\n            return;\n        };\n\n        let mut locked = shared.lock().unwrap();\n\n        locked.update_last_read_at();\n    }\n\n    /// If the incoming stream is already closed, convert self into\n    /// a disabled reporter.\n    #[cfg(feature = \"client\")]\n    pub(super) fn for_stream(self, stream: &h2::RecvStream) -> Self {\n        if stream.is_end_stream() {\n            disabled()\n        } else {\n            self\n        }\n    }\n\n    pub(super) fn ensure_not_timed_out(&self) -> crate::Result<()> {\n        if let Some(ref shared) = self.shared {\n            let locked = shared.lock().unwrap();\n            if locked.is_keep_alive_timed_out {\n                return Err(KeepAliveTimedOut.crate_error());\n            }\n        }\n\n        // else\n        Ok(())\n    }\n}\n\n// ===== impl Ponger =====\n\nimpl Ponger {\n    pub(super) fn poll(&mut self, cx: &mut task::Context<'_>) -> Poll<Ponged> {\n        let mut locked = self.shared.lock().unwrap();\n        let now = locked.timer.now(); // hoping this is fine to move within the lock\n        let is_idle = self.is_idle();\n\n        if let Some(ref mut ka) = self.keep_alive {\n            ka.maybe_schedule(is_idle, &locked);\n            ka.maybe_ping(cx, is_idle, &mut locked);\n        }\n\n        if !locked.is_ping_sent() {\n            // XXX: this doesn't register a waker...?\n            return Poll::Pending;\n        }\n\n        match locked.ping_pong.poll_pong(cx) {\n            Poll::Ready(Ok(_pong)) => {\n                let start = locked\n                    .ping_sent_at\n                    .expect(\"pong received implies ping_sent_at\");\n                locked.ping_sent_at = None;\n                let rtt = now - start;\n                trace!(\"recv pong\");\n\n                if let Some(ref mut ka) = self.keep_alive {\n                    locked.update_last_read_at();\n                    ka.maybe_schedule(is_idle, &locked);\n                    ka.maybe_ping(cx, is_idle, &mut locked);\n                }\n\n                if let Some(ref mut bdp) = self.bdp {\n                    let bytes = locked.bytes.expect(\"bdp enabled implies bytes\");\n                    locked.bytes = Some(0); // reset\n                    trace!(\"received BDP ack; bytes = {}, rtt = {:?}\", bytes, rtt);\n\n                    let update = bdp.calculate(bytes, rtt);\n                    locked.next_bdp_at = Some(now + bdp.ping_delay);\n                    if let Some(update) = update {\n                        return Poll::Ready(Ponged::SizeUpdate(update));\n                    }\n                }\n            }\n            Poll::Ready(Err(_e)) => {\n                debug!(\"pong error: {}\", _e);\n            }\n            Poll::Pending => {\n                if let Some(ref mut ka) = self.keep_alive {\n                    if let Err(KeepAliveTimedOut) = ka.maybe_timeout(cx) {\n                        self.keep_alive = None;\n                        locked.is_keep_alive_timed_out = true;\n                        return Poll::Ready(Ponged::KeepAliveTimedOut);\n                    }\n                }\n            }\n        }\n\n        // XXX: this doesn't register a waker...?\n        Poll::Pending\n    }\n\n    fn is_idle(&self) -> bool {\n        Arc::strong_count(&self.shared) <= 2\n    }\n}\n\n// ===== impl Shared =====\n\nimpl Shared {\n    fn send_ping(&mut self) {\n        match self.ping_pong.send_ping(Ping::opaque()) {\n            Ok(()) => {\n                self.ping_sent_at = Some(self.timer.now());\n                trace!(\"sent ping\");\n            }\n            Err(_err) => {\n                debug!(\"error sending ping: {}\", _err);\n            }\n        }\n    }\n\n    fn is_ping_sent(&self) -> bool {\n        self.ping_sent_at.is_some()\n    }\n\n    fn update_last_read_at(&mut self) {\n        if self.last_read_at.is_some() {\n            self.last_read_at = Some(self.timer.now());\n        }\n    }\n\n    fn last_read_at(&self) -> Instant {\n        self.last_read_at.expect(\"keep_alive expects last_read_at\")\n    }\n}\n\n// ===== impl Bdp =====\n\n/// Any higher than this likely will be hitting the TCP flow control.\nconst BDP_LIMIT: usize = 1024 * 1024 * 16;\n\nimpl Bdp {\n    fn calculate(&mut self, bytes: usize, rtt: Duration) -> Option<WindowSize> {\n        // No need to do any math if we're at the limit.\n        if self.bdp as usize == BDP_LIMIT {\n            self.stabilize_delay();\n            return None;\n        }\n\n        // average the rtt\n        let rtt = seconds(rtt);\n        if self.rtt == 0.0 {\n            // First sample means rtt is first rtt.\n            self.rtt = rtt;\n        } else {\n            // Weigh this rtt as 1/8 for a moving average.\n            self.rtt += (rtt - self.rtt) * 0.125;\n        }\n\n        // calculate the current bandwidth\n        let bw = (bytes as f64) / (self.rtt * 1.5);\n        trace!(\"current bandwidth = {:.1}B/s\", bw);\n\n        if bw < self.max_bandwidth {\n            // not a faster bandwidth, so don't update\n            self.stabilize_delay();\n            return None;\n        } else {\n            self.max_bandwidth = bw;\n        }\n\n        // if the current `bytes` sample is at least 2/3 the previous\n        // bdp, increase to double the current sample.\n        if bytes >= self.bdp as usize * 2 / 3 {\n            self.bdp = (bytes * 2).min(BDP_LIMIT) as WindowSize;\n            trace!(\"BDP increased to {}\", self.bdp);\n\n            self.stable_count = 0;\n            self.ping_delay /= 2;\n            Some(self.bdp)\n        } else {\n            self.stabilize_delay();\n            None\n        }\n    }\n\n    fn stabilize_delay(&mut self) {\n        if self.ping_delay < Duration::from_secs(10) {\n            self.stable_count += 1;\n\n            if self.stable_count >= 2 {\n                self.ping_delay *= 4;\n                self.stable_count = 0;\n            }\n        }\n    }\n}\n\nfn seconds(dur: Duration) -> f64 {\n    const NANOS_PER_SEC: f64 = 1_000_000_000.0;\n    let secs = dur.as_secs() as f64;\n    secs + (dur.subsec_nanos() as f64) / NANOS_PER_SEC\n}\n\n// ===== impl KeepAlive =====\n\nimpl KeepAlive {\n    fn maybe_schedule(&mut self, is_idle: bool, shared: &Shared) {\n        match self.state {\n            KeepAliveState::Init => {\n                if !self.while_idle && is_idle {\n                    return;\n                }\n\n                self.schedule(shared);\n            }\n            KeepAliveState::PingSent => {\n                if shared.is_ping_sent() {\n                    return;\n                }\n                self.schedule(shared);\n            }\n            KeepAliveState::Scheduled(..) => (),\n        }\n    }\n\n    fn schedule(&mut self, shared: &Shared) {\n        let interval = shared.last_read_at() + self.interval;\n        self.state = KeepAliveState::Scheduled(interval);\n        self.timer.reset(&mut self.sleep, interval);\n    }\n\n    fn maybe_ping(&mut self, cx: &mut task::Context<'_>, is_idle: bool, shared: &mut Shared) {\n        match self.state {\n            KeepAliveState::Scheduled(at) => {\n                if Pin::new(&mut self.sleep).poll(cx).is_pending() {\n                    return;\n                }\n                // check if we've received a frame while we were scheduled\n                if shared.last_read_at() + self.interval > at {\n                    self.state = KeepAliveState::Init;\n                    cx.waker().wake_by_ref(); // schedule us again\n                    return;\n                }\n                if !self.while_idle && is_idle {\n                    trace!(\"keep-alive no need to ping when idle and while_idle=false\");\n                    return;\n                }\n                trace!(\"keep-alive interval ({:?}) reached\", self.interval);\n                shared.send_ping();\n                self.state = KeepAliveState::PingSent;\n                let timeout = self.timer.now() + self.timeout;\n                self.timer.reset(&mut self.sleep, timeout);\n            }\n            KeepAliveState::Init | KeepAliveState::PingSent => (),\n        }\n    }\n\n    fn maybe_timeout(&mut self, cx: &mut task::Context<'_>) -> Result<(), KeepAliveTimedOut> {\n        match self.state {\n            KeepAliveState::PingSent => {\n                if Pin::new(&mut self.sleep).poll(cx).is_pending() {\n                    return Ok(());\n                }\n                trace!(\"keep-alive timeout ({:?}) reached\", self.timeout);\n                Err(KeepAliveTimedOut)\n            }\n            KeepAliveState::Init | KeepAliveState::Scheduled(..) => Ok(()),\n        }\n    }\n}\n\n// ===== impl KeepAliveTimedOut =====\n\nimpl KeepAliveTimedOut {\n    pub(super) fn crate_error(self) -> crate::Error {\n        crate::Error::new(crate::error::Kind::Http2).with(self)\n    }\n}\n\nimpl fmt::Display for KeepAliveTimedOut {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"keep-alive timed out\")\n    }\n}\n\nimpl std::error::Error for KeepAliveTimedOut {\n    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {\n        Some(&crate::error::TimedOut)\n    }\n}\n"
  },
  {
    "path": "src/proto/h2/server.rs",
    "content": "use std::error::Error as StdError;\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\nuse std::time::Duration;\n\nuse bytes::Bytes;\nuse futures_core::ready;\nuse h2::server::{Connection, Handshake, SendResponse};\nuse h2::{Reason, RecvStream};\nuse http::{Method, Request};\nuse pin_project_lite::pin_project;\n\nuse super::{ping, PipeToSendStream, SendBuf};\nuse crate::body::{Body, Incoming as IncomingBody};\nuse crate::common::date;\nuse crate::common::io::Compat;\nuse crate::common::time::Time;\nuse crate::ext::Protocol;\nuse crate::headers;\nuse crate::proto::h2::ping::Recorder;\nuse crate::proto::Dispatched;\nuse crate::rt::bounds::{Http2ServerConnExec, Http2UpgradedExec};\nuse crate::rt::{Read, Write};\nuse crate::service::HttpService;\n\nuse crate::upgrade::{OnUpgrade, Pending, Upgraded};\nuse crate::Response;\n\n// Our defaults are chosen for the \"majority\" case, which usually are not\n// resource constrained, and so the spec default of 64kb can be too limiting\n// for performance.\n//\n// At the same time, a server more often has multiple clients connected, and\n// so is more likely to use more resources than a client would.\nconst DEFAULT_CONN_WINDOW: u32 = 1024 * 1024; // 1mb\nconst DEFAULT_STREAM_WINDOW: u32 = 1024 * 1024; // 1mb\nconst DEFAULT_MAX_FRAME_SIZE: u32 = 1024 * 16; // 16kb\nconst DEFAULT_MAX_SEND_BUF_SIZE: usize = 1024 * 400; // 400kb\nconst DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE: u32 = 1024 * 16; // 16kb\nconst DEFAULT_MAX_LOCAL_ERROR_RESET_STREAMS: usize = 1024;\n\n#[derive(Clone, Debug)]\npub(crate) struct Config {\n    pub(crate) adaptive_window: bool,\n    pub(crate) initial_conn_window_size: u32,\n    pub(crate) initial_stream_window_size: u32,\n    pub(crate) max_frame_size: u32,\n    pub(crate) enable_connect_protocol: bool,\n    pub(crate) max_concurrent_streams: Option<u32>,\n    pub(crate) max_pending_accept_reset_streams: Option<usize>,\n    pub(crate) max_local_error_reset_streams: Option<usize>,\n    pub(crate) keep_alive_interval: Option<Duration>,\n    pub(crate) keep_alive_timeout: Duration,\n    pub(crate) max_send_buffer_size: usize,\n    pub(crate) max_header_list_size: u32,\n    pub(crate) date_header: bool,\n}\n\nimpl Default for Config {\n    fn default() -> Config {\n        Config {\n            adaptive_window: false,\n            initial_conn_window_size: DEFAULT_CONN_WINDOW,\n            initial_stream_window_size: DEFAULT_STREAM_WINDOW,\n            max_frame_size: DEFAULT_MAX_FRAME_SIZE,\n            enable_connect_protocol: false,\n            max_concurrent_streams: Some(200),\n            max_pending_accept_reset_streams: None,\n            max_local_error_reset_streams: Some(DEFAULT_MAX_LOCAL_ERROR_RESET_STREAMS),\n            keep_alive_interval: None,\n            keep_alive_timeout: Duration::from_secs(20),\n            max_send_buffer_size: DEFAULT_MAX_SEND_BUF_SIZE,\n            max_header_list_size: DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE,\n            date_header: true,\n        }\n    }\n}\n\npin_project! {\n    pub(crate) struct Server<T, S, B, E>\n    where\n        S: HttpService<IncomingBody>,\n        B: Body,\n    {\n        exec: E,\n        timer: Time,\n        service: S,\n        state: State<T, B>,\n        date_header: bool,\n        close_pending: bool\n    }\n}\n\nenum State<T, B>\nwhere\n    B: Body,\n{\n    Handshaking {\n        ping_config: ping::Config,\n        hs: Handshake<Compat<T>, SendBuf<B::Data>>,\n    },\n    Serving(Serving<T, B>),\n}\n\nstruct Serving<T, B>\nwhere\n    B: Body,\n{\n    ping: Option<(ping::Recorder, ping::Ponger)>,\n    conn: Connection<Compat<T>, SendBuf<B::Data>>,\n    closing: Option<crate::Error>,\n    date_header: bool,\n}\n\nimpl<T, S, B, E> Server<T, S, B, E>\nwhere\n    T: Read + Write + Unpin,\n    S: HttpService<IncomingBody, ResBody = B>,\n    S::Error: Into<Box<dyn StdError + Send + Sync>>,\n    B: Body + 'static,\n    E: Http2ServerConnExec<S::Future, B>,\n{\n    pub(crate) fn new(\n        io: T,\n        service: S,\n        config: &Config,\n        exec: E,\n        timer: Time,\n    ) -> Server<T, S, B, E> {\n        let mut builder = h2::server::Builder::default();\n        builder\n            .initial_window_size(config.initial_stream_window_size)\n            .initial_connection_window_size(config.initial_conn_window_size)\n            .max_frame_size(config.max_frame_size)\n            .max_header_list_size(config.max_header_list_size)\n            .max_local_error_reset_streams(config.max_local_error_reset_streams)\n            .max_send_buffer_size(config.max_send_buffer_size);\n        if let Some(max) = config.max_concurrent_streams {\n            builder.max_concurrent_streams(max);\n        }\n        if let Some(max) = config.max_pending_accept_reset_streams {\n            builder.max_pending_accept_reset_streams(max);\n        }\n        if config.enable_connect_protocol {\n            builder.enable_connect_protocol();\n        }\n        let handshake = builder.handshake(Compat::new(io));\n\n        let bdp = if config.adaptive_window {\n            Some(config.initial_stream_window_size)\n        } else {\n            None\n        };\n\n        let ping_config = ping::Config {\n            bdp_initial_window: bdp,\n            keep_alive_interval: config.keep_alive_interval,\n            keep_alive_timeout: config.keep_alive_timeout,\n            // If keep-alive is enabled for servers, always enabled while\n            // idle, so it can more aggressively close dead connections.\n            keep_alive_while_idle: true,\n        };\n\n        Server {\n            exec,\n            timer,\n            state: State::Handshaking {\n                ping_config,\n                hs: handshake,\n            },\n            service,\n            date_header: config.date_header,\n            close_pending: false,\n        }\n    }\n\n    pub(crate) fn graceful_shutdown(&mut self) {\n        trace!(\"graceful_shutdown\");\n        match self.state {\n            State::Handshaking { .. } => {\n                self.close_pending = true;\n            }\n            State::Serving(ref mut srv) => {\n                if srv.closing.is_none() {\n                    srv.conn.graceful_shutdown();\n                }\n            }\n        }\n    }\n}\n\nimpl<T, S, B, E> Future for Server<T, S, B, E>\nwhere\n    T: Read + Write + Unpin,\n    S: HttpService<IncomingBody, ResBody = B>,\n    S::Error: Into<Box<dyn StdError + Send + Sync>>,\n    B: Body + 'static,\n    E: Http2ServerConnExec<S::Future, B>,\n{\n    type Output = crate::Result<Dispatched>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let me = &mut *self;\n        loop {\n            let next = match me.state {\n                State::Handshaking {\n                    ref mut hs,\n                    ref ping_config,\n                } => {\n                    let mut conn = ready!(Pin::new(hs).poll(cx).map_err(crate::Error::new_h2))?;\n                    let ping = if ping_config.is_enabled() {\n                        let pp = conn.ping_pong().expect(\"conn.ping_pong\");\n                        Some(ping::channel(pp, ping_config.clone(), me.timer.clone()))\n                    } else {\n                        None\n                    };\n                    State::Serving(Serving {\n                        ping,\n                        conn,\n                        closing: None,\n                        date_header: me.date_header,\n                    })\n                }\n                State::Serving(ref mut srv) => {\n                    // graceful_shutdown was called before handshaking finished,\n                    if me.close_pending && srv.closing.is_none() {\n                        srv.conn.graceful_shutdown();\n                    }\n                    ready!(srv.poll_server(cx, &mut me.service, &mut me.exec))?;\n                    return Poll::Ready(Ok(Dispatched::Shutdown));\n                }\n            };\n            me.state = next;\n        }\n    }\n}\n\nimpl<T, B> Serving<T, B>\nwhere\n    T: Read + Write + Unpin,\n    B: Body + 'static,\n{\n    fn poll_server<S, E>(\n        &mut self,\n        cx: &mut Context<'_>,\n        service: &mut S,\n        exec: &mut E,\n    ) -> Poll<crate::Result<()>>\n    where\n        S: HttpService<IncomingBody, ResBody = B>,\n        S::Error: Into<Box<dyn StdError + Send + Sync>>,\n        E: Http2ServerConnExec<S::Future, B>,\n    {\n        if self.closing.is_none() {\n            loop {\n                self.poll_ping(cx);\n\n                match ready!(self.conn.poll_accept(cx)) {\n                    Some(Ok((req, mut respond))) => {\n                        trace!(\"incoming request\");\n                        let content_length = headers::content_length_parse_all(req.headers());\n                        let ping = self\n                            .ping\n                            .as_ref()\n                            .map(|ping| ping.0.clone())\n                            .unwrap_or_else(ping::disabled);\n\n                        // Record the headers received\n                        ping.record_non_data();\n\n                        let is_connect = req.method() == Method::CONNECT;\n                        let (mut parts, stream) = req.into_parts();\n                        let (mut req, connect_parts) = if !is_connect {\n                            (\n                                Request::from_parts(\n                                    parts,\n                                    IncomingBody::h2(stream, content_length.into(), ping),\n                                ),\n                                None,\n                            )\n                        } else {\n                            if content_length.map_or(false, |len| len != 0) {\n                                warn!(\"h2 connect request with non-zero body not supported\");\n                                respond.send_reset(h2::Reason::INTERNAL_ERROR);\n                                return Poll::Ready(Ok(()));\n                            }\n                            let (pending, upgrade) = crate::upgrade::pending();\n                            debug_assert!(parts.extensions.get::<OnUpgrade>().is_none());\n                            parts.extensions.insert(upgrade);\n                            (\n                                Request::from_parts(parts, IncomingBody::empty()),\n                                Some(ConnectParts {\n                                    pending,\n                                    ping,\n                                    recv_stream: stream,\n                                }),\n                            )\n                        };\n\n                        if let Some(protocol) = req.extensions_mut().remove::<h2::ext::Protocol>() {\n                            req.extensions_mut().insert(Protocol::from_inner(protocol));\n                        }\n\n                        let fut = H2Stream::new(\n                            service.call(req),\n                            connect_parts,\n                            respond,\n                            self.date_header,\n                            exec.clone(),\n                        );\n\n                        exec.execute_h2stream(fut);\n                    }\n                    Some(Err(e)) => {\n                        return Poll::Ready(Err(crate::Error::new_h2(e)));\n                    }\n                    None => {\n                        // no more incoming streams...\n                        if let Some((ref ping, _)) = self.ping {\n                            ping.ensure_not_timed_out()?;\n                        }\n\n                        trace!(\"incoming connection complete\");\n                        return Poll::Ready(Ok(()));\n                    }\n                }\n            }\n        }\n\n        debug_assert!(\n            self.closing.is_some(),\n            \"poll_server broke loop without closing\"\n        );\n\n        ready!(self.conn.poll_closed(cx).map_err(crate::Error::new_h2))?;\n\n        Poll::Ready(Err(self.closing.take().expect(\"polled after error\")))\n    }\n\n    fn poll_ping(&mut self, cx: &mut Context<'_>) {\n        if let Some((_, ref mut estimator)) = self.ping {\n            match estimator.poll(cx) {\n                Poll::Ready(ping::Ponged::SizeUpdate(wnd)) => {\n                    self.conn.set_target_window_size(wnd);\n                    let _ = self.conn.set_initial_window_size(wnd);\n                }\n                Poll::Ready(ping::Ponged::KeepAliveTimedOut) => {\n                    debug!(\"keep-alive timed out, closing connection\");\n                    self.conn.abrupt_shutdown(h2::Reason::NO_ERROR);\n                }\n                Poll::Pending => {}\n            }\n        }\n    }\n}\n\npin_project! {\n    #[allow(missing_debug_implementations)]\n    pub struct H2Stream<F, B, E>\n    where\n        B: Body,\n    {\n        reply: SendResponse<SendBuf<B::Data>>,\n        #[pin]\n        state: H2StreamState<F, B>,\n        date_header: bool,\n        exec: E,\n    }\n}\n\npin_project! {\n    #[project = H2StreamStateProj]\n    enum H2StreamState<F, B>\n    where\n        B: Body,\n    {\n        Service {\n            #[pin]\n            fut: F,\n            connect_parts: Option<ConnectParts>,\n        },\n        Body {\n            #[pin]\n            pipe: PipeToSendStream<B>,\n        },\n    }\n}\n\nstruct ConnectParts {\n    pending: Pending,\n    ping: Recorder,\n    recv_stream: RecvStream,\n}\n\nimpl<F, B, E> H2Stream<F, B, E>\nwhere\n    B: Body,\n{\n    fn new(\n        fut: F,\n        connect_parts: Option<ConnectParts>,\n        respond: SendResponse<SendBuf<B::Data>>,\n        date_header: bool,\n        exec: E,\n    ) -> H2Stream<F, B, E> {\n        H2Stream {\n            reply: respond,\n            state: H2StreamState::Service { fut, connect_parts },\n            date_header,\n            exec,\n        }\n    }\n}\n\nmacro_rules! reply {\n    ($me:expr, $res:expr, $eos:expr) => {{\n        match $me.reply.send_response($res, $eos) {\n            Ok(tx) => tx,\n            Err(e) => {\n                debug!(\"send response error: {}\", e);\n                $me.reply.send_reset(Reason::INTERNAL_ERROR);\n                return Poll::Ready(Err(crate::Error::new_h2(e)));\n            }\n        }\n    }};\n}\n\nimpl<F, B, Ex, E> H2Stream<F, B, Ex>\nwhere\n    F: Future<Output = Result<Response<B>, E>>,\n    B: Body,\n    B::Data: 'static,\n    B::Error: Into<Box<dyn StdError + Send + Sync>>,\n    Ex: Http2UpgradedExec<B::Data>,\n    E: Into<Box<dyn StdError + Send + Sync>>,\n{\n    fn poll2(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<crate::Result<()>> {\n        let mut me = self.as_mut().project();\n        loop {\n            let next = match me.state.as_mut().project() {\n                H2StreamStateProj::Service {\n                    fut: h,\n                    connect_parts,\n                } => {\n                    let res = match h.poll(cx) {\n                        Poll::Ready(Ok(r)) => r,\n                        Poll::Pending => {\n                            // Response is not yet ready, so we want to check if the client has sent a\n                            // RST_STREAM frame which would cancel the current request.\n                            if let Poll::Ready(reason) =\n                                me.reply.poll_reset(cx).map_err(crate::Error::new_h2)?\n                            {\n                                debug!(\"stream received RST_STREAM: {:?}\", reason);\n                                return Poll::Ready(Err(crate::Error::new_h2(reason.into())));\n                            }\n                            return Poll::Pending;\n                        }\n                        Poll::Ready(Err(e)) => {\n                            let err = crate::Error::new_user_service(e);\n                            warn!(\"http2 service errored: {}\", err);\n                            me.reply.send_reset(err.h2_reason());\n                            return Poll::Ready(Err(err));\n                        }\n                    };\n\n                    let (head, body) = res.into_parts();\n                    let mut res = ::http::Response::from_parts(head, ());\n                    super::strip_connection_headers(res.headers_mut(), false);\n\n                    // set Date header if it isn't already set if instructed\n                    if *me.date_header {\n                        res.headers_mut()\n                            .entry(::http::header::DATE)\n                            .or_insert_with(date::update_and_header_value);\n                    }\n\n                    if let Some(connect_parts) = connect_parts.take() {\n                        if res.status().is_success() {\n                            if headers::content_length_parse_all(res.headers())\n                                .map_or(false, |len| len != 0)\n                            {\n                                warn!(\"h2 successful response to CONNECT request with body not supported\");\n                                me.reply.send_reset(h2::Reason::INTERNAL_ERROR);\n                                return Poll::Ready(Err(crate::Error::new_user_header()));\n                            }\n                            if res\n                                .headers_mut()\n                                .remove(::http::header::CONTENT_LENGTH)\n                                .is_some()\n                            {\n                                warn!(\"successful response to CONNECT request disallows content-length header\");\n                            }\n                            let send_stream = reply!(me, res, false);\n                            let (h2_up, up_task) = super::upgrade::pair(\n                                send_stream,\n                                connect_parts.recv_stream,\n                                connect_parts.ping,\n                            );\n                            connect_parts\n                                .pending\n                                .fulfill(Upgraded::new(h2_up, Bytes::new()));\n                            self.exec.execute_upgrade(up_task);\n                            return Poll::Ready(Ok(()));\n                        }\n                    }\n\n                    if !body.is_end_stream() {\n                        // automatically set Content-Length from body...\n                        if let Some(len) = body.size_hint().exact() {\n                            headers::set_content_length_if_missing(res.headers_mut(), len);\n                        }\n\n                        let body_tx = reply!(me, res, false);\n                        H2StreamState::Body {\n                            pipe: PipeToSendStream::new(body, body_tx),\n                        }\n                    } else {\n                        reply!(me, res, true);\n                        return Poll::Ready(Ok(()));\n                    }\n                }\n                H2StreamStateProj::Body { pipe } => {\n                    return pipe.poll(cx);\n                }\n            };\n            me.state.set(next);\n        }\n    }\n}\n\nimpl<F, B, Ex, E> Future for H2Stream<F, B, Ex>\nwhere\n    F: Future<Output = Result<Response<B>, E>>,\n    B: Body,\n    B::Data: 'static,\n    B::Error: Into<Box<dyn StdError + Send + Sync>>,\n    Ex: Http2UpgradedExec<B::Data>,\n    E: Into<Box<dyn StdError + Send + Sync>>,\n{\n    type Output = ();\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        self.poll2(cx).map(|res| {\n            if let Err(_e) = res {\n                debug!(\"stream error: {}\", _e);\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "src/proto/h2/upgrade.rs",
    "content": "use std::future::Future;\nuse std::io::Cursor;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse bytes::{Buf, Bytes};\nuse futures_channel::{mpsc, oneshot};\nuse futures_core::{ready, Stream};\nuse h2::{Reason, RecvStream, SendStream};\nuse pin_project_lite::pin_project;\n\nuse super::ping::Recorder;\nuse super::SendBuf;\nuse crate::rt::{Read, ReadBufCursor, Write};\n\npub(super) fn pair<B>(\n    send_stream: SendStream<SendBuf<B>>,\n    recv_stream: RecvStream,\n    ping: Recorder,\n) -> (H2Upgraded, UpgradedSendStreamTask<B>) {\n    let (tx, rx) = mpsc::channel(1);\n    let (error_tx, error_rx) = oneshot::channel();\n\n    (\n        H2Upgraded {\n            send_stream: UpgradedSendStreamBridge { tx, error_rx },\n            recv_stream,\n            ping,\n            buf: Bytes::new(),\n        },\n        UpgradedSendStreamTask {\n            h2_tx: send_stream,\n            rx,\n            error_tx: Some(error_tx),\n        },\n    )\n}\n\npub(super) struct H2Upgraded {\n    ping: Recorder,\n    send_stream: UpgradedSendStreamBridge,\n    recv_stream: RecvStream,\n    buf: Bytes,\n}\n\nstruct UpgradedSendStreamBridge {\n    tx: mpsc::Sender<Cursor<Box<[u8]>>>,\n    error_rx: oneshot::Receiver<crate::Error>,\n}\n\npin_project! {\n    #[must_use = \"futures do nothing unless polled\"]\n    pub struct UpgradedSendStreamTask<B> {\n        #[pin]\n        h2_tx: SendStream<SendBuf<B>>,\n        #[pin]\n        rx: mpsc::Receiver<Cursor<Box<[u8]>>>,\n        error_tx: Option<oneshot::Sender<crate::Error>>,\n    }\n}\n\n// ===== impl UpgradedSendStreamTask =====\n\nimpl<B> UpgradedSendStreamTask<B>\nwhere\n    B: Buf,\n{\n    fn tick(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), crate::Error>> {\n        let mut me = self.project();\n\n        // this is a manual `select()` over 3 \"futures\", so we always need\n        // to be sure they are ready and/or we are waiting notification of\n        // one of the sides hanging up, so the task doesn't live around\n        // longer than it's meant to.\n        loop {\n            // we don't have the next chunk of data yet, so just reserve 1 byte to make\n            // sure there's some capacity available. h2 will handle the capacity management\n            // for the actual body chunk.\n            me.h2_tx.reserve_capacity(1);\n\n            if me.h2_tx.capacity() == 0 {\n                // poll_capacity oddly needs a loop\n                'capacity: loop {\n                    match me.h2_tx.poll_capacity(cx) {\n                        Poll::Ready(Some(Ok(0))) => {}\n                        Poll::Ready(Some(Ok(_))) => break,\n                        Poll::Ready(Some(Err(e))) => {\n                            return Poll::Ready(Err(crate::Error::new_body_write(e)))\n                        }\n                        Poll::Ready(None) => {\n                            // None means the stream is no longer in a\n                            // streaming state, we either finished it\n                            // somehow, or the remote reset us.\n                            return Poll::Ready(Err(crate::Error::new_body_write(\n                                \"send stream capacity unexpectedly closed\",\n                            )));\n                        }\n                        Poll::Pending => break 'capacity,\n                    }\n                }\n            }\n\n            match me.h2_tx.poll_reset(cx) {\n                Poll::Ready(Ok(reason)) => {\n                    trace!(\"stream received RST_STREAM: {:?}\", reason);\n                    return Poll::Ready(Err(crate::Error::new_body_write(::h2::Error::from(\n                        reason,\n                    ))));\n                }\n                Poll::Ready(Err(err)) => {\n                    return Poll::Ready(Err(crate::Error::new_body_write(err)))\n                }\n                Poll::Pending => (),\n            }\n\n            match me.rx.as_mut().poll_next(cx) {\n                Poll::Ready(Some(cursor)) => {\n                    me.h2_tx\n                        .send_data(SendBuf::Cursor(cursor), false)\n                        .map_err(crate::Error::new_body_write)?;\n                }\n                Poll::Ready(None) => {\n                    me.h2_tx\n                        .send_data(SendBuf::None, true)\n                        .map_err(crate::Error::new_body_write)?;\n                    return Poll::Ready(Ok(()));\n                }\n                Poll::Pending => {\n                    return Poll::Pending;\n                }\n            }\n        }\n    }\n}\n\nimpl<B> Future for UpgradedSendStreamTask<B>\nwhere\n    B: Buf,\n{\n    type Output = ();\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        match self.as_mut().tick(cx) {\n            Poll::Ready(Ok(())) => Poll::Ready(()),\n            Poll::Ready(Err(err)) => {\n                if let Some(tx) = self.error_tx.take() {\n                    let _oh_well = tx.send(err);\n                }\n                Poll::Ready(())\n            }\n            Poll::Pending => Poll::Pending,\n        }\n    }\n}\n\n// ===== impl H2Upgraded =====\n\nimpl Read for H2Upgraded {\n    fn poll_read(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        mut read_buf: ReadBufCursor<'_>,\n    ) -> Poll<Result<(), std::io::Error>> {\n        if self.buf.is_empty() {\n            self.buf = loop {\n                match ready!(self.recv_stream.poll_data(cx)) {\n                    None => return Poll::Ready(Ok(())),\n                    Some(Ok(buf)) if buf.is_empty() && !self.recv_stream.is_end_stream() => {\n                        continue\n                    }\n                    Some(Ok(buf)) => {\n                        self.ping.record_data(buf.len());\n                        break buf;\n                    }\n                    Some(Err(e)) => {\n                        return Poll::Ready(match e.reason() {\n                            Some(Reason::NO_ERROR) | Some(Reason::CANCEL) => Ok(()),\n                            Some(Reason::STREAM_CLOSED) => {\n                                Err(std::io::Error::new(std::io::ErrorKind::BrokenPipe, e))\n                            }\n                            _ => Err(h2_to_io_error(e)),\n                        })\n                    }\n                }\n            };\n        }\n        let cnt = std::cmp::min(self.buf.len(), read_buf.remaining());\n        read_buf.put_slice(&self.buf[..cnt]);\n        self.buf.advance(cnt);\n        let _ = self.recv_stream.flow_control().release_capacity(cnt);\n        Poll::Ready(Ok(()))\n    }\n}\n\nimpl Write for H2Upgraded {\n    fn poll_write(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<Result<usize, std::io::Error>> {\n        if buf.is_empty() {\n            return Poll::Ready(Ok(0));\n        }\n\n        match self.send_stream.tx.poll_ready(cx) {\n            Poll::Ready(Ok(())) => {}\n            Poll::Ready(Err(_task_dropped)) => {\n                // if the task dropped, check if there was an error\n                // otherwise i guess its a broken pipe\n                return match Pin::new(&mut self.send_stream.error_rx).poll(cx) {\n                    Poll::Ready(Ok(reason)) => Poll::Ready(Err(io_error(reason))),\n                    Poll::Ready(Err(_task_dropped)) => {\n                        Poll::Ready(Err(std::io::ErrorKind::BrokenPipe.into()))\n                    }\n                    Poll::Pending => Poll::Pending,\n                };\n            }\n            Poll::Pending => return Poll::Pending,\n        }\n\n        let n = buf.len();\n        match self.send_stream.tx.start_send(Cursor::new(buf.into())) {\n            Ok(()) => Poll::Ready(Ok(n)),\n            Err(_task_dropped) => {\n                // if the task dropped, check if there was an error\n                // otherwise i guess its a broken pipe\n                match Pin::new(&mut self.send_stream.error_rx).poll(cx) {\n                    Poll::Ready(Ok(reason)) => Poll::Ready(Err(io_error(reason))),\n                    Poll::Ready(Err(_task_dropped)) => {\n                        Poll::Ready(Err(std::io::ErrorKind::BrokenPipe.into()))\n                    }\n                    Poll::Pending => Poll::Pending,\n                }\n            }\n        }\n    }\n\n    fn poll_flush(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Result<(), std::io::Error>> {\n        match self.send_stream.tx.poll_ready(cx) {\n            Poll::Ready(Ok(())) => Poll::Ready(Ok(())),\n            Poll::Ready(Err(_task_dropped)) => {\n                // if the task dropped, check if there was an error\n                // otherwise it was a clean close\n                match Pin::new(&mut self.send_stream.error_rx).poll(cx) {\n                    Poll::Ready(Ok(reason)) => Poll::Ready(Err(io_error(reason))),\n                    Poll::Ready(Err(_task_dropped)) => Poll::Ready(Ok(())),\n                    Poll::Pending => Poll::Pending,\n                }\n            }\n            Poll::Pending => Poll::Pending,\n        }\n    }\n\n    fn poll_shutdown(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Result<(), std::io::Error>> {\n        self.send_stream.tx.close_channel();\n        match Pin::new(&mut self.send_stream.error_rx).poll(cx) {\n            Poll::Ready(Ok(reason)) => Poll::Ready(Err(io_error(reason))),\n            Poll::Ready(Err(_task_dropped)) => Poll::Ready(Ok(())),\n            Poll::Pending => Poll::Pending,\n        }\n    }\n}\n\nfn io_error(e: crate::Error) -> std::io::Error {\n    std::io::Error::new(std::io::ErrorKind::Other, e)\n}\n\nfn h2_to_io_error(e: h2::Error) -> std::io::Error {\n    if e.is_io() {\n        e.into_io().unwrap()\n    } else {\n        std::io::Error::new(std::io::ErrorKind::Other, e)\n    }\n}\n"
  },
  {
    "path": "src/proto/mod.rs",
    "content": "//! Pieces pertaining to the HTTP message protocol.\n\ncfg_feature! {\n    #![feature = \"http1\"]\n\n    pub(crate) mod h1;\n\n    pub(crate) use self::h1::Conn;\n\n    #[cfg(feature = \"client\")]\n    pub(crate) use self::h1::dispatch;\n    #[cfg(feature = \"server\")]\n    pub(crate) use self::h1::ServerTransaction;\n}\n\n#[cfg(feature = \"http2\")]\npub(crate) mod h2;\n\n/// An Incoming Message head. Includes request/status line, and headers.\n#[cfg(feature = \"http1\")]\n#[derive(Debug, Default)]\npub(crate) struct MessageHead<S> {\n    /// HTTP version of the message.\n    pub(crate) version: http::Version,\n    /// Subject (request line or status line) of Incoming message.\n    pub(crate) subject: S,\n    /// Headers of the Incoming message.\n    pub(crate) headers: http::HeaderMap,\n    /// Extensions.\n    extensions: http::Extensions,\n}\n\n/// An incoming request message.\n#[cfg(feature = \"http1\")]\npub(crate) type RequestHead = MessageHead<RequestLine>;\n\n#[derive(Debug, Default, PartialEq)]\n#[cfg(feature = \"http1\")]\npub(crate) struct RequestLine(pub(crate) http::Method, pub(crate) http::Uri);\n\n/// An incoming response message.\n#[cfg(all(feature = \"http1\", feature = \"client\"))]\npub(crate) type ResponseHead = MessageHead<http::StatusCode>;\n\n#[derive(Debug)]\n#[cfg(feature = \"http1\")]\npub(crate) enum BodyLength {\n    /// Content-Length\n    Known(u64),\n    /// Transfer-Encoding: chunked (if h1)\n    Unknown,\n}\n\n/// Status of when a Dispatcher future completes.\npub(crate) enum Dispatched {\n    /// Dispatcher completely shutdown connection.\n    Shutdown,\n    /// Dispatcher has pending upgrade, and so did not shutdown.\n    #[cfg(feature = \"http1\")]\n    Upgrade(crate::upgrade::Pending),\n}\n\n#[cfg(all(feature = \"client\", feature = \"http1\"))]\nimpl MessageHead<http::StatusCode> {\n    fn into_response<B>(self, body: B) -> http::Response<B> {\n        let mut res = http::Response::new(body);\n        *res.status_mut() = self.subject;\n        *res.headers_mut() = self.headers;\n        *res.version_mut() = self.version;\n        *res.extensions_mut() = self.extensions;\n        res\n    }\n}\n"
  },
  {
    "path": "src/rt/bounds.rs",
    "content": "//! Trait aliases\n//!\n//! Traits in this module ease setting bounds and usually automatically\n//! implemented by implementing another trait.\n\n#[cfg(all(feature = \"client\", feature = \"http2\"))]\npub use self::h2_client::Http2ClientConnExec;\n#[cfg(all(feature = \"server\", feature = \"http2\"))]\npub use self::h2_server::Http2ServerConnExec;\n\n#[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http2\"))]\npub(crate) use self::h2_common::Http2UpgradedExec;\n\n#[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http2\"))]\nmod h2_common {\n    use crate::proto::h2::upgrade::UpgradedSendStreamTask;\n    use crate::rt::Executor;\n\n    pub trait Http2UpgradedExec<B> {\n        #[doc(hidden)]\n        fn execute_upgrade(&self, fut: UpgradedSendStreamTask<B>);\n    }\n\n    #[doc(hidden)]\n    impl<E, B> Http2UpgradedExec<B> for E\n    where\n        E: Executor<UpgradedSendStreamTask<B>>,\n    {\n        fn execute_upgrade(&self, fut: UpgradedSendStreamTask<B>) {\n            self.execute(fut)\n        }\n    }\n}\n\n#[cfg(all(feature = \"client\", feature = \"http2\"))]\n#[cfg_attr(docsrs, doc(cfg(all(feature = \"client\", feature = \"http2\"))))]\nmod h2_client {\n    use std::{error::Error, future::Future};\n\n    use crate::rt::{Read, Write};\n    use crate::{proto::h2::client::H2ClientFuture, rt::Executor};\n\n    /// An executor to spawn http2 futures for the client.\n    ///\n    /// This trait is implemented for any type that implements [`Executor`]\n    /// trait for any future.\n    ///\n    /// This trait is sealed and cannot be implemented for types outside this crate.\n    ///\n    /// [`Executor`]: crate::rt::Executor\n    pub trait Http2ClientConnExec<B, T>:\n        super::Http2UpgradedExec<B::Data> + sealed_client::Sealed<(B, T)> + Clone\n    where\n        B: http_body::Body,\n        B::Error: Into<Box<dyn Error + Send + Sync>>,\n        T: Read + Write + Unpin,\n    {\n        #[doc(hidden)]\n        fn execute_h2_future(&mut self, future: H2ClientFuture<B, T, Self>);\n    }\n\n    impl<E, B, T> Http2ClientConnExec<B, T> for E\n    where\n        E: Clone,\n        E: Executor<H2ClientFuture<B, T, E>>,\n        E: super::Http2UpgradedExec<B::Data>,\n        B: http_body::Body + 'static,\n        B::Error: Into<Box<dyn Error + Send + Sync>>,\n        H2ClientFuture<B, T, E>: Future<Output = ()>,\n        T: Read + Write + Unpin,\n    {\n        fn execute_h2_future(&mut self, future: H2ClientFuture<B, T, E>) {\n            self.execute(future)\n        }\n    }\n\n    impl<E, B, T> sealed_client::Sealed<(B, T)> for E\n    where\n        E: Clone,\n        E: Executor<H2ClientFuture<B, T, E>>,\n        E: super::Http2UpgradedExec<B::Data>,\n        B: http_body::Body + 'static,\n        B::Error: Into<Box<dyn Error + Send + Sync>>,\n        H2ClientFuture<B, T, E>: Future<Output = ()>,\n        T: Read + Write + Unpin,\n    {\n    }\n\n    mod sealed_client {\n        pub trait Sealed<X> {}\n    }\n}\n\n#[cfg(all(feature = \"server\", feature = \"http2\"))]\n#[cfg_attr(docsrs, doc(cfg(all(feature = \"server\", feature = \"http2\"))))]\nmod h2_server {\n    use crate::{proto::h2::server::H2Stream, rt::Executor};\n    use http_body::Body;\n    use std::future::Future;\n\n    /// An executor to spawn http2 connections.\n    ///\n    /// This trait is implemented for any type that implements [`Executor`]\n    /// trait for any future.\n    ///\n    /// This trait is sealed and cannot be implemented for types outside this crate.\n    ///\n    /// [`Executor`]: crate::rt::Executor\n    pub trait Http2ServerConnExec<F, B: Body>:\n        super::Http2UpgradedExec<B::Data> + sealed::Sealed<(F, B)> + Clone\n    {\n        #[doc(hidden)]\n        fn execute_h2stream(&mut self, fut: H2Stream<F, B, Self>);\n    }\n\n    #[doc(hidden)]\n    impl<E, F, B> Http2ServerConnExec<F, B> for E\n    where\n        E: Clone,\n        E: Executor<H2Stream<F, B, E>>,\n        E: super::Http2UpgradedExec<B::Data>,\n        H2Stream<F, B, E>: Future<Output = ()>,\n        B: Body,\n    {\n        fn execute_h2stream(&mut self, fut: H2Stream<F, B, E>) {\n            self.execute(fut)\n        }\n    }\n\n    impl<E, F, B> sealed::Sealed<(F, B)> for E\n    where\n        E: Clone,\n        E: Executor<H2Stream<F, B, E>>,\n        E: super::Http2UpgradedExec<B::Data>,\n        H2Stream<F, B, E>: Future<Output = ()>,\n        B: Body,\n    {\n    }\n\n    mod sealed {\n        pub trait Sealed<T> {}\n    }\n}\n"
  },
  {
    "path": "src/rt/io.rs",
    "content": "use std::fmt;\nuse std::mem::MaybeUninit;\nuse std::ops::DerefMut;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\n// New IO traits? What?! Why, are you bonkers?\n//\n// I mean, yes, probably. But, here's the goals:\n//\n// 1. Supports poll-based IO operations.\n// 2. Opt-in vectored IO.\n// 3. Can use an optional buffer pool.\n// 4. Able to add completion-based (uring) IO eventually.\n//\n// Frankly, the last point is the entire reason we're doing this. We want to\n// have forwards-compatibility with an eventually stable io-uring runtime. We\n// don't need that to work right away. But it must be possible to add in here\n// without breaking hyper 1.0.\n//\n// While in here, if there's small tweaks to poll_read or poll_write that would\n// allow even the \"slow\" path to be faster, such as if someone didn't remember\n// to forward along an `is_completion` call.\n\n/// Reads bytes from a source.\n///\n/// This trait is similar to `std::io::Read`, but supports asynchronous reads.\n///\n/// # Implementing `Read`\n///\n/// Implementations should read data into the provided [`ReadBufCursor`] and\n/// advance the cursor to indicate how many bytes were written. The simplest\n/// and safest approach is to use [`ReadBufCursor::put_slice`]:\n///\n/// ```\n/// use hyper::rt::{Read, ReadBufCursor};\n/// use std::pin::Pin;\n/// use std::task::{Context, Poll};\n/// use std::io;\n///\n/// struct MyReader {\n///     data: Vec<u8>,\n///     position: usize,\n/// }\n///\n/// impl Read for MyReader {\n///     fn poll_read(\n///         mut self: Pin<&mut Self>,\n///         _cx: &mut Context<'_>,\n///         mut buf: ReadBufCursor<'_>,\n///     ) -> Poll<Result<(), io::Error>> {\n///         let remaining_data = &self.data[self.position..];\n///         if remaining_data.is_empty() {\n///             // No more data to read, signal EOF by returning Ok without\n///             // advancing the buffer\n///             return Poll::Ready(Ok(()));\n///         }\n///\n///         // Calculate how many bytes we can write\n///         let to_copy = remaining_data.len().min(buf.remaining());\n///         // Use put_slice to safely copy data and advance the cursor\n///         buf.put_slice(&remaining_data[..to_copy]);\n///\n///         self.position += to_copy;\n///         Poll::Ready(Ok(()))\n///     }\n/// }\n/// ```\n///\n/// For more advanced use cases where you need direct access to the buffer\n/// (e.g., when interfacing with APIs that write directly to a pointer),\n/// you can use the unsafe [`ReadBufCursor::as_mut`] and [`ReadBufCursor::advance`]\n/// methods. See their documentation for safety requirements.\npub trait Read {\n    /// Attempts to read bytes into the `buf`.\n    ///\n    /// On success, returns `Poll::Ready(Ok(()))` and places data in the\n    /// unfilled portion of `buf`. If no data was read (`buf.remaining()` is\n    /// unchanged), it implies that EOF has been reached.\n    ///\n    /// If no data is available for reading, the method returns `Poll::Pending`\n    /// and arranges for the current task (via `cx.waker()`) to receive a\n    /// notification when the object becomes readable or is closed.\n    fn poll_read(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: ReadBufCursor<'_>,\n    ) -> Poll<Result<(), std::io::Error>>;\n}\n\n/// Write bytes asynchronously.\n///\n/// This trait is similar to `std::io::Write`, but for asynchronous writes.\npub trait Write {\n    /// Attempt to write bytes from `buf` into the destination.\n    ///\n    /// On success, returns `Poll::Ready(Ok(num_bytes_written)))`. If\n    /// successful, it must be guaranteed that `n <= buf.len()`. A return value\n    /// of `0` means that the underlying object is no longer able to accept\n    /// bytes, or that the provided buffer is empty.\n    ///\n    /// If the object is not ready for writing, the method returns\n    /// `Poll::Pending` and arranges for the current task (via `cx.waker()`) to\n    /// receive a notification when the object becomes writable or is closed.\n    fn poll_write(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<Result<usize, std::io::Error>>;\n\n    /// Attempts to flush the object.\n    ///\n    /// On success, returns `Poll::Ready(Ok(()))`.\n    ///\n    /// If flushing cannot immediately complete, this method returns\n    /// `Poll::Pending` and arranges for the current task (via `cx.waker()`) to\n    /// receive a notification when the object can make progress.\n    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>>;\n\n    /// Attempts to shut down this writer.\n    fn poll_shutdown(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Result<(), std::io::Error>>;\n\n    /// Returns whether this writer has an efficient `poll_write_vectored`\n    /// implementation.\n    ///\n    /// The default implementation returns `false`.\n    fn is_write_vectored(&self) -> bool {\n        false\n    }\n\n    /// Like `poll_write`, except that it writes from a slice of buffers.\n    fn poll_write_vectored(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        bufs: &[std::io::IoSlice<'_>],\n    ) -> Poll<Result<usize, std::io::Error>> {\n        let buf = bufs\n            .iter()\n            .find(|b| !b.is_empty())\n            .map_or(&[][..], |b| &**b);\n        self.poll_write(cx, buf)\n    }\n}\n\n/// A wrapper around a byte buffer that is incrementally filled and initialized.\n///\n/// This type is a sort of \"double cursor\". It tracks three regions in the\n/// buffer: a region at the beginning of the buffer that has been logically\n/// filled with data, a region that has been initialized at some point but not\n/// yet logically filled, and a region at the end that may be uninitialized.\n/// The filled region is guaranteed to be a subset of the initialized region.\n///\n/// In summary, the contents of the buffer can be visualized as:\n///\n/// ```not_rust\n/// [             capacity              ]\n/// [ filled |         unfilled         ]\n/// [    initialized    | uninitialized ]\n/// ```\n///\n/// It is undefined behavior to de-initialize any bytes from the uninitialized\n/// region, since it is merely unknown whether this region is uninitialized or\n/// not, and if part of it turns out to be initialized, it must stay initialized.\npub struct ReadBuf<'a> {\n    raw: &'a mut [MaybeUninit<u8>],\n    filled: usize,\n    init: usize,\n}\n\n/// The cursor part of a [`ReadBuf`], representing the unfilled portion.\n///\n/// This is created by calling [`ReadBuf::unfilled()`].\n///\n/// `ReadBufCursor` provides safe and unsafe methods for writing data into the\n/// buffer:\n///\n/// - **Safe approach**: Use [`put_slice`](Self::put_slice) to copy data from\n///   a slice. This handles initialization tracking and cursor advancement\n///   automatically.\n///\n/// - **Unsafe approach**: For zero-copy scenarios or when interfacing with\n///   low-level APIs, use [`as_mut`](Self::as_mut) to get a mutable slice\n///   of `MaybeUninit<u8>`, then call [`advance`](Self::advance) after writing.\n///   This is more efficient but requires careful attention to safety invariants.\n///\n/// # Example using safe methods\n///\n/// ```\n/// use hyper::rt::ReadBuf;\n///\n/// let mut backing = [0u8; 64];\n/// let mut read_buf = ReadBuf::new(&mut backing);\n///\n/// {\n///     let mut cursor = read_buf.unfilled();\n///     // put_slice handles everything safely\n///     cursor.put_slice(b\"hello\");\n/// }\n///\n/// assert_eq!(read_buf.filled(), b\"hello\");\n/// ```\n///\n/// # Example using unsafe methods\n///\n/// ```\n/// use hyper::rt::ReadBuf;\n///\n/// let mut backing = [0u8; 64];\n/// let mut read_buf = ReadBuf::new(&mut backing);\n///\n/// {\n///     let mut cursor = read_buf.unfilled();\n///     // SAFETY: we will initialize exactly 5 bytes\n///     let slice = unsafe { cursor.as_mut() };\n///     slice[0].write(b'h');\n///     slice[1].write(b'e');\n///     slice[2].write(b'l');\n///     slice[3].write(b'l');\n///     slice[4].write(b'o');\n///     // SAFETY: we have initialized 5 bytes\n///     unsafe { cursor.advance(5) };\n/// }\n///\n/// assert_eq!(read_buf.filled(), b\"hello\");\n/// ```\n#[derive(Debug)]\npub struct ReadBufCursor<'a> {\n    buf: &'a mut ReadBuf<'a>,\n}\n\nimpl<'data> ReadBuf<'data> {\n    /// Create a new `ReadBuf` with a slice of initialized bytes.\n    #[inline]\n    pub fn new(raw: &'data mut [u8]) -> Self {\n        let len = raw.len();\n        Self {\n            // SAFETY: We never de-init the bytes ourselves.\n            raw: unsafe { &mut *(raw as *mut [u8] as *mut [MaybeUninit<u8>]) },\n            filled: 0,\n            init: len,\n        }\n    }\n\n    /// Create a new `ReadBuf` with a slice of uninitialized bytes.\n    #[inline]\n    pub fn uninit(raw: &'data mut [MaybeUninit<u8>]) -> Self {\n        Self {\n            raw,\n            filled: 0,\n            init: 0,\n        }\n    }\n\n    /// Get a slice of the buffer that has been filled in with bytes.\n    #[inline]\n    pub fn filled(&self) -> &[u8] {\n        // SAFETY: We only slice the filled part of the buffer, which is always valid\n        unsafe { &*(&self.raw[0..self.filled] as *const [MaybeUninit<u8>] as *const [u8]) }\n    }\n\n    /// Get a cursor to the unfilled portion of the buffer.\n    #[inline]\n    pub fn unfilled<'cursor>(&'cursor mut self) -> ReadBufCursor<'cursor> {\n        ReadBufCursor {\n            // SAFETY: self.buf is never re-assigned, so its safe to narrow\n            // the lifetime.\n            buf: unsafe {\n                std::mem::transmute::<&'cursor mut ReadBuf<'data>, &'cursor mut ReadBuf<'cursor>>(\n                    self,\n                )\n            },\n        }\n    }\n\n    #[inline]\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http2\"))]\n    pub(crate) unsafe fn set_init(&mut self, n: usize) {\n        self.init = self.init.max(n);\n    }\n\n    #[inline]\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http2\"))]\n    pub(crate) unsafe fn set_filled(&mut self, n: usize) {\n        self.filled = self.filled.max(n);\n    }\n\n    #[inline]\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http2\"))]\n    pub(crate) fn len(&self) -> usize {\n        self.filled\n    }\n\n    #[inline]\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http2\"))]\n    pub(crate) fn init_len(&self) -> usize {\n        self.init\n    }\n\n    #[inline]\n    fn remaining(&self) -> usize {\n        self.capacity() - self.filled\n    }\n\n    #[inline]\n    fn capacity(&self) -> usize {\n        self.raw.len()\n    }\n}\n\nimpl fmt::Debug for ReadBuf<'_> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"ReadBuf\")\n            .field(\"filled\", &self.filled)\n            .field(\"init\", &self.init)\n            .field(\"capacity\", &self.capacity())\n            .finish()\n    }\n}\n\nimpl ReadBufCursor<'_> {\n    /// Access the unfilled part of the buffer.\n    ///\n    /// # Safety\n    ///\n    /// The caller must not uninitialize any bytes that may have been\n    /// initialized before.\n    #[inline]\n    pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {\n        &mut self.buf.raw[self.buf.filled..]\n    }\n\n    /// Advance the `filled` cursor by `n` bytes.\n    ///\n    /// # Safety\n    ///\n    /// The caller must take care that `n` more bytes have been initialized.\n    #[inline]\n    pub unsafe fn advance(&mut self, n: usize) {\n        self.buf.filled = self.buf.filled.checked_add(n).expect(\"overflow\");\n        self.buf.init = self.buf.filled.max(self.buf.init);\n    }\n\n    /// Returns the number of bytes that can be written from the current\n    /// position until the end of the buffer is reached.\n    ///\n    /// This value is equal to the length of the slice returned by `as_mut()``.\n    #[inline]\n    pub fn remaining(&self) -> usize {\n        self.buf.remaining()\n    }\n\n    /// Transfer bytes into `self` from `src` and advance the cursor\n    /// by the number of bytes written.\n    ///\n    /// # Panics\n    ///\n    /// `self` must have enough remaining capacity to contain all of `src`.\n    #[inline]\n    pub fn put_slice(&mut self, src: &[u8]) {\n        assert!(\n            self.buf.remaining() >= src.len(),\n            \"src.len() must fit in remaining()\"\n        );\n\n        let amt = src.len();\n        // Cannot overflow, asserted above\n        let end = self.buf.filled + amt;\n\n        // Safety: the length is asserted above\n        unsafe {\n            self.buf.raw[self.buf.filled..end]\n                .as_mut_ptr()\n                .cast::<u8>()\n                .copy_from_nonoverlapping(src.as_ptr(), amt);\n        }\n\n        if self.buf.init < end {\n            self.buf.init = end;\n        }\n        self.buf.filled = end;\n    }\n}\n\nmacro_rules! deref_async_read {\n    () => {\n        fn poll_read(\n            mut self: Pin<&mut Self>,\n            cx: &mut Context<'_>,\n            buf: ReadBufCursor<'_>,\n        ) -> Poll<std::io::Result<()>> {\n            Pin::new(&mut **self).poll_read(cx, buf)\n        }\n    };\n}\n\nimpl<T: ?Sized + Read + Unpin> Read for Box<T> {\n    deref_async_read!();\n}\n\nimpl<T: ?Sized + Read + Unpin> Read for &mut T {\n    deref_async_read!();\n}\n\nimpl<P> Read for Pin<P>\nwhere\n    P: DerefMut,\n    P::Target: Read,\n{\n    fn poll_read(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: ReadBufCursor<'_>,\n    ) -> Poll<std::io::Result<()>> {\n        pin_as_deref_mut(self).poll_read(cx, buf)\n    }\n}\n\nmacro_rules! deref_async_write {\n    () => {\n        fn poll_write(\n            mut self: Pin<&mut Self>,\n            cx: &mut Context<'_>,\n            buf: &[u8],\n        ) -> Poll<std::io::Result<usize>> {\n            Pin::new(&mut **self).poll_write(cx, buf)\n        }\n\n        fn poll_write_vectored(\n            mut self: Pin<&mut Self>,\n            cx: &mut Context<'_>,\n            bufs: &[std::io::IoSlice<'_>],\n        ) -> Poll<std::io::Result<usize>> {\n            Pin::new(&mut **self).poll_write_vectored(cx, bufs)\n        }\n\n        fn is_write_vectored(&self) -> bool {\n            (**self).is_write_vectored()\n        }\n\n        fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {\n            Pin::new(&mut **self).poll_flush(cx)\n        }\n\n        fn poll_shutdown(\n            mut self: Pin<&mut Self>,\n            cx: &mut Context<'_>,\n        ) -> Poll<std::io::Result<()>> {\n            Pin::new(&mut **self).poll_shutdown(cx)\n        }\n    };\n}\n\nimpl<T: ?Sized + Write + Unpin> Write for Box<T> {\n    deref_async_write!();\n}\n\nimpl<T: ?Sized + Write + Unpin> Write for &mut T {\n    deref_async_write!();\n}\n\nimpl<P> Write for Pin<P>\nwhere\n    P: DerefMut,\n    P::Target: Write,\n{\n    fn poll_write(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<std::io::Result<usize>> {\n        pin_as_deref_mut(self).poll_write(cx, buf)\n    }\n\n    fn poll_write_vectored(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        bufs: &[std::io::IoSlice<'_>],\n    ) -> Poll<std::io::Result<usize>> {\n        pin_as_deref_mut(self).poll_write_vectored(cx, bufs)\n    }\n\n    fn is_write_vectored(&self) -> bool {\n        (**self).is_write_vectored()\n    }\n\n    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {\n        pin_as_deref_mut(self).poll_flush(cx)\n    }\n\n    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {\n        pin_as_deref_mut(self).poll_shutdown(cx)\n    }\n}\n\n/// Polyfill for Pin::as_deref_mut()\n/// TODO: use Pin::as_deref_mut() instead once stabilized\nfn pin_as_deref_mut<P: DerefMut>(pin: Pin<&mut Pin<P>>) -> Pin<&mut P::Target> {\n    // SAFETY: we go directly from Pin<&mut Pin<P>> to Pin<&mut P::Target>, without moving or\n    // giving out the &mut Pin<P> in the process. See Pin::as_deref_mut() for more detail.\n    unsafe { pin.get_unchecked_mut() }.as_mut()\n}\n"
  },
  {
    "path": "src/rt/mod.rs",
    "content": "//! Runtime components\n//!\n//! This module provides traits and types that allow hyper to be runtime-agnostic.\n//! By abstracting over async runtimes, hyper can work with different executors, timers, and IO transports.\n//!\n//! The main components in this module are:\n//!\n//! - **Executors**: Traits for spawning and running futures, enabling integration with any async runtime.\n//! - **Timers**: Abstractions for sleeping and scheduling tasks, allowing time-based operations to be runtime-independent.\n//! - **IO Transports**: Traits for asynchronous reading and writing, so hyper can work with various IO backends.\n//!\n//! By implementing these traits, you can customize how hyper interacts with your chosen runtime environment.\n//!\n//! To learn more, [check out the runtime guide](https://hyper.rs/guides/1/init/runtime/).\n\npub mod bounds;\nmod io;\nmod timer;\n\npub use self::io::{Read, ReadBuf, ReadBufCursor, Write};\npub use self::timer::{Sleep, Timer};\n\n/// An executor of futures.\n///\n/// This trait allows Hyper to abstract over async runtimes. Implement this trait for your own type.\n///\n/// # Example\n///\n/// ```\n/// # use hyper::rt::Executor;\n/// # use std::future::Future;\n/// #[derive(Clone)]\n/// struct TokioExecutor;\n///\n/// impl<F> Executor<F> for TokioExecutor\n/// where\n///     F: Future + Send + 'static,\n///     F::Output: Send + 'static,\n/// {\n///     fn execute(&self, future: F) {\n///         tokio::spawn(future);\n///     }\n/// }\n/// ```\npub trait Executor<Fut> {\n    /// Place the future into the executor to be run.\n    fn execute(&self, fut: Fut);\n}\n"
  },
  {
    "path": "src/rt/timer.rs",
    "content": "//! Provides a timer trait with timer-like functions\n//!\n//! Example using tokio timer:\n//! ```rust\n//! use std::{\n//!     future::Future,\n//!     pin::Pin,\n//!     task::{Context, Poll},\n//!     time::{Duration, Instant},\n//! };\n//!\n//! use pin_project_lite::pin_project;\n//! use hyper::rt::{Timer, Sleep};\n//!\n//! #[derive(Clone, Debug)]\n//! pub struct TokioTimer;\n//!\n//! impl Timer for TokioTimer {\n//!     fn sleep(&self, duration: Duration) -> Pin<Box<dyn Sleep>> {\n//!         Box::pin(TokioSleep {\n//!             inner: tokio::time::sleep(duration),\n//!         })\n//!     }\n//!\n//!     fn sleep_until(&self, deadline: Instant) -> Pin<Box<dyn Sleep>> {\n//!         Box::pin(TokioSleep {\n//!             inner: tokio::time::sleep_until(deadline.into()),\n//!         })\n//!     }\n//!\n//!     fn reset(&self, sleep: &mut Pin<Box<dyn Sleep>>, new_deadline: Instant) {\n//!         if let Some(sleep) = sleep.as_mut().downcast_mut_pin::<TokioSleep>() {\n//!             sleep.reset(new_deadline.into())\n//!         }\n//!     }\n//! }\n//!\n//! pin_project! {\n//!     pub(crate) struct TokioSleep {\n//!         #[pin]\n//!         pub(crate) inner: tokio::time::Sleep,\n//!     }\n//! }\n//!\n//! impl Future for TokioSleep {\n//!     type Output = ();\n//!\n//!     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n//!         self.project().inner.poll(cx)\n//!     }\n//! }\n//!\n//! impl Sleep for TokioSleep {}\n//!\n//! impl TokioSleep {\n//!     pub fn reset(self: Pin<&mut Self>, deadline: Instant) {\n//!         self.project().inner.as_mut().reset(deadline.into());\n//!     }\n//! }\n//! ```\n\nuse std::{\n    any::TypeId,\n    future::Future,\n    pin::Pin,\n    time::{Duration, Instant},\n};\n\n/// A timer which provides timer-like functions.\npub trait Timer {\n    /// Return a future that resolves in `duration` time.\n    fn sleep(&self, duration: Duration) -> Pin<Box<dyn Sleep>>;\n\n    /// Return a future that resolves at `deadline`.\n    fn sleep_until(&self, deadline: Instant) -> Pin<Box<dyn Sleep>>;\n\n    /// Return an `Instant` representing the current time.\n    ///\n    /// The default implementation returns [`Instant::now()`].\n    fn now(&self) -> Instant {\n        Instant::now()\n    }\n\n    /// Reset a future to resolve at `new_deadline` instead.\n    fn reset(&self, sleep: &mut Pin<Box<dyn Sleep>>, new_deadline: Instant) {\n        *sleep = self.sleep_until(new_deadline);\n    }\n}\n\n/// A future returned by a `Timer`.\npub trait Sleep: Send + Sync + Future<Output = ()> {\n    #[doc(hidden)]\n    /// This method is private and can not be implemented by downstream crate\n    fn __type_id(&self, _: private::Sealed) -> TypeId\n    where\n        Self: 'static,\n    {\n        TypeId::of::<Self>()\n    }\n}\n\nimpl dyn Sleep {\n    //! This is a re-implementation of downcast methods from std::any::Any\n\n    /// Check whether the type is the same as `T`\n    pub fn is<T>(&self) -> bool\n    where\n        T: Sleep + 'static,\n    {\n        self.__type_id(private::Sealed {}) == TypeId::of::<T>()\n    }\n\n    /// Downcast a pinned &mut Sleep object to its original type\n    pub fn downcast_mut_pin<T>(self: Pin<&mut Self>) -> Option<Pin<&mut T>>\n    where\n        T: Sleep + 'static,\n    {\n        if self.is::<T>() {\n            unsafe {\n                let inner = Pin::into_inner_unchecked(self);\n                Some(Pin::new_unchecked(\n                    &mut *(&mut *inner as *mut dyn Sleep as *mut T),\n                ))\n            }\n        } else {\n            None\n        }\n    }\n}\n\nmod private {\n    #![allow(missing_debug_implementations)]\n    pub struct Sealed {}\n}\n"
  },
  {
    "path": "src/server/conn/http1.rs",
    "content": "//! HTTP/1 Server Connections\n\nuse std::error::Error as StdError;\nuse std::fmt;\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::sync::Arc;\nuse std::task::{Context, Poll};\nuse std::time::Duration;\n\nuse crate::rt::{Read, Write};\nuse crate::upgrade::Upgraded;\nuse bytes::Bytes;\nuse futures_core::ready;\n\nuse crate::body::{Body, Incoming as IncomingBody};\nuse crate::proto;\nuse crate::service::HttpService;\nuse crate::{\n    common::time::{Dur, Time},\n    rt::Timer,\n};\n\ntype Http1Dispatcher<T, B, S> = proto::h1::Dispatcher<\n    proto::h1::dispatch::Server<S, IncomingBody>,\n    B,\n    T,\n    proto::ServerTransaction,\n>;\n\npin_project_lite::pin_project! {\n    /// A [`Future`](core::future::Future) representing an HTTP/1 connection, bound to a\n    /// [`Service`](crate::service::Service), returned from\n    /// [`Builder::serve_connection`](struct.Builder.html#method.serve_connection).\n    ///\n    /// To drive HTTP on this connection this future **must be polled**, typically with\n    /// `.await`. If it isn't polled, no progress will be made on this connection.\n    #[must_use = \"futures do nothing unless polled\"]\n    pub struct Connection<T, S>\n    where\n        S: HttpService<IncomingBody>,\n    {\n        conn: Http1Dispatcher<T, S::ResBody, S>,\n    }\n}\n\n/// A configuration builder for HTTP/1 server connections.\n///\n/// **Note**: The default values of options are *not considered stable*. They\n/// are subject to change at any time.\n///\n/// # Example\n///\n/// ```\n/// # use std::time::Duration;\n/// # use hyper::server::conn::http1::Builder;\n/// # fn main() {\n/// let mut http = Builder::new();\n/// // Set options one at a time\n/// http.half_close(false);\n///\n/// // Or, chain multiple options\n/// http.keep_alive(false).title_case_headers(true).max_buf_size(8192);\n///\n/// # }\n/// ```\n///\n/// Use [`Builder::serve_connection`](struct.Builder.html#method.serve_connection)\n/// to bind the built connection to a service.\n#[derive(Clone, Debug)]\npub struct Builder {\n    h1_parser_config: httparse::ParserConfig,\n    timer: Time,\n    h1_half_close: bool,\n    h1_keep_alive: bool,\n    h1_title_case_headers: bool,\n    h1_preserve_header_case: bool,\n    h1_max_headers: Option<usize>,\n    h1_header_read_timeout: Dur,\n    h1_writev: Option<bool>,\n    max_buf_size: Option<usize>,\n    pipeline_flush: bool,\n    date_header: bool,\n}\n\n/// Deconstructed parts of a `Connection`.\n///\n/// This allows taking apart a `Connection` at a later time, in order to\n/// reclaim the IO object, and additional related pieces.\n#[derive(Debug)]\n#[non_exhaustive]\npub struct Parts<T, S> {\n    /// The original IO object used in the handshake.\n    pub io: T,\n    /// A buffer of bytes that have been read but not processed as HTTP.\n    ///\n    /// If the client sent additional bytes after its last request, and\n    /// this connection \"ended\" with an upgrade, the read buffer will contain\n    /// those bytes.\n    ///\n    /// You will want to check for any existing bytes if you plan to continue\n    /// communicating on the IO object.\n    pub read_buf: Bytes,\n    /// The `Service` used to serve this connection.\n    pub service: S,\n}\n\n// ===== impl Connection =====\n\nimpl<I, S> fmt::Debug for Connection<I, S>\nwhere\n    S: HttpService<IncomingBody>,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Connection\").finish()\n    }\n}\n\nimpl<I, B, S> Connection<I, S>\nwhere\n    S: HttpService<IncomingBody, ResBody = B>,\n    S::Error: Into<Box<dyn StdError + Send + Sync>>,\n    I: Read + Write + Unpin,\n    B: Body + 'static,\n    B::Error: Into<Box<dyn StdError + Send + Sync>>,\n{\n    /// Start a graceful shutdown process for this connection.\n    ///\n    /// This `Connection` should continue to be polled until shutdown\n    /// can finish.\n    ///\n    /// # Note\n    ///\n    /// This should only be called while the `Connection` future is still\n    /// pending. If called after `Connection::poll` has resolved, this does\n    /// nothing.\n    pub fn graceful_shutdown(mut self: Pin<&mut Self>) {\n        self.conn.disable_keep_alive();\n    }\n\n    /// Return the inner IO object, and additional information.\n    ///\n    /// If the IO object has been \"rewound\" the io will not contain those bytes rewound.\n    /// This should only be called after `poll_without_shutdown` signals\n    /// that the connection is \"done\". Otherwise, it may not have finished\n    /// flushing all necessary HTTP bytes.\n    ///\n    /// # Panics\n    /// This method will panic if this connection is using an h2 protocol.\n    pub fn into_parts(self) -> Parts<I, S> {\n        let (io, read_buf, dispatch) = self.conn.into_inner();\n        Parts {\n            io,\n            read_buf,\n            service: dispatch.into_service(),\n        }\n    }\n\n    /// Poll the connection for completion, but without calling `shutdown`\n    /// on the underlying IO.\n    ///\n    /// This is useful to allow running a connection while doing an HTTP\n    /// upgrade. Once the upgrade is completed, the connection would be \"done\",\n    /// but it is not desired to actually shutdown the IO object. Instead you\n    /// would take it back using `into_parts`.\n    pub fn poll_without_shutdown(&mut self, cx: &mut Context<'_>) -> Poll<crate::Result<()>>\n    where\n        S: Unpin,\n        S::Future: Unpin,\n    {\n        self.conn.poll_without_shutdown(cx)\n    }\n\n    /// Prevent shutdown of the underlying IO object at the end of service the request,\n    /// instead run `into_parts`. This is a convenience wrapper over `poll_without_shutdown`.\n    ///\n    /// # Error\n    ///\n    /// This errors if the underlying connection protocol is not HTTP/1.\n    pub fn without_shutdown(self) -> impl Future<Output = crate::Result<Parts<I, S>>> {\n        let mut zelf = Some(self);\n        crate::common::future::poll_fn(move |cx| {\n            ready!(zelf.as_mut().unwrap().conn.poll_without_shutdown(cx))?;\n            Poll::Ready(Ok(zelf.take().unwrap().into_parts()))\n        })\n    }\n\n    /// Enable this connection to support higher-level HTTP upgrades.\n    ///\n    /// See [the `upgrade` module](crate::upgrade) for more.\n    pub fn with_upgrades(self) -> UpgradeableConnection<I, S>\n    where\n        I: Send,\n    {\n        UpgradeableConnection { inner: Some(self) }\n    }\n}\n\nimpl<I, B, S> Future for Connection<I, S>\nwhere\n    S: HttpService<IncomingBody, ResBody = B>,\n    S::Error: Into<Box<dyn StdError + Send + Sync>>,\n    I: Read + Write + Unpin,\n    B: Body + 'static,\n    B::Error: Into<Box<dyn StdError + Send + Sync>>,\n{\n    type Output = crate::Result<()>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        match ready!(Pin::new(&mut self.conn).poll(cx)) {\n            Ok(done) => {\n                match done {\n                    proto::Dispatched::Shutdown => {}\n                    proto::Dispatched::Upgrade(pending) => {\n                        // With no `Send` bound on `I`, we can't try to do\n                        // upgrades here. In case a user was trying to use\n                        // `Body::on_upgrade` with this API, send a special\n                        // error letting them know about that.\n                        pending.manual();\n                    }\n                };\n                Poll::Ready(Ok(()))\n            }\n            Err(e) => Poll::Ready(Err(e)),\n        }\n    }\n}\n\n// ===== impl Builder =====\n\nimpl Builder {\n    /// Create a new connection builder.\n    pub fn new() -> Self {\n        Self {\n            h1_parser_config: Default::default(),\n            timer: Time::Empty,\n            h1_half_close: false,\n            h1_keep_alive: true,\n            h1_title_case_headers: false,\n            h1_preserve_header_case: false,\n            h1_max_headers: None,\n            h1_header_read_timeout: Dur::Default(Some(Duration::from_secs(30))),\n            h1_writev: None,\n            max_buf_size: None,\n            pipeline_flush: false,\n            date_header: true,\n        }\n    }\n    /// Set whether HTTP/1 connections should support half-closures.\n    ///\n    /// Clients can chose to shutdown their write-side while waiting\n    /// for the server to respond. Setting this to `true` will\n    /// prevent closing the connection immediately if `read`\n    /// detects an EOF in the middle of a request.\n    ///\n    /// Default is `false`.\n    pub fn half_close(&mut self, val: bool) -> &mut Self {\n        self.h1_half_close = val;\n        self\n    }\n\n    /// Enables or disables HTTP/1 keep-alive.\n    ///\n    /// Default is `true`.\n    pub fn keep_alive(&mut self, val: bool) -> &mut Self {\n        self.h1_keep_alive = val;\n        self\n    }\n\n    /// Set whether HTTP/1 connections will write header names as title case at\n    /// the socket level.\n    ///\n    /// Default is `false`.\n    pub fn title_case_headers(&mut self, enabled: bool) -> &mut Self {\n        self.h1_title_case_headers = enabled;\n        self\n    }\n\n    /// Set whether multiple spaces are allowed as delimiters in request lines.\n    ///\n    /// Default is `false`.\n    pub fn allow_multiple_spaces_in_request_line_delimiters(&mut self, enabled: bool) -> &mut Self {\n        self.h1_parser_config\n            .allow_multiple_spaces_in_request_line_delimiters(enabled);\n        self\n    }\n\n    /// Set whether HTTP/1 connections will silently ignored malformed header lines.\n    ///\n    /// If this is enabled and a header line does not start with a valid header\n    /// name, or does not include a colon at all, the line will be silently ignored\n    /// and no error will be reported.\n    ///\n    /// Default is `false`.\n    pub fn ignore_invalid_headers(&mut self, enabled: bool) -> &mut Builder {\n        self.h1_parser_config\n            .ignore_invalid_headers_in_requests(enabled);\n        self\n    }\n\n    /// Set whether to support preserving original header cases.\n    ///\n    /// Currently, this will record the original cases received, and store them\n    /// in a private extension on the `Request`. It will also look for and use\n    /// such an extension in any provided `Response`.\n    ///\n    /// Since the relevant extension is still private, there is no way to\n    /// interact with the original cases. The only effect this can have now is\n    /// to forward the cases in a proxy-like fashion.\n    ///\n    /// Default is `false`.\n    pub fn preserve_header_case(&mut self, enabled: bool) -> &mut Self {\n        self.h1_preserve_header_case = enabled;\n        self\n    }\n\n    /// Set the maximum number of headers.\n    ///\n    /// When a request is received, the parser will reserve a buffer to store headers for optimal\n    /// performance.\n    ///\n    /// If server receives more headers than the buffer size, it responds to the client with\n    /// \"431 Request Header Fields Too Large\".\n    ///\n    /// Note that headers is allocated on the stack by default, which has higher performance. After\n    /// setting this value, headers will be allocated in heap memory, that is, heap memory\n    /// allocation will occur for each request, and there will be a performance drop of about 5%.\n    ///\n    /// Default is 100.\n    pub fn max_headers(&mut self, val: usize) -> &mut Self {\n        self.h1_max_headers = Some(val);\n        self\n    }\n\n    /// Set a timeout for reading client request headers. If a client does not\n    /// transmit the entire header within this time, the connection is closed.\n    ///\n    /// Requires a [`Timer`] set by [`Builder::timer`] to take effect. Panics if `header_read_timeout` is configured\n    /// without a [`Timer`].\n    ///\n    /// Pass `None` to disable.\n    ///\n    /// Default is 30 seconds.\n    pub fn header_read_timeout(&mut self, read_timeout: impl Into<Option<Duration>>) -> &mut Self {\n        self.h1_header_read_timeout = Dur::Configured(read_timeout.into());\n        self\n    }\n\n    /// Set whether HTTP/1 connections should try to use vectored writes,\n    /// or always flatten into a single buffer.\n    ///\n    /// Note that setting this to false may mean more copies of body data,\n    /// but may also improve performance when an IO transport doesn't\n    /// support vectored writes well, such as most TLS implementations.\n    ///\n    /// Setting this to true will force hyper to use queued strategy\n    /// which may eliminate unnecessary cloning on some TLS backends\n    ///\n    /// Default is `auto`. In this mode hyper will try to guess which\n    /// mode to use\n    pub fn writev(&mut self, val: bool) -> &mut Self {\n        self.h1_writev = Some(val);\n        self\n    }\n\n    /// Set the maximum buffer size for the connection.\n    ///\n    /// Default is ~400kb.\n    ///\n    /// # Panics\n    ///\n    /// The minimum value allowed is 8192. This method panics if the passed `max` is less than the minimum.\n    pub fn max_buf_size(&mut self, max: usize) -> &mut Self {\n        assert!(\n            max >= proto::h1::MINIMUM_MAX_BUFFER_SIZE,\n            \"the max_buf_size cannot be smaller than the minimum that h1 specifies.\"\n        );\n        self.max_buf_size = Some(max);\n        self\n    }\n\n    /// Set whether the `date` header should be included in HTTP responses.\n    ///\n    /// Note that including the `date` header is recommended by RFC 7231.\n    ///\n    /// Default is `true`.\n    pub fn auto_date_header(&mut self, enabled: bool) -> &mut Self {\n        self.date_header = enabled;\n        self\n    }\n\n    /// Aggregates flushes to better support pipelined responses.\n    ///\n    /// Experimental, may have bugs.\n    ///\n    /// Default is `false`.\n    pub fn pipeline_flush(&mut self, enabled: bool) -> &mut Self {\n        self.pipeline_flush = enabled;\n        self\n    }\n\n    /// Set the timer used in background tasks.\n    pub fn timer<M>(&mut self, timer: M) -> &mut Self\n    where\n        M: Timer + Send + Sync + 'static,\n    {\n        self.timer = Time::Timer(Arc::new(timer));\n        self\n    }\n\n    /// Bind a connection together with a [`Service`](crate::service::Service).\n    ///\n    /// This returns a Future that must be polled in order for HTTP to be\n    /// driven on the connection.\n    ///\n    /// # Panics\n    ///\n    /// If a timeout option has been configured, but a `timer` has not been\n    /// provided, calling `serve_connection` will panic.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// # use hyper::{body::Incoming, Request, Response};\n    /// # use hyper::service::Service;\n    /// # use hyper::server::conn::http1::Builder;\n    /// # use hyper::rt::{Read, Write};\n    /// # async fn run<I, S>(some_io: I, some_service: S)\n    /// # where\n    /// #     I: Read + Write + Unpin + Send + 'static,\n    /// #     S: Service<hyper::Request<Incoming>, Response=hyper::Response<Incoming>> + Send + 'static,\n    /// #     S::Error: Into<Box<dyn std::error::Error + Send + Sync>>,\n    /// #     S::Future: Send,\n    /// # {\n    /// let http = Builder::new();\n    /// let conn = http.serve_connection(some_io, some_service);\n    ///\n    /// if let Err(e) = conn.await {\n    ///     eprintln!(\"server connection error: {}\", e);\n    /// }\n    /// # }\n    /// # fn main() {}\n    /// ```\n    pub fn serve_connection<I, S>(&self, io: I, service: S) -> Connection<I, S>\n    where\n        S: HttpService<IncomingBody>,\n        S::Error: Into<Box<dyn StdError + Send + Sync>>,\n        S::ResBody: 'static,\n        <S::ResBody as Body>::Error: Into<Box<dyn StdError + Send + Sync>>,\n        I: Read + Write + Unpin,\n    {\n        let mut conn = proto::Conn::new(io);\n        conn.set_h1_parser_config(self.h1_parser_config.clone());\n        conn.set_timer(self.timer.clone());\n        if !self.h1_keep_alive {\n            conn.disable_keep_alive();\n        }\n        if self.h1_half_close {\n            conn.set_allow_half_close();\n        }\n        if self.h1_title_case_headers {\n            conn.set_title_case_headers();\n        }\n        if self.h1_preserve_header_case {\n            conn.set_preserve_header_case();\n        }\n        if let Some(max_headers) = self.h1_max_headers {\n            conn.set_http1_max_headers(max_headers);\n        }\n        if let Some(dur) = self\n            .timer\n            .check(self.h1_header_read_timeout, \"header_read_timeout\")\n        {\n            conn.set_http1_header_read_timeout(dur);\n        };\n        if let Some(writev) = self.h1_writev {\n            if writev {\n                conn.set_write_strategy_queue();\n            } else {\n                conn.set_write_strategy_flatten();\n            }\n        }\n        conn.set_flush_pipeline(self.pipeline_flush);\n        if let Some(max) = self.max_buf_size {\n            conn.set_max_buf_size(max);\n        }\n        if !self.date_header {\n            conn.disable_date_header();\n        }\n        let sd = proto::h1::dispatch::Server::new(service);\n        let proto = proto::h1::Dispatcher::new(sd, conn);\n        Connection { conn: proto }\n    }\n}\n\n/// A future binding a connection with a Service with Upgrade support.\n#[must_use = \"futures do nothing unless polled\"]\n#[allow(missing_debug_implementations)]\npub struct UpgradeableConnection<T, S>\nwhere\n    S: HttpService<IncomingBody>,\n{\n    pub(super) inner: Option<Connection<T, S>>,\n}\n\nimpl<I, B, S> UpgradeableConnection<I, S>\nwhere\n    S: HttpService<IncomingBody, ResBody = B>,\n    S::Error: Into<Box<dyn StdError + Send + Sync>>,\n    I: Read + Write + Unpin,\n    B: Body + 'static,\n    B::Error: Into<Box<dyn StdError + Send + Sync>>,\n{\n    /// Start a graceful shutdown process for this connection.\n    ///\n    /// This `Connection` should continue to be polled until shutdown\n    /// can finish.\n    pub fn graceful_shutdown(mut self: Pin<&mut Self>) {\n        // Connection (`inner`) is `None` if it was upgraded (and `poll` is `Ready`).\n        // In that case, we don't need to call `graceful_shutdown`.\n        if let Some(conn) = self.inner.as_mut() {\n            Pin::new(conn).graceful_shutdown()\n        }\n    }\n}\n\nimpl<I, B, S> Future for UpgradeableConnection<I, S>\nwhere\n    S: HttpService<IncomingBody, ResBody = B>,\n    S::Error: Into<Box<dyn StdError + Send + Sync>>,\n    I: Read + Write + Unpin + Send + 'static,\n    B: Body + 'static,\n    B::Error: Into<Box<dyn StdError + Send + Sync>>,\n{\n    type Output = crate::Result<()>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        if let Some(conn) = self.inner.as_mut() {\n            match ready!(Pin::new(&mut conn.conn).poll(cx)) {\n                Ok(proto::Dispatched::Shutdown) => Poll::Ready(Ok(())),\n                Ok(proto::Dispatched::Upgrade(pending)) => {\n                    let (io, buf, _) = self.inner.take().unwrap().conn.into_inner();\n                    pending.fulfill(Upgraded::new(io, buf));\n                    Poll::Ready(Ok(()))\n                }\n                Err(e) => Poll::Ready(Err(e)),\n            }\n        } else {\n            // inner is `None`, meaning the connection was upgraded, thus it's `Poll::Ready(Ok(()))`\n            Poll::Ready(Ok(()))\n        }\n    }\n}\n"
  },
  {
    "path": "src/server/conn/http2.rs",
    "content": "//! HTTP/2 Server Connections\n\nuse std::error::Error as StdError;\nuse std::fmt;\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::sync::Arc;\nuse std::task::{Context, Poll};\nuse std::time::Duration;\n\nuse crate::rt::{Read, Write};\nuse futures_core::ready;\nuse pin_project_lite::pin_project;\n\nuse crate::body::{Body, Incoming as IncomingBody};\nuse crate::proto;\nuse crate::rt::bounds::Http2ServerConnExec;\nuse crate::service::HttpService;\nuse crate::{common::time::Time, rt::Timer};\n\npin_project! {\n    /// A [`Future`](core::future::Future) representing an HTTP/2 connection, bound to a\n    /// [`Service`](crate::service::Service), returned from\n    /// [`Builder::serve_connection`](struct.Builder.html#method.serve_connection).\n    ///\n    /// To drive HTTP on this connection this future **must be polled**, typically with\n    /// `.await`. If it isn't polled, no progress will be made on this connection.\n    #[must_use = \"futures do nothing unless polled\"]\n    pub struct Connection<T, S, E>\n    where\n        S: HttpService<IncomingBody>,\n    {\n        conn: proto::h2::Server<T, S, S::ResBody, E>,\n    }\n}\n\n/// A configuration builder for HTTP/2 server connections.\n///\n/// **Note**: The default values of options are *not considered stable*. They\n/// are subject to change at any time.\n#[derive(Clone, Debug)]\npub struct Builder<E> {\n    exec: E,\n    timer: Time,\n    h2_builder: proto::h2::server::Config,\n}\n\n// ===== impl Connection =====\n\nimpl<I, S, E> fmt::Debug for Connection<I, S, E>\nwhere\n    S: HttpService<IncomingBody>,\n{\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Connection\").finish()\n    }\n}\n\nimpl<I, B, S, E> Connection<I, S, E>\nwhere\n    S: HttpService<IncomingBody, ResBody = B>,\n    S::Error: Into<Box<dyn StdError + Send + Sync>>,\n    I: Read + Write + Unpin,\n    B: Body + 'static,\n    B::Error: Into<Box<dyn StdError + Send + Sync>>,\n    E: Http2ServerConnExec<S::Future, B>,\n{\n    /// Start a graceful shutdown process for this connection.\n    ///\n    /// This `Connection` should continue to be polled until shutdown\n    /// can finish.\n    ///\n    /// # Note\n    ///\n    /// This should only be called while the `Connection` future is still\n    /// pending. If called after `Connection::poll` has resolved, this does\n    /// nothing.\n    pub fn graceful_shutdown(mut self: Pin<&mut Self>) {\n        self.conn.graceful_shutdown();\n    }\n}\n\nimpl<I, B, S, E> Future for Connection<I, S, E>\nwhere\n    S: HttpService<IncomingBody, ResBody = B>,\n    S::Error: Into<Box<dyn StdError + Send + Sync>>,\n    I: Read + Write + Unpin,\n    B: Body + 'static,\n    B::Error: Into<Box<dyn StdError + Send + Sync>>,\n    E: Http2ServerConnExec<S::Future, B>,\n{\n    type Output = crate::Result<()>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        match ready!(Pin::new(&mut self.conn).poll(cx)) {\n            Ok(_done) => {\n                //TODO: the proto::h2::Server no longer needs to return\n                //the Dispatched enum\n                Poll::Ready(Ok(()))\n            }\n            Err(e) => Poll::Ready(Err(e)),\n        }\n    }\n}\n\n// ===== impl Builder =====\n\nimpl<E> Builder<E> {\n    /// Create a new connection builder.\n    ///\n    /// This starts with the default options, and an executor which is a type\n    /// that implements [`Http2ServerConnExec`] trait.\n    ///\n    /// [`Http2ServerConnExec`]: crate::rt::bounds::Http2ServerConnExec\n    pub fn new(exec: E) -> Self {\n        Self {\n            exec,\n            timer: Time::Empty,\n            h2_builder: Default::default(),\n        }\n    }\n\n    /// Configures the maximum number of pending reset streams allowed before a GOAWAY will be sent.\n    ///\n    /// This will default to the default value set by the [`h2` crate](https://crates.io/crates/h2).\n    /// As of v0.4.0, it is 20.\n    ///\n    /// See <https://github.com/hyperium/hyper/issues/2877> for more information.\n    pub fn max_pending_accept_reset_streams(&mut self, max: impl Into<Option<usize>>) -> &mut Self {\n        self.h2_builder.max_pending_accept_reset_streams = max.into();\n        self\n    }\n\n    /// Configures the maximum number of local reset streams allowed before a GOAWAY will be sent.\n    ///\n    /// If not set, hyper will use a default, currently of 1024.\n    ///\n    /// If `None` is supplied, hyper will not apply any limit.\n    /// This is not advised, as it can potentially expose servers to DOS vulnerabilities.\n    ///\n    /// See <https://rustsec.org/advisories/RUSTSEC-2024-0003.html> for more information.\n    #[cfg(feature = \"http2\")]\n    #[cfg_attr(docsrs, doc(cfg(feature = \"http2\")))]\n    pub fn max_local_error_reset_streams(&mut self, max: impl Into<Option<usize>>) -> &mut Self {\n        self.h2_builder.max_local_error_reset_streams = max.into();\n        self\n    }\n\n    /// Sets the [`SETTINGS_INITIAL_WINDOW_SIZE`][spec] option for HTTP2\n    /// stream-level flow control.\n    ///\n    /// Passing `None` will do nothing.\n    ///\n    /// If not set, hyper will use a default.\n    ///\n    /// [spec]: https://httpwg.org/specs/rfc9113.html#SETTINGS_INITIAL_WINDOW_SIZE\n    pub fn initial_stream_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {\n        if let Some(sz) = sz.into() {\n            self.h2_builder.adaptive_window = false;\n            self.h2_builder.initial_stream_window_size = sz;\n        }\n        self\n    }\n\n    /// Sets the max connection-level flow control for HTTP2.\n    ///\n    /// Passing `None` will do nothing.\n    ///\n    /// If not set, hyper will use a default.\n    pub fn initial_connection_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {\n        if let Some(sz) = sz.into() {\n            self.h2_builder.adaptive_window = false;\n            self.h2_builder.initial_conn_window_size = sz;\n        }\n        self\n    }\n\n    /// Sets whether to use an adaptive flow control.\n    ///\n    /// Enabling this will override the limits set in\n    /// `initial_stream_window_size` and\n    /// `initial_connection_window_size`.\n    pub fn adaptive_window(&mut self, enabled: bool) -> &mut Self {\n        use proto::h2::SPEC_WINDOW_SIZE;\n\n        self.h2_builder.adaptive_window = enabled;\n        if enabled {\n            self.h2_builder.initial_conn_window_size = SPEC_WINDOW_SIZE;\n            self.h2_builder.initial_stream_window_size = SPEC_WINDOW_SIZE;\n        }\n        self\n    }\n\n    /// Sets the maximum frame size to use for HTTP2.\n    ///\n    /// Passing `None` will do nothing.\n    ///\n    /// If not set, hyper will use a default.\n    pub fn max_frame_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {\n        if let Some(sz) = sz.into() {\n            self.h2_builder.max_frame_size = sz;\n        }\n        self\n    }\n\n    /// Sets the [`SETTINGS_MAX_CONCURRENT_STREAMS`][spec] option for HTTP2\n    /// connections.\n    ///\n    /// Default is 200, but not part of the stability of hyper. It could change\n    /// in a future release. You are encouraged to set your own limit.\n    ///\n    /// Passing `None` will remove any limit.\n    ///\n    /// [spec]: https://httpwg.org/specs/rfc9113.html#SETTINGS_MAX_CONCURRENT_STREAMS\n    pub fn max_concurrent_streams(&mut self, max: impl Into<Option<u32>>) -> &mut Self {\n        self.h2_builder.max_concurrent_streams = max.into();\n        self\n    }\n\n    /// Sets an interval for HTTP2 Ping frames should be sent to keep a\n    /// connection alive.\n    ///\n    /// Pass `None` to disable HTTP2 keep-alive.\n    ///\n    /// Default is currently disabled.\n    pub fn keep_alive_interval(&mut self, interval: impl Into<Option<Duration>>) -> &mut Self {\n        self.h2_builder.keep_alive_interval = interval.into();\n        self\n    }\n\n    /// Sets a timeout for receiving an acknowledgement of the keep-alive ping.\n    ///\n    /// If the ping is not acknowledged within the timeout, the connection will\n    /// be closed. Does nothing if `keep_alive_interval` is disabled.\n    ///\n    /// Default is 20 seconds.\n    pub fn keep_alive_timeout(&mut self, timeout: Duration) -> &mut Self {\n        self.h2_builder.keep_alive_timeout = timeout;\n        self\n    }\n\n    /// Set the maximum write buffer size for each HTTP/2 stream.\n    ///\n    /// Default is currently ~400KB, but may change.\n    ///\n    /// # Panics\n    ///\n    /// The value must be no larger than `u32::MAX`.\n    pub fn max_send_buf_size(&mut self, max: usize) -> &mut Self {\n        assert!(max <= u32::MAX as usize);\n        self.h2_builder.max_send_buffer_size = max;\n        self\n    }\n\n    /// Enables the [extended CONNECT protocol].\n    ///\n    /// [extended CONNECT protocol]: https://datatracker.ietf.org/doc/html/rfc8441#section-4\n    pub fn enable_connect_protocol(&mut self) -> &mut Self {\n        self.h2_builder.enable_connect_protocol = true;\n        self\n    }\n\n    /// Sets the max size of received header frames.\n    ///\n    /// Default is currently 16KB, but can change.\n    pub fn max_header_list_size(&mut self, max: u32) -> &mut Self {\n        self.h2_builder.max_header_list_size = max;\n        self\n    }\n\n    /// Set the timer used in background tasks.\n    pub fn timer<M>(&mut self, timer: M) -> &mut Self\n    where\n        M: Timer + Send + Sync + 'static,\n    {\n        self.timer = Time::Timer(Arc::new(timer));\n        self\n    }\n\n    /// Set whether the `date` header should be included in HTTP responses.\n    ///\n    /// Note that including the `date` header is recommended by RFC 7231.\n    ///\n    /// Default is true.\n    pub fn auto_date_header(&mut self, enabled: bool) -> &mut Self {\n        self.h2_builder.date_header = enabled;\n        self\n    }\n\n    /// Bind a connection together with a [`Service`](crate::service::Service).\n    ///\n    /// This returns a Future that must be polled in order for HTTP to be\n    /// driven on the connection.\n    pub fn serve_connection<S, I, Bd>(&self, io: I, service: S) -> Connection<I, S, E>\n    where\n        S: HttpService<IncomingBody, ResBody = Bd>,\n        S::Error: Into<Box<dyn StdError + Send + Sync>>,\n        Bd: Body + 'static,\n        Bd::Error: Into<Box<dyn StdError + Send + Sync>>,\n        I: Read + Write + Unpin,\n        E: Http2ServerConnExec<S::Future, Bd>,\n    {\n        let proto = proto::h2::Server::new(\n            io,\n            service,\n            &self.h2_builder,\n            self.exec.clone(),\n            self.timer.clone(),\n        );\n        Connection { conn: proto }\n    }\n}\n"
  },
  {
    "path": "src/server/conn/mod.rs",
    "content": "//!  Server connection API.\n//!\n//! The types in this module are to provide a lower-level API based around a\n//! single connection. Accepting a connection and binding it with a service\n//! are not handled at this level. This module provides the building blocks to\n//! customize those things externally.\n//!\n//! This module is split by HTTP version, providing a connection builder for\n//! each. They work similarly, but they each have specific options.\n//!\n//! If your server needs to support both versions, an auto-connection builder is\n//! provided in the [`hyper-util`](https://github.com/hyperium/hyper-util/tree/master)\n//! crate. This builder wraps the HTTP/1 and HTTP/2 connection builders from this\n//! module, allowing you to set configuration for both. The builder will then check\n//! the version of the incoming connection and serve it accordingly.\n\n#[cfg(feature = \"http1\")]\npub mod http1;\n#[cfg(feature = \"http2\")]\npub mod http2;\n"
  },
  {
    "path": "src/server/mod.rs",
    "content": "//! HTTP Server\n//!\n//! A \"server\" is usually created by listening on a port for new connections,\n//! parse HTTP requests, and hand them off to a `Service`.\n//!\n//! How exactly you choose to listen for connections is not something hyper\n//! concerns itself with. After you have a connection, you can handle HTTP over\n//! it with the types in the [`conn`] module.\npub mod conn;\n"
  },
  {
    "path": "src/service/http.rs",
    "content": "use std::error::Error as StdError;\nuse std::future::Future;\n\nuse crate::body::Body;\nuse crate::service::service::Service;\nuse crate::{Request, Response};\n\n/// An asynchronous function from [`Request`] to [`Response`].\n///\n/// This is a *sealed* trait, meaning that it can not be implemented directly. Rather, it is an\n/// alias for [`Service`]s that accept a [`Request`] and return a [`Future`] that resolves to a\n/// [`Response`]. External callers should implement [`Service`] instead.\n///\n/// Rather than being generic over the request and response, this trait is generic across the\n/// request [`Body`] and response [`Body`].\n///\n/// See the crate-level [`service`][crate::service] documentation for more information.\n///\n/// See [`Service`] for more information.\npub trait HttpService<ReqBody>: sealed::Sealed<ReqBody> {\n    /// The [`Body`] body of the [`Response`].\n    type ResBody: Body;\n\n    /// The error type that can occur within this [`Service`].\n    ///\n    /// Note: Returning an `Error` to a hyper server, the behavior depends on the protocol. In\n    /// most cases, hyper will cause the connection to be abruptly aborted. In most cases, it is\n    /// better to return a `Response` with a 4xx or 5xx status code.\n    ///\n    /// See [`Service::Error`] for more information.\n    type Error: Into<Box<dyn StdError + Send + Sync>>;\n\n    /// The [`Future`] returned by this [`Service`].\n    type Future: Future<Output = Result<Response<Self::ResBody>, Self::Error>>;\n\n    #[doc(hidden)]\n    fn call(&mut self, req: Request<ReqBody>) -> Self::Future;\n}\n\nimpl<T, B1, B2> HttpService<B1> for T\nwhere\n    T: Service<Request<B1>, Response = Response<B2>>,\n    B2: Body,\n    T::Error: Into<Box<dyn StdError + Send + Sync>>,\n{\n    type ResBody = B2;\n\n    type Error = T::Error;\n    type Future = T::Future;\n\n    fn call(&mut self, req: Request<B1>) -> Self::Future {\n        Service::call(self, req)\n    }\n}\n\nimpl<T, B1, B2> sealed::Sealed<B1> for T\nwhere\n    T: Service<Request<B1>, Response = Response<B2>>,\n    B2: Body,\n{\n}\n\nmod sealed {\n    pub trait Sealed<T> {}\n}\n"
  },
  {
    "path": "src/service/mod.rs",
    "content": "//! Asynchronous Services\n//!\n//! A [`Service`] is a trait representing an asynchronous\n//! function of a request to a response. It's similar to\n//! `async fn(Request) -> Result<Response, Error>`.\n//!\n//! The argument and return value isn't strictly required to be for HTTP.\n//! Therefore, hyper uses several \"trait aliases\" to reduce clutter around\n//! bounds. These are:\n//!\n//! - `HttpService`: This is blanketly implemented for all types that\n//!   implement `Service<http::Request<B1>, Response = http::Response<B2>>`.\n//!\n//! # HttpService\n//!\n//! In hyper, especially in the server setting, a `Service` is usually bound\n//! to a single connection. It defines how to respond to **all** requests that\n//! connection will receive.\n//!\n//! The helper [`service_fn`] should be sufficient for most cases, but\n//! if you need to implement `Service` for a type manually, you can follow the example\n//! in `service_struct_impl.rs`.\n\nmod http;\nmod service;\nmod util;\n\npub use self::http::HttpService;\npub use self::service::Service;\npub use self::util::service_fn;\n"
  },
  {
    "path": "src/service/service.rs",
    "content": "use std::future::Future;\n\n/// An asynchronous function from a `Request` to a `Response`.\n///\n/// The `Service` trait is a simplified interface making it easy to write\n/// network applications in a modular and reusable way, decoupled from the\n/// underlying protocol.\n///\n/// # Functional\n///\n/// A `Service` is a function of a `Request`. It immediately returns a\n/// [`Future`] representing the eventual completion of processing the\n/// request. The actual request processing may happen at any time in the\n/// future, on any thread or executor. The processing may depend on calling\n/// other services. At some point in the future, the processing will complete,\n/// and the [`Future`] will resolve to a response or an error.\n///\n/// At a high level, the `Service::call` function represents an RPC request. The\n/// `Service` value can be a server or a client.\n///\n/// # Utilities\n///\n/// The [`hyper-util`][util] crate provides facilities to bridge this trait to\n/// other libraries, such as [`tower`][tower], which might provide their\n/// own `Service` variants.\n///\n/// See [`hyper_util::service`][util-service] for more information.\n///\n/// [tower]: https://docs.rs/tower\n/// [util]: https://docs.rs/hyper-util\n/// [util-service]: https://docs.rs/hyper-util/latest/hyper_util/service/index.html\npub trait Service<Request> {\n    /// Responses given by the service.\n    type Response;\n\n    /// Errors produced by the service.\n    ///\n    /// Note: Returning an `Error` to a hyper server, the behavior depends on the\n    /// protocol. In most cases, hyper will cause the connection to be abruptly aborted.\n    /// It will abort the request however the protocol allows, either with some sort of RST_STREAM,\n    /// or killing the connection if that doesn't exist.\n    type Error;\n\n    /// The future response value.\n    type Future: Future<Output = Result<Self::Response, Self::Error>>;\n\n    /// Process the request and return the response asynchronously.\n    /// `call` takes `&self` instead of `mut &self` because:\n    /// - It prepares the way for async fn,\n    ///   since then the future only borrows `&self`, and thus a Service can concurrently handle\n    ///   multiple outstanding requests at once.\n    /// - It's clearer that Services can likely be cloned.\n    /// - To share state across clones, you generally need `Arc<Mutex<_>>`\n    ///   That means you're not really using the `&mut self` and could do with a `&self`.\n    ///   The discussion on this is here: <https://github.com/hyperium/hyper/issues/3040>\n    fn call(&self, req: Request) -> Self::Future;\n}\n\nimpl<Request, S: Service<Request> + ?Sized> Service<Request> for &'_ S {\n    type Response = S::Response;\n    type Error = S::Error;\n    type Future = S::Future;\n\n    #[inline]\n    fn call(&self, req: Request) -> Self::Future {\n        (**self).call(req)\n    }\n}\n\nimpl<Request, S: Service<Request> + ?Sized> Service<Request> for &'_ mut S {\n    type Response = S::Response;\n    type Error = S::Error;\n    type Future = S::Future;\n\n    #[inline]\n    fn call(&self, req: Request) -> Self::Future {\n        (**self).call(req)\n    }\n}\n\nimpl<Request, S: Service<Request> + ?Sized> Service<Request> for Box<S> {\n    type Response = S::Response;\n    type Error = S::Error;\n    type Future = S::Future;\n\n    #[inline]\n    fn call(&self, req: Request) -> Self::Future {\n        (**self).call(req)\n    }\n}\n\nimpl<Request, S: Service<Request> + ?Sized> Service<Request> for std::rc::Rc<S> {\n    type Response = S::Response;\n    type Error = S::Error;\n    type Future = S::Future;\n\n    #[inline]\n    fn call(&self, req: Request) -> Self::Future {\n        (**self).call(req)\n    }\n}\n\nimpl<Request, S: Service<Request> + ?Sized> Service<Request> for std::sync::Arc<S> {\n    type Response = S::Response;\n    type Error = S::Error;\n    type Future = S::Future;\n\n    #[inline]\n    fn call(&self, req: Request) -> Self::Future {\n        (**self).call(req)\n    }\n}\n"
  },
  {
    "path": "src/service/util.rs",
    "content": "use std::error::Error as StdError;\nuse std::fmt;\nuse std::future::Future;\nuse std::marker::PhantomData;\n\nuse crate::body::Body;\nuse crate::service::service::Service;\nuse crate::{Request, Response};\n\n/// Create a `Service` from a function.\n///\n/// # Example\n///\n/// ```\n/// use bytes::Bytes;\n/// use hyper::{body, Request, Response, Version};\n/// use http_body_util::Full;\n/// use hyper::service::service_fn;\n///\n/// let service = service_fn(|req: Request<body::Incoming>| async move {\n///     if req.version() == Version::HTTP_11 {\n///         Ok(Response::new(Full::<Bytes>::from(\"Hello World\")))\n///     } else {\n///         // Note: it's usually better to return a Response\n///         // with an appropriate StatusCode instead of an Err.\n///         Err(\"not HTTP/1.1, abort connection\")\n///     }\n/// });\n/// ```\npub fn service_fn<F, R, S>(f: F) -> ServiceFn<F, R>\nwhere\n    F: Fn(Request<R>) -> S,\n    S: Future,\n{\n    ServiceFn {\n        f,\n        _req: PhantomData,\n    }\n}\n\n/// Service returned by [`service_fn`]\npub struct ServiceFn<F, R> {\n    f: F,\n    _req: PhantomData<fn(R)>,\n}\n\nimpl<F, ReqBody, Ret, ResBody, E> Service<Request<ReqBody>> for ServiceFn<F, ReqBody>\nwhere\n    F: Fn(Request<ReqBody>) -> Ret,\n    ReqBody: Body,\n    Ret: Future<Output = Result<Response<ResBody>, E>>,\n    E: Into<Box<dyn StdError + Send + Sync>>,\n    ResBody: Body,\n{\n    type Response = crate::Response<ResBody>;\n    type Error = E;\n    type Future = Ret;\n\n    fn call(&self, req: Request<ReqBody>) -> Self::Future {\n        (self.f)(req)\n    }\n}\n\nimpl<F, R> fmt::Debug for ServiceFn<F, R> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"impl Service\").finish()\n    }\n}\n\nimpl<F, R> Clone for ServiceFn<F, R>\nwhere\n    F: Clone,\n{\n    fn clone(&self) -> Self {\n        ServiceFn {\n            f: self.f.clone(),\n            _req: PhantomData,\n        }\n    }\n}\n\nimpl<F, R> Copy for ServiceFn<F, R> where F: Copy {}\n"
  },
  {
    "path": "src/trace.rs",
    "content": "// For completeness, wrappers around all of tracing's public logging and span macros are provided,\n// even if they are not used at the present time.\n#![allow(unused_macros)]\n\n#[cfg(all(not(hyper_unstable_tracing), feature = \"tracing\"))]\ncompile_error!(\n    \"\\\n    The `tracing` feature is unstable, and requires the \\\n    `RUSTFLAGS='--cfg hyper_unstable_tracing'` environment variable to be set.\\\n\"\n);\n\nmacro_rules! debug {\n    ($($arg:tt)+) => {\n        #[cfg(feature = \"tracing\")]\n        {\n            tracing::debug!($($arg)+);\n        }\n    }\n}\n\nmacro_rules! debug_span {\n    ($($arg:tt)*) => {\n        {\n            #[cfg(feature = \"tracing\")]\n            {\n                let _span = tracing::debug_span!($($arg)+);\n                _span.entered()\n            }\n        }\n    }\n}\n\nmacro_rules! error {\n    ($($arg:tt)*) => {\n        #[cfg(feature = \"tracing\")]\n        {\n            tracing::error!($($arg)+);\n        }\n    }\n}\n\nmacro_rules! error_span {\n    ($($arg:tt)*) => {\n        {\n            #[cfg(feature = \"tracing\")]\n            {\n                let _span = tracing::error_span!($($arg)+);\n                _span.entered()\n            }\n        }\n    }\n}\n\nmacro_rules! info {\n    ($($arg:tt)*) => {\n        #[cfg(feature = \"tracing\")]\n        {\n            tracing::info!($($arg)+);\n        }\n    }\n}\n\nmacro_rules! info_span {\n    ($($arg:tt)*) => {\n        {\n            #[cfg(feature = \"tracing\")]\n            {\n                let _span = tracing::info_span!($($arg)+);\n                _span.entered()\n            }\n        }\n    }\n}\n\nmacro_rules! trace {\n    ($($arg:tt)*) => {\n        #[cfg(feature = \"tracing\")]\n        {\n            tracing::trace!($($arg)+);\n        }\n    }\n}\n\nmacro_rules! trace_span {\n    ($($arg:tt)*) => {\n        {\n            #[cfg(feature = \"tracing\")]\n            {\n                let _span = tracing::trace_span!($($arg)+);\n                _span.entered()\n            }\n        }\n    }\n}\n\nmacro_rules! span {\n    ($($arg:tt)*) => {\n        {\n            #[cfg(feature = \"tracing\")]\n            {\n                let _span = tracing::span!($($arg)+);\n                _span.entered()\n            }\n        }\n    }\n}\n\nmacro_rules! warn {\n    ($($arg:tt)*) => {\n        #[cfg(feature = \"tracing\")]\n        {\n            tracing::warn!($($arg)+);\n        }\n    }\n}\n\nmacro_rules! warn_span {\n    ($($arg:tt)*) => {\n        {\n            #[cfg(feature = \"tracing\")]\n            {\n                let _span = tracing::warn_span!($($arg)+);\n                _span.entered()\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/upgrade.rs",
    "content": "//! HTTP Upgrades\n//!\n//! This module deals with managing [HTTP Upgrades][mdn] in hyper. Since\n//! several concepts in HTTP allow for first talking HTTP, and then converting\n//! to a different protocol, this module conflates them into a single API.\n//! Those include:\n//!\n//! - HTTP/1.1 Upgrades\n//! - HTTP `CONNECT`\n//!\n//! You are responsible for any other pre-requisites to establish an upgrade,\n//! such as sending the appropriate headers, methods, and status codes. You can\n//! then use [`on`][] to grab a `Future` which will resolve to the upgraded\n//! connection object, or an error if the upgrade fails.\n//!\n//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism\n//!\n//! # Client\n//!\n//! Sending an HTTP upgrade from the [`client`](super::client) involves setting\n//! either the appropriate method, if wanting to `CONNECT`, or headers such as\n//! `Upgrade` and `Connection`, on the `http::Request`. Once receiving the\n//! `http::Response` back, you must check for the specific information that the\n//! upgrade is agreed upon by the server (such as a `101` status code), and then\n//! get the `Future` from the `Response`.\n//!\n//! # Server\n//!\n//! Receiving upgrade requests in a server requires you to check the relevant\n//! headers in a `Request`, and if an upgrade should be done, you then send the\n//! corresponding headers in a response. To then wait for hyper to finish the\n//! upgrade, you call `on()` with the `Request`, and then can spawn a task\n//! awaiting it.\n//!\n//! # Example\n//!\n//! See [this example][example] showing how upgrades work with both\n//! Clients and Servers.\n//!\n//! [example]: https://github.com/hyperium/hyper/blob/master/examples/upgrades.rs\n\nuse std::any::TypeId;\nuse std::error::Error as StdError;\nuse std::fmt;\nuse std::future::Future;\nuse std::io;\nuse std::pin::Pin;\nuse std::sync::{Arc, Mutex};\nuse std::task::{Context, Poll};\n\nuse crate::rt::{Read, ReadBufCursor, Write};\nuse bytes::Bytes;\nuse tokio::sync::oneshot;\n\nuse crate::common::io::Rewind;\n\n/// An upgraded HTTP connection.\n///\n/// This type holds a trait object internally of the original IO that\n/// was used to speak HTTP before the upgrade. It can be used directly\n/// as a [`Read`] or [`Write`] for convenience.\n///\n/// Alternatively, if the exact type is known, this can be deconstructed\n/// into its parts.\npub struct Upgraded {\n    io: Rewind<Box<dyn Io + Send>>,\n}\n\n/// A future for a possible HTTP upgrade.\n///\n/// If no upgrade was available, or it doesn't succeed, yields an `Error`.\n#[derive(Clone)]\npub struct OnUpgrade {\n    rx: Option<Arc<Mutex<oneshot::Receiver<crate::Result<Upgraded>>>>>,\n}\n\n/// The deconstructed parts of an [`Upgraded`] type.\n///\n/// Includes the original IO type, and a read buffer of bytes that the\n/// HTTP state machine may have already read before completing an upgrade.\n#[derive(Debug)]\n#[non_exhaustive]\npub struct Parts<T> {\n    /// The original IO object used before the upgrade.\n    pub io: T,\n    /// A buffer of bytes that have been read but not processed as HTTP.\n    ///\n    /// For instance, if the `Connection` is used for an HTTP upgrade request,\n    /// it is possible the server sent back the first bytes of the new protocol\n    /// along with the response upgrade.\n    ///\n    /// You will want to check for any existing bytes if you plan to continue\n    /// communicating on the IO object.\n    pub read_buf: Bytes,\n}\n\n/// Gets a pending HTTP upgrade from this message.\n///\n/// This can be called on the following types:\n///\n/// - `http::Request<B>`\n/// - `http::Response<B>`\n/// - `&mut http::Request<B>`\n/// - `&mut http::Response<B>`\npub fn on<T: sealed::CanUpgrade>(msg: T) -> OnUpgrade {\n    msg.on_upgrade()\n}\n\n#[cfg(all(\n    any(feature = \"client\", feature = \"server\"),\n    any(feature = \"http1\", feature = \"http2\"),\n))]\npub(super) struct Pending {\n    tx: oneshot::Sender<crate::Result<Upgraded>>,\n}\n\n#[cfg(all(\n    any(feature = \"client\", feature = \"server\"),\n    any(feature = \"http1\", feature = \"http2\"),\n))]\npub(super) fn pending() -> (Pending, OnUpgrade) {\n    let (tx, rx) = oneshot::channel();\n    (\n        Pending { tx },\n        OnUpgrade {\n            rx: Some(Arc::new(Mutex::new(rx))),\n        },\n    )\n}\n\n// ===== impl Upgraded =====\n\nimpl Upgraded {\n    #[cfg(all(\n        any(feature = \"client\", feature = \"server\"),\n        any(feature = \"http1\", feature = \"http2\")\n    ))]\n    pub(super) fn new<T>(io: T, read_buf: Bytes) -> Self\n    where\n        T: Read + Write + Unpin + Send + 'static,\n    {\n        Upgraded {\n            io: Rewind::new_buffered(Box::new(io), read_buf),\n        }\n    }\n\n    /// Tries to downcast the internal trait object to the type passed.\n    ///\n    /// On success, returns the downcasted parts. On error, returns the\n    /// `Upgraded` back.\n    pub fn downcast<T: Read + Write + Unpin + 'static>(self) -> Result<Parts<T>, Self> {\n        let (io, buf) = self.io.into_inner();\n        match io.__hyper_downcast() {\n            Ok(t) => Ok(Parts {\n                io: *t,\n                read_buf: buf,\n            }),\n            Err(io) => Err(Upgraded {\n                io: Rewind::new_buffered(io, buf),\n            }),\n        }\n    }\n}\n\nimpl Read for Upgraded {\n    fn poll_read(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: ReadBufCursor<'_>,\n    ) -> Poll<io::Result<()>> {\n        Pin::new(&mut self.io).poll_read(cx, buf)\n    }\n}\n\nimpl Write for Upgraded {\n    fn poll_write(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<io::Result<usize>> {\n        Pin::new(&mut self.io).poll_write(cx, buf)\n    }\n\n    fn poll_write_vectored(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        bufs: &[io::IoSlice<'_>],\n    ) -> Poll<io::Result<usize>> {\n        Pin::new(&mut self.io).poll_write_vectored(cx, bufs)\n    }\n\n    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        Pin::new(&mut self.io).poll_flush(cx)\n    }\n\n    fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        Pin::new(&mut self.io).poll_shutdown(cx)\n    }\n\n    fn is_write_vectored(&self) -> bool {\n        self.io.is_write_vectored()\n    }\n}\n\nimpl fmt::Debug for Upgraded {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Upgraded\").finish()\n    }\n}\n\n// ===== impl OnUpgrade =====\n\nimpl OnUpgrade {\n    pub(super) fn none() -> Self {\n        OnUpgrade { rx: None }\n    }\n\n    #[cfg(all(any(feature = \"client\", feature = \"server\"), feature = \"http1\"))]\n    pub(super) fn is_none(&self) -> bool {\n        self.rx.is_none()\n    }\n}\n\nimpl Future for OnUpgrade {\n    type Output = Result<Upgraded, crate::Error>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        match self.rx {\n            Some(ref rx) => Pin::new(&mut *rx.lock().unwrap())\n                .poll(cx)\n                .map(|res| match res {\n                    Ok(Ok(upgraded)) => Ok(upgraded),\n                    Ok(Err(err)) => Err(err),\n                    Err(_oneshot_canceled) => {\n                        Err(crate::Error::new_canceled().with(UpgradeExpected))\n                    }\n                }),\n            None => Poll::Ready(Err(crate::Error::new_user_no_upgrade())),\n        }\n    }\n}\n\nimpl fmt::Debug for OnUpgrade {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"OnUpgrade\").finish()\n    }\n}\n\n// ===== impl Pending =====\n\n#[cfg(all(\n    any(feature = \"client\", feature = \"server\"),\n    any(feature = \"http1\", feature = \"http2\")\n))]\nimpl Pending {\n    pub(super) fn fulfill(self, upgraded: Upgraded) {\n        trace!(\"pending upgrade fulfill\");\n        let _ = self.tx.send(Ok(upgraded));\n    }\n\n    #[cfg(feature = \"http1\")]\n    /// Don't fulfill the pending Upgrade, but instead signal that\n    /// upgrades are handled manually.\n    pub(super) fn manual(self) {\n        #[cfg(any(feature = \"http1\", feature = \"http2\"))]\n        trace!(\"pending upgrade handled manually\");\n        let _ = self.tx.send(Err(crate::Error::new_user_manual_upgrade()));\n    }\n}\n\n// ===== impl UpgradeExpected =====\n\n/// Error cause returned when an upgrade was expected but canceled\n/// for whatever reason.\n///\n/// This likely means the actual `Conn` future wasn't polled and upgraded.\n#[derive(Debug)]\nstruct UpgradeExpected;\n\nimpl fmt::Display for UpgradeExpected {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"upgrade expected but not completed\")\n    }\n}\n\nimpl StdError for UpgradeExpected {}\n\n// ===== impl Io =====\n\npub(super) trait Io: Read + Write + Unpin + 'static {\n    fn __hyper_type_id(&self) -> TypeId {\n        TypeId::of::<Self>()\n    }\n}\n\nimpl<T: Read + Write + Unpin + 'static> Io for T {}\n\nimpl dyn Io + Send {\n    fn __hyper_is<T: Io>(&self) -> bool {\n        let t = TypeId::of::<T>();\n        self.__hyper_type_id() == t\n    }\n\n    fn __hyper_downcast<T: Io>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {\n        if self.__hyper_is::<T>() {\n            // Taken from `std::error::Error::downcast()`.\n            unsafe {\n                let raw: *mut dyn Io = Box::into_raw(self);\n                Ok(Box::from_raw(raw as *mut T))\n            }\n        } else {\n            Err(self)\n        }\n    }\n}\n\nmod sealed {\n    use super::OnUpgrade;\n\n    pub trait CanUpgrade {\n        fn on_upgrade(self) -> OnUpgrade;\n    }\n\n    impl<B> CanUpgrade for http::Request<B> {\n        fn on_upgrade(mut self) -> OnUpgrade {\n            self.extensions_mut()\n                .remove::<OnUpgrade>()\n                .unwrap_or_else(OnUpgrade::none)\n        }\n    }\n\n    impl<B> CanUpgrade for &'_ mut http::Request<B> {\n        fn on_upgrade(self) -> OnUpgrade {\n            self.extensions_mut()\n                .remove::<OnUpgrade>()\n                .unwrap_or_else(OnUpgrade::none)\n        }\n    }\n\n    impl<B> CanUpgrade for http::Response<B> {\n        fn on_upgrade(mut self) -> OnUpgrade {\n            self.extensions_mut()\n                .remove::<OnUpgrade>()\n                .unwrap_or_else(OnUpgrade::none)\n        }\n    }\n\n    impl<B> CanUpgrade for &'_ mut http::Response<B> {\n        fn on_upgrade(self) -> OnUpgrade {\n            self.extensions_mut()\n                .remove::<OnUpgrade>()\n                .unwrap_or_else(OnUpgrade::none)\n        }\n    }\n}\n\n#[cfg(all(\n    any(feature = \"client\", feature = \"server\"),\n    any(feature = \"http1\", feature = \"http2\"),\n))]\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn upgraded_downcast() {\n        let upgraded = Upgraded::new(Mock, Bytes::new());\n\n        let upgraded = upgraded\n            .downcast::<crate::common::io::Compat<std::io::Cursor<Vec<u8>>>>()\n            .unwrap_err();\n\n        upgraded.downcast::<Mock>().unwrap();\n    }\n\n    // TODO: replace with tokio_test::io when it can test write_buf\n    struct Mock;\n\n    impl Read for Mock {\n        fn poll_read(\n            self: Pin<&mut Self>,\n            _cx: &mut Context<'_>,\n            _buf: ReadBufCursor<'_>,\n        ) -> Poll<io::Result<()>> {\n            unreachable!(\"Mock::poll_read\")\n        }\n    }\n\n    impl Write for Mock {\n        fn poll_write(\n            self: Pin<&mut Self>,\n            _: &mut Context<'_>,\n            buf: &[u8],\n        ) -> Poll<io::Result<usize>> {\n            // panic!(\"poll_write shouldn't be called\");\n            Poll::Ready(Ok(buf.len()))\n        }\n\n        fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n            unreachable!(\"Mock::poll_flush\")\n        }\n\n        fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n            unreachable!(\"Mock::poll_shutdown\")\n        }\n    }\n}\n"
  },
  {
    "path": "tests/client.rs",
    "content": "#![deny(warnings)]\n#![warn(rust_2018_idioms)]\n\nuse std::convert::Infallible;\nuse std::fmt;\nuse std::future::Future;\nuse std::io::{Read, Write};\nuse std::net::{SocketAddr, TcpListener};\nuse std::pin::Pin;\nuse std::thread;\nuse std::time::Duration;\n\nuse http::uri::PathAndQuery;\nuse http_body_util::{BodyExt, StreamBody};\nuse hyper::body::Frame;\nuse hyper::header::{HeaderMap, HeaderName, HeaderValue};\nuse hyper::{Method, Request, StatusCode, Uri, Version};\n\nuse bytes::Bytes;\nuse futures_channel::oneshot;\nuse futures_util::future::{self, FutureExt, TryFuture, TryFutureExt};\nuse support::TokioIo;\nuse tokio::net::TcpStream;\nmod support;\n\nfn s(buf: &[u8]) -> &str {\n    std::str::from_utf8(buf).expect(\"from_utf8\")\n}\n\nasync fn concat<B>(b: B) -> Result<Bytes, B::Error>\nwhere\n    B: hyper::body::Body,\n{\n    b.collect().await.map(|c| c.to_bytes())\n}\n\nasync fn concat_with_trailers<B>(b: B) -> Result<(Bytes, Option<HeaderMap>), B::Error>\nwhere\n    B: hyper::body::Body,\n{\n    let collect = b.collect().await?;\n    let trailers = collect.trailers().cloned();\n    let bytes = collect.to_bytes();\n\n    Ok((bytes, trailers))\n}\n\nasync fn tcp_connect(addr: &SocketAddr) -> std::io::Result<TokioIo<TcpStream>> {\n    TcpStream::connect(*addr).await.map(TokioIo::new)\n}\n\n#[derive(Clone)]\nstruct HttpInfo {\n    remote_addr: SocketAddr,\n}\n\n#[derive(Debug)]\nenum Error {\n    Io(std::io::Error),\n    Hyper(hyper::Error),\n    AbsoluteUriRequired,\n    UnsupportedVersion,\n}\n\nimpl Error {\n    fn is_incomplete_message(&self) -> bool {\n        match self {\n            Self::Hyper(err) => err.is_incomplete_message(),\n            _ => false,\n        }\n    }\n\n    fn is_parse(&self) -> bool {\n        match self {\n            Self::Hyper(err) => err.is_parse(),\n            _ => false,\n        }\n    }\n\n    fn is_parse_too_large(&self) -> bool {\n        match self {\n            Self::Hyper(err) => err.is_parse_too_large(),\n            _ => false,\n        }\n    }\n\n    fn is_parse_status(&self) -> bool {\n        match self {\n            Self::Hyper(err) => err.is_parse_status(),\n            _ => false,\n        }\n    }\n}\n\nimpl fmt::Display for Error {\n    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::Io(err) => err.fmt(fmt),\n            Self::Hyper(err) => err.fmt(fmt),\n            Self::AbsoluteUriRequired => write!(fmt, \"client requires absolute-form URIs\"),\n            Self::UnsupportedVersion => write!(fmt, \"request has unsupported HTTP version\"),\n        }\n    }\n}\n\nimpl From<std::io::Error> for Error {\n    fn from(err: std::io::Error) -> Self {\n        Self::Io(err)\n    }\n}\n\nimpl From<hyper::Error> for Error {\n    fn from(err: hyper::Error) -> Self {\n        Self::Hyper(err)\n    }\n}\n\nmacro_rules! test {\n    (\n        name: $name:ident,\n        server:\n            expected: $server_expected:expr,\n            reply: $server_reply:expr,\n        client:\n            $(options: {$(\n                $c_opt_prop:ident: $c_opt_val:tt,\n            )*},)?\n            request: {$(\n                $c_req_prop:ident: $c_req_val:tt,\n            )*},\n\n            response:\n                status: $client_status:ident,\n                headers: { $($response_header_name:expr => $response_header_val:expr,)* },\n                body: $response_body:expr,\n                $(trailers: {$(\n                    $response_trailer_name:expr => $response_trailer_val:expr,\n                )*},)?\n    ) => (\n        #[test]\n        fn $name() {\n            let _ = pretty_env_logger::try_init();\n            let rt = support::runtime();\n\n            let res = test! {\n                INNER;\n                name: $name,\n                runtime: &rt,\n                server:\n                    expected: $server_expected,\n                    reply: $server_reply,\n                client:\n                    $(options: {$(\n                        $c_opt_prop: $c_opt_val,\n                    )*},)?\n                    request: {$(\n                        $c_req_prop: $c_req_val,\n                    )*},\n            }.expect(\"test\");\n\n\n            assert_eq!(res.status(), StatusCode::$client_status);\n            $(\n                assert_eq!(\n                    res\n                        .headers()\n                        .get($response_header_name)\n                        .expect(concat!(\"response header '\", stringify!($response_header_name), \"'\")),\n                    $response_header_val,\n                    \"response header '{}'\",\n                    stringify!($response_header_name),\n                );\n            )*\n\n            let (body, _trailers) = rt.block_on(concat_with_trailers(res))\n                .expect(\"body concat wait\");\n\n            let expected_res_body = Option::<&[u8]>::from($response_body)\n                .unwrap_or_default();\n            assert_eq!(body.as_ref(), expected_res_body);\n\n            $($(\n                assert_eq!(\n                    _trailers.as_ref().expect(\"trailers is None\")\n                        .get($response_trailer_name)\n                        .expect(concat!(\"trailer header '\", stringify!($response_trailer_name), \"'\")),\n                    $response_trailer_val,\n                    \"trailer '{}'\",\n                    stringify!($response_trailer_name),\n                );\n            )*)?\n        }\n    );\n    (\n        name: $name:ident,\n        server:\n            expected: $server_expected:expr,\n            reply: $server_reply:expr,\n        client:\n            request: {$(\n                $c_req_prop:ident: $c_req_val:tt,\n            )*},\n\n            error: $err:expr,\n    ) => (\n        #[test]\n        fn $name() {\n            let _ = pretty_env_logger::try_init();\n            let rt = support::runtime();\n\n            let err: Error = test! {\n                INNER;\n                name: $name,\n                runtime: &rt,\n                server:\n                    expected: $server_expected,\n                    reply: $server_reply,\n                client:\n                    request: {$(\n                        $c_req_prop: $c_req_val,\n                    )*},\n            }.unwrap_err();\n\n            fn infer_closure<F: FnOnce(&Error) -> bool>(f: F) -> F { f }\n\n            let closure = infer_closure($err);\n            if !closure(&err) {\n                panic!(\"expected error, unexpected variant: {:?}\", err);\n            }\n        }\n    );\n\n    (\n        INNER;\n        name: $name:ident,\n        runtime: $runtime:expr,\n        server:\n            expected: $server_expected:expr,\n            reply: $server_reply:expr,\n        client:\n            $(options: {$(\n                $c_opt_prop:ident: $c_opt_val:tt,\n            )*},)?\n            request: {$(\n                $c_req_prop:ident: $c_req_val:tt,\n            )*},\n    ) => ({\n        let server = TcpListener::bind(\"127.0.0.1:0\").expect(\"bind\");\n        let addr = server.local_addr().expect(\"local_addr\");\n        let rt = $runtime;\n\n        #[allow(unused_assignments, unused_mut)]\n        let mut body = BodyExt::boxed(http_body_util::Empty::<bytes::Bytes>::new());\n        let mut req_builder = Request::builder();\n        $(\n            test!(@client_request; req_builder, body, addr, $c_req_prop: $c_req_val);\n        )*\n        let mut req = req_builder\n            .body(body)\n            .expect(\"request builder\");\n\n        let res = async move {\n            // Wrapper around hyper::client::conn::Builder with set_host field to mimic\n            // hyper::client::Builder.\n            struct Builder {\n                inner: hyper::client::conn::http1::Builder,\n                set_host: bool,\n                http09_responses: bool,\n            }\n\n            impl Builder {\n                fn new() -> Self {\n                    Self {\n                        inner: hyper::client::conn::http1::Builder::new(),\n                        set_host: true,\n                        http09_responses: false,\n                    }\n                }\n\n                #[allow(unused)]\n                fn set_host(&mut self, val: bool) -> &mut Self {\n                    self.set_host = val;\n                    self\n                }\n\n                #[allow(unused)]\n                fn http09_responses(&mut self, val: bool) -> &mut Self {\n                    self.http09_responses = val;\n                    self.inner.http09_responses(val);\n                    self\n                }\n            }\n\n            impl std::ops::Deref for Builder {\n                type Target = hyper::client::conn::http1::Builder;\n\n                fn deref(&self) -> &Self::Target {\n                    &self.inner\n                }\n            }\n\n            impl std::ops::DerefMut for Builder {\n                fn deref_mut(&mut self) -> &mut Self::Target {\n                    &mut self.inner\n                }\n            }\n\n            #[allow(unused_mut)]\n            let mut builder = Builder::new();\n            $(builder$(.$c_opt_prop($c_opt_val))*;)?\n\n\n            if req.version() == Version::HTTP_09 && !builder.http09_responses {\n                return Err(Error::UnsupportedVersion);\n            }\n\n            if req.version() == Version::HTTP_2 {\n                return Err(Error::UnsupportedVersion);\n            }\n\n            let host = req.uri().host().ok_or(Error::AbsoluteUriRequired)?;\n            let port = req.uri().port_u16().unwrap_or(80);\n\n            let stream = TcpStream::connect(format!(\"{}:{}\", host, port)).await?;\n\n            let extra = HttpInfo {\n                remote_addr: stream.peer_addr().unwrap(),\n            };\n\n            if builder.set_host {\n                let host = req.uri().host().expect(\"no host in uri\");\n                let port = req.uri().port_u16().expect(\"no port in uri\");\n\n                let host = format!(\"{}:{}\", host, port);\n\n                req.headers_mut().append(\"Host\", HeaderValue::from_str(&host).unwrap());\n            }\n\n            let (mut sender, conn) = builder.handshake(TokioIo::new(stream)).await?;\n\n            tokio::task::spawn(async move {\n                if let Err(err) = conn.await {\n                    panic!(\"{}\", err);\n                }\n            });\n\n            let mut builder = Uri::builder();\n            if req.method() == Method::CONNECT {\n                builder = builder.path_and_query(format!(\"{}:{}\", req.uri().host().unwrap(), req.uri().port_u16().unwrap()));\n            } else {\n                builder = builder.path_and_query(req.uri().path_and_query().cloned().unwrap_or(PathAndQuery::from_static(\"/\")));\n            }\n            *req.uri_mut() = builder.build().unwrap();\n\n            let mut resp = sender.send_request(req).await?;\n\n            resp.extensions_mut().insert(extra);\n            Ok(resp)\n        };\n\n        let (tx, rx) = oneshot::channel();\n\n        let thread = thread::Builder::new()\n            .name(format!(\"tcp-server<{}>\", stringify!($name)));\n        thread.spawn(move || {\n            let mut inc = server.accept().expect(\"accept\").0;\n            inc.set_read_timeout(Some(Duration::from_secs(5))).expect(\"set_read_timeout\");\n            inc.set_write_timeout(Some(Duration::from_secs(5))).expect(\"set_write_timeout\");\n            let expected = format!($server_expected, addr=addr);\n            let mut buf = [0; 4096];\n            let mut n = 0;\n            while n < buf.len() && n < expected.len() {\n                n += match inc.read(&mut buf[n..]) {\n                    Ok(n) => n,\n                    Err(e) => panic!(\"failed to read request, partially read = {:?}, error: {}\", s(&buf[..n]), e),\n                };\n            }\n            assert_eq!(s(&buf[..n]), expected);\n\n            inc.write_all($server_reply.as_ref()).expect(\"write_all\");\n            let _ = tx.send(Ok::<_, Error>(()));\n        }).expect(\"thread spawn\");\n\n        let rx = rx.expect(\"thread panicked\");\n\n        rt.block_on(future::try_join(res, rx).map_ok(|r| r.0)).map(move |mut resp| {\n            // Always check that HttpConnector has set the \"extra\" info...\n            let extra = resp\n                .extensions_mut()\n                .remove::<HttpInfo>()\n                .expect(\"HttpConnector should set HttpInfo\");\n\n            assert_eq!(extra.remote_addr, addr, \"HttpInfo should have server addr\");\n\n            resp\n        })\n    });\n\n    (\n        @client_request;\n        $req_builder:ident,\n        $body:ident,\n        $addr:ident,\n        $c_req_prop:ident: $c_req_val:tt\n    ) => ({\n        __client_req_prop!($req_builder, $body, $addr, $c_req_prop: $c_req_val)\n    });\n}\n\nmacro_rules! __client_req_prop {\n    ($req_builder:ident, $body:ident, $addr:ident, headers: $map:tt) => {{\n        __client_req_header!($req_builder, $map)\n    }};\n\n    ($req_builder:ident, $body:ident, $addr:ident, method: $method:ident) => {{\n        $req_builder = $req_builder.method(Method::$method);\n    }};\n\n    ($req_builder:ident, $body:ident, $addr:ident, version: $version:ident) => {{\n        $req_builder = $req_builder.version(hyper::Version::$version);\n    }};\n\n    ($req_builder:ident, $body:ident, $addr:ident, url: $url:expr) => {{\n        $req_builder = $req_builder.uri(format!($url, addr = $addr));\n    }};\n\n    ($req_builder:ident, $body:ident, $addr:ident, body: $body_e:expr) => {{\n        $body = BodyExt::boxed(http_body_util::Full::from($body_e));\n    }};\n\n    ($req_builder:ident, $body:ident, $addr:ident, body_stream: $body_e:expr) => {{\n        $body = BodyExt::boxed(StreamBody::new(futures_util::TryStreamExt::map_ok(\n            $body_e,\n            Frame::data,\n        )));\n    }};\n\n    ($req_builder:ident, $body:ident, $addr:ident, body_stream_with_trailers: $body_e:expr) => {{\n        use support::trailers::StreamBodyWithTrailers;\n        let (body, trailers) = $body_e;\n        $body = BodyExt::boxed(StreamBodyWithTrailers::with_trailers(\n            futures_util::TryStreamExt::map_ok(body, Frame::data),\n            trailers,\n        ));\n    }};\n}\n\nmacro_rules! __client_req_header {\n    ($req_builder:ident, { $($name:expr => $val:expr,)* }) => {{\n        $(\n        $req_builder = $req_builder.header($name, $val);\n        )*\n    }}\n}\n\nstatic REPLY_OK: &str = \"HTTP/1.1 200 OK\\r\\nContent-Length: 0\\r\\n\\r\\n\";\n\ntest! {\n    name: client_get,\n\n    server:\n        expected: \"GET / HTTP/1.1\\r\\nhost: {addr}\\r\\n\\r\\n\",\n        reply: REPLY_OK,\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/\",\n        },\n        response:\n            status: OK,\n            headers: {\n                \"Content-Length\" => \"0\",\n            },\n            body: None,\n}\n\ntest! {\n    name: client_get_query,\n\n    server:\n        expected: \"GET /foo?key=val HTTP/1.1\\r\\nhost: {addr}\\r\\n\\r\\n\",\n        reply: REPLY_OK,\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/foo?key=val#dont_send_me\",\n        },\n        response:\n            status: OK,\n            headers: {\n                \"Content-Length\" => \"0\",\n            },\n            body: None,\n}\n\ntest! {\n    name: client_get_req_body_implicitly_empty,\n\n    server:\n        expected: \"GET / HTTP/1.1\\r\\nhost: {addr}\\r\\n\\r\\n\",\n        reply: REPLY_OK,\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/\",\n            body: \"\", // not Body::empty\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n}\n\ntest! {\n    name: client_get_req_body_chunked,\n\n    server:\n        expected: \"\\\n            GET / HTTP/1.1\\r\\n\\\n            transfer-encoding: chunked\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            5\\r\\n\\\n            hello\\r\\n\\\n            0\\r\\n\\r\\n\\\n            \",\n        reply: REPLY_OK,\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/\",\n            headers: {\n                \"transfer-encoding\" => \"chunked\",\n            },\n            body: \"hello\", // not Body::empty\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n}\n\ntest! {\n    name: client_transfer_encoding_repair,\n\n    server:\n        expected: \"\\\n            GET / HTTP/1.1\\r\\n\\\n            transfer-encoding: foo, chunked\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            5\\r\\n\\\n            hello\\r\\n\\\n            0\\r\\n\\r\\n\\\n            \",\n        reply: REPLY_OK,\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/\",\n            headers: {\n                \"transfer-encoding\" => \"foo\",\n            },\n            body: \"hello\", // not Body::empty\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n}\n\ntest! {\n    name: client_get_req_body_chunked_http10,\n\n    server:\n        expected: \"\\\n            GET / HTTP/1.0\\r\\n\\\n            host: {addr}\\r\\n\\\n            content-length: 5\\r\\n\\\n            \\r\\n\\\n            hello\\\n            \",\n        reply: \"HTTP/1.0 200 OK\\r\\ncontent-length: 0\\r\\n\\r\\n\",\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/\",\n            headers: {\n                \"transfer-encoding\" => \"chunked\",\n            },\n            version: HTTP_10,\n            body: \"hello\",\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n}\n\ntest! {\n    name: client_get_req_body_chunked_with_trailer,\n\n    server:\n        expected: \"\\\n            GET / HTTP/1.1\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: \"\\\n            HTTP/1.1 200 OK\\r\\n\\\n            Transfer-Encoding: chunked\\r\\n\\\n            \\r\\n\\\n            5\\r\\n\\\n            hello\\r\\n\\\n            0\\r\\n\\\n            Trailer: value\\r\\n\\\n            \\r\\n\\\n            \",\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/\",\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: &b\"hello\"[..],\n}\n\ntest! {\n    name: client_get_req_body_chunked_with_multiple_trailers,\n\n    server:\n        expected: \"\\\n            GET / HTTP/1.1\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: \"\\\n            HTTP/1.1 200 OK\\r\\n\\\n            Transfer-Encoding: chunked\\r\\n\\\n            \\r\\n\\\n            5\\r\\n\\\n            hello\\r\\n\\\n            0\\r\\n\\\n            Trailer: value\\r\\n\\\n            another-trainer: another-value\\r\\n\\\n            \\r\\n\\\n            \",\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/\",\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: &b\"hello\"[..],\n}\n\ntest! {\n    name: client_post_req_body_chunked_with_trailer,\n\n    server:\n        expected: \"\\\n            POST / HTTP/1.1\\r\\n\\\n            trailer: chunky-trailer\\r\\n\\\n            host: {addr}\\r\\n\\\n            transfer-encoding: chunked\\r\\n\\\n            \\r\\n\\\n            5\\r\\n\\\n            hello\\r\\n\\\n            0\\r\\n\\\n            chunky-trailer: header data\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: REPLY_OK,\n\n    client:\n        request: {\n            method: POST,\n            url: \"http://{addr}/\",\n            headers: {\n                \"trailer\" => \"chunky-trailer\",\n            },\n            body_stream_with_trailers: (\n                (futures_util::stream::once(async { Ok::<_, Infallible>(Bytes::from(\"hello\"))})),\n                HeaderMap::from_iter(vec![(\n                    HeaderName::from_static(\"chunky-trailer\"),\n                    HeaderValue::from_static(\"header data\")\n                )].into_iter())),\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n}\n\ntest! {\n    name: client_post_req_body_chunked_with_trailer_titlecase,\n\n    server:\n        expected: \"\\\n            POST / HTTP/1.1\\r\\n\\\n            trailer: Chunky-Trailer\\r\\n\\\n            host: {addr}\\r\\n\\\n            transfer-encoding: chunked\\r\\n\\\n            \\r\\n\\\n            5\\r\\n\\\n            hello\\r\\n\\\n            0\\r\\n\\\n            chunky-trailer: header data\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: REPLY_OK,\n\n    client:\n        request: {\n            method: POST,\n            url: \"http://{addr}/\",\n            headers: {\n                \"trailer\" => \"Chunky-Trailer\",\n            },\n            body_stream_with_trailers: (\n                (futures_util::stream::once(async { Ok::<_, Infallible>(Bytes::from(\"hello\"))})),\n                HeaderMap::from_iter(vec![(\n                    HeaderName::from_static(\"chunky-trailer\"),\n                    HeaderValue::from_static(\"header data\")\n                )].into_iter())),\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n}\n\ntest! {\n    name: client_res_body_chunked_with_trailer,\n\n    server:\n        expected: \"GET / HTTP/1.1\\r\\nte: trailers\\r\\nhost: {addr}\\r\\n\\r\\n\",\n        reply: \"\\\n            HTTP/1.1 200 OK\\r\\n\\\n            transfer-encoding: chunked\\r\\n\\\n            trailer: chunky-trailer\\r\\n\\\n            \\r\\n\\\n            5\\r\\n\\\n            hello\\r\\n\\\n            0\\r\\n\\\n            chunky-trailer: header data\\r\\n\\\n            \\r\\n\\\n            \",\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/\",\n            headers: {\n                \"te\" => \"trailers\",\n            },\n        },\n        response:\n            status: OK,\n            headers: {\n                \"Transfer-Encoding\" => \"chunked\",\n            },\n            body: &b\"hello\"[..],\n            trailers: {\n                \"chunky-trailer\" => \"header data\",\n            },\n}\n\ntest! {\n    name: client_res_body_chunked_with_trailer_titlecase,\n\n    server:\n        expected: \"GET / HTTP/1.1\\r\\nte: trailers\\r\\nhost: {addr}\\r\\n\\r\\n\",\n        reply: \"\\\n            HTTP/1.1 200 OK\\r\\n\\\n            transfer-encoding: chunked\\r\\n\\\n            trailer: Chunky-Trailer\\r\\n\\\n            \\r\\n\\\n            5\\r\\n\\\n            hello\\r\\n\\\n            0\\r\\n\\\n            chunky-trailer: header data\\r\\n\\\n            \\r\\n\\\n            \",\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/\",\n            headers: {\n                \"te\" => \"trailers\",\n            },\n        },\n        response:\n            status: OK,\n            headers: {\n                \"Transfer-Encoding\" => \"chunked\",\n            },\n            body: &b\"hello\"[..],\n            trailers: {\n                \"chunky-trailer\" => \"header data\",\n            },\n}\n\ntest! {\n    name: client_res_body_chunked_with_pathological_trailers,\n\n    server:\n        expected: \"GET / HTTP/1.1\\r\\nte: trailers\\r\\nhost: {addr}\\r\\n\\r\\n\",\n        reply: \"\\\n            HTTP/1.1 200 OK\\r\\n\\\n            transfer-encoding: chunked\\r\\n\\\n            trailer: chunky-trailer1, chunky-trailer2, chunky-trailer3, chunky-trailer4, chunky-trailer5\\r\\n\\\n            \\r\\n\\\n            5\\r\\n\\\n            hello\\r\\n\\\n            0\\r\\n\\\n            chunky-trailer1: header data1\\r\\n\\\n            chunky-trailer2: header data2\\r\\n\\\n            chunky-trailer3: header data3\\r\\n\\\n            chunky-trailer4: header data4\\r\\n\\\n            chunky-trailer5: header data5\\r\\n\\\n            sneaky-trailer: not in trailer header\\r\\n\\\n            transfer-encoding: chunked\\r\\n\\\n            content-length: 5\\r\\n\\\n            trailer: foo\\r\\n\\\n            \\r\\n\\\n            \",\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/\",\n            headers: {\n                \"te\" => \"trailers\",\n            },\n        },\n        response:\n            status: OK,\n            headers: {\n                \"Transfer-Encoding\" => \"chunked\",\n            },\n            body: &b\"hello\"[..],\n            trailers: {\n                \"chunky-trailer1\" => \"header data1\",\n                \"chunky-trailer2\" => \"header data2\",\n                \"chunky-trailer3\" => \"header data3\",\n                \"chunky-trailer4\" => \"header data4\",\n                \"chunky-trailer5\" => \"header data5\",\n                \"sneaky-trailer\" => \"not in trailer header\",\n                \"transfer-encoding\" => \"chunked\",\n                \"content-length\" => \"5\",\n                \"trailer\" => \"foo\",\n            },\n}\n\ntest! {\n    name: client_get_req_body_sized,\n\n    server:\n        expected: \"\\\n            GET / HTTP/1.1\\r\\n\\\n            content-length: 5\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            hello\\\n            \",\n        reply: REPLY_OK,\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/\",\n            headers: {\n                \"Content-Length\" => \"5\",\n            },\n            // use a \"stream\" (where Body doesn't know length) with a\n            // content-length header\n            body_stream: (futures_util::stream::once(async {\n                Ok::<_, Infallible>(Bytes::from(\"hello\"))\n            })),\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n}\n\ntest! {\n    name: client_get_req_body_unknown,\n\n    server:\n        expected: \"\\\n            GET / HTTP/1.1\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: REPLY_OK,\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/\",\n            // steam means we don't know the content-length,\n            // but we're wrapping a non-empty stream.\n            //\n            // But since the headers cannot tell us, and the method typically\n            // doesn't have a body, the body must be ignored.\n            body_stream: (futures_util::stream::once(async {\n                Ok::<_, Infallible>(Bytes::from(\"hello\"))\n            })),\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n}\n\ntest! {\n    name: client_get_req_body_unknown_http10,\n\n    server:\n        expected: \"\\\n            GET / HTTP/1.0\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: \"HTTP/1.0 200 OK\\r\\ncontent-length: 0\\r\\n\\r\\n\",\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/\",\n            headers: {\n                \"transfer-encoding\" => \"chunked\",\n            },\n            version: HTTP_10,\n            // steam means we don't know the content-length,\n            // but we're wrapping a non-empty stream.\n            //\n            // But since the headers cannot tell us, the body must be ignored.\n            body_stream: (futures_util::stream::once(async {\n                Ok::<_, Infallible>(Bytes::from(\"hello\"))\n            })),\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n}\n\ntest! {\n    name: client_post_sized,\n\n    server:\n        expected: \"\\\n            POST /length HTTP/1.1\\r\\n\\\n            content-length: 7\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            foo bar\\\n            \",\n        reply: REPLY_OK,\n\n    client:\n        request: {\n            method: POST,\n            url: \"http://{addr}/length\",\n            headers: {\n                \"Content-Length\" => \"7\",\n            },\n            body: \"foo bar\",\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n}\n\ntest! {\n    name: client_post_chunked,\n\n    server:\n        expected: \"\\\n            POST /chunks HTTP/1.1\\r\\n\\\n            transfer-encoding: chunked\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            B\\r\\n\\\n            foo bar baz\\r\\n\\\n            0\\r\\n\\r\\n\\\n            \",\n        reply: REPLY_OK,\n\n    client:\n        request: {\n            method: POST,\n            url: \"http://{addr}/chunks\",\n            headers: {\n                \"Transfer-Encoding\" => \"chunked\",\n            },\n            body: \"foo bar baz\",\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n}\n\ntest! {\n    name: client_post_unknown,\n\n    server:\n        expected: \"\\\n            POST /chunks HTTP/1.1\\r\\n\\\n            host: {addr}\\r\\n\\\n            transfer-encoding: chunked\\r\\n\\\n            \\r\\n\\\n            B\\r\\n\\\n            foo bar baz\\r\\n\\\n            0\\r\\n\\r\\n\\\n            \",\n        reply: REPLY_OK,\n\n    client:\n        request: {\n            method: POST,\n            url: \"http://{addr}/chunks\",\n            // use a stream to \"hide\" that the full amount is known\n            body_stream: (futures_util::stream::once(async {\n                Ok::<_, Infallible>(Bytes::from(\"foo bar baz\"))\n            })),\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n}\n\ntest! {\n    name: client_post_empty,\n\n    server:\n        expected: \"\\\n            POST /empty HTTP/1.1\\r\\n\\\n            content-length: 0\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: REPLY_OK,\n\n    client:\n        request: {\n            method: POST,\n            url: \"http://{addr}/empty\",\n            headers: {\n                \"Content-Length\" => \"0\",\n            },\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n}\n\ntest! {\n    name: client_head_ignores_body,\n\n    server:\n        expected: \"\\\n            HEAD /head HTTP/1.1\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: \"\\\n            HTTP/1.1 200 OK\\r\\n\\\n            content-Length: 11\\r\\n\\\n            \\r\\n\\\n            Hello World\\\n            \",\n\n    client:\n        request: {\n            method: HEAD,\n            url: \"http://{addr}/head\",\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n}\n\ntest! {\n    name: client_response_transfer_encoding_not_chunked,\n\n    server:\n        expected: \"\\\n            GET /te-not-chunked HTTP/1.1\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: \"\\\n            HTTP/1.1 200 OK\\r\\n\\\n            transfer-encoding: yolo\\r\\n\\\n            \\r\\n\\\n            hallo\\\n            \",\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/te-not-chunked\",\n        },\n        response:\n            status: OK,\n            headers: {\n                \"transfer-encoding\" => \"yolo\",\n            },\n            body: &b\"hallo\"[..],\n}\n\ntest! {\n    name: client_pipeline_responses_extra,\n\n    server:\n        expected: \"\\\n            GET /pipe HTTP/1.1\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: \"\\\n            HTTP/1.1 200 OK\\r\\n\\\n            Content-Length: 0\\r\\n\\\n            \\r\\n\\\n            HTTP/1.1 200 OK\\r\\n\\\n            Content-Length: 0\\r\\n\\\n            \\r\\n\\\n            \",\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/pipe\",\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n}\n\ntest! {\n    name: client_requires_absolute_uri,\n\n    server:\n        expected: \"won't get here {addr}\",\n        reply: \"won't reply\",\n\n    client:\n        request: {\n            method: GET,\n            url: \"/relative-{addr}\",\n        },\n        error: |err| err.to_string() == \"client requires absolute-form URIs\",\n}\n\ntest! {\n    name: client_error_unexpected_eof,\n\n    server:\n        expected: \"\\\n            GET /err HTTP/1.1\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: \"\\\n            HTTP/1.1 200 OK\\r\\n\\\n            \", // unexpected eof before double CRLF\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/err\",\n        },\n        error: |err| err.is_incomplete_message(),\n}\n\ntest! {\n    name: client_error_parse_version,\n\n    server:\n        expected: \"\\\n            GET /err HTTP/1.1\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: \"\\\n            HEAT/1.1 200 OK\\r\\n\\\n            \\r\\n\\\n            \",\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/err\",\n        },\n        // should get a Parse(Version) error\n        error: |err| err.is_parse(),\n\n}\n\ntest! {\n    name: client_error_parse_too_large,\n\n    server:\n        expected: \"\\\n            GET /err HTTP/1.1\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: {\n            let long_header = \"A\".repeat(500_000);\n            format!(\"\\\n                HTTP/1.1 200 OK\\r\\n\\\n                {}: {}\\r\\n\\\n                \\r\\n\\\n                \",\n                long_header,\n                long_header,\n            )\n        },\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/err\",\n        },\n        // should get a Parse(TooLarge) error\n        error: |err| err.is_parse() && err.is_parse_too_large(),\n\n}\n\ntest! {\n    name: client_error_parse_status_out_of_range,\n\n    server:\n        expected: \"\\\n            GET /err HTTP/1.1\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: \"\\\n            HTTP/1.1 001 OK\\r\\n\\\n            \\r\\n\\\n            \",\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/err\",\n        },\n        // should get a Parse(Status) error\n        error: |err| err.is_parse() && err.is_parse_status(),\n}\n\ntest! {\n    name: client_error_parse_status_syntactically_invalid,\n\n    server:\n        expected: \"\\\n            GET /err HTTP/1.1\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: \"\\\n            HTTP/1.1 1 OK\\r\\n\\\n            \\r\\n\\\n            \",\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/err\",\n        },\n        // should get a Parse(Status) error\n        error: |err| err.is_parse() && err.is_parse_status(),\n}\n\ntest! {\n    name: client_100_continue,\n\n    server:\n        expected: \"\\\n            POST /continue HTTP/1.1\\r\\n\\\n            content-length: 7\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            foo bar\\\n            \",\n        reply: \"\\\n            HTTP/1.1 100 Continue\\r\\n\\\n            \\r\\n\\\n            HTTP/1.1 200 OK\\r\\n\\\n            Content-Length: 0\\r\\n\\\n            \\r\\n\\\n            \",\n\n    client:\n        request: {\n            method: POST,\n            url: \"http://{addr}/continue\",\n            headers: {\n                \"Content-Length\" => \"7\",\n            },\n            body: \"foo bar\",\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n}\n\ntest! {\n    name: client_connect_method,\n\n    server:\n        expected: \"\\\n            CONNECT {addr} HTTP/1.1\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: \"\\\n            HTTP/1.1 200 OK\\r\\n\\\n            \\r\\n\\\n            \",\n\n    client:\n        request: {\n            method: CONNECT,\n            url: \"{addr}\",\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n\n}\n\ntest! {\n    name: client_connect_method_with_absolute_uri,\n\n    server:\n        expected: \"\\\n            CONNECT {addr} HTTP/1.1\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: \"\\\n            HTTP/1.1 200 OK\\r\\n\\\n            \\r\\n\\\n            \",\n\n    client:\n        request: {\n            method: CONNECT,\n            url: \"http://{addr}\",\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n\n}\n\ntest! {\n    name: client_set_host_false,\n\n    server:\n        // {addr} is here because format! requires it to exist in the string\n        expected: \"\\\n            GET /no-host/{addr} HTTP/1.1\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: \"\\\n            HTTP/1.1 200 OK\\r\\n\\\n            Content-Length: 0\\r\\n\\\n            \\r\\n\\\n            \",\n\n    client:\n        options: {\n            set_host: false,\n        },\n        request: {\n            method: GET,\n            url: \"http://{addr}/no-host/{addr}\",\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n}\n\ntest! {\n    name: client_set_http1_title_case_headers,\n\n    server:\n        expected: \"\\\n            GET / HTTP/1.1\\r\\n\\\n            X-Test-Header: test\\r\\n\\\n            Host: {addr}\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: \"\\\n            HTTP/1.1 200 OK\\r\\n\\\n            Content-Length: 0\\r\\n\\\n            \\r\\n\\\n            \",\n\n    client:\n        options: {\n            title_case_headers: true,\n        },\n        request: {\n            method: GET,\n            url: \"http://{addr}/\",\n            headers: {\n                \"X-Test-Header\" => \"test\",\n            },\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: None,\n}\n\ntest! {\n    name: client_h1_rejects_http2,\n\n    server:\n        expected: \"won't get here {addr}\",\n        reply: \"won't reply\",\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/\",\n            version: HTTP_2,\n        },\n        error: |err| err.to_string() == \"request has unsupported HTTP version\",\n}\n\ntest! {\n    name: client_always_rejects_http09,\n\n    server:\n        expected: \"won't get here {addr}\",\n        reply: \"won't reply\",\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/\",\n            version: HTTP_09,\n        },\n        error: |err| err.to_string() == \"request has unsupported HTTP version\",\n}\n\ntest! {\n    name: client_handles_contentlength_values_on_same_line,\n\n    server:\n        expected: \"GET /foo HTTP/1.1\\r\\nhost: {addr}\\r\\n\\r\\n\",\n        reply: \"\\\n            HTTP/1.1 200 OK\\r\\n\\\n            Content-Length: 3,3\\r\\n\\\n            Content-Length: 3,3\\r\\n\\\n            \\r\\n\\\n            abc\\r\\n\",\n\n    client:\n        request: {\n            method: GET,\n            url: \"http://{addr}/foo\",\n        },\n        response:\n            status: OK,\n            headers: {\n            },\n            body: &b\"abc\"[..],\n}\n\ntest! {\n    name: client_allows_http09_when_requested,\n\n    server:\n        expected: \"\\\n            GET / HTTP/1.1\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: \"Mmmmh, baguettes.\",\n\n    client:\n        options: {\n            http09_responses: true,\n        },\n        request: {\n            method: GET,\n            url: \"http://{addr}/\",\n        },\n        response:\n            status: OK,\n            headers: {},\n            body: &b\"Mmmmh, baguettes.\"[..],\n}\n\ntest! {\n    name: client_obs_fold_headers,\n\n    server:\n        expected: \"\\\n            GET / HTTP/1.1\\r\\n\\\n            host: {addr}\\r\\n\\\n            \\r\\n\\\n            \",\n        reply: \"\\\n            HTTP/1.1 200 OK\\r\\n\\\n            Content-Length: 0\\r\\n\\\n            Fold: just\\r\\n some\\r\\n\\t folding\\r\\n\\\n            \\r\\n\\\n            \",\n\n    client:\n        options: {\n            allow_obsolete_multiline_headers_in_responses: true,\n        },\n        request: {\n            method: GET,\n            url: \"http://{addr}/\",\n        },\n        response:\n            status: OK,\n            headers: {\n                \"fold\" => \"just some folding\",\n            },\n            body: None,\n}\n\nmod conn {\n    use std::error::Error;\n    use std::io::{self, Read, Write};\n    use std::net::{SocketAddr, TcpListener};\n    use std::pin::Pin;\n    use std::task::{Context, Poll};\n    use std::thread;\n    use std::time::Duration;\n\n    use bytes::{Buf, Bytes};\n    use futures_channel::{mpsc, oneshot};\n    use futures_util::future::{self, poll_fn, FutureExt, TryFutureExt};\n    use http_body_util::{BodyExt, Empty, Full, StreamBody};\n    use hyper::rt::Timer;\n    use tokio::io::{AsyncReadExt as _, AsyncWriteExt as _, DuplexStream};\n    use tokio::net::{TcpListener as TkTcpListener, TcpStream};\n\n    use hyper::body::{Body, Frame};\n    use hyper::client::conn;\n    use hyper::upgrade::OnUpgrade;\n    use hyper::{Method, Request, Response, StatusCode};\n\n    use super::{concat, s, support, tcp_connect, FutureHyperExt};\n\n    use support::{TokioExecutor, TokioIo, TokioTimer};\n\n    fn setup_logger() {\n        let _ = pretty_env_logger::try_init();\n    }\n\n    async fn setup_tk_test_server() -> (TkTcpListener, SocketAddr) {\n        setup_logger();\n        let listener = TkTcpListener::bind(SocketAddr::from(([127, 0, 0, 1], 0)))\n            .await\n            .unwrap();\n        let addr = listener.local_addr().unwrap();\n        (listener, addr)\n    }\n\n    fn setup_std_test_server() -> (TcpListener, SocketAddr) {\n        setup_logger();\n        let listener = TcpListener::bind(SocketAddr::from(([127, 0, 0, 1], 0))).unwrap();\n        let addr = listener.local_addr().unwrap();\n        (listener, addr)\n    }\n\n    fn setup_duplex_test_server() -> (DuplexStream, DuplexStream, SocketAddr) {\n        use std::net::{IpAddr, Ipv6Addr};\n        setup_logger();\n\n        const BUF_SIZE: usize = 1024;\n        let (ioa, iob) = tokio::io::duplex(BUF_SIZE);\n\n        /// A test address inside the 'documentation' address range.\n        /// See: <https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml>\n        const TEST_ADDR: IpAddr = IpAddr::V6(Ipv6Addr::new(0x3fff, 0, 0, 0, 0, 0, 0, 1));\n        const TEST_SOCKET: SocketAddr = SocketAddr::new(TEST_ADDR, 8080);\n\n        (ioa, iob, TEST_SOCKET)\n    }\n\n    #[tokio::test]\n    async fn get() {\n        let (listener, addr) = setup_tk_test_server().await;\n\n        let server = async move {\n            let mut sock = listener.accept().await.unwrap().0;\n            let mut buf = [0; 4096];\n            let n = sock.read(&mut buf).await.expect(\"read 1\");\n\n            // Notably:\n            // - Just a path, since just a path was set\n            // - No host, since no host was set\n            let expected = \"GET /a HTTP/1.1\\r\\n\\r\\n\";\n            assert_eq!(s(&buf[..n]), expected);\n\n            sock.write_all(b\"HTTP/1.1 200 OK\\r\\nContent-Length: 0\\r\\n\\r\\n\")\n                .await\n                .unwrap();\n        };\n\n        let client = async move {\n            let tcp = tcp_connect(&addr).await.expect(\"connect\");\n            let (mut client, conn) = conn::http1::handshake(tcp).await.expect(\"handshake\");\n\n            tokio::task::spawn(async move {\n                conn.await.expect(\"http conn\");\n            });\n\n            let req = Request::builder()\n                .uri(\"/a\")\n                .body(Empty::<Bytes>::new())\n                .unwrap();\n            let mut res = client.send_request(req).await.expect(\"send_request\");\n            assert_eq!(res.status(), hyper::StatusCode::OK);\n            assert!(res.body_mut().frame().await.is_none());\n        };\n\n        future::join(server, client).await;\n    }\n\n    #[tokio::test]\n    async fn get_custom_reason_phrase() {\n        let (listener, addr) = setup_tk_test_server().await;\n\n        let server = async move {\n            let mut sock = listener.accept().await.unwrap().0;\n            let mut buf = [0; 4096];\n            let n = sock.read(&mut buf).await.expect(\"read 1\");\n\n            // Notably:\n            // - Just a path, since just a path was set\n            // - No host, since no host was set\n            let expected = \"GET /a HTTP/1.1\\r\\n\\r\\n\";\n            assert_eq!(s(&buf[..n]), expected);\n\n            sock.write_all(b\"HTTP/1.1 200 Alright\\r\\nContent-Length: 0\\r\\n\\r\\n\")\n                .await\n                .unwrap();\n        };\n\n        let client = async move {\n            let tcp = tcp_connect(&addr).await.expect(\"connect\");\n            let (mut client, conn) = conn::http1::handshake(tcp).await.expect(\"handshake\");\n\n            tokio::task::spawn(async move {\n                conn.await.expect(\"http conn\");\n            });\n\n            let req = Request::builder()\n                .uri(\"/a\")\n                .body(Empty::<Bytes>::new())\n                .unwrap();\n            let mut res = client.send_request(req).await.expect(\"send_request\");\n            assert_eq!(res.status(), hyper::StatusCode::OK);\n            assert_eq!(\n                res.extensions()\n                    .get::<hyper::ext::ReasonPhrase>()\n                    .expect(\"custom reason phrase is present\")\n                    .as_bytes(),\n                &b\"Alright\"[..]\n            );\n            assert_eq!(res.headers().len(), 1);\n            assert_eq!(\n                res.headers().get(http::header::CONTENT_LENGTH).unwrap(),\n                \"0\"\n            );\n            assert!(res.body_mut().frame().await.is_none());\n        };\n\n        future::join(server, client).await;\n    }\n\n    #[test]\n    fn incoming_content_length() {\n        let (server, addr) = setup_std_test_server();\n        let rt = support::runtime();\n\n        let (tx1, rx1) = oneshot::channel();\n\n        thread::spawn(move || {\n            let mut sock = server.accept().unwrap().0;\n            sock.set_read_timeout(Some(Duration::from_secs(5))).unwrap();\n            sock.set_write_timeout(Some(Duration::from_secs(5)))\n                .unwrap();\n            let mut buf = [0; 4096];\n            let n = sock.read(&mut buf).expect(\"read 1\");\n\n            let expected = \"GET / HTTP/1.1\\r\\n\\r\\n\";\n            assert_eq!(s(&buf[..n]), expected);\n\n            sock.write_all(b\"HTTP/1.1 200 OK\\r\\nContent-Length: 5\\r\\n\\r\\nhello\")\n                .unwrap();\n            let _ = tx1.send(());\n        });\n\n        let tcp = rt.block_on(tcp_connect(&addr)).unwrap();\n\n        let (mut client, conn) = rt.block_on(conn::http1::handshake(tcp)).unwrap();\n\n        rt.spawn(conn.map_err(|e| panic!(\"conn error: {}\", e)).map(|_| ()));\n\n        let req = Request::builder()\n            .uri(\"/\")\n            .body(Empty::<Bytes>::new())\n            .unwrap();\n        let res = client.send_request(req).and_then(move |mut res| {\n            assert_eq!(res.status(), hyper::StatusCode::OK);\n            assert_eq!(res.body().size_hint().exact(), Some(5));\n            assert!(!res.body().is_end_stream());\n            poll_fn(move |ctx| Pin::new(res.body_mut()).poll_frame(ctx)).map(Option::unwrap)\n        });\n\n        let rx = rx1.expect(\"thread panicked\");\n        let rx = rx.then(|_| TokioTimer.sleep(Duration::from_millis(200)));\n        let chunk = rt.block_on(future::join(res, rx).map(|r| r.0)).unwrap();\n        assert_eq!(chunk.data_ref().unwrap().len(), 5);\n    }\n\n    #[test]\n    fn aborted_body_isnt_completed() {\n        let _ = ::pretty_env_logger::try_init();\n        let (server, addr) = setup_std_test_server();\n        let rt = support::runtime();\n\n        let (tx, rx) = oneshot::channel();\n        let server = thread::spawn(move || {\n            let mut sock = server.accept().unwrap().0;\n            sock.set_read_timeout(Some(Duration::from_secs(5))).unwrap();\n            sock.set_write_timeout(Some(Duration::from_secs(5)))\n                .unwrap();\n            let expected = \"POST / HTTP/1.1\\r\\ntransfer-encoding: chunked\\r\\n\\r\\n5\\r\\nhello\\r\\n\";\n            let mut buf = vec![0; expected.len()];\n            sock.read_exact(&mut buf).expect(\"read 1\");\n            assert_eq!(s(&buf), expected);\n\n            let _ = tx.send(());\n\n            assert_eq!(sock.read(&mut buf).expect(\"read 2\"), 0);\n        });\n\n        let tcp = rt.block_on(tcp_connect(&addr)).unwrap();\n\n        let (mut client, conn) = rt.block_on(conn::http1::handshake(tcp)).unwrap();\n\n        rt.spawn(conn.map_err(|e| panic!(\"conn error: {}\", e)).map(|_| ()));\n\n        let (mut sender, recv) =\n            mpsc::channel::<Result<Frame<Bytes>, Box<dyn Error + Send + Sync>>>(0);\n\n        let sender = thread::spawn(move || {\n            sender\n                .try_send(Ok(Frame::data(\"hello\".into())))\n                .expect(\"try_send_data\");\n            support::runtime().block_on(rx).unwrap();\n\n            // Aborts the body in an abnormal fashion.\n            let _ = sender.try_send(Err(Box::new(std::io::Error::new(\n                io::ErrorKind::Other,\n                \"body write aborted\",\n            ))));\n        });\n\n        let req = Request::builder()\n            .method(Method::POST)\n            .uri(\"/\")\n            .body(StreamBody::new(recv))\n            .unwrap();\n        let res = client.send_request(req);\n        rt.block_on(res).unwrap_err();\n\n        server.join().expect(\"server thread panicked\");\n        sender.join().expect(\"sender thread panicked\");\n    }\n\n    #[test]\n    fn uri_absolute_form() {\n        let (server, addr) = setup_std_test_server();\n        let rt = support::runtime();\n\n        let (tx1, rx1) = oneshot::channel();\n\n        thread::spawn(move || {\n            let mut sock = server.accept().unwrap().0;\n            sock.set_read_timeout(Some(Duration::from_secs(5))).unwrap();\n            sock.set_write_timeout(Some(Duration::from_secs(5)))\n                .unwrap();\n            let mut buf = [0; 4096];\n            let n = sock.read(&mut buf).expect(\"read 1\");\n\n            // Notably:\n            // - Still no Host header, since it wasn't set\n            let expected = \"GET http://hyper.local/a HTTP/1.1\\r\\n\\r\\n\";\n            assert_eq!(s(&buf[..n]), expected);\n\n            sock.write_all(b\"HTTP/1.1 200 OK\\r\\nContent-Length: 0\\r\\n\\r\\n\")\n                .unwrap();\n            let _ = tx1.send(());\n        });\n\n        let tcp = rt.block_on(tcp_connect(&addr)).unwrap();\n\n        let (mut client, conn) = rt.block_on(conn::http1::handshake(tcp)).unwrap();\n\n        rt.spawn(conn.map_err(|e| panic!(\"conn error: {}\", e)).map(|_| ()));\n\n        let req = Request::builder()\n            .uri(\"http://hyper.local/a\")\n            .body(Empty::<Bytes>::new())\n            .unwrap();\n\n        let res = client.send_request(req).and_then(move |res| {\n            assert_eq!(res.status(), hyper::StatusCode::OK);\n            concat(res)\n        });\n        let rx = rx1.expect(\"thread panicked\");\n        let rx = rx.then(|_| TokioTimer.sleep(Duration::from_millis(200)));\n        rt.block_on(future::join(res, rx).map(|r| r.0)).unwrap();\n    }\n\n    #[test]\n    fn http1_conn_coerces_http2_request() {\n        let (server, addr) = setup_std_test_server();\n        let rt = support::runtime();\n\n        let (tx1, rx1) = oneshot::channel();\n\n        thread::spawn(move || {\n            let mut sock = server.accept().unwrap().0;\n            sock.set_read_timeout(Some(Duration::from_secs(5))).unwrap();\n            sock.set_write_timeout(Some(Duration::from_secs(5)))\n                .unwrap();\n            let mut buf = [0; 4096];\n            let n = sock.read(&mut buf).expect(\"read 1\");\n\n            // Not HTTP/2, nor panicked\n            let expected = \"GET /a HTTP/1.1\\r\\n\\r\\n\";\n            assert_eq!(s(&buf[..n]), expected);\n\n            sock.write_all(b\"HTTP/1.1 200 OK\\r\\nContent-Length: 0\\r\\n\\r\\n\")\n                .unwrap();\n            let _ = tx1.send(());\n        });\n\n        let tcp = rt.block_on(tcp_connect(&addr)).unwrap();\n\n        let (mut client, conn) = rt.block_on(conn::http1::handshake(tcp)).unwrap();\n\n        rt.spawn(conn.map_err(|e| panic!(\"conn error: {}\", e)).map(|_| ()));\n\n        let req = Request::builder()\n            .uri(\"/a\")\n            .version(hyper::Version::HTTP_2)\n            .body(Empty::<Bytes>::new())\n            .unwrap();\n\n        let res = client.send_request(req).and_then(move |res| {\n            assert_eq!(res.status(), hyper::StatusCode::OK);\n            concat(res)\n        });\n        let rx = rx1.expect(\"thread panicked\");\n        let rx = rx.then(|_| TokioTimer.sleep(Duration::from_millis(200)));\n        rt.block_on(future::join(res, rx).map(|r| r.0)).unwrap();\n    }\n\n    #[test]\n    fn pipeline() {\n        let (server, addr) = setup_std_test_server();\n        let rt = support::runtime();\n\n        let (tx1, rx1) = oneshot::channel();\n\n        thread::spawn(move || {\n            let mut sock = server.accept().unwrap().0;\n            sock.set_read_timeout(Some(Duration::from_secs(5))).unwrap();\n            sock.set_write_timeout(Some(Duration::from_secs(5)))\n                .unwrap();\n            let mut buf = [0; 4096];\n            sock.read(&mut buf).expect(\"read 1\");\n            sock.write_all(b\"HTTP/1.1 200 OK\\r\\nContent-Length: 0\\r\\n\\r\\n\")\n                .unwrap();\n\n            let _ = tx1.send(Ok::<_, ()>(()));\n        });\n\n        let tcp = rt.block_on(tcp_connect(&addr)).unwrap();\n\n        let (mut client, conn) = rt.block_on(conn::http1::handshake(tcp)).unwrap();\n\n        rt.spawn(conn.map_err(|e| panic!(\"conn error: {}\", e)).map(|_| ()));\n\n        let req = Request::builder()\n            .uri(\"/a\")\n            .body(Empty::<Bytes>::new())\n            .unwrap();\n        let res1 = client.send_request(req).and_then(move |res| {\n            assert_eq!(res.status(), hyper::StatusCode::OK);\n            concat(res)\n        });\n\n        // pipelined request will hit NotReady, and thus should return an Error::Cancel\n        let req = Request::builder()\n            .uri(\"/b\")\n            .body(Empty::<Bytes>::new())\n            .unwrap();\n        let res2 = client.send_request(req).map(|result| {\n            let err = result.expect_err(\"res2\");\n            assert!(err.is_canceled(), \"err not canceled, {:?}\", err);\n            Ok::<_, ()>(())\n        });\n\n        let rx = rx1.expect(\"thread panicked\");\n        let rx = rx.then(|_| TokioTimer.sleep(Duration::from_millis(200)));\n        rt.block_on(future::join3(res1, res2, rx).map(|r| r.0))\n            .unwrap();\n    }\n\n    #[test]\n    fn upgrade() {\n        let (server, addr) = setup_std_test_server();\n        let rt = support::runtime();\n\n        let (tx1, rx1) = oneshot::channel();\n\n        thread::spawn(move || {\n            let mut sock = server.accept().unwrap().0;\n            sock.set_read_timeout(Some(Duration::from_secs(5))).unwrap();\n            sock.set_write_timeout(Some(Duration::from_secs(5)))\n                .unwrap();\n            let mut buf = [0; 4096];\n            sock.read(&mut buf).expect(\"read 1\");\n            sock.write_all(\n                b\"\\\n                HTTP/1.1 101 Switching Protocols\\r\\n\\\n                Upgrade: foobar\\r\\n\\\n                \\r\\n\\\n                foobar=ready\\\n            \",\n            )\n            .unwrap();\n            let _ = tx1.send(());\n\n            let n = sock.read(&mut buf).expect(\"read 2\");\n            assert_eq!(&buf[..n], b\"foo=bar\");\n            sock.write_all(b\"bar=foo\").expect(\"write 2\");\n        });\n\n        let tcp = rt.block_on(tcp_connect(&addr)).unwrap();\n\n        let io = DebugStream {\n            tcp,\n            shutdown_called: false,\n        };\n\n        let (mut client, mut conn) = rt.block_on(conn::http1::handshake(io)).unwrap();\n\n        {\n            let until_upgrade = poll_fn(|ctx| conn.poll_without_shutdown(ctx));\n\n            let req = Request::builder()\n                .uri(\"/a\")\n                .body(Empty::<Bytes>::new())\n                .unwrap();\n            let res = client.send_request(req).and_then(move |res| {\n                assert_eq!(res.status(), hyper::StatusCode::SWITCHING_PROTOCOLS);\n                assert_eq!(res.headers()[\"Upgrade\"], \"foobar\");\n                concat(res)\n            });\n\n            let rx = rx1.expect(\"thread panicked\");\n            let rx = rx.then(|_| TokioTimer.sleep(Duration::from_millis(200)));\n            rt.block_on(future::join3(until_upgrade, res, rx).map(|r| r.0))\n                .unwrap();\n\n            // should not be ready now\n            rt.block_on(poll_fn(|ctx| {\n                assert!(client.poll_ready(ctx).is_pending());\n                Poll::Ready(Ok::<_, ()>(()))\n            }))\n            .unwrap();\n        }\n\n        let parts = conn.into_parts();\n        let io = parts.io;\n        let buf = parts.read_buf;\n\n        assert_eq!(buf, b\"foobar=ready\"[..]);\n        assert!(!io.shutdown_called, \"upgrade shouldn't shutdown AsyncWrite\");\n        rt.block_on(poll_fn(|ctx| {\n            let ready = client.poll_ready(ctx);\n            assert!(matches!(ready, Poll::Ready(Err(_))));\n            ready\n        }))\n        .unwrap_err();\n\n        let mut io = io.tcp.inner();\n        let mut vec = vec![];\n        rt.block_on(io.write_all(b\"foo=bar\")).unwrap();\n        rt.block_on(io.read_to_end(&mut vec)).unwrap();\n        assert_eq!(vec, b\"bar=foo\");\n    }\n\n    #[test]\n    fn connect_method() {\n        let (server, addr) = setup_std_test_server();\n        let rt = support::runtime();\n\n        let (tx1, rx1) = oneshot::channel();\n\n        thread::spawn(move || {\n            let mut sock = server.accept().unwrap().0;\n            sock.set_read_timeout(Some(Duration::from_secs(5))).unwrap();\n            sock.set_write_timeout(Some(Duration::from_secs(5)))\n                .unwrap();\n            let mut buf = [0; 4096];\n            sock.read(&mut buf).expect(\"read 1\");\n            sock.write_all(\n                b\"\\\n                HTTP/1.1 200 OK\\r\\n\\\n                \\r\\n\\\n                foobar=ready\\\n            \",\n            )\n            .unwrap();\n            let _ = tx1.send(Ok::<_, ()>(()));\n\n            let n = sock.read(&mut buf).expect(\"read 2\");\n            assert_eq!(&buf[..n], b\"foo=bar\", \"sock read 2 bytes\");\n            sock.write_all(b\"bar=foo\").expect(\"write 2\");\n        });\n\n        let tcp = rt.block_on(tcp_connect(&addr)).unwrap();\n\n        let io = DebugStream {\n            tcp,\n            shutdown_called: false,\n        };\n\n        let (mut client, mut conn) = rt.block_on(conn::http1::handshake(io)).unwrap();\n\n        {\n            let until_tunneled = poll_fn(|ctx| conn.poll_without_shutdown(ctx));\n\n            let req = Request::builder()\n                .method(\"CONNECT\")\n                .uri(addr.to_string())\n                .body(Empty::<Bytes>::new())\n                .unwrap();\n            let res = client\n                .send_request(req)\n                .and_then(move |res| {\n                    assert_eq!(res.status(), hyper::StatusCode::OK);\n                    concat(res)\n                })\n                .map_ok(|body| {\n                    assert_eq!(body.as_ref(), b\"\");\n                });\n\n            let rx = rx1.expect(\"thread panicked\");\n            let rx = rx.then(|_| TokioTimer.sleep(Duration::from_millis(200)));\n            rt.block_on(future::join3(until_tunneled, res, rx).map(|r| r.0))\n                .unwrap();\n\n            // should not be ready now\n            rt.block_on(poll_fn(|ctx| {\n                assert!(client.poll_ready(ctx).is_pending());\n                Poll::Ready(Ok::<_, ()>(()))\n            }))\n            .unwrap();\n        }\n\n        let parts = conn.into_parts();\n        let io = parts.io;\n        let buf = parts.read_buf;\n\n        assert_eq!(buf, b\"foobar=ready\"[..]);\n        assert!(!io.shutdown_called, \"tunnel shouldn't shutdown AsyncWrite\");\n\n        rt.block_on(poll_fn(|ctx| {\n            let ready = client.poll_ready(ctx);\n            assert!(matches!(ready, Poll::Ready(Err(_))));\n            ready\n        }))\n        .unwrap_err();\n\n        let mut io = io.tcp.inner();\n        let mut vec = vec![];\n        rt.block_on(io.write_all(b\"foo=bar\")).unwrap();\n        rt.block_on(io.read_to_end(&mut vec)).unwrap();\n        assert_eq!(vec, b\"bar=foo\");\n    }\n\n    #[tokio::test]\n    async fn client_100_then_http09() {\n        let (server, addr) = setup_std_test_server();\n\n        thread::spawn(move || {\n            let mut sock = server.accept().unwrap().0;\n            sock.set_read_timeout(Some(Duration::from_secs(5))).unwrap();\n            sock.set_write_timeout(Some(Duration::from_secs(5)))\n                .unwrap();\n            let mut buf = [0; 4096];\n            sock.read(&mut buf).expect(\"read 1\");\n            sock.write_all(\n                b\"\\\n                HTTP/1.1 100 Continue\\r\\n\\\n                Content-Type: text/plain\\r\\n\\\n                Server: BaseHTTP/0.6 Python/3.12.5\\r\\n\\\n                Date: Mon, 16 Dec 2024 03:08:27 GMT\\r\\n\\\n            \",\n            )\n            .unwrap();\n            // That it's separate writes is important to this test\n            thread::sleep(Duration::from_millis(50));\n            sock.write_all(\n                b\"\\\n                \\r\\n\\\n            \",\n            )\n            .expect(\"write 2\");\n            thread::sleep(Duration::from_millis(50));\n            sock.write_all(\n                b\"\\\n                This is a sample text/plain document, without final headers.\\\n                \\n\\n\\\n            \",\n            )\n            .expect(\"write 3\");\n        });\n\n        let tcp = tcp_connect(&addr).await.unwrap();\n\n        let (mut client, conn) = conn::http1::Builder::new()\n            .http09_responses(true)\n            .handshake(tcp)\n            .await\n            .unwrap();\n\n        tokio::spawn(async move {\n            let _ = conn.await;\n        });\n\n        let req = Request::builder()\n            .uri(\"/a\")\n            .body(Empty::<Bytes>::new())\n            .unwrap();\n        let _res = client.send_request(req).await.expect(\"send_request\");\n    }\n\n    #[tokio::test]\n    async fn client_on_informational_ext() {\n        use std::sync::atomic::{AtomicUsize, Ordering};\n        use std::sync::Arc;\n        let (server, addr) = setup_std_test_server();\n\n        thread::spawn(move || {\n            let mut sock = server.accept().unwrap().0;\n            sock.set_read_timeout(Some(Duration::from_secs(5))).unwrap();\n            sock.set_write_timeout(Some(Duration::from_secs(5)))\n                .unwrap();\n            let mut buf = [0; 4096];\n            sock.read(&mut buf).expect(\"read 1\");\n            sock.write_all(b\"HTTP/1.1 100 Continue\\r\\n\\r\\n\").unwrap();\n            sock.write_all(b\"HTTP/1.1 200 OK\\r\\ncontent-length: 0\\r\\n\\r\\n\")\n                .unwrap();\n        });\n\n        let tcp = tcp_connect(&addr).await.unwrap();\n\n        let (mut client, conn) = conn::http1::handshake(tcp).await.unwrap();\n\n        tokio::spawn(async move {\n            let _ = conn.await;\n        });\n\n        let mut req = Request::builder()\n            .uri(\"/a\")\n            .body(Empty::<Bytes>::new())\n            .unwrap();\n        let cnt = Arc::new(AtomicUsize::new(0));\n        let cnt2 = cnt.clone();\n        hyper::ext::on_informational(&mut req, move |res| {\n            assert_eq!(res.status(), 100);\n            cnt2.fetch_add(1, Ordering::Relaxed);\n        });\n        let _res = client.send_request(req).await.expect(\"send_request\");\n        assert_eq!(1, cnt.load(Ordering::Relaxed));\n    }\n\n    #[tokio::test]\n    async fn test_try_send_request() {\n        use std::future::Future;\n        let (done_tx, done_rx) = tokio::sync::oneshot::channel::<()>();\n        let (io_srv, io_cli) = tokio_test::io::Builder::new()\n            .write(b\"GET / HTTP/1.1\\r\\n\\r\\n\")\n            .read(b\"HTTP/1.1 200 OK\\r\\ncontent-length: 0\\r\\n\\r\\n\")\n            .build_with_handle();\n\n        tokio::spawn(async move {\n            let _io = io_cli;\n            let _ = done_rx.await;\n        });\n\n        // make polling fair by putting both in spawns\n        tokio::spawn(async move {\n            let io = TokioIo::new(io_srv);\n            let (mut client, mut conn) = conn::http1::Builder::new()\n                .handshake::<_, Empty<Bytes>>(io)\n                .await\n                .expect(\"http handshake\");\n\n            // get the conn ready\n            assert!(\n                future::poll_fn(|cx| Poll::Ready(Pin::new(&mut conn).poll(cx)))\n                    .await\n                    .is_pending()\n            );\n            assert!(client.is_ready());\n\n            // use the connection once\n            let mut fut1 = std::pin::pin!(client.send_request(http::Request::new(Empty::new())));\n            let _res1 = future::poll_fn(|cx| loop {\n                if let Poll::Ready(res) = fut1.as_mut().poll(cx) {\n                    return Poll::Ready(res);\n                }\n                return match Pin::new(&mut conn).poll(cx) {\n                    Poll::Ready(_) => panic!(\"ruh roh\"),\n                    Poll::Pending => Poll::Pending,\n                };\n            })\n            .await\n            .expect(\"resp 1\");\n\n            assert!(client.is_ready());\n\n            // simulate the server dropping the conn\n            let _ = done_tx.send(());\n            // let the server task die\n            tokio::task::yield_now().await;\n\n            let mut fut2 =\n                std::pin::pin!(client.try_send_request(http::Request::new(Empty::new())));\n            let poll1 = future::poll_fn(|cx| Poll::Ready(fut2.as_mut().poll(cx))).await;\n            assert!(poll1.is_pending(), \"not already known to error\");\n\n            let mut conn_opt = Some(conn);\n            // wasn't a known error, req is in queue, and now the next poll, the\n            // conn will be noticed as errored\n            let mut err = future::poll_fn(|cx| {\n                loop {\n                    if let Poll::Ready(res) = fut2.as_mut().poll(cx) {\n                        return Poll::Ready(res);\n                    }\n                    if let Some(ref mut conn) = conn_opt {\n                        match Pin::new(conn).poll(cx) {\n                            Poll::Ready(_) => {\n                                conn_opt = None;\n                            } // ok\n                            Poll::Pending => return Poll::Pending,\n                        };\n                    }\n                }\n            })\n            .await\n            .expect_err(\"resp 2\");\n\n            assert!(err.take_message().is_some(), \"request was returned\");\n        })\n        .await\n        .unwrap();\n    }\n\n    #[tokio::test]\n    async fn http2_detect_conn_eof() {\n        use futures_util::future;\n\n        let (listener, addr) = setup_tk_test_server().await;\n\n        let (shdn_tx, mut shdn_rx) = tokio::sync::watch::channel(false);\n        tokio::task::spawn(async move {\n            use hyper::server::conn::http2;\n            use hyper::service::service_fn;\n\n            loop {\n                tokio::select! {\n                    res = listener.accept() => {\n                        let (stream, _) = res.unwrap();\n                        let stream = TokioIo::new(stream);\n\n                        let service = service_fn(|_:Request<hyper::body::Incoming>| future::ok::<_, hyper::Error>(Response::new(Empty::<Bytes>::new())));\n\n                        let mut shdn_rx = shdn_rx.clone();\n                        tokio::task::spawn(async move {\n                            let mut conn = http2::Builder::new(TokioExecutor)\n                                .serve_connection(stream, service);\n\n                            tokio::select! {\n                                res = &mut conn => {\n                                    res.unwrap();\n                                }\n                                _ = shdn_rx.changed() => {\n                                    Pin::new(&mut conn).graceful_shutdown();\n                                    conn.await.unwrap();\n                                }\n                            }\n                        });\n                    }\n                    _ = shdn_rx.changed() => {\n                        break;\n                    }\n                }\n            }\n        });\n\n        let io = tcp_connect(&addr).await.expect(\"tcp connect\");\n        let (mut client, conn) = conn::http2::Builder::new(TokioExecutor)\n            .handshake(io)\n            .await\n            .expect(\"http handshake\");\n\n        tokio::task::spawn(async move {\n            conn.await.expect(\"client conn\");\n        });\n\n        // Sanity check that client is ready\n        future::poll_fn(|ctx| client.poll_ready(ctx))\n            .await\n            .expect(\"client poll ready sanity\");\n\n        let req = Request::builder()\n            .uri(format!(\"http://{}/\", addr))\n            .body(Empty::<Bytes>::new())\n            .expect(\"request builder\");\n\n        client.send_request(req).await.expect(\"req1 send\");\n\n        // Sanity check that client is STILL ready\n        future::poll_fn(|ctx| client.poll_ready(ctx))\n            .await\n            .expect(\"client poll ready after\");\n\n        // Trigger the server shutdown...\n        let _ = shdn_tx.send(true);\n\n        // Allow time for graceful shutdown roundtrips...\n        TokioTimer.sleep(Duration::from_millis(100)).await;\n\n        // After graceful shutdown roundtrips, the client should be closed...\n        future::poll_fn(|ctx| client.poll_ready(ctx))\n            .await\n            .expect_err(\"client should be closed\");\n    }\n\n    #[tokio::test(flavor = \"multi_thread\", worker_threads = 2)]\n    async fn http2_connect_detect_close() {\n        // Regression test for failure to fully close connections when using HTTP2 CONNECT\n        // We send 2 requests and then drop them. We should see the connection gracefully close.\n        use futures_util::future;\n        let (client_io, server_io, addr) = setup_duplex_test_server();\n        let (tx, rxx) = oneshot::channel::<()>();\n\n        tokio::task::spawn(async move {\n            use hyper::server::conn::http2;\n            use hyper::service::service_fn;\n\n            let stream = TokioIo::new(server_io);\n\n            let service = service_fn(move |req: Request<hyper::body::Incoming>| {\n                tokio::task::spawn(async move {\n                    let io = &mut TokioIo::new(hyper::upgrade::on(req).await.unwrap());\n                    io.write_all(b\"hello\\n\").await.unwrap();\n                });\n\n                future::ok::<_, hyper::Error>(Response::new(Empty::<Bytes>::new()))\n            });\n\n            tokio::task::spawn(async move {\n                let conn = http2::Builder::new(TokioExecutor).serve_connection(stream, service);\n                let _ = conn.await;\n                tx.send(()).unwrap();\n            });\n        });\n\n        let io = TokioIo::new(client_io);\n        let (mut client, conn) = conn::http2::Builder::new(TokioExecutor)\n            .handshake(io)\n            .await\n            .expect(\"http handshake\");\n\n        tokio::task::spawn(async move {\n            conn.await.expect(\"client conn\");\n        });\n\n        // Sanity check that client is ready\n        future::poll_fn(|ctx| client.poll_ready(ctx))\n            .await\n            .expect(\"client poll ready sanity\");\n        let requests = 2;\n        let mut clients = vec![client.clone(), client];\n        let (tx, rx) = oneshot::channel::<()>();\n        let (tx2, rx2) = oneshot::channel::<()>();\n        let mut rxs = vec![rx, rx2];\n        for _i in 0..requests {\n            let mut client = clients.pop().unwrap();\n            let rx = rxs.pop().unwrap();\n            let req = Request::builder()\n                .method(Method::CONNECT)\n                .uri(format!(\"{}\", addr))\n                .body(Empty::<Bytes>::new())\n                .expect(\"request builder\");\n\n            let resp = client.send_request(req).await.expect(\"req1 send\");\n            assert_eq!(resp.status(), 200);\n            let upgrade = hyper::upgrade::on(resp).await.unwrap();\n            tokio::task::spawn(async move {\n                let _ = rx.await;\n                drop(upgrade);\n            });\n        }\n        drop(tx);\n        drop(tx2);\n        tokio::time::timeout(Duration::from_secs(1), rxx)\n            .await\n            .expect(\"drop with 1s\")\n            .expect(\"tx dropped without sending\");\n    }\n\n    #[tokio::test]\n    async fn http2_keep_alive_detects_unresponsive_server() {\n        let (client_io, server_io, _) = setup_duplex_test_server();\n\n        // spawn a server that reads but doesn't write\n        tokio::spawn(async move {\n            let mut sock = server_io;\n            let mut buf = [0u8; 1024];\n            loop {\n                let n = sock.read(&mut buf).await.expect(\"server read\");\n                if n == 0 {\n                    // server closed, lets go!\n                    break;\n                }\n            }\n        });\n\n        let io = TokioIo::new(client_io);\n        let (_client, conn) = conn::http2::Builder::new(TokioExecutor)\n            .timer(TokioTimer)\n            .keep_alive_interval(Duration::from_secs(1))\n            .keep_alive_timeout(Duration::from_secs(1))\n            // enable while idle since we aren't sending requests\n            .keep_alive_while_idle(true)\n            .handshake::<_, hyper::body::Incoming>(io)\n            .await\n            .expect(\"http handshake\");\n\n        conn.await.expect_err(\"conn should time out\");\n    }\n\n    #[tokio::test]\n    async fn http2_keep_alive_not_while_idle() {\n        // This tests that not setting `http2_keep_alive_while_idle(true)`\n        // will use the default behavior which will NOT detect the server\n        // is unresponsive while no streams are active.\n\n        let (client_io, server_io, _) = setup_duplex_test_server();\n\n        // spawn a server that reads but doesn't write\n        tokio::spawn(async move {\n            drain_til_eof(server_io).await.expect(\"server read\");\n        });\n\n        let io = TokioIo::new(client_io);\n        let (mut client, conn) = conn::http2::Builder::new(TokioExecutor)\n            .timer(TokioTimer)\n            .keep_alive_interval(Duration::from_secs(1))\n            .keep_alive_timeout(Duration::from_secs(1))\n            .handshake::<_, hyper::body::Incoming>(io)\n            .await\n            .expect(\"http handshake\");\n\n        tokio::spawn(async move {\n            conn.await.expect(\"client conn shouldn't error\");\n        });\n\n        // sleep longer than keepalive would trigger\n        TokioTimer.sleep(Duration::from_secs(4)).await;\n\n        future::poll_fn(|ctx| client.poll_ready(ctx))\n            .await\n            .expect(\"client should be open\");\n    }\n\n    #[tokio::test]\n    async fn http2_keep_alive_closes_open_streams() {\n        let (client_io, server_io, _addr) = setup_duplex_test_server();\n\n        // spawn a server that reads but doesn't write\n        tokio::spawn(async move {\n            drain_til_eof(server_io).await.expect(\"server read\");\n        });\n\n        let io = TokioIo::new(client_io);\n        let (mut client, conn) = conn::http2::Builder::new(TokioExecutor)\n            .timer(TokioTimer)\n            .keep_alive_interval(Duration::from_secs(1))\n            .keep_alive_timeout(Duration::from_secs(1))\n            .handshake(io)\n            .await\n            .expect(\"http handshake\");\n\n        tokio::spawn(async move {\n            let err = conn.await.expect_err(\"client conn should timeout\");\n            assert!(err.is_timeout());\n        });\n\n        let req = http::Request::new(Empty::<Bytes>::new());\n        let err = client\n            .send_request(req)\n            .await\n            .expect_err(\"request should timeout\");\n        assert!(err.is_timeout());\n\n        let err = future::poll_fn(|ctx| client.poll_ready(ctx))\n            .await\n            .expect_err(\"client should be closed\");\n        assert!(\n            err.is_closed(),\n            \"poll_ready error should be closed: {:?}\",\n            err\n        );\n    }\n\n    #[tokio::test]\n    async fn http2_keep_alive_with_responsive_server() {\n        // Test that a responsive server works just when client keep\n        // alive is enabled\n        use hyper::service::service_fn;\n\n        let (client_io, server_io, _addr) = setup_duplex_test_server();\n\n        // Spawn an HTTP2 server that reads the whole body and responds\n        tokio::spawn(async move {\n            let sock = TokioIo::new(server_io);\n            hyper::server::conn::http2::Builder::new(TokioExecutor)\n                .timer(TokioTimer)\n                .serve_connection(\n                    sock,\n                    service_fn(|req| async move {\n                        tokio::spawn(async move {\n                            let _ = concat(req.into_body())\n                                .await\n                                .expect(\"server req body aggregate\");\n                        });\n                        Ok::<_, hyper::Error>(http::Response::new(Empty::<Bytes>::new()))\n                    }),\n                )\n                .await\n                .expect(\"serve_connection\");\n        });\n\n        let io = TokioIo::new(client_io);\n        let (mut client, conn) = conn::http2::Builder::new(TokioExecutor)\n            .timer(TokioTimer)\n            .keep_alive_interval(Duration::from_secs(1))\n            .keep_alive_timeout(Duration::from_secs(1))\n            .handshake(io)\n            .await\n            .expect(\"http handshake\");\n\n        tokio::spawn(async move {\n            conn.await.expect(\"client conn shouldn't error\");\n        });\n\n        // Use a channel to keep request stream open\n        let (_tx, recv) = mpsc::channel::<Result<Frame<Bytes>, Box<dyn Error + Send + Sync>>>(0);\n        let req = http::Request::new(StreamBody::new(recv));\n\n        let _resp = client.send_request(req).await.expect(\"send_request\");\n\n        // sleep longer than keepalive would trigger\n        TokioTimer.sleep(Duration::from_secs(4)).await;\n\n        future::poll_fn(|ctx| client.poll_ready(ctx))\n            .await\n            .expect(\"client should be open\");\n    }\n\n    #[tokio::test]\n    async fn http2_responds_before_consuming_request_body() {\n        // Test that a early-response from server works correctly (request body wasn't fully consumed).\n        // https://github.com/hyperium/hyper/issues/2872\n        use hyper::service::service_fn;\n\n        let _ = pretty_env_logger::try_init();\n\n        let (listener, addr) = setup_tk_test_server().await;\n\n        // Spawn an HTTP2 server that responds before reading the whole request body.\n        // It's normal case to decline the request due to headers or size of the body.\n        tokio::spawn(async move {\n            let sock = TokioIo::new(listener.accept().await.unwrap().0);\n            hyper::server::conn::http2::Builder::new(TokioExecutor)\n                .timer(TokioTimer)\n                .serve_connection(\n                    sock,\n                    service_fn(|_req| async move {\n                        Ok::<_, hyper::Error>(Response::new(Full::new(Bytes::from(\n                            \"No bread for you!\",\n                        ))))\n                    }),\n                )\n                .await\n                .expect(\"serve_connection\");\n        });\n\n        let io = tcp_connect(&addr).await.expect(\"tcp connect\");\n        let (mut client, conn) = conn::http2::Builder::new(TokioExecutor)\n            .timer(TokioTimer)\n            .handshake(io)\n            .await\n            .expect(\"http handshake\");\n\n        tokio::spawn(async move {\n            conn.await.expect(\"client conn shouldn't error\");\n        });\n\n        // Use a channel to keep request stream open\n        let (_tx, recv) = mpsc::channel::<Result<Frame<Bytes>, Box<dyn Error + Send + Sync>>>(0);\n        let req = Request::post(\"/a\").body(StreamBody::new(recv)).unwrap();\n        let resp = client.send_request(req).await.expect(\"send_request\");\n        assert!(resp.status().is_success());\n\n        let mut body = String::new();\n        concat(resp.into_body())\n            .await\n            .unwrap()\n            .reader()\n            .read_to_string(&mut body)\n            .unwrap();\n\n        assert_eq!(&body, \"No bread for you!\");\n    }\n\n    #[tokio::test]\n    async fn h2_connect() {\n        let (client_io, server_io, _) = setup_duplex_test_server();\n\n        // Spawn an HTTP2 server that asks for bread and responds with baguette.\n        tokio::spawn(async move {\n            let sock = server_io;\n            let mut h2 = h2::server::handshake(sock).await.unwrap();\n\n            let (req, mut respond) = h2.accept().await.unwrap().unwrap();\n            tokio::spawn(async move {\n                poll_fn(|cx| h2.poll_closed(cx)).await.unwrap();\n            });\n            assert_eq!(req.method(), Method::CONNECT);\n\n            let mut body = req.into_body();\n\n            let mut send_stream = respond.send_response(Response::new(()), false).unwrap();\n\n            send_stream.send_data(\"Bread?\".into(), true).unwrap();\n\n            let bytes = body.data().await.unwrap().unwrap();\n            assert_eq!(&bytes[..], b\"Baguette!\");\n            let _ = body.flow_control().release_capacity(bytes.len());\n\n            assert!(body.data().await.is_none());\n        });\n\n        let io = TokioIo::new(client_io);\n        let (mut client, conn) = conn::http2::Builder::new(TokioExecutor)\n            .handshake(io)\n            .await\n            .expect(\"http handshake\");\n\n        tokio::spawn(async move {\n            conn.await.expect(\"client conn shouldn't error\");\n        });\n\n        let req = Request::connect(\"localhost\")\n            .body(Empty::<Bytes>::new())\n            .unwrap();\n        let res = client.send_request(req).await.expect(\"send_request\");\n        assert_eq!(res.status(), StatusCode::OK);\n\n        let mut upgraded = TokioIo::new(hyper::upgrade::on(res).await.unwrap());\n\n        let mut vec = vec![];\n        upgraded.read_to_end(&mut vec).await.unwrap();\n        assert_eq!(s(&vec), \"Bread?\");\n\n        upgraded.write_all(b\"Baguette!\").await.unwrap();\n\n        upgraded.shutdown().await.unwrap();\n    }\n\n    #[tokio::test]\n    async fn h2_connect_rejected() {\n        let (client_io, server_io, _) = setup_duplex_test_server();\n        let (done_tx, done_rx) = oneshot::channel();\n\n        tokio::spawn(async move {\n            let sock = server_io;\n            let mut h2 = h2::server::handshake(sock).await.unwrap();\n\n            let (req, mut respond) = h2.accept().await.unwrap().unwrap();\n            tokio::spawn(async move {\n                poll_fn(|cx| h2.poll_closed(cx)).await.unwrap();\n            });\n            assert_eq!(req.method(), Method::CONNECT);\n\n            let res = Response::builder().status(400).body(()).unwrap();\n            let mut send_stream = respond.send_response(res, false).unwrap();\n            send_stream\n                .send_data(\"No bread for you!\".into(), true)\n                .unwrap();\n            done_rx.await.unwrap();\n        });\n\n        let io = TokioIo::new(client_io);\n        let (mut client, conn) = conn::http2::Builder::new(TokioExecutor)\n            .handshake::<_, Empty<Bytes>>(io)\n            .await\n            .expect(\"http handshake\");\n\n        tokio::spawn(async move {\n            conn.await.expect(\"client conn shouldn't error\");\n        });\n\n        let req = Request::connect(\"localhost\").body(Empty::new()).unwrap();\n        let res = client.send_request(req).await.expect(\"send_request\");\n        assert_eq!(res.status(), StatusCode::BAD_REQUEST);\n        assert!(res.extensions().get::<OnUpgrade>().is_none());\n\n        let mut body = String::new();\n        concat(res.into_body())\n            .await\n            .unwrap()\n            .reader()\n            .read_to_string(&mut body)\n            .unwrap();\n        assert_eq!(body, \"No bread for you!\");\n\n        done_tx.send(()).unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_body_panics() {\n        let (client_io, server_io, _) = setup_duplex_test_server();\n\n        // spawn a server that reads but doesn't write\n        tokio::spawn(async move {\n            let sock = server_io;\n            drain_til_eof(sock).await.expect(\"server read\");\n        });\n\n        let io = TokioIo::new(client_io);\n        let (mut client, conn) = conn::http1::Builder::new()\n            .handshake(io)\n            .await\n            .expect(\"handshake\");\n\n        tokio::spawn(async move {\n            conn.await.expect(\"client conn shouldn't error\");\n        });\n\n        let req = Request::post(\"/a\")\n            .body(http_body_util::BodyExt::map_frame::<_, bytes::Bytes>(\n                http_body_util::Full::<bytes::Bytes>::from(\"baguette\"),\n                |_| panic!(\"oopsie\"),\n            ))\n            .unwrap();\n\n        let error = client.send_request(req).await.unwrap_err();\n\n        assert!(error.is_user());\n    }\n\n    async fn drain_til_eof<T: tokio::io::AsyncRead + Unpin>(mut sock: T) -> io::Result<()> {\n        let mut buf = [0u8; 1024];\n        loop {\n            let n = sock.read(&mut buf).await?;\n            if n == 0 {\n                // socket closed, lets go!\n                return Ok(());\n            }\n        }\n    }\n\n    struct DebugStream {\n        tcp: TokioIo<TcpStream>,\n        shutdown_called: bool,\n    }\n\n    impl hyper::rt::Write for DebugStream {\n        fn poll_shutdown(\n            mut self: Pin<&mut Self>,\n            cx: &mut Context<'_>,\n        ) -> Poll<Result<(), io::Error>> {\n            self.shutdown_called = true;\n            Pin::new(&mut self.tcp).poll_shutdown(cx)\n        }\n\n        fn poll_flush(\n            mut self: Pin<&mut Self>,\n            cx: &mut Context<'_>,\n        ) -> Poll<Result<(), io::Error>> {\n            Pin::new(&mut self.tcp).poll_flush(cx)\n        }\n\n        fn poll_write(\n            mut self: Pin<&mut Self>,\n            cx: &mut Context<'_>,\n            buf: &[u8],\n        ) -> Poll<Result<usize, io::Error>> {\n            Pin::new(&mut self.tcp).poll_write(cx, buf)\n        }\n    }\n\n    impl hyper::rt::Read for DebugStream {\n        fn poll_read(\n            mut self: Pin<&mut Self>,\n            cx: &mut Context<'_>,\n            buf: hyper::rt::ReadBufCursor<'_>,\n        ) -> Poll<io::Result<()>> {\n            Pin::new(&mut self.tcp).poll_read(cx, buf)\n        }\n    }\n}\n\ntrait FutureHyperExt: TryFuture {\n    fn expect(self, msg: &'static str) -> Pin<Box<dyn Future<Output = Self::Ok>>>;\n}\n\nimpl<F> FutureHyperExt for F\nwhere\n    F: TryFuture + 'static,\n    F::Error: std::fmt::Debug,\n{\n    fn expect(self, msg: &'static str) -> Pin<Box<dyn Future<Output = Self::Ok>>> {\n        Box::pin(\n            self.inspect_err(move |e| panic!(\"expect: {}; error={:?}\", msg, e))\n                .map(Result::unwrap),\n        )\n    }\n}\n"
  },
  {
    "path": "tests/integration.rs",
    "content": "#![deny(warnings)]\n#[macro_use]\nmod support;\nuse self::support::*;\n\nt! {\n    get_1,\n    client:\n        request:\n            uri: \"/\",\n            ;\n        response:\n            status: 200,\n            headers: {\n                \"date\" => SOME,\n            },\n            ;\n    server:\n        request:\n            uri: \"/\",\n            ;\n        response:\n            ;\n}\n\nt! {\n    get_implicit_path,\n    client:\n        request:\n            uri: \"\",\n            ;\n        response:\n            status: 200,\n            ;\n    server:\n        request:\n            uri: \"/\",\n            ;\n        response:\n            ;\n}\n\nt! {\n    date_isnt_overwritten,\n    client:\n        request:\n            ;\n        response:\n            status: 200,\n            headers: {\n                \"date\" => \"let me through\",\n            },\n            ;\n    server:\n        request:\n            ;\n        response:\n            headers: {\n                \"date\" => \"let me through\",\n            },\n            ;\n}\n\nt! {\n    get_body,\n    client:\n        request:\n            uri: \"/\",\n            ;\n        response:\n            status: 200,\n            headers: {\n                \"content-length\" => 11,\n            },\n            body: \"hello world\",\n            ;\n    server:\n        request:\n            uri: \"/\",\n            ;\n        response:\n            headers: {\n                \"content-length\" => 11,\n            },\n            body: \"hello world\",\n            ;\n}\n\nt! {\n    get_body_2_keeps_alive,\n    client:\n        request:\n            uri: \"/\",\n            ;\n        response:\n            status: 200,\n            headers: {\n                \"content-length\" => 11,\n            },\n            body: \"hello world\",\n            ;\n        request:\n            uri: \"/\",\n            ;\n        response:\n            status: 200,\n            headers: {\n                \"content-length\" => 11,\n            },\n            body: \"hello world\",\n            ;\n    server:\n        request:\n            uri: \"/\",\n            ;\n        response:\n            headers: {\n                \"content-length\" => 11,\n            },\n            body: \"hello world\",\n            ;\n        request:\n            uri: \"/\",\n            ;\n        response:\n            headers: {\n                \"content-length\" => 11,\n            },\n            body: \"hello world\",\n            ;\n}\n\nt! {\n    get_strip_connection_header,\n    client:\n        request:\n            uri: \"/\",\n            ;\n        response:\n            status: 200,\n            headers: {\n                // h2 doesn't actually receive the connection header\n            },\n            body: \"hello world\",\n            ;\n    server:\n        request:\n            uri: \"/\",\n            ;\n        response:\n            headers: {\n                // http2 should strip this header\n                \"connection\" => \"close\",\n            },\n            body: \"hello world\",\n            ;\n}\n\nt! {\n    get_strip_keep_alive_header,\n    client:\n        request:\n            uri: \"/\",\n            ;\n        response:\n            status: 200,\n            headers: {\n                // h2 doesn't actually receive the keep-alive header\n            },\n            body: \"hello world\",\n            ;\n    server:\n        request:\n            uri: \"/\",\n            ;\n        response:\n            headers: {\n                // http2 should strip this header\n                \"keep-alive\" => \"timeout=5, max=1000\",\n            },\n            body: \"hello world\",\n            ;\n}\n\nt! {\n    get_strip_upgrade_header,\n    client:\n        request:\n            uri: \"/\",\n            ;\n        response:\n            status: 200,\n            headers: {\n                // h2 doesn't actually receive the upgrade header\n            },\n            body: \"hello world\",\n            ;\n    server:\n        request:\n            uri: \"/\",\n            ;\n        response:\n            headers: {\n                // http2 should strip this header\n                \"upgrade\" => \"h2c\",\n            },\n            body: \"hello world\",\n            ;\n}\n\nt! {\n    get_allow_te_trailers_header,\n    client:\n        request:\n            uri: \"/\",\n            headers: {\n                // http2 strips connection headers other than TE \"trailers\"\n                \"te\" => \"trailers\",\n            },\n            ;\n        response:\n            status: 200,\n            ;\n    server:\n        request:\n            uri: \"/\",\n            headers: {\n                \"te\" => \"trailers\",\n            },\n            ;\n        response:\n            ;\n}\n\nt! {\n    get_body_chunked,\n    client:\n        request:\n            uri: \"/\",\n            ;\n        response:\n            status: 200,\n            headers: {\n                // h2 doesn't actually receive the transfer-encoding header\n            },\n            body: \"hello world\",\n            ;\n    server:\n        request:\n            uri: \"/\",\n            ;\n        response:\n            headers: {\n                // http2 should strip this header\n                \"transfer-encoding\" => \"chunked\",\n            },\n            body: \"hello world\",\n            ;\n}\n\nt! {\n    post_outgoing_length,\n    client:\n        request:\n            method: \"POST\",\n            uri: \"/hello\",\n            body: \"hello, world!\",\n            ;\n        response:\n            ;\n    server:\n        request:\n            method: \"POST\",\n            uri: \"/hello\",\n            headers: {\n                \"content-length\" => \"13\",\n            },\n            body: \"hello, world!\",\n            ;\n        response:\n            ;\n}\n\nt! {\n    post_chunked,\n    client:\n        request:\n            method: \"POST\",\n            uri: \"/post_chunked\",\n            headers: {\n                // http2 should strip this header\n                \"transfer-encoding\" => \"chunked\",\n            },\n            body: \"hello world\",\n            ;\n        response:\n            ;\n    server:\n        request:\n            method: \"POST\",\n            uri: \"/post_chunked\",\n            body: \"hello world\",\n            ;\n        response:\n            ;\n}\n\nt! {\n    get_2,\n    client:\n        request:\n            uri: \"/1\",\n            ;\n        response:\n            status: 200,\n            ;\n        request:\n            uri: \"/2\",\n            ;\n        response:\n            status: 200,\n            ;\n    server:\n        request:\n            uri: \"/1\",\n            ;\n        response:\n            ;\n        request:\n            uri: \"/2\",\n            ;\n        response:\n            ;\n}\n\nt! {\n    http2_parallel_10,\n    parallel: 0..10\n}\n"
  },
  {
    "path": "tests/server.rs",
    "content": "#![deny(warnings)]\n#![deny(rust_2018_idioms)]\n\nuse std::future::Future;\nuse std::io::{self, Read, Write};\nuse std::net::TcpListener as StdTcpListener;\nuse std::net::{Shutdown, SocketAddr, TcpStream};\nuse std::pin::Pin;\nuse std::sync::atomic::{AtomicBool, Ordering};\nuse std::sync::mpsc;\nuse std::sync::{Arc, Mutex};\nuse std::task::{Context, Poll};\nuse std::thread;\nuse std::time::Duration;\n\nuse bytes::Bytes;\nuse futures_channel::oneshot;\nuse futures_util::future::{self, Either, FutureExt};\nuse h2::client::SendRequest;\nuse h2::{RecvStream, SendStream};\nuse http::header::{HeaderMap, HeaderName, HeaderValue};\nuse http_body_util::{combinators::BoxBody, BodyExt, Empty, Full, StreamBody};\nuse hyper::rt::Timer;\nuse hyper::rt::{Read as AsyncRead, Write as AsyncWrite};\nuse support::{TokioExecutor, TokioIo, TokioTimer};\nuse tokio::io::{AsyncReadExt, AsyncWriteExt, DuplexStream};\nuse tokio::net::{TcpListener as TkTcpListener, TcpListener, TcpStream as TkTcpStream};\n\nuse hyper::body::{Body, Incoming as IncomingBody};\nuse hyper::server::conn::{http1, http2};\nuse hyper::service::{service_fn, Service};\nuse hyper::{Method, Request, Response, StatusCode, Uri, Version};\nuse tokio::pin;\n\nmod support;\n\n#[test]\nfn get_should_ignore_body() {\n    let server = serve();\n\n    let mut req = connect(server.addr());\n    // Connection: close = don't try to parse the body as a new request\n    req.write_all(\n        b\"\\\n        GET / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: close\\r\\n\\\n        \\r\\n\\\n        I shouldn't be read.\\r\\n\\\n    \",\n    )\n    .unwrap();\n    req.read(&mut [0; 256]).unwrap();\n\n    assert_eq!(server.body(), b\"\");\n}\n\n#[test]\nfn get_with_body() {\n    let server = serve();\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        GET / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Content-Length: 19\\r\\n\\\n        \\r\\n\\\n        I'm a good request.\\r\\n\\\n    \",\n    )\n    .unwrap();\n    req.read(&mut [0; 256]).unwrap();\n\n    // note: doesn't include trailing \\r\\n, cause Content-Length wasn't 21\n    assert_eq!(server.body(), b\"I'm a good request.\");\n}\n\nmod response_body_lengths {\n    use super::*;\n\n    struct TestCase {\n        version: usize,\n        headers: &'static [(&'static str, &'static str)],\n        body: Bd,\n        expects_chunked: bool,\n        expects_con_len: bool,\n    }\n\n    enum Bd {\n        Known(&'static str),\n        Unknown(&'static str),\n    }\n\n    fn run_test(case: TestCase) {\n        let _ = pretty_env_logger::try_init();\n        assert!(\n            case.version == 0 || case.version == 1,\n            \"TestCase.version must 0 or 1\"\n        );\n\n        let server = serve();\n\n        let mut reply = server.reply();\n        for header in case.headers {\n            reply = reply.header(header.0, header.1);\n        }\n\n        let body_str = match case.body {\n            Bd::Known(b) => {\n                reply.body(b);\n                b\n            }\n            Bd::Unknown(b) => {\n                let body = futures_util::stream::once(async move { Ok(b.into()) });\n                reply.body_stream(body);\n                b\n            }\n        };\n\n        let mut req = connect(server.addr());\n        write!(\n            req,\n            \"\\\n             GET / HTTP/1.{}\\r\\n\\\n             Host: example.domain\\r\\n\\\n             Connection: close\\r\\n\\\n             \\r\\n\\\n             \",\n            case.version\n        )\n        .expect(\"request write\");\n        let mut body = String::new();\n        req.read_to_string(&mut body).unwrap();\n\n        assert_eq!(\n            case.expects_chunked,\n            has_header(&body, \"transfer-encoding:\"),\n            \"expects_chunked, headers = {:?}\",\n            body\n        );\n\n        assert_eq!(\n            case.expects_chunked,\n            has_header(&body, \"chunked\\r\\n\"),\n            \"expects_chunked, headers = {:?}\",\n            body\n        );\n\n        assert_eq!(\n            case.expects_con_len,\n            has_header(&body, \"content-length:\"),\n            \"expects_con_len, headers = {:?}\",\n            body\n        );\n\n        let n = body.find(\"\\r\\n\\r\\n\").unwrap() + 4;\n\n        if case.expects_chunked {\n            if !body_str.is_empty() {\n                let len = body.len();\n                assert_eq!(\n                    &body[n + 1..n + 3],\n                    \"\\r\\n\",\n                    \"expected body chunk size header\"\n                );\n                assert_eq!(&body[n + 3..len - 7], body_str, \"expected body\");\n                assert_eq!(\n                    &body[len - 7..],\n                    \"\\r\\n0\\r\\n\\r\\n\",\n                    \"expected body final chunk size header\"\n                );\n            } else {\n                assert_eq!(&body[n..], \"0\\r\\n\\r\\n\");\n            }\n        } else {\n            assert_eq!(&body[n..], body_str, \"expected body\");\n        }\n    }\n\n    #[test]\n    fn fixed_response_known() {\n        run_test(TestCase {\n            version: 1,\n            headers: &[(\"content-length\", \"11\")],\n            body: Bd::Known(\"foo bar baz\"),\n            expects_chunked: false,\n            expects_con_len: true,\n        });\n    }\n\n    #[test]\n    fn fixed_response_unknown() {\n        run_test(TestCase {\n            version: 1,\n            headers: &[(\"content-length\", \"11\")],\n            body: Bd::Unknown(\"foo bar baz\"),\n            expects_chunked: false,\n            expects_con_len: true,\n        });\n    }\n\n    #[test]\n    fn fixed_response_known_empty() {\n        run_test(TestCase {\n            version: 1,\n            headers: &[(\"content-length\", \"0\")],\n            body: Bd::Known(\"\"),\n            expects_chunked: false,\n            expects_con_len: true,\n        });\n    }\n\n    #[test]\n    fn chunked_response_known() {\n        run_test(TestCase {\n            version: 1,\n            headers: &[(\"transfer-encoding\", \"chunked\")],\n            // even though we know the length, don't strip user's TE header\n            body: Bd::Known(\"foo bar baz\"),\n            expects_chunked: true,\n            expects_con_len: false,\n        });\n    }\n\n    #[test]\n    fn chunked_response_known_empty() {\n        run_test(TestCase {\n            version: 1,\n            headers: &[(\"transfer-encoding\", \"chunked\")],\n            body: Bd::Known(\"\"),\n            expects_chunked: true, // should still send chunked, and 0\\r\\n\\r\\n\n            expects_con_len: false,\n        });\n    }\n\n    #[test]\n    fn chunked_response_unknown() {\n        run_test(TestCase {\n            version: 1,\n            headers: &[(\"transfer-encoding\", \"chunked\")],\n            body: Bd::Unknown(\"foo bar baz\"),\n            expects_chunked: true,\n            expects_con_len: false,\n        });\n    }\n\n    #[test]\n    fn te_response_adds_chunked() {\n        run_test(TestCase {\n            version: 1,\n            headers: &[(\"transfer-encoding\", \"gzip\")],\n            body: Bd::Unknown(\"foo bar baz\"),\n            expects_chunked: true,\n            expects_con_len: false,\n        });\n    }\n\n    #[test]\n    #[ignore]\n    // This used to be the case, but providing this functionality got in the\n    // way of performance. It can probably be brought back later, and doing\n    // so should be backwards-compatible...\n    fn chunked_response_trumps_length() {\n        run_test(TestCase {\n            version: 1,\n            headers: &[\n                (\"transfer-encoding\", \"chunked\"),\n                // both headers means content-length is stripped\n                (\"content-length\", \"11\"),\n            ],\n            body: Bd::Known(\"foo bar baz\"),\n            expects_chunked: true,\n            expects_con_len: false,\n        });\n    }\n\n    #[test]\n    fn auto_response_with_unknown_length() {\n        run_test(TestCase {\n            version: 1,\n            // no headers means trying to guess from Body\n            headers: &[],\n            body: Bd::Unknown(\"foo bar baz\"),\n            expects_chunked: true,\n            expects_con_len: false,\n        });\n    }\n\n    #[test]\n    fn auto_response_with_known_length() {\n        run_test(TestCase {\n            version: 1,\n            // no headers means trying to guess from Body\n            headers: &[],\n            body: Bd::Known(\"foo bar baz\"),\n            expects_chunked: false,\n            expects_con_len: true,\n        });\n    }\n\n    #[test]\n    fn auto_response_known_empty() {\n        run_test(TestCase {\n            version: 1,\n            // no headers means trying to guess from Body\n            headers: &[],\n            body: Bd::Known(\"\"),\n            expects_chunked: false,\n            expects_con_len: true,\n        });\n    }\n\n    #[test]\n    fn http10_auto_response_with_unknown_length() {\n        run_test(TestCase {\n            version: 0,\n            // no headers means trying to guess from Body\n            headers: &[],\n            body: Bd::Unknown(\"foo bar baz\"),\n            expects_chunked: false,\n            expects_con_len: false,\n        });\n    }\n\n    #[test]\n    fn http10_chunked_response() {\n        run_test(TestCase {\n            version: 0,\n            // http/1.0 should strip this header\n            headers: &[(\"transfer-encoding\", \"chunked\")],\n            // even when we don't know the length\n            body: Bd::Unknown(\"foo bar baz\"),\n            expects_chunked: false,\n            expects_con_len: false,\n        });\n    }\n\n    #[tokio::test]\n    async fn http2_auto_response_with_known_length() {\n        let server = serve_opts().http2().serve();\n        let addr_str = format!(\"http://{}\", server.addr());\n        server.reply().body(\"Hello, World!\");\n\n        let client = TestClient::new().http2_only();\n        let uri = addr_str\n            .parse::<hyper::Uri>()\n            .expect(\"server addr should parse\");\n\n        let res = client.get(uri).await.unwrap();\n        assert_eq!(res.headers().get(\"content-length\").unwrap(), \"13\");\n        assert_eq!(res.body().size_hint().exact(), Some(13));\n    }\n\n    #[tokio::test]\n    async fn http2_auto_response_with_conflicting_lengths() {\n        let server = serve_opts().http2().serve();\n        let addr_str = format!(\"http://{}\", server.addr());\n        server\n            .reply()\n            .header(\"content-length\", \"10\")\n            .body(\"Hello, World!\");\n\n        let client = TestClient::new().http2_only();\n        let uri = addr_str\n            .parse::<hyper::Uri>()\n            .expect(\"server addr should parse\");\n\n        let res = client.get(uri).await.unwrap();\n        assert_eq!(res.headers().get(\"content-length\").unwrap(), \"10\");\n        assert_eq!(res.body().size_hint().exact(), Some(10));\n    }\n\n    #[tokio::test]\n    async fn http2_implicit_empty_size_hint() {\n        let server = serve_opts().http2().serve();\n        let addr_str = format!(\"http://{}\", server.addr());\n        server.reply();\n\n        let client = TestClient::new().http2_only();\n        let uri = addr_str\n            .parse::<hyper::Uri>()\n            .expect(\"server addr should parse\");\n\n        let res = client.get(uri).await.unwrap();\n        assert_eq!(res.headers().get(\"content-length\"), None);\n        assert_eq!(res.body().size_hint().exact(), Some(0));\n    }\n}\n\n#[test]\nfn get_response_custom_reason_phrase() {\n    let _ = pretty_env_logger::try_init();\n    let server = serve();\n    server.reply().reason_phrase(\"Cool\");\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        GET / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: close\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .unwrap();\n\n    let mut response = String::new();\n    req.read_to_string(&mut response).unwrap();\n\n    let mut lines = response.lines();\n    assert_eq!(lines.next(), Some(\"HTTP/1.1 200 Cool\"));\n\n    let mut lines = lines.skip_while(|line| !line.is_empty());\n    assert_eq!(lines.next(), Some(\"\"));\n    assert_eq!(lines.next(), None);\n}\n\n#[test]\nfn get_chunked_response_with_ka() {\n    let foo_bar = b\"foo bar baz\";\n    let foo_bar_chunk = b\"\\r\\nfoo bar baz\\r\\n0\\r\\n\\r\\n\";\n    let server = serve();\n    server\n        .reply()\n        .header(\"transfer-encoding\", \"chunked\")\n        .body(foo_bar);\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        GET / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: keep-alive\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"writing 1\");\n\n    read_until(&mut req, |buf| buf.ends_with(foo_bar_chunk)).expect(\"reading 1\");\n\n    // try again!\n\n    let quux = b\"zar quux\";\n    server\n        .reply()\n        .header(\"content-length\", quux.len().to_string())\n        .body(quux);\n    req.write_all(\n        b\"\\\n        GET /quux HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: close\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"writing 2\");\n\n    read_until(&mut req, |buf| buf.ends_with(quux)).expect(\"reading 2\");\n}\n\n#[test]\nfn post_with_content_length_body() {\n    let server = serve();\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        POST / HTTP/1.1\\r\\n\\\n        Content-Length: 5\\r\\n\\\n        \\r\\n\\\n        hello\\\n    \",\n    )\n    .unwrap();\n    req.read(&mut [0; 256]).unwrap();\n\n    assert_eq!(server.body(), b\"hello\");\n}\n\n#[test]\nfn post_with_invalid_prefix_content_length() {\n    let server = serve();\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        POST / HTTP/1.1\\r\\n\\\n        Content-Length: +5\\r\\n\\\n        \\r\\n\\\n        hello\\\n    \",\n    )\n    .unwrap();\n\n    let mut buf = [0; 256];\n    let _n = req.read(&mut buf).unwrap();\n    let expected = \"HTTP/1.1 400 Bad Request\\r\\n\";\n    assert_eq!(s(&buf[..expected.len()]), expected);\n}\n\n#[test]\nfn post_with_chunked_body() {\n    let server = serve();\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        POST / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Transfer-Encoding: chunked\\r\\n\\\n        \\r\\n\\\n        1\\r\\n\\\n        q\\r\\n\\\n        2\\r\\n\\\n        we\\r\\n\\\n        2\\r\\n\\\n        rt\\r\\n\\\n        0\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .unwrap();\n    req.read(&mut [0; 256]).unwrap();\n\n    assert_eq!(server.body(), b\"qwert\");\n}\n\n#[test]\nfn post_with_chunked_overflow() {\n    use std::error::Error as _;\n    let server = serve();\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        POST / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Transfer-Encoding: chunked\\r\\n\\\n        \\r\\n\\\n        f0000000000000003\\r\\n\\\n        abc\\r\\n\\\n        0\\r\\n\\\n        \\r\\n\\\n        GET /sneaky HTTP/1.1\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .unwrap();\n    req.read(&mut [0; 256]).unwrap();\n\n    let err = server.body_err().source().unwrap().to_string();\n    assert!(\n        err.contains(\"overflow\"),\n        \"error should be overflow: {:?}\",\n        err\n    );\n}\n\n#[test]\nfn post_with_incomplete_body() {\n    let _ = pretty_env_logger::try_init();\n    let server = serve();\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        POST / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Content-Length: 10\\r\\n\\\n        \\r\\n\\\n        12345\\\n    \",\n    )\n    .expect(\"write\");\n    req.shutdown(Shutdown::Write).expect(\"shutdown write\");\n\n    server.body_err();\n\n    req.read(&mut [0; 256]).expect(\"read\");\n}\n\n#[test]\nfn post_with_chunked_missing_final_digit() {\n    let _ = pretty_env_logger::try_init();\n    let server = serve();\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        POST / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        transfer-encoding: chunked\\r\\n\\\n        \\r\\n\\\n        1\\r\\n\\\n        Z\\r\\n\\\n        \\r\\n\\r\\n\\\n    \",\n    )\n    .expect(\"write\");\n\n    server.body_err();\n\n    req.read(&mut [0; 256]).expect(\"read\");\n}\n\n#[test]\nfn head_response_can_send_content_length() {\n    let _ = pretty_env_logger::try_init();\n    let server = serve();\n    server.reply().header(\"content-length\", \"1024\");\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        HEAD / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: close\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .unwrap();\n\n    let mut response = String::new();\n    req.read_to_string(&mut response).unwrap();\n\n    assert!(response.contains(\"content-length: 1024\\r\\n\"));\n\n    let mut lines = response.lines();\n    assert_eq!(lines.next(), Some(\"HTTP/1.1 200 OK\"));\n\n    let mut lines = lines.skip_while(|line| !line.is_empty());\n    assert_eq!(lines.next(), Some(\"\"));\n    assert_eq!(lines.next(), None);\n}\n\n#[test]\nfn head_response_doesnt_send_body() {\n    let _ = pretty_env_logger::try_init();\n    let foo_bar = b\"foo bar baz\";\n    let server = serve();\n    server.reply().body(foo_bar);\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        HEAD / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: close\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .unwrap();\n\n    let mut response = String::new();\n    req.read_to_string(&mut response).unwrap();\n\n    assert!(response.contains(\"content-length: 11\\r\\n\"));\n\n    let mut lines = response.lines();\n    assert_eq!(lines.next(), Some(\"HTTP/1.1 200 OK\"));\n\n    let mut lines = lines.skip_while(|line| !line.is_empty());\n    assert_eq!(lines.next(), Some(\"\"));\n    assert_eq!(lines.next(), None);\n}\n\n#[test]\nfn response_does_not_set_chunked_if_body_not_allowed() {\n    let _ = pretty_env_logger::try_init();\n    let server = serve();\n    server\n        .reply()\n        .status(hyper::StatusCode::NOT_MODIFIED)\n        .header(\"transfer-encoding\", \"chunked\");\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        GET / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: close\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .unwrap();\n\n    let mut response = String::new();\n    req.read_to_string(&mut response).unwrap();\n\n    assert!(!response.contains(\"transfer-encoding\"));\n\n    let mut lines = response.lines();\n    assert_eq!(lines.next(), Some(\"HTTP/1.1 304 Not Modified\"));\n\n    // no body or 0\\r\\n\\r\\n\n    let mut lines = lines.skip_while(|line| !line.is_empty());\n    assert_eq!(lines.next(), Some(\"\"));\n    assert_eq!(lines.next(), None);\n}\n\n#[test]\nfn keep_alive() {\n    let foo_bar = b\"foo bar baz\";\n    let server = serve();\n    server\n        .reply()\n        .header(\"content-length\", foo_bar.len().to_string())\n        .body(foo_bar);\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        GET / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"writing 1\");\n\n    read_until(&mut req, |buf| buf.ends_with(foo_bar)).expect(\"reading 1\");\n\n    // try again!\n\n    let quux = b\"zar quux\";\n    server\n        .reply()\n        .header(\"content-length\", quux.len().to_string())\n        .body(quux);\n    req.write_all(\n        b\"\\\n        GET /quux HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: close\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"writing 2\");\n\n    read_until(&mut req, |buf| buf.ends_with(quux)).expect(\"reading 2\");\n}\n\n#[test]\nfn http_10_keep_alive() {\n    let foo_bar = b\"foo bar baz\";\n    let server = serve();\n    // Response version 1.1 with no keep-alive header will downgrade to 1.0 when served\n    server\n        .reply()\n        .header(\"content-length\", foo_bar.len().to_string())\n        .body(foo_bar);\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        GET / HTTP/1.0\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: keep-alive\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"writing 1\");\n\n    // Connection: keep-alive header should be added when downgrading to a 1.0 response\n    let res = read_until(&mut req, |buf| buf.ends_with(foo_bar)).expect(\"reading 1\");\n\n    let sres = s(&res);\n    assert!(\n        sres.contains(\"connection: keep-alive\\r\\n\"),\n        \"HTTP/1.0 response should have sent keep-alive: {:?}\",\n        sres,\n    );\n\n    // try again!\n\n    let quux = b\"zar quux\";\n    server\n        .reply()\n        .header(\"content-length\", quux.len().to_string())\n        .body(quux);\n    req.write_all(\n        b\"\\\n        GET /quux HTTP/1.0\\r\\n\\\n        Host: example.domain\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"writing 2\");\n\n    read_until(&mut req, |buf| buf.ends_with(quux)).expect(\"reading 2\");\n}\n\n#[test]\nfn http_10_close_on_no_ka() {\n    let foo_bar = b\"foo bar baz\";\n    let server = serve();\n\n    // A server response with version 1.0 but no keep-alive header\n    server\n        .reply()\n        .version(Version::HTTP_10)\n        .header(\"content-length\", foo_bar.len().to_string())\n        .body(foo_bar);\n    let mut req = connect(server.addr());\n\n    // The client request with version 1.0 that may have the keep-alive header\n    req.write_all(\n        b\"\\\n        GET / HTTP/1.0\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: keep-alive\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"writing 1\");\n\n    // server isn't keeping-alive, so the socket should be closed after\n    // writing the response. thus, read_to_end should succeed.\n    let mut buf = Vec::new();\n    req.read_to_end(&mut buf).expect(\"reading 1\");\n\n    assert!(buf.ends_with(foo_bar));\n    let sbuf = s(&buf);\n    assert!(\n        !sbuf.contains(\"connection: keep-alive\\r\\n\"),\n        \"HTTP/1.0 response shouldn't have sent keep-alive: {:?}\",\n        sbuf,\n    );\n}\n\n#[test]\nfn disable_keep_alive() {\n    let foo_bar = b\"foo bar baz\";\n    let server = serve_opts().keep_alive(false).serve();\n    server\n        .reply()\n        .header(\"content-length\", foo_bar.len().to_string())\n        .body(foo_bar);\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        GET / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: keep-alive\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"writing 1\");\n\n    // server isn't keeping-alive, so the socket should be closed after\n    // writing the response. thus, read_to_end should succeed.\n    let mut buf = Vec::new();\n    req.read_to_end(&mut buf).expect(\"reading 1\");\n    assert!(buf.ends_with(foo_bar));\n}\n\n#[test]\nfn header_connection_close() {\n    let foo_bar = b\"foo bar baz\";\n    let server = serve();\n    server\n        .reply()\n        .header(\"content-length\", foo_bar.len().to_string())\n        .header(\"connection\", \"close\")\n        .body(foo_bar);\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        GET / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: keep-alive\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"writing 1\");\n\n    // server isn't keeping-alive, so the socket should be closed after\n    // writing the response. thus, read_to_end should succeed.\n    let mut buf = Vec::new();\n    req.read_to_end(&mut buf).expect(\"reading 1\");\n    assert!(buf.ends_with(foo_bar));\n    let sbuf = s(&buf);\n    assert!(\n        sbuf.contains(\"connection: close\\r\\n\"),\n        \"response should have sent close: {:?}\",\n        sbuf,\n    );\n}\n\n#[test]\nfn expect_continue_sends_100() {\n    let server = serve();\n    let mut req = connect(server.addr());\n    server.reply();\n\n    req.write_all(\n        b\"\\\n        POST /foo HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Expect: 100-continue\\r\\n\\\n        Content-Length: 5\\r\\n\\\n        Connection: Close\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"write 1\");\n\n    let msg = b\"HTTP/1.1 100 Continue\\r\\n\\r\\n\";\n    let mut buf = vec![0; msg.len()];\n    req.read_exact(&mut buf).expect(\"read 1\");\n    assert_eq!(buf, msg);\n\n    let msg = b\"hello\";\n    req.write_all(msg).expect(\"write 2\");\n\n    let mut body = String::new();\n    req.read_to_string(&mut body).expect(\"read 2\");\n\n    let body = server.body();\n    assert_eq!(body, msg);\n}\n\n#[test]\nfn expect_continue_accepts_upper_cased_expectation() {\n    let server = serve();\n    let mut req = connect(server.addr());\n    server.reply();\n\n    req.write_all(\n        b\"\\\n        POST /foo HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Expect: 100-Continue\\r\\n\\\n        Content-Length: 5\\r\\n\\\n        Connection: Close\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"write 1\");\n\n    let msg = b\"HTTP/1.1 100 Continue\\r\\n\\r\\n\";\n    let mut buf = vec![0; msg.len()];\n    req.read_exact(&mut buf).expect(\"read 1\");\n    assert_eq!(buf, msg);\n\n    let msg = b\"hello\";\n    req.write_all(msg).expect(\"write 2\");\n\n    let mut body = String::new();\n    req.read_to_string(&mut body).expect(\"read 2\");\n\n    let body = server.body();\n    assert_eq!(body, msg);\n}\n\n#[test]\nfn expect_continue_but_http_10_is_ignored() {\n    let server = serve();\n    let mut req = connect(server.addr());\n    server.reply();\n\n    req.write_all(\n        b\"\\\n        POST /foo HTTP/1.0\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Expect: 100-Continue\\r\\n\\\n        Content-Length: 5\\r\\n\\\n        Connection: Close\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"write 1\");\n\n    let msg = b\"hello\";\n    req.write_all(msg).expect(\"write 2\");\n\n    let s_line = b\"HTTP/1.0 200 OK\\r\\n\";\n    let mut buf = vec![0; s_line.len()];\n    req.read_exact(&mut buf).expect(\"read 1\");\n    assert_eq!(buf, s_line);\n\n    let mut body = String::new();\n    req.read_to_string(&mut body).expect(\"read 2\");\n\n    let body = server.body();\n    assert_eq!(body, msg);\n}\n\n#[test]\nfn expect_continue_but_no_body_is_ignored() {\n    let server = serve();\n    let mut req = connect(server.addr());\n    server.reply();\n\n    // no content-length or transfer-encoding means no body!\n    req.write_all(\n        b\"\\\n        POST /foo HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Expect: 100-continue\\r\\n\\\n        Connection: Close\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"write\");\n\n    let expected = \"HTTP/1.1 200 OK\\r\\n\";\n    let mut resp = String::new();\n    req.read_to_string(&mut resp).expect(\"read\");\n\n    assert_eq!(&resp[..expected.len()], expected);\n}\n\nfn setup_tcp_listener() -> (TcpListener, SocketAddr) {\n    let _ = pretty_env_logger::try_init();\n    let listener = tcp_bind(&\"127.0.0.1:0\".parse().unwrap()).unwrap();\n    let addr = listener.local_addr().unwrap();\n    (listener, addr)\n}\n\nfn setup_duplex_test_server() -> (DuplexStream, DuplexStream, SocketAddr) {\n    use std::net::{IpAddr, Ipv6Addr};\n    let _ = pretty_env_logger::try_init();\n\n    const BUF_SIZE: usize = 1024;\n    let (ioa, iob) = tokio::io::duplex(BUF_SIZE);\n\n    /// A test address inside the 'documentation' address range.\n    /// See: <https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml>\n    const TEST_ADDR: IpAddr = IpAddr::V6(Ipv6Addr::new(0x3fff, 0, 0, 0, 0, 0, 0, 1));\n    const TEST_SOCKET: SocketAddr = SocketAddr::new(TEST_ADDR, 8080);\n\n    (ioa, iob, TEST_SOCKET)\n}\n\n#[tokio::test]\nasync fn expect_continue_waits_for_body_poll() {\n    let (listener, addr) = setup_tcp_listener();\n\n    let child = thread::spawn(move || {\n        let mut tcp = connect(&addr);\n\n        tcp.write_all(\n            b\"\\\n            POST /foo HTTP/1.1\\r\\n\\\n            Host: example.domain\\r\\n\\\n            Expect: 100-continue\\r\\n\\\n            Content-Length: 100\\r\\n\\\n            Connection: Close\\r\\n\\\n            \\r\\n\\\n        \",\n        )\n        .expect(\"write\");\n\n        let expected = \"HTTP/1.1 400 Bad Request\\r\\n\";\n        let mut resp = String::new();\n        tcp.read_to_string(&mut resp).expect(\"read\");\n\n        assert_eq!(&resp[..expected.len()], expected);\n    });\n\n    let (socket, _) = listener.accept().await.expect(\"accept\");\n    let socket = TokioIo::new(socket);\n\n    http1::Builder::new()\n        .serve_connection(\n            socket,\n            service_fn(|req| {\n                assert_eq!(req.headers()[\"expect\"], \"100-continue\");\n                // But! We're never going to poll the body!\n                drop(req);\n                TokioTimer.sleep(Duration::from_millis(50)).map(move |_| {\n                    Response::builder()\n                        .status(StatusCode::BAD_REQUEST)\n                        .body(Empty::<Bytes>::new())\n                })\n            }),\n        )\n        .await\n        .expect(\"serve_connection\");\n\n    child.join().expect(\"client thread\");\n}\n\n#[test]\nfn pipeline_disabled() {\n    let server = serve();\n    let mut req = connect(server.addr());\n    server\n        .reply()\n        .header(\"content-length\", \"12\")\n        .body(\"Hello World!\");\n    server\n        .reply()\n        .header(\"content-length\", \"12\")\n        .body(\"Hello World!\");\n\n    req.write_all(\n        b\"\\\n        GET / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        \\r\\n\\\n        GET / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"write 1\");\n\n    let mut buf = vec![0; 4096];\n    let n = req.read(&mut buf).expect(\"read 1\");\n    assert_ne!(n, 0);\n    // Woah there. What?\n    //\n    // This test is wishy-washy because of race conditions in access of the\n    // socket. The test is still useful, since it allows for the responses\n    // to be received in 2 reads. But it might sometimes come in 1 read.\n    //\n    // TODO: add in a delay to the `ServeReply` interface, to allow this\n    // delay to prevent the 2 writes from happening before this test thread\n    // can read from the socket.\n    if let Ok(n) = req.read(&mut buf) {\n        // won't be 0, because we didn't say to close, and so socket\n        // will be open until `server` drops\n        assert_ne!(n, 0);\n    }\n}\n\n#[test]\nfn pipeline_enabled() {\n    let server = serve_opts().pipeline(true).serve();\n    let mut req = connect(server.addr());\n    server\n        .reply()\n        .header(\"content-length\", \"12\")\n        .body(\"Hello World\\n\");\n    server\n        .reply()\n        .header(\"content-length\", \"12\")\n        .body(\"Hello World\\n\");\n\n    req.write_all(\n        b\"\\\n        GET / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        \\r\\n\\\n        GET / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: close\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"write 1\");\n\n    let mut buf = vec![0; 4096];\n    let n = req.read(&mut buf).expect(\"read 1\");\n    assert_ne!(n, 0);\n\n    {\n        let mut lines = buf.split(|&b| b == b'\\n');\n        assert_eq!(s(lines.next().unwrap()), \"HTTP/1.1 200 OK\\r\");\n        assert_eq!(s(lines.next().unwrap()), \"content-length: 12\\r\");\n        lines.next().unwrap(); // Date\n        assert_eq!(s(lines.next().unwrap()), \"\\r\");\n        assert_eq!(s(lines.next().unwrap()), \"Hello World\");\n\n        assert_eq!(s(lines.next().unwrap()), \"HTTP/1.1 200 OK\\r\");\n        assert_eq!(s(lines.next().unwrap()), \"content-length: 12\\r\");\n        // close because the last request said to close\n        assert_eq!(s(lines.next().unwrap()), \"connection: close\\r\");\n        lines.next().unwrap(); // Date\n        assert_eq!(s(lines.next().unwrap()), \"\\r\");\n        assert_eq!(s(lines.next().unwrap()), \"Hello World\");\n    }\n\n    // with pipeline enabled, both responses should have been in the first read\n    // so a second read should be EOF\n    let n = req.read(&mut buf).expect(\"read 2\");\n    assert_eq!(n, 0);\n}\n\n#[test]\nfn http_10_request_receives_http_10_response() {\n    let server = serve();\n\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        GET / HTTP/1.0\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .unwrap();\n\n    let expected = \"HTTP/1.0 200 OK\\r\\ncontent-length: 0\\r\\n\";\n    let mut buf = [0; 256];\n    let n = req.read(&mut buf).unwrap();\n    assert!(n >= expected.len(), \"read: {:?} >= {:?}\", n, expected.len());\n    assert_eq!(s(&buf[..expected.len()]), expected);\n}\n\n#[test]\nfn http_11_uri_too_long() {\n    let server = serve();\n\n    let long_path = \"a\".repeat(65534);\n    let request_line = format!(\"GET /{} HTTP/1.1\\r\\n\\r\\n\", long_path);\n\n    let mut req = connect(server.addr());\n    req.write_all(request_line.as_bytes()).unwrap();\n\n    let expected = \"HTTP/1.1 414 URI Too Long\\r\\nconnection: close\\r\\ncontent-length: 0\\r\\n\";\n    let mut buf = [0; 256];\n    let n = req.read(&mut buf).unwrap();\n    assert!(n >= expected.len(), \"read: {:?} >= {:?}\", n, expected.len());\n    assert_eq!(s(&buf[..expected.len()]), expected);\n}\n\n#[tokio::test]\nasync fn disable_keep_alive_mid_request() {\n    let (client_io, server_io, _) = setup_duplex_test_server();\n    let (tx1, rx1) = oneshot::channel();\n    let (tx2, rx2) = oneshot::channel();\n\n    let client_task = tokio::spawn(async move {\n        let mut client_io = client_io;\n        // Send partial request\n        client_io.write_all(b\"GET / HTTP/1.1\\r\\n\").await.unwrap();\n        // Signal server that partial request sent\n        tx1.send(()).unwrap();\n        // Wait for server to be ready for rest of request\n        rx2.await.unwrap();\n        // Send rest of request\n        client_io\n            .write_all(b\"Host: localhost\\r\\n\\r\\n\")\n            .await\n            .unwrap();\n        // Read response\n        let mut buf = vec![];\n        client_io.read_to_end(&mut buf).await.unwrap();\n        assert!(\n            buf.starts_with(b\"HTTP/1.1 200 OK\\r\\n\"),\n            \"should receive OK response, but buf: {:?}\",\n            buf,\n        );\n        let sbuf = s(&buf);\n        assert!(\n            sbuf.contains(\"connection: close\\r\\n\"),\n            \"response should have sent close: {:?}\",\n            sbuf,\n        );\n    });\n\n    let server_io = TokioIo::new(server_io);\n    let srv = http1::Builder::new().serve_connection(server_io, HelloWorld);\n    future::try_select(srv, rx1)\n        .then(|r| match r {\n            Ok(Either::Left(_)) => panic!(\"expected rx first\"),\n            Ok(Either::Right(((), mut conn))) => {\n                Pin::new(&mut conn).graceful_shutdown();\n                tx2.send(()).unwrap();\n                conn\n            }\n            Err(Either::Left((e, _))) => panic!(\"unexpected error {}\", e),\n            Err(Either::Right((e, _))) => panic!(\"unexpected error {}\", e),\n        })\n        .await\n        .unwrap();\n\n    client_task.await.unwrap();\n}\n\n#[tokio::test]\nasync fn disable_keep_alive_post_request() {\n    let (listener, addr) = setup_tcp_listener();\n    let (tx1, rx1) = oneshot::channel();\n\n    let child = thread::spawn(move || {\n        let mut req = connect(&addr);\n        req.write_all(\n            b\"\\\n            GET / HTTP/1.1\\r\\n\\\n            Host: localhost\\r\\n\\\n            \\r\\n\\\n        \",\n        )\n        .unwrap();\n\n        read_until(&mut req, |buf| buf.ends_with(HELLO.as_bytes())).expect(\"reading 1\");\n\n        // Connection should get closed *after* tx is sent on\n        tx1.send(()).unwrap();\n\n        let nread = req.read(&mut [0u8; 1024]).expect(\"keep-alive reading\");\n        assert_eq!(nread, 0);\n    });\n\n    let dropped = Dropped::new();\n    let dropped2 = dropped.clone();\n    let (socket, _) = listener.accept().await.unwrap();\n    let transport = DebugStream {\n        stream: TokioIo::new(socket),\n        _debug: dropped2,\n    };\n    let server = http1::Builder::new().serve_connection(transport, HelloWorld);\n    let fut = future::try_select(server, rx1).then(|r| match r {\n        Ok(Either::Left(_)) => panic!(\"expected rx first\"),\n        Ok(Either::Right(((), mut conn))) => {\n            Pin::new(&mut conn).graceful_shutdown();\n            conn\n        }\n        Err(Either::Left((e, _))) => panic!(\"unexpected error {}\", e),\n        Err(Either::Right((e, _))) => panic!(\"unexpected error {}\", e),\n    });\n\n    assert!(!dropped.load());\n    fut.await.unwrap();\n    assert!(dropped.load());\n    child.join().unwrap();\n}\n\n#[tokio::test]\nasync fn http1_graceful_shutdown_after_upgrade() {\n    let (listener, addr) = setup_tcp_listener();\n    let (read_101_tx, read_101_rx) = oneshot::channel();\n\n    thread::spawn(move || {\n        let mut tcp = connect(&addr);\n        tcp.write_all(\n            b\"\\\n            GET / HTTP/1.1\\r\\n\\\n            Upgrade: foobar\\r\\n\\\n            Connection: upgrade\\r\\n\\\n            \\r\\n\\\n            eagerly optimistic\\\n        \",\n        )\n        .expect(\"write 1\");\n        let mut buf = [0; 256];\n        tcp.read(&mut buf).expect(\"read 1\");\n\n        let response = s(&buf);\n        assert!(response.starts_with(\"HTTP/1.1 101 Switching Protocols\\r\\n\"));\n        assert!(!has_header(response, \"content-length\"));\n        let _ = read_101_tx.send(());\n    });\n\n    let (upgrades_tx, upgrades_rx) = mpsc::channel();\n    let svc = service_fn(move |req: Request<IncomingBody>| {\n        let on_upgrade = hyper::upgrade::on(req);\n        let _ = upgrades_tx.send(on_upgrade);\n        future::ok::<_, hyper::Error>(\n            Response::builder()\n                .status(101)\n                .header(\"upgrade\", \"foobar\")\n                .body(Empty::<Bytes>::new())\n                .unwrap(),\n        )\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n\n    let mut conn = http1::Builder::new()\n        .serve_connection(socket, svc)\n        .with_upgrades();\n    (&mut conn).await.unwrap();\n\n    let on_upgrade = upgrades_rx.recv().unwrap();\n\n    // wait so that we don't write until other side saw 101 response\n    read_101_rx.await.unwrap();\n\n    let upgraded = on_upgrade.await.expect(\"on_upgrade\");\n    let parts = upgraded.downcast::<TokioIo<TkTcpStream>>().unwrap();\n    assert_eq!(parts.read_buf, \"eagerly optimistic\");\n\n    pin!(conn);\n    // graceful shutdown doesn't cause issues or panic. It should be ignored after upgrade\n    conn.as_mut().graceful_shutdown();\n}\n\n#[tokio::test]\nasync fn empty_parse_eof_does_not_return_error() {\n    let (listener, addr) = setup_tcp_listener();\n    thread::spawn(move || {\n        let _tcp = connect(&addr);\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    http1::Builder::new()\n        .serve_connection(socket, HelloWorld)\n        .await\n        .expect(\"empty parse eof is ok\");\n}\n\n#[tokio::test]\nasync fn nonempty_parse_eof_returns_error() {\n    let (listener, addr) = setup_tcp_listener();\n\n    thread::spawn(move || {\n        let mut tcp = connect(&addr);\n        tcp.write_all(b\"GET / HTTP/1.1\").unwrap();\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    http1::Builder::new()\n        .serve_connection(socket, HelloWorld)\n        .await\n        .expect_err(\"partial parse eof is error\");\n}\n\n#[cfg(feature = \"http1\")]\n#[tokio::test]\nasync fn http1_allow_half_close() {\n    let (listener, addr) = setup_tcp_listener();\n\n    let t1 = thread::spawn(move || {\n        let mut tcp = connect(&addr);\n        tcp.write_all(b\"GET / HTTP/1.1\\r\\n\\r\\n\").unwrap();\n        tcp.shutdown(::std::net::Shutdown::Write).expect(\"SHDN_WR\");\n\n        let mut buf = [0; 256];\n        tcp.read(&mut buf).unwrap();\n        let expected = \"HTTP/1.1 200 OK\\r\\n\";\n        assert_eq!(s(&buf[..expected.len()]), expected);\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    http1::Builder::new()\n        .half_close(true)\n        .serve_connection(\n            socket,\n            service_fn(|_| {\n                TokioTimer\n                    .sleep(Duration::from_millis(500))\n                    .map(|_| Ok::<_, hyper::Error>(Response::new(Empty::<Bytes>::new())))\n            }),\n        )\n        .await\n        .unwrap();\n\n    t1.join().expect(\"client thread\");\n}\n\n#[cfg(feature = \"http1\")]\n#[tokio::test]\nasync fn disconnect_after_reading_request_before_responding() {\n    let (listener, addr) = setup_tcp_listener();\n\n    thread::spawn(move || {\n        let mut tcp = connect(&addr);\n        tcp.write_all(b\"GET / HTTP/1.1\\r\\n\\r\\n\").unwrap();\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    http1::Builder::new()\n        .half_close(false)\n        .serve_connection(\n            socket,\n            service_fn(|_| {\n                TokioTimer.sleep(Duration::from_secs(2)).map(\n                    |_| -> Result<Response<IncomingBody>, hyper::Error> {\n                        panic!(\"response future should have been dropped\");\n                    },\n                )\n            }),\n        )\n        .await\n        .expect_err(\"socket disconnected\");\n}\n\n#[tokio::test]\nasync fn returning_1xx_response_is_error() {\n    let (listener, addr) = setup_tcp_listener();\n\n    thread::spawn(move || {\n        let mut tcp = connect(&addr);\n        tcp.write_all(b\"GET / HTTP/1.1\\r\\n\\r\\n\").unwrap();\n        let mut buf = [0; 256];\n        tcp.read(&mut buf).unwrap();\n\n        let expected = \"HTTP/1.1 500 \";\n        assert_eq!(s(&buf[..expected.len()]), expected);\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    http1::Builder::new()\n        .serve_connection(\n            socket,\n            service_fn(|_| async move {\n                Ok::<_, hyper::Error>(\n                    Response::builder()\n                        .status(StatusCode::CONTINUE)\n                        .body(Empty::<Bytes>::new())\n                        .unwrap(),\n                )\n            }),\n        )\n        .await\n        .expect_err(\"1xx status code should error\");\n}\n\n#[test]\nfn header_name_too_long() {\n    let server = serve();\n\n    let mut req = connect(server.addr());\n    let mut write = Vec::with_capacity(1024 * 66);\n    write.extend_from_slice(b\"GET / HTTP/1.1\\r\\n\");\n    write.extend_from_slice(vec![b'x'; 1024 * 64].as_slice());\n\n    write.extend_from_slice(b\": foo\\r\\n\\r\\n\");\n    req.write_all(&write).unwrap();\n\n    let mut buf = [0; 1024];\n    let n = req.read(&mut buf).unwrap();\n    assert!(s(&buf[..n]).starts_with(\"HTTP/1.1 431 Request Header Fields Too Large\\r\\n\"));\n}\n\n#[tokio::test]\nasync fn header_read_timeout_slow_writes() {\n    let (listener, addr) = setup_tcp_listener();\n\n    thread::spawn(move || {\n        let mut tcp = connect(&addr);\n        tcp.write_all(\n            b\"\\\n            GET / HTTP/1.1\\r\\n\\\n        \",\n        )\n        .expect(\"write 1\");\n        thread::sleep(Duration::from_secs(3));\n        tcp.write_all(\n            b\"\\\n            Something: 1\\r\\n\\\n        \",\n        )\n        .expect(\"write 2\");\n        thread::sleep(Duration::from_secs(6));\n        tcp.write_all(\n            b\"\\\n            Works: 0\\r\\n\\\n            \\r\\n\\\n        \",\n        )\n        .expect_err(\"write 3\");\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    let conn = http1::Builder::new()\n        .timer(TokioTimer)\n        .header_read_timeout(Duration::from_secs(5))\n        .serve_connection(\n            socket,\n            service_fn(|_| {\n                let res = Response::builder()\n                    .status(200)\n                    .body(Empty::<Bytes>::new())\n                    .unwrap();\n                future::ready(Ok::<_, hyper::Error>(res))\n            }),\n        );\n    conn.without_shutdown().await.expect_err(\"header timeout\");\n}\n\n#[tokio::test]\nasync fn header_read_timeout_starts_immediately() {\n    let (listener, addr) = setup_tcp_listener();\n\n    thread::spawn(move || {\n        let mut tcp = connect(&addr);\n        thread::sleep(Duration::from_secs(3));\n        let mut buf = [0u8; 256];\n        let n = tcp.read(&mut buf).expect(\"read 1\");\n        assert_eq!(n, 0); //eof\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    let conn = http1::Builder::new()\n        .timer(TokioTimer)\n        .header_read_timeout(Duration::from_secs(2))\n        .serve_connection(socket, unreachable_service());\n    assert!(conn.await.unwrap_err().is_timeout());\n}\n\n#[tokio::test]\nasync fn header_read_timeout_slow_writes_multiple_requests() {\n    let (listener, addr) = setup_tcp_listener();\n\n    thread::spawn(move || {\n        let mut tcp = connect(&addr);\n\n        tcp.write_all(\n            b\"\\\n            GET / HTTP/1.1\\r\\n\\\n        \",\n        )\n        .expect(\"write 1\");\n        thread::sleep(Duration::from_secs(3));\n        tcp.write_all(\n            b\"\\\n            Something: 1\\r\\n\\\n            \\r\\n\\\n        \",\n        )\n        .expect(\"write 2\");\n\n        thread::sleep(Duration::from_secs(3));\n\n        tcp.write_all(\n            b\"\\\n            GET / HTTP/1.1\\r\\n\\\n        \",\n        )\n        .expect(\"write 3\");\n        thread::sleep(Duration::from_secs(3));\n        tcp.write_all(\n            b\"\\\n            Something: 1\\r\\n\\\n            \\r\\n\\\n        \",\n        )\n        .expect(\"write 4\");\n\n        thread::sleep(Duration::from_secs(6));\n\n        tcp.write_all(\n            b\"\\\n            GET / HTTP/1.1\\r\\n\\\n            Something: 1\\r\\n\\\n        \",\n        )\n        .expect(\"write 5\");\n        thread::sleep(Duration::from_secs(6));\n        tcp.write_all(\n            b\"\\\n            Works: 0\\r\\n\\\n            \\r\\n\n        \",\n        )\n        .expect_err(\"write 6\");\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    let conn = http1::Builder::new()\n        .timer(TokioTimer)\n        .header_read_timeout(Duration::from_secs(5))\n        .serve_connection(\n            socket,\n            service_fn(|_| {\n                let res = Response::builder()\n                    .status(200)\n                    .body(Empty::<Bytes>::new())\n                    .unwrap();\n                future::ready(Ok::<_, hyper::Error>(res))\n            }),\n        );\n    assert!(conn.without_shutdown().await.unwrap_err().is_timeout());\n}\n\n#[tokio::test]\nasync fn header_read_timeout_as_idle_timeout() {\n    let (listener, addr) = setup_tcp_listener();\n\n    thread::spawn(move || {\n        let mut tcp = connect(&addr);\n\n        tcp.write_all(\n            b\"\\\n            GET / HTTP/1.1\\r\\n\\\n            \\r\\n\\\n        \",\n        )\n        .expect(\"request 1\");\n\n        thread::sleep(Duration::from_secs(6));\n\n        tcp.write_all(\n            b\"\\\n            GET / HTTP/1.1\\r\\n\\\n            \\r\\n\\\n        \",\n        )\n        .expect_err(\"request 2\");\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    let conn = http1::Builder::new()\n        .timer(TokioTimer)\n        .header_read_timeout(Duration::from_secs(3))\n        .serve_connection(\n            socket,\n            service_fn(|_| {\n                let res = Response::builder()\n                    .status(200)\n                    .body(Empty::<Bytes>::new())\n                    .unwrap();\n                future::ready(Ok::<_, hyper::Error>(res))\n            }),\n        );\n    assert!(conn.without_shutdown().await.unwrap_err().is_timeout());\n}\n\n#[tokio::test]\nasync fn upgrades() {\n    let (listener, addr) = setup_tcp_listener();\n    let (tx, rx) = oneshot::channel();\n\n    thread::spawn(move || {\n        let mut tcp = connect(&addr);\n        tcp.write_all(\n            b\"\\\n            GET / HTTP/1.1\\r\\n\\\n            Upgrade: foobar\\r\\n\\\n            Connection: upgrade\\r\\n\\\n            \\r\\n\\\n            eagerly optimistic\\\n        \",\n        )\n        .expect(\"write 1\");\n        let mut buf = [0; 256];\n        tcp.read(&mut buf).expect(\"read 1\");\n\n        let expected = \"HTTP/1.1 101 Switching Protocols\\r\\n\";\n        assert_eq!(s(&buf[..expected.len()]), expected);\n        let _ = tx.send(());\n\n        let n = tcp.read(&mut buf).expect(\"read 2\");\n        assert_eq!(s(&buf[..n]), \"foo=bar\");\n        tcp.write_all(b\"bar=foo\").expect(\"write 2\");\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    let conn = http1::Builder::new().serve_connection(\n        socket,\n        service_fn(|_| {\n            let res = Response::builder()\n                .status(101)\n                .header(\"upgrade\", \"foobar\")\n                .body(Empty::<Bytes>::new())\n                .unwrap();\n            future::ready(Ok::<_, hyper::Error>(res))\n        }),\n    );\n\n    let parts = conn.without_shutdown().await.unwrap();\n    assert_eq!(parts.read_buf, \"eagerly optimistic\");\n\n    // wait so that we don't write until other side saw 101 response\n    rx.await.unwrap();\n\n    let mut io = parts.io.inner();\n    io.write_all(b\"foo=bar\").await.unwrap();\n    let mut vec = vec![];\n    io.read_to_end(&mut vec).await.unwrap();\n    assert_eq!(vec, b\"bar=foo\");\n}\n\n#[tokio::test]\nasync fn http_connect() {\n    let (listener, addr) = setup_tcp_listener();\n    let (tx, rx) = oneshot::channel();\n\n    thread::spawn(move || {\n        let mut tcp = connect(&addr);\n        tcp.write_all(\n            b\"\\\n            CONNECT localhost:80 HTTP/1.1\\r\\n\\\n            \\r\\n\\\n            eagerly optimistic\\\n        \",\n        )\n        .expect(\"write 1\");\n        let mut buf = [0; 256];\n        tcp.read(&mut buf).expect(\"read 1\");\n\n        let expected = \"HTTP/1.1 200 OK\\r\\n\";\n        assert_eq!(s(&buf[..expected.len()]), expected);\n        let _ = tx.send(());\n\n        let n = tcp.read(&mut buf).expect(\"read 2\");\n        assert_eq!(s(&buf[..n]), \"foo=bar\");\n        tcp.write_all(b\"bar=foo\").expect(\"write 2\");\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    let conn = http1::Builder::new().serve_connection(\n        socket,\n        service_fn(|_| {\n            let res = Response::builder()\n                .status(200)\n                .body(Empty::<Bytes>::new())\n                .unwrap();\n            future::ready(Ok::<_, hyper::Error>(res))\n        }),\n    );\n\n    let parts = conn.without_shutdown().await.unwrap();\n    assert_eq!(parts.read_buf, \"eagerly optimistic\");\n\n    // wait so that we don't write until other side saw 101 response\n    rx.await.unwrap();\n\n    let mut io = parts.io.inner();\n    io.write_all(b\"foo=bar\").await.unwrap();\n    let mut vec = vec![];\n    io.read_to_end(&mut vec).await.unwrap();\n    assert_eq!(vec, b\"bar=foo\");\n}\n\n#[tokio::test]\nasync fn upgrades_new() {\n    use tokio::io::{AsyncReadExt, AsyncWriteExt};\n\n    let (listener, addr) = setup_tcp_listener();\n    let (read_101_tx, read_101_rx) = oneshot::channel();\n\n    thread::spawn(move || {\n        let mut tcp = connect(&addr);\n        tcp.write_all(\n            b\"\\\n            GET / HTTP/1.1\\r\\n\\\n            Upgrade: foobar\\r\\n\\\n            Connection: upgrade\\r\\n\\\n            \\r\\n\\\n            eagerly optimistic\\\n        \",\n        )\n        .expect(\"write 1\");\n        let mut buf = [0; 256];\n        tcp.read(&mut buf).expect(\"read 1\");\n\n        let response = s(&buf);\n        assert!(response.starts_with(\"HTTP/1.1 101 Switching Protocols\\r\\n\"));\n        assert!(!has_header(response, \"content-length\"));\n        let _ = read_101_tx.send(());\n\n        let n = tcp.read(&mut buf).expect(\"read 2\");\n        assert_eq!(s(&buf[..n]), \"foo=bar\");\n        tcp.write_all(b\"bar=foo\").expect(\"write 2\");\n    });\n\n    let (upgrades_tx, upgrades_rx) = mpsc::channel();\n    let svc = service_fn(move |req: Request<IncomingBody>| {\n        let on_upgrade = hyper::upgrade::on(req);\n        let _ = upgrades_tx.send(on_upgrade);\n        future::ok::<_, hyper::Error>(\n            Response::builder()\n                .status(101)\n                .header(\"upgrade\", \"foobar\")\n                .body(Empty::<Bytes>::new())\n                .unwrap(),\n        )\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    http1::Builder::new()\n        .serve_connection(socket, svc)\n        .with_upgrades()\n        .await\n        .unwrap();\n\n    let on_upgrade = upgrades_rx.recv().unwrap();\n\n    // wait so that we don't write until other side saw 101 response\n    read_101_rx.await.unwrap();\n\n    let upgraded = on_upgrade.await.expect(\"on_upgrade\");\n    let parts = upgraded.downcast::<TokioIo<TkTcpStream>>().unwrap();\n    assert_eq!(parts.read_buf, \"eagerly optimistic\");\n\n    let mut io = parts.io.inner();\n    io.write_all(b\"foo=bar\").await.unwrap();\n    let mut vec = vec![];\n    io.read_to_end(&mut vec).await.unwrap();\n    assert_eq!(s(&vec), \"bar=foo\");\n}\n\n#[tokio::test]\nasync fn upgrades_ignored() {\n    let (listener, addr) = setup_tcp_listener();\n\n    tokio::spawn(async move {\n        let svc = service_fn(move |req: Request<IncomingBody>| {\n            assert_eq!(req.headers()[\"upgrade\"], \"yolo\");\n            future::ok::<_, hyper::Error>(Response::new(Empty::<Bytes>::new()))\n        });\n\n        loop {\n            let (socket, _) = listener.accept().await.unwrap();\n            let socket = TokioIo::new(socket);\n            tokio::task::spawn(async move {\n                http1::Builder::new()\n                    .serve_connection(socket, svc)\n                    .with_upgrades()\n                    .await\n                    .expect(\"server task\");\n            });\n        }\n    });\n\n    let client = TestClient::new();\n    let url = format!(\"http://{}/\", addr);\n\n    let make_req = || {\n        hyper::Request::builder()\n            .uri(&*url)\n            .header(\"upgrade\", \"yolo\")\n            .header(\"connection\", \"upgrade\")\n            .body(Empty::<Bytes>::new())\n            .expect(\"make_req\")\n    };\n\n    let res1 = client.request(make_req()).await.expect(\"req 1\");\n    assert_eq!(res1.status(), 200);\n    drop(res1);\n\n    let res2 = client.request(make_req()).await.expect(\"req 2\");\n    assert_eq!(res2.status(), 200);\n}\n\n#[tokio::test]\nasync fn http_connect_new() {\n    let (listener, addr) = setup_tcp_listener();\n    let (read_200_tx, read_200_rx) = oneshot::channel();\n\n    thread::spawn(move || {\n        let mut tcp = connect(&addr);\n        tcp.write_all(\n            b\"\\\n            CONNECT localhost HTTP/1.1\\r\\n\\\n            \\r\\n\\\n            eagerly optimistic\\\n        \",\n        )\n        .expect(\"write 1\");\n        let mut buf = [0; 256];\n        tcp.read(&mut buf).expect(\"read 1\");\n\n        let expected = \"HTTP/1.1 200 OK\\r\\n\";\n        assert_eq!(s(&buf[..expected.len()]), expected);\n        let _ = read_200_tx.send(());\n\n        let n = tcp.read(&mut buf).expect(\"read 2\");\n        assert_eq!(s(&buf[..n]), \"foo=bar\");\n        tcp.write_all(b\"bar=foo\").expect(\"write 2\");\n    });\n\n    let (upgrades_tx, upgrades_rx) = mpsc::channel();\n    let svc = service_fn(move |req: Request<IncomingBody>| {\n        let on_upgrade = hyper::upgrade::on(req);\n        let _ = upgrades_tx.send(on_upgrade);\n        future::ok::<_, hyper::Error>(\n            Response::builder()\n                .status(200)\n                .body(Empty::<Bytes>::new())\n                .unwrap(),\n        )\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    http1::Builder::new()\n        .serve_connection(socket, svc)\n        .with_upgrades()\n        .await\n        .unwrap();\n\n    let on_upgrade = upgrades_rx.recv().unwrap();\n\n    // wait so that we don't write until other side saw 200\n    read_200_rx.await.unwrap();\n\n    let upgraded = on_upgrade.await.expect(\"on_upgrade\");\n    let parts = upgraded.downcast::<TokioIo<TkTcpStream>>().unwrap();\n    assert_eq!(parts.read_buf, \"eagerly optimistic\");\n\n    let mut io = parts.io.inner();\n    io.write_all(b\"foo=bar\").await.unwrap();\n    let mut vec = vec![];\n    io.read_to_end(&mut vec).await.unwrap();\n    assert_eq!(s(&vec), \"bar=foo\");\n}\n\n#[tokio::test]\nasync fn h2_connect() {\n    let (listener, addr) = setup_tcp_listener();\n    let conn = connect_async(addr).await;\n\n    let (h2, connection) = h2::client::handshake(conn).await.unwrap();\n    tokio::spawn(async move {\n        connection.await.unwrap();\n    });\n    let mut h2 = h2.ready().await.unwrap();\n\n    async fn connect_and_recv_bread(\n        h2: &mut SendRequest<Bytes>,\n    ) -> (RecvStream, SendStream<Bytes>) {\n        let request = Request::connect(\"localhost\").body(()).unwrap();\n        let (response, send_stream) = h2.send_request(request, false).unwrap();\n        let response = response.await.unwrap();\n        assert_eq!(response.status(), StatusCode::OK);\n\n        let mut body = response.into_body();\n        let bytes = body.data().await.unwrap().unwrap();\n        assert_eq!(&bytes[..], b\"Bread?\");\n        let _ = body.flow_control().release_capacity(bytes.len());\n\n        (body, send_stream)\n    }\n\n    tokio::spawn(async move {\n        let (mut recv_stream, mut send_stream) = connect_and_recv_bread(&mut h2).await;\n\n        send_stream.send_data(\"Baguette!\".into(), true).unwrap();\n\n        assert!(recv_stream.data().await.unwrap().unwrap().is_empty());\n    });\n\n    let svc = service_fn(move |req: Request<IncomingBody>| {\n        let on_upgrade = hyper::upgrade::on(req);\n\n        tokio::spawn(async move {\n            let mut upgraded = TokioIo::new(on_upgrade.await.expect(\"on_upgrade\"));\n            upgraded.write_all(b\"Bread?\").await.unwrap();\n\n            let mut vec = vec![];\n            upgraded.read_to_end(&mut vec).await.unwrap();\n            assert_eq!(s(&vec), \"Baguette!\");\n\n            upgraded.shutdown().await.unwrap();\n        });\n\n        future::ok::<_, hyper::Error>(\n            Response::builder()\n                .status(200)\n                .body(Empty::<Bytes>::new())\n                .unwrap(),\n        )\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    http2::Builder::new(TokioExecutor)\n        .serve_connection(socket, svc)\n        //.with_upgrades()\n        .await\n        .unwrap();\n}\n\n#[tokio::test]\nasync fn h2_connect_multiplex() {\n    use futures_util::stream::FuturesUnordered;\n    use futures_util::StreamExt;\n\n    let (listener, addr) = setup_tcp_listener();\n    let conn = connect_async(addr).await;\n\n    let (h2, connection) = h2::client::handshake(conn).await.unwrap();\n    tokio::spawn(async move {\n        connection.await.unwrap();\n    });\n    let mut h2 = h2.ready().await.unwrap();\n\n    tokio::spawn(async move {\n        let mut streams = vec![];\n        for i in 0..80 {\n            let request = Request::connect(format!(\"localhost_{}\", i % 4))\n                .body(())\n                .unwrap();\n            let (response, send_stream) = h2.send_request(request, false).unwrap();\n            streams.push((i, response, send_stream));\n        }\n\n        let futures = streams\n            .into_iter()\n            .map(|(i, response, mut send_stream)| async move {\n                if i % 4 == 0 {\n                    return;\n                }\n\n                let response = response.await.unwrap();\n                assert_eq!(response.status(), StatusCode::OK);\n\n                if i % 4 == 1 {\n                    return;\n                }\n\n                let mut body = response.into_body();\n                let bytes = body.data().await.unwrap().unwrap();\n                assert_eq!(&bytes[..], b\"Bread?\");\n                let _ = body.flow_control().release_capacity(bytes.len());\n\n                if i % 4 == 2 {\n                    return;\n                }\n\n                send_stream.send_data(\"Baguette!\".into(), true).unwrap();\n\n                assert!(body.data().await.unwrap().unwrap().is_empty());\n            })\n            .collect::<FuturesUnordered<_>>();\n\n        futures.for_each(future::ready).await;\n    });\n\n    let svc = service_fn(move |req: Request<IncomingBody>| {\n        let authority = req.uri().authority().unwrap().to_string();\n        let on_upgrade = hyper::upgrade::on(req);\n\n        tokio::spawn(async move {\n            let upgrade_res = on_upgrade.await;\n            if authority == \"localhost_0\" {\n                assert!(upgrade_res.expect_err(\"upgrade cancelled\").is_canceled());\n                return;\n            }\n            let mut upgraded = TokioIo::new(upgrade_res.expect(\"upgrade successful\"));\n\n            upgraded.write_all(b\"Bread?\").await.unwrap();\n\n            let mut vec = vec![];\n            let read_res = upgraded.read_to_end(&mut vec).await;\n\n            if authority == \"localhost_1\" || authority == \"localhost_2\" {\n                let err = read_res.expect_err(\"read failed\");\n                assert_eq!(err.kind(), io::ErrorKind::Other);\n                assert_eq!(\n                    err.get_ref()\n                        .unwrap()\n                        .downcast_ref::<h2::Error>()\n                        .unwrap()\n                        .reason(),\n                    Some(h2::Reason::CANCEL),\n                );\n                return;\n            }\n\n            read_res.unwrap();\n            assert_eq!(s(&vec), \"Baguette!\");\n\n            upgraded.shutdown().await.unwrap();\n        });\n\n        future::ok::<_, hyper::Error>(\n            Response::builder()\n                .status(200)\n                .body(Empty::<Bytes>::new())\n                .unwrap(),\n        )\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    http2::Builder::new(TokioExecutor)\n        .serve_connection(socket, svc)\n        //.with_upgrades()\n        .await\n        .unwrap();\n}\n\n#[tokio::test]\nasync fn h2_connect_large_body() {\n    let (listener, addr) = setup_tcp_listener();\n    let conn = connect_async(addr).await;\n\n    let (h2, connection) = h2::client::handshake(conn).await.unwrap();\n    tokio::spawn(async move {\n        connection.await.unwrap();\n    });\n    let mut h2 = h2.ready().await.unwrap();\n\n    const NO_BREAD: &str = \"All work and no bread makes nox a dull boy.\\n\";\n\n    async fn connect_and_recv_bread(\n        h2: &mut SendRequest<Bytes>,\n    ) -> (RecvStream, SendStream<Bytes>) {\n        let request = Request::connect(\"localhost\").body(()).unwrap();\n        let (response, send_stream) = h2.send_request(request, false).unwrap();\n        let response = response.await.unwrap();\n        assert_eq!(response.status(), StatusCode::OK);\n\n        let mut body = response.into_body();\n        let bytes = body.data().await.unwrap().unwrap();\n        assert_eq!(&bytes[..], b\"Bread?\");\n        let _ = body.flow_control().release_capacity(bytes.len());\n\n        (body, send_stream)\n    }\n\n    tokio::spawn(async move {\n        let (mut recv_stream, mut send_stream) = connect_and_recv_bread(&mut h2).await;\n\n        let large_body = Bytes::from(NO_BREAD.repeat(9000));\n\n        send_stream.send_data(large_body.clone(), false).unwrap();\n        send_stream.send_data(large_body, true).unwrap();\n\n        assert!(recv_stream.data().await.unwrap().unwrap().is_empty());\n    });\n\n    let svc = service_fn(move |req: Request<IncomingBody>| {\n        let on_upgrade = hyper::upgrade::on(req);\n\n        tokio::spawn(async move {\n            let mut upgraded = TokioIo::new(on_upgrade.await.expect(\"on_upgrade\"));\n            upgraded.write_all(b\"Bread?\").await.unwrap();\n\n            let mut vec = vec![];\n            if upgraded.read_to_end(&mut vec).await.is_err() {\n                return;\n            }\n            assert_eq!(vec.len(), NO_BREAD.len() * 9000 * 2);\n\n            upgraded.shutdown().await.unwrap();\n        });\n\n        future::ok::<_, hyper::Error>(\n            Response::builder()\n                .status(200)\n                .body(Empty::<Bytes>::new())\n                .unwrap(),\n        )\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    http2::Builder::new(TokioExecutor)\n        .serve_connection(socket, svc)\n        //.with_upgrades()\n        .await\n        .unwrap();\n}\n\n#[tokio::test]\nasync fn h2_connect_empty_frames() {\n    let (listener, addr) = setup_tcp_listener();\n    let conn = connect_async(addr).await;\n\n    let (h2, connection) = h2::client::handshake(conn).await.unwrap();\n    tokio::spawn(async move {\n        connection.await.unwrap();\n    });\n    let mut h2 = h2.ready().await.unwrap();\n\n    async fn connect_and_recv_bread(\n        h2: &mut SendRequest<Bytes>,\n    ) -> (RecvStream, SendStream<Bytes>) {\n        let request = Request::connect(\"localhost\").body(()).unwrap();\n        let (response, send_stream) = h2.send_request(request, false).unwrap();\n        let response = response.await.unwrap();\n        assert_eq!(response.status(), StatusCode::OK);\n\n        let mut body = response.into_body();\n        let bytes = body.data().await.unwrap().unwrap();\n        assert_eq!(&bytes[..], b\"Bread?\");\n        let _ = body.flow_control().release_capacity(bytes.len());\n\n        (body, send_stream)\n    }\n\n    tokio::spawn(async move {\n        let (mut recv_stream, mut send_stream) = connect_and_recv_bread(&mut h2).await;\n\n        send_stream.send_data(\"\".into(), false).unwrap();\n        send_stream.send_data(\"\".into(), false).unwrap();\n        send_stream.send_data(\"\".into(), false).unwrap();\n        send_stream.send_data(\"Baguette!\".into(), false).unwrap();\n        send_stream.send_data(\"\".into(), true).unwrap();\n\n        assert!(recv_stream.data().await.unwrap().unwrap().is_empty());\n    });\n\n    let svc = service_fn(move |req: Request<IncomingBody>| {\n        let on_upgrade = hyper::upgrade::on(req);\n\n        tokio::spawn(async move {\n            let mut upgraded = TokioIo::new(on_upgrade.await.expect(\"on_upgrade\"));\n            upgraded.write_all(b\"Bread?\").await.unwrap();\n\n            let mut vec = vec![];\n            upgraded.read_to_end(&mut vec).await.unwrap();\n            assert_eq!(s(&vec), \"Baguette!\");\n\n            upgraded.shutdown().await.unwrap();\n        });\n\n        future::ok::<_, hyper::Error>(\n            Response::builder()\n                .status(200)\n                .body(Empty::<Bytes>::new())\n                .unwrap(),\n        )\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    http2::Builder::new(TokioExecutor)\n        .serve_connection(socket, svc)\n        //.with_upgrades()\n        .await\n        .unwrap();\n}\n\n#[tokio::test]\nasync fn parse_errors_send_4xx_response() {\n    let (listener, addr) = setup_tcp_listener();\n\n    thread::spawn(move || {\n        let mut tcp = connect(&addr);\n        tcp.write_all(b\"GE T / HTTP/1.1\\r\\n\\r\\n\").unwrap();\n        let mut buf = [0; 256];\n        tcp.read(&mut buf).unwrap();\n\n        let expected = \"HTTP/1.1 400 \";\n        assert_eq!(s(&buf[..expected.len()]), expected);\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    http1::Builder::new()\n        .serve_connection(socket, HelloWorld)\n        .await\n        .expect_err(\"HTTP parse error\");\n}\n\n#[tokio::test]\nasync fn illegal_request_length_returns_400_response() {\n    let (listener, addr) = setup_tcp_listener();\n\n    thread::spawn(move || {\n        let mut tcp = connect(&addr);\n        tcp.write_all(b\"POST / HTTP/1.1\\r\\nContent-Length: foo\\r\\n\\r\\n\")\n            .unwrap();\n        let mut buf = [0; 256];\n        tcp.read(&mut buf).unwrap();\n\n        let expected = \"HTTP/1.1 400 \";\n        assert_eq!(s(&buf[..expected.len()]), expected);\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    http1::Builder::new()\n        .serve_connection(socket, HelloWorld)\n        .await\n        .expect_err(\"illegal Content-Length should error\");\n}\n\n#[cfg(feature = \"http1\")]\n#[test]\n#[should_panic]\nfn max_buf_size_panic_too_small() {\n    const MAX: usize = 8191;\n    http1::Builder::new().max_buf_size(MAX);\n}\n\n#[cfg(feature = \"http1\")]\n#[test]\nfn max_buf_size_no_panic() {\n    const MAX: usize = 8193;\n    http1::Builder::new().max_buf_size(MAX);\n}\n\n#[cfg(feature = \"http1\")]\n#[tokio::test]\nasync fn max_buf_size() {\n    let (listener, addr) = setup_tcp_listener();\n\n    const MAX: usize = 16_000;\n\n    thread::spawn(move || {\n        let mut tcp = connect(&addr);\n        tcp.write_all(b\"POST /\").expect(\"write 1\");\n        tcp.write_all(&[b'a'; MAX]).expect(\"write 2\");\n        let mut buf = [0; 256];\n        tcp.read(&mut buf).expect(\"read 1\");\n\n        let expected = \"HTTP/1.1 431 \";\n        assert_eq!(s(&buf[..expected.len()]), expected);\n    });\n\n    let (socket, _) = listener.accept().await.unwrap();\n    let socket = TokioIo::new(socket);\n    http1::Builder::new()\n        .max_buf_size(MAX)\n        .serve_connection(socket, HelloWorld)\n        .await\n        .expect_err(\"should TooLarge error\");\n}\n\n#[cfg(feature = \"http1\")]\n#[tokio::test]\nasync fn graceful_shutdown_before_first_request_no_block() {\n    let (listener, addr) = setup_tcp_listener();\n\n    tokio::spawn(async move {\n        let socket = listener.accept().await.unwrap().0;\n        let socket = TokioIo::new(socket);\n\n        let future = http1::Builder::new().serve_connection(socket, HelloWorld);\n        pin!(future);\n        future.as_mut().graceful_shutdown();\n\n        future.await.unwrap();\n    });\n\n    let mut stream = TkTcpStream::connect(addr).await.unwrap();\n\n    let mut buf = vec![];\n\n    tokio::time::timeout(Duration::from_secs(5), stream.read_to_end(&mut buf))\n        .await\n        .expect(\"timed out waiting for graceful shutdown\")\n        .expect(\"error receiving response\");\n}\n\n#[test]\nfn streaming_body() {\n    use futures_util::StreamExt;\n    let _ = pretty_env_logger::try_init();\n\n    // disable keep-alive so we can use read_to_end\n    let server = serve_opts().keep_alive(false).serve();\n\n    static S: &[&[u8]] = &[&[b'x'; 1_000] as &[u8]; 100] as _;\n    let b =\n        futures_util::stream::iter(S.iter()).map(|&s| Ok::<_, BoxError>(Bytes::copy_from_slice(s)));\n    server.reply().body_stream(b);\n\n    let mut tcp = connect(server.addr());\n    tcp.write_all(b\"GET / HTTP/1.1\\r\\n\\r\\n\").unwrap();\n    let mut buf = Vec::new();\n    tcp.read_to_end(&mut buf).expect(\"read 1\");\n\n    assert!(\n        buf.starts_with(b\"HTTP/1.1 200 OK\\r\\n\"),\n        \"response is 200 OK\"\n    );\n    assert_eq!(buf.len(), 100_808, \"full streamed body read\");\n}\n\n#[test]\nfn http1_response_with_http2_version() {\n    let server = serve();\n    let addr_str = format!(\"http://{}\", server.addr());\n\n    let rt = support::runtime();\n\n    server.reply().version(hyper::Version::HTTP_2);\n\n    let client = TestClient::new();\n    rt.block_on({\n        let uri = addr_str.parse().expect(\"server addr should parse\");\n        client.get(uri)\n    })\n    .unwrap();\n}\n\n#[test]\nfn http1_only() {\n    let server = serve_opts().serve();\n    let addr_str = format!(\"http://{}\", server.addr());\n\n    let rt = support::runtime();\n\n    let client = TestClient::new().http2_only();\n    rt.block_on({\n        let uri = addr_str.parse().expect(\"server addr should parse\");\n        client.get(uri)\n    })\n    .unwrap_err();\n}\n\n#[tokio::test]\nasync fn http2_service_error_sends_reset_reason() {\n    use std::error::Error;\n\n    let server = serve_opts().http2().serve();\n    let addr_str = format!(\"http://{}\", server.addr());\n\n    server\n        .reply()\n        .error(h2::Error::from(h2::Reason::INADEQUATE_SECURITY));\n\n    let uri = addr_str.parse().expect(\"server addr should parse\");\n    dbg!(\"start\");\n    let err = dbg!(TestClient::new()\n        .http2_only()\n        .get(uri)\n        .await\n        .expect_err(\"client.get\"));\n\n    let h2_err = err\n        .source()\n        .expect(\"err.source\")\n        .downcast_ref::<h2::Error>()\n        .expect(\"downcast\");\n\n    assert_eq!(h2_err.reason(), Some(h2::Reason::INADEQUATE_SECURITY));\n}\n\n#[test]\nfn http2_body_user_error_sends_reset_reason() {\n    use std::error::Error;\n    let server = serve_opts().http2().serve();\n    let addr_str = format!(\"http://{}\", server.addr());\n\n    let b = futures_util::stream::once(future::err::<Bytes, BoxError>(Box::new(h2::Error::from(\n        h2::Reason::INADEQUATE_SECURITY,\n    ))));\n    server.reply().body_stream(b);\n\n    let rt = support::runtime();\n\n    let err: hyper::Error = rt\n        .block_on(async move {\n            let client = TestClient::new().http2_only();\n\n            let uri = addr_str.parse().expect(\"server addr should parse\");\n\n            let mut res = client.get(uri).await?;\n\n            while let Some(item) = res.body_mut().frame().await {\n                item?;\n            }\n            Ok(())\n        })\n        .unwrap_err();\n\n    let h2_err = err.source().unwrap().downcast_ref::<h2::Error>().unwrap();\n\n    assert_eq!(h2_err.reason(), Some(h2::Reason::INADEQUATE_SECURITY));\n}\n\n#[test]\nfn skips_content_length_for_304_responses() {\n    let server = serve();\n    server\n        .reply()\n        .status(hyper::StatusCode::NOT_MODIFIED)\n        .body(\"foo\");\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        GET / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: close\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .unwrap();\n\n    let mut response = String::new();\n    req.read_to_string(&mut response).unwrap();\n    assert!(!response.contains(\"content-length:\"));\n}\n\n#[test]\nfn skips_content_length_and_body_for_304_responses() {\n    let server = serve();\n    server\n        .reply()\n        .status(hyper::StatusCode::NOT_MODIFIED)\n        .body(\"foo\");\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        GET / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: close\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .unwrap();\n\n    let mut response = String::new();\n    req.read_to_string(&mut response).unwrap();\n    assert!(!response.contains(\"content-length:\"));\n    let mut lines = response.lines();\n    assert_eq!(lines.next(), Some(\"HTTP/1.1 304 Not Modified\"));\n\n    let mut lines = lines.skip_while(|line| !line.is_empty());\n    assert_eq!(lines.next(), Some(\"\"));\n    assert_eq!(lines.next(), None);\n}\n\n#[test]\nfn no_implicit_zero_content_length_for_head_responses() {\n    let server = serve();\n    server.reply().status(hyper::StatusCode::OK).body([]);\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        HEAD / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: close\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .unwrap();\n\n    let mut response = String::new();\n    req.read_to_string(&mut response).unwrap();\n    assert!(!response.contains(\"content-length:\"));\n}\n\n#[tokio::test]\nasync fn http2_keep_alive_detects_unresponsive_client() {\n    let (listener, addr) = setup_tcp_listener();\n\n    // Spawn a \"client\" conn that only reads until EOF\n    tokio::spawn(async move {\n        let mut conn = connect_async(addr).await;\n\n        // write h2 magic preface and settings frame\n        conn.write_all(b\"PRI * HTTP/2.0\\r\\n\\r\\nSM\\r\\n\\r\\n\")\n            .await\n            .expect(\"client preface\");\n        conn.write_all(&[\n            0, 0, 0, // len\n            4, // kind\n            0, // flag\n            0, 0, 0, // stream id\n        ])\n        .await\n        .expect(\"client settings\");\n\n        // read until eof\n        let mut buf = [0u8; 1024];\n        loop {\n            let n = conn.read(&mut buf).await.expect(\"client.read\");\n            if n == 0 {\n                // eof\n                break;\n            }\n        }\n    });\n\n    let (socket, _) = listener.accept().await.expect(\"accept\");\n    let socket = TokioIo::new(socket);\n\n    let err = http2::Builder::new(TokioExecutor)\n        .timer(TokioTimer)\n        .keep_alive_interval(Duration::from_secs(1))\n        .keep_alive_timeout(Duration::from_secs(1))\n        .auto_date_header(true)\n        .serve_connection(socket, unreachable_service())\n        .await\n        .expect_err(\"serve_connection should error\");\n\n    assert!(err.is_timeout());\n}\n\n#[tokio::test]\nasync fn http2_keep_alive_with_responsive_client() {\n    let (listener, addr) = setup_tcp_listener();\n\n    tokio::spawn(async move {\n        let (socket, _) = listener.accept().await.expect(\"accept\");\n        let socket = TokioIo::new(socket);\n\n        http2::Builder::new(TokioExecutor)\n            .timer(TokioTimer)\n            .keep_alive_interval(Duration::from_secs(1))\n            .keep_alive_timeout(Duration::from_secs(1))\n            .serve_connection(socket, HelloWorld)\n            .await\n            .expect(\"serve_connection\");\n    });\n\n    let tcp = TokioIo::new(connect_async(addr).await);\n    let (mut client, conn) = hyper::client::conn::http2::Builder::new(TokioExecutor)\n        .handshake(tcp)\n        .await\n        .expect(\"http handshake\");\n\n    tokio::spawn(async move {\n        conn.await.expect(\"client conn\");\n    });\n\n    TokioTimer.sleep(Duration::from_secs(4)).await;\n\n    let req = http::Request::new(Empty::<Bytes>::new());\n    client.send_request(req).await.expect(\"client.send_request\");\n}\n\n#[tokio::test]\nasync fn http2_check_date_header_disabled() {\n    let (listener, addr) = setup_tcp_listener();\n\n    tokio::spawn(async move {\n        let (socket, _) = listener.accept().await.expect(\"accept\");\n        let socket = TokioIo::new(socket);\n\n        http2::Builder::new(TokioExecutor)\n            .timer(TokioTimer)\n            .keep_alive_interval(Duration::from_secs(1))\n            .auto_date_header(false)\n            .keep_alive_timeout(Duration::from_secs(1))\n            .serve_connection(socket, HelloWorld)\n            .await\n            .expect(\"serve_connection\");\n    });\n\n    let tcp = TokioIo::new(connect_async(addr).await);\n    let (mut client, conn) = hyper::client::conn::http2::Builder::new(TokioExecutor)\n        .handshake(tcp)\n        .await\n        .expect(\"http handshake\");\n\n    tokio::spawn(async move {\n        conn.await.expect(\"client conn\");\n    });\n\n    TokioTimer.sleep(Duration::from_secs(4)).await;\n\n    let req = http::Request::new(Empty::<Bytes>::new());\n    let resp = client.send_request(req).await.expect(\"client.send_request\");\n\n    assert!(resp.headers().get(\"Date\").is_none());\n}\n\nfn is_ping_frame(buf: &[u8]) -> bool {\n    buf[3] == 6\n}\n\nfn assert_ping_frame(buf: &[u8], len: usize) {\n    // Assert the StreamId is zero\n    let mut ubuf = [0; 4];\n    ubuf.copy_from_slice(&buf[5..9]);\n    let unpacked = u32::from_be_bytes(ubuf);\n    assert_eq!(unpacked & !(1 << 31), 0);\n\n    // Assert ACK flag is unset (only set for PONG).\n    let flags = buf[4];\n    assert_eq!(flags & 0x1, 0);\n\n    // Assert total frame size\n    assert_eq!(len, 17);\n}\n\nasync fn write_pong_frame(conn: &mut TkTcpStream) {\n    conn.write_all(&[\n        0, 0, 8,   // len\n        6,   // kind\n        0x1, // flag\n        0, 0, 0, 0, // stream id\n        0x3b, 0x7c, 0xdb, 0x7a, 0x0b, 0x87, 0x16, 0xb4, // payload\n    ])\n    .await\n    .expect(\"client pong\");\n}\n\n#[tokio::test]\nasync fn http2_keep_alive_count_server_pings() {\n    let (listener, addr) = setup_tcp_listener();\n\n    tokio::spawn(async move {\n        let (socket, _) = listener.accept().await.expect(\"accept\");\n        let socket = TokioIo::new(socket);\n\n        http2::Builder::new(TokioExecutor)\n            .timer(TokioTimer)\n            .keep_alive_interval(Duration::from_secs(1))\n            .keep_alive_timeout(Duration::from_secs(1))\n            .serve_connection(socket, unreachable_service())\n            .await\n            .expect(\"serve_connection\");\n    });\n\n    // Spawn a \"client\" conn that only reads until EOF\n    let mut conn = connect_async(addr).await;\n\n    // write h2 magic preface and settings frame\n    conn.write_all(b\"PRI * HTTP/2.0\\r\\n\\r\\nSM\\r\\n\\r\\n\")\n        .await\n        .expect(\"client preface\");\n    conn.write_all(&[\n        0, 0, 0, // len\n        4, // kind\n        0, // flag\n        0, 0, 0, 0, // stream id\n    ])\n    .await\n    .expect(\"client settings\");\n\n    let read_pings = async {\n        // read until 3 pings are received\n        let mut pings = 0;\n        let mut buf = [0u8; 1024];\n        while pings < 3 {\n            let n = conn.read(&mut buf).await.expect(\"client.read\");\n            assert!(n != 0);\n\n            if is_ping_frame(&buf) {\n                assert_ping_frame(&buf, n);\n                write_pong_frame(&mut conn).await;\n                pings += 1;\n            }\n        }\n    };\n\n    // Expect all pings to occurs under 5 seconds\n    tokio::time::timeout(Duration::from_secs(5), read_pings)\n        .await\n        .expect(\"timed out waiting for pings\");\n}\n\n#[test]\nfn http1_trailer_send_fields() {\n    let body = futures_util::stream::once(async move { Ok(\"hello\".into()) });\n    let mut headers = HeaderMap::new();\n    headers.insert(\"chunky-trailer\", \"header data\".parse().unwrap());\n    // Invalid trailer field that should not be sent\n    headers.insert(\"Host\", \"www.example.com\".parse().unwrap());\n    // Not specified in Trailer header, so should not be sent\n    headers.insert(\"foo\", \"bar\".parse().unwrap());\n\n    let server = serve();\n    server\n        .reply()\n        .header(\"transfer-encoding\", \"chunked\")\n        .header(\"trailer\", \"chunky-trailer\")\n        .body_stream_with_trailers(body, headers);\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        GET / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: keep-alive\\r\\n\\\n        TE: trailers\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"writing\");\n\n    let chunky_trailer_chunk = b\"\\r\\nchunky-trailer: header data\\r\\n\\r\\n\";\n    let res = read_until(&mut req, |buf| buf.ends_with(chunky_trailer_chunk)).expect(\"reading\");\n    let sres = s(&res);\n\n    let expected_head =\n        \"HTTP/1.1 200 OK\\r\\ntransfer-encoding: chunked\\r\\ntrailer: chunky-trailer\\r\\n\";\n    assert_eq!(&sres[..expected_head.len()], expected_head);\n\n    // skip the date header\n    let date_fragment = \"GMT\\r\\n\\r\\n\";\n    let pos = sres.find(date_fragment).expect(\"find GMT\");\n    let body = &sres[pos + date_fragment.len()..];\n\n    let expected_body = \"5\\r\\nhello\\r\\n0\\r\\nchunky-trailer: header data\\r\\n\\r\\n\";\n    assert_eq!(body, expected_body);\n}\n\n#[test]\nfn http1_trailer_send_fields_titlecase() {\n    let body = futures_util::stream::once(async move { Ok(\"hello\".into()) });\n    let mut headers = HeaderMap::new();\n    headers.insert(\"chunky-trailer\", \"header data\".parse().unwrap());\n    // Invalid trailer field that should not be sent\n    headers.insert(\"Host\", \"www.example.com\".parse().unwrap());\n    // Not specified in Trailer header, so should not be sent\n    headers.insert(\"foo\", \"bar\".parse().unwrap());\n\n    let server = serve();\n    server\n        .reply()\n        .header(\"transfer-encoding\", \"chunked\")\n        .header(\"trailer\", \"Chunky-Trailer\")\n        .body_stream_with_trailers(body, headers);\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        GET / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: keep-alive\\r\\n\\\n        TE: trailers\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"writing\");\n\n    let chunky_trailer_chunk = b\"\\r\\nchunky-trailer: header data\\r\\n\\r\\n\";\n    let res = read_until(&mut req, |buf| buf.ends_with(chunky_trailer_chunk)).expect(\"reading\");\n    let sres = s(&res);\n\n    let expected_head =\n        \"HTTP/1.1 200 OK\\r\\ntransfer-encoding: chunked\\r\\ntrailer: Chunky-Trailer\\r\\n\";\n    assert_eq!(&sres[..expected_head.len()], expected_head);\n\n    // skip the date header\n    let date_fragment = \"GMT\\r\\n\\r\\n\";\n    let pos = sres.find(date_fragment).expect(\"find GMT\");\n    let body = &sres[pos + date_fragment.len()..];\n\n    let expected_body = \"5\\r\\nhello\\r\\n0\\r\\nchunky-trailer: header data\\r\\n\\r\\n\";\n    assert_eq!(body, expected_body);\n}\n\n#[test]\nfn http1_trailer_fields_not_allowed() {\n    let body = futures_util::stream::once(async move { Ok(\"hello\".into()) });\n    let mut headers = HeaderMap::new();\n    headers.insert(\"chunky-trailer\", \"header data\".parse().unwrap());\n\n    let server = serve();\n    server\n        .reply()\n        .header(\"transfer-encoding\", \"chunked\")\n        .header(\"trailer\", \"chunky-trailer\")\n        .body_stream_with_trailers(body, headers);\n    let mut req = connect(server.addr());\n\n    // TE: trailers is not specified in request headers\n    req.write_all(\n        b\"\\\n        GET / HTTP/1.1\\r\\n\\\n        Host: example.domain\\r\\n\\\n        Connection: keep-alive\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"writing\");\n\n    let last_chunk = b\"\\r\\n0\\r\\n\\r\\n\";\n    let res = read_until(&mut req, |buf| buf.ends_with(last_chunk)).expect(\"reading\");\n    let sres = s(&res);\n\n    let expected_head =\n        \"HTTP/1.1 200 OK\\r\\ntransfer-encoding: chunked\\r\\ntrailer: chunky-trailer\\r\\n\";\n    assert_eq!(&sres[..expected_head.len()], expected_head);\n\n    // skip the date header\n    let date_fragment = \"GMT\\r\\n\\r\\n\";\n    let pos = sres.find(date_fragment).expect(\"find GMT\");\n    let body = &sres[pos + date_fragment.len()..];\n\n    // no trailer fields should be sent because TE: trailers was not in request headers\n    let expected_body = \"5\\r\\nhello\\r\\n0\\r\\n\\r\\n\";\n    assert_eq!(body, expected_body);\n}\n\n#[test]\nfn http1_trailer_recv_fields() {\n    let server = serve();\n    let mut req = connect(server.addr());\n    req.write_all(\n        b\"\\\n        POST / HTTP/1.1\\r\\n\\\n        trailer: chunky-trailer\\r\\n\\\n        host: example.domain\\r\\n\\\n        transfer-encoding: chunked\\r\\n\\\n        \\r\\n\\\n        5\\r\\n\\\n        hello\\r\\n\\\n        0\\r\\n\\\n        chunky-trailer: header data\\r\\n\\\n        \\r\\n\\\n    \",\n    )\n    .expect(\"writing\");\n\n    assert_eq!(server.body(), b\"hello\");\n\n    let trailers = server.trailers();\n    assert_eq!(\n        trailers.get(\"chunky-trailer\"),\n        Some(&\"header data\".parse().unwrap())\n    );\n}\n\n// -------------------------------------------------\n// the Server that is used to run all the tests with\n// -------------------------------------------------\n\nstruct Serve {\n    addr: SocketAddr,\n    msg_rx: mpsc::Receiver<Msg>,\n    trailers_rx: mpsc::Receiver<HeaderMap>,\n    reply_tx: Mutex<spmc::Sender<Reply>>,\n    shutdown_signal: Option<oneshot::Sender<()>>,\n    thread: Option<thread::JoinHandle<()>>,\n}\n\nimpl Serve {\n    fn addr(&self) -> &SocketAddr {\n        &self.addr\n    }\n\n    fn body(&self) -> Vec<u8> {\n        self.try_body().expect(\"body\")\n    }\n\n    fn body_err(&self) -> hyper::Error {\n        self.try_body().expect_err(\"body_err\")\n    }\n\n    fn try_body(&self) -> Result<Vec<u8>, hyper::Error> {\n        let mut buf = vec![];\n        loop {\n            match self.msg_rx.recv() {\n                Ok(Msg::Chunk(msg)) => {\n                    buf.extend(&msg);\n                }\n                Ok(Msg::Error(e)) => return Err(e),\n                Ok(Msg::End) => break,\n                Err(e) => panic!(\"expected body, found: {:?}\", e),\n            }\n        }\n        Ok(buf)\n    }\n\n    fn trailers(&self) -> HeaderMap {\n        self.trailers_rx.recv().expect(\"trailers\")\n    }\n\n    fn reply(&self) -> ReplyBuilder<'_> {\n        ReplyBuilder { tx: &self.reply_tx }\n    }\n}\n\ntype BoxError = Box<dyn std::error::Error + Send + Sync>;\ntype BoxFuture = Pin<Box<dyn Future<Output = Result<Response<ReplyBody>, BoxError>> + Send>>;\n\nstruct ReplyBuilder<'a> {\n    tx: &'a Mutex<spmc::Sender<Reply>>,\n}\n\nimpl ReplyBuilder<'_> {\n    fn status(self, status: hyper::StatusCode) -> Self {\n        self.tx.lock().unwrap().send(Reply::Status(status)).unwrap();\n        self\n    }\n\n    fn reason_phrase(self, reason: &str) -> Self {\n        self.tx\n            .lock()\n            .unwrap()\n            .send(Reply::ReasonPhrase(\n                reason.as_bytes().try_into().expect(\"reason phrase\"),\n            ))\n            .unwrap();\n        self\n    }\n\n    fn version(self, version: hyper::Version) -> Self {\n        self.tx\n            .lock()\n            .unwrap()\n            .send(Reply::Version(version))\n            .unwrap();\n        self\n    }\n\n    fn header<V: AsRef<str>>(self, name: &str, value: V) -> Self {\n        let name = HeaderName::from_bytes(name.as_bytes()).expect(\"header name\");\n        let value = HeaderValue::from_str(value.as_ref()).expect(\"header value\");\n        self.tx\n            .lock()\n            .unwrap()\n            .send(Reply::Header(name, value))\n            .unwrap();\n        self\n    }\n\n    fn body<T: AsRef<[u8]>>(self, body: T) {\n        let chunk = Bytes::copy_from_slice(body.as_ref());\n        let body = BodyExt::boxed(http_body_util::Full::new(chunk).map_err(|e| match e {}));\n        self.tx.lock().unwrap().send(Reply::Body(body)).unwrap();\n    }\n\n    fn body_stream<S>(self, stream: S)\n    where\n        S: futures_util::Stream<Item = Result<Bytes, BoxError>> + Send + Sync + 'static,\n    {\n        use futures_util::TryStreamExt;\n        use hyper::body::Frame;\n        let body = BodyExt::boxed(StreamBody::new(stream.map_ok(Frame::data)));\n        self.tx.lock().unwrap().send(Reply::Body(body)).unwrap();\n    }\n\n    fn body_stream_with_trailers<S>(self, stream: S, trailers: HeaderMap)\n    where\n        S: futures_util::Stream<Item = Result<Bytes, BoxError>> + Send + Sync + 'static,\n    {\n        use futures_util::TryStreamExt;\n        use hyper::body::Frame;\n        use support::trailers::StreamBodyWithTrailers;\n        let mut stream_body = StreamBodyWithTrailers::new(stream.map_ok(Frame::data));\n        stream_body.set_trailers(trailers);\n        let body = BodyExt::boxed(stream_body);\n        self.tx.lock().unwrap().send(Reply::Body(body)).unwrap();\n    }\n\n    #[allow(dead_code)]\n    fn error<E: Into<BoxError>>(self, err: E) {\n        self.tx\n            .lock()\n            .unwrap()\n            .send(Reply::Error(err.into()))\n            .unwrap();\n    }\n}\n\nimpl Drop for ReplyBuilder<'_> {\n    fn drop(&mut self) {\n        if let Ok(mut tx) = self.tx.lock() {\n            let _ = tx.send(Reply::End);\n        }\n    }\n}\n\nimpl Drop for Serve {\n    fn drop(&mut self) {\n        drop(self.shutdown_signal.take());\n        drop(self.thread.take());\n        /*\n        let r = self.thread.take().unwrap().join();\n        if let Err(ref e) = r {\n            println!(\"{:?}\", e);\n        }\n        r.unwrap();\n        */\n    }\n}\n\n#[derive(Clone)]\nstruct TestService {\n    tx: mpsc::Sender<Msg>,\n    trailers_tx: mpsc::Sender<HeaderMap>,\n    reply: spmc::Receiver<Reply>,\n}\n\ntype ReplyBody = BoxBody<Bytes, BoxError>;\n\n#[derive(Debug)]\nenum Reply {\n    Status(hyper::StatusCode),\n    ReasonPhrase(hyper::ext::ReasonPhrase),\n    Version(hyper::Version),\n    Header(HeaderName, HeaderValue),\n    Body(ReplyBody),\n    Error(BoxError),\n    End,\n}\n\n#[derive(Debug)]\nenum Msg {\n    Chunk(Vec<u8>),\n    Error(hyper::Error),\n    End,\n}\n\nimpl Service<Request<IncomingBody>> for TestService {\n    type Response = Response<ReplyBody>;\n    type Error = BoxError;\n    type Future = BoxFuture;\n\n    fn call(&self, mut req: Request<IncomingBody>) -> Self::Future {\n        let tx = self.tx.clone();\n        let trailers_tx = self.trailers_tx.clone();\n        let replies = self.reply.clone();\n\n        Box::pin(async move {\n            while let Some(item) = req.frame().await {\n                match item {\n                    Ok(frame) => {\n                        if frame.is_data() {\n                            tx.send(Msg::Chunk(frame.into_data().unwrap().to_vec()))\n                                .unwrap();\n                        } else if frame.is_trailers() {\n                            let trailers = frame.into_trailers().unwrap();\n                            trailers_tx.send(trailers).unwrap();\n                        }\n                    }\n                    Err(err) => {\n                        tx.send(Msg::Error(err)).unwrap();\n                        return Err(\"req body error\".into());\n                    }\n                }\n            }\n\n            tx.send(Msg::End).unwrap();\n\n            TestService::build_reply(replies)\n        })\n    }\n}\n\nimpl TestService {\n    fn build_reply(replies: spmc::Receiver<Reply>) -> Result<Response<ReplyBody>, BoxError> {\n        let empty =\n            BodyExt::boxed(http_body_util::Empty::new().map_err(|e| -> BoxError { match e {} }));\n        let mut res = Response::new(empty);\n        while let Ok(reply) = replies.try_recv() {\n            match reply {\n                Reply::Status(s) => {\n                    *res.status_mut() = s;\n                }\n                Reply::ReasonPhrase(reason) => {\n                    res.extensions_mut().insert(reason);\n                }\n                Reply::Version(v) => {\n                    *res.version_mut() = v;\n                }\n                Reply::Header(name, value) => {\n                    res.headers_mut().insert(name, value);\n                }\n                Reply::Body(body) => {\n                    *res.body_mut() = body;\n                }\n                Reply::Error(err) => return Err(err),\n                Reply::End => break,\n            }\n        }\n        Ok(res)\n    }\n}\n\nconst HELLO: &str = \"hello\";\n\nstruct HelloWorld;\n\nimpl Service<Request<IncomingBody>> for HelloWorld {\n    type Response = Response<Full<Bytes>>;\n    type Error = hyper::Error;\n    type Future = future::Ready<Result<Self::Response, Self::Error>>;\n\n    fn call(&self, _req: Request<IncomingBody>) -> Self::Future {\n        let response = Response::new(Full::new(HELLO.into()));\n        future::ok(response)\n    }\n}\n\nfn unreachable_service() -> impl Service<\n    http::Request<IncomingBody>,\n    Response = http::Response<ReplyBody>,\n    Error = BoxError,\n    Future = BoxFuture,\n> {\n    service_fn(|_req| Box::pin(async { Err(\"request shouldn't be received\".into()) }) as BoxFuture)\n}\n\nfn connect(addr: &SocketAddr) -> TcpStream {\n    let req = TcpStream::connect(addr).unwrap();\n    req.set_read_timeout(Some(Duration::from_secs(1))).unwrap();\n    req.set_write_timeout(Some(Duration::from_secs(1))).unwrap();\n    req\n}\n\nasync fn connect_async(addr: SocketAddr) -> TkTcpStream {\n    TkTcpStream::connect(addr).await.expect(\"connect_async\")\n}\n\nfn serve() -> Serve {\n    serve_opts().serve()\n}\n\nfn serve_opts() -> ServeOptions {\n    ServeOptions::default()\n}\n\n#[derive(Clone, Copy)]\nstruct ServeOptions {\n    http2: bool,\n    keep_alive: bool,\n    pipeline: bool,\n}\n\nimpl Default for ServeOptions {\n    fn default() -> Self {\n        ServeOptions {\n            http2: false,\n            keep_alive: true,\n            pipeline: false,\n        }\n    }\n}\n\nimpl ServeOptions {\n    fn http2(mut self) -> Self {\n        self.http2 = true;\n        self\n    }\n\n    fn keep_alive(mut self, enabled: bool) -> Self {\n        self.keep_alive = enabled;\n        self\n    }\n\n    fn pipeline(mut self, enabled: bool) -> Self {\n        self.pipeline = enabled;\n        self\n    }\n\n    fn serve(self) -> Serve {\n        let _ = pretty_env_logger::try_init();\n        let _options = self;\n\n        let (addr_tx, addr_rx) = mpsc::channel();\n        let (msg_tx, msg_rx) = mpsc::channel();\n        let (trailers_tx, trailers_rx) = mpsc::channel();\n        let (reply_tx, reply_rx) = spmc::channel();\n        let (shutdown_tx, mut shutdown_rx) = oneshot::channel();\n\n        let addr: SocketAddr = ([127, 0, 0, 1], 0).into();\n\n        let thread_name = format!(\n            \"test-server-{}\",\n            thread::current()\n                .name()\n                .unwrap_or(\"<unknown test case name>\")\n        );\n        let thread = thread::Builder::new()\n            .name(thread_name)\n            .spawn(move || {\n                support::runtime().block_on(async move {\n                    let listener = TkTcpListener::bind(addr).await.unwrap();\n\n                    addr_tx\n                        .send(listener.local_addr().unwrap())\n                        .expect(\"server addr tx\");\n\n                    loop {\n                        let msg_tx = msg_tx.clone();\n                        let trailers_tx = trailers_tx.clone();\n                        let reply_rx = reply_rx.clone();\n\n                        tokio::select! {\n                            res = listener.accept() => {\n                                let (stream, _) = res.unwrap();\n                                let stream = TokioIo::new(stream);\n\n                                tokio::task::spawn(async move {\n                                    let msg_tx = msg_tx.clone();\n                                    let reply_rx = reply_rx.clone();\n                                    let service = TestService {\n                                        tx: msg_tx,\n                                        trailers_tx,\n                                        reply: reply_rx,\n                                    };\n\n                                    if _options.http2 {\n                                        http2::Builder::new(TokioExecutor)\n                                            .serve_connection(stream, service).await.unwrap();\n                                    } else {\n                                        http1::Builder::new()\n                                            .keep_alive(_options.keep_alive)\n                                            .pipeline_flush(_options.pipeline)\n                                            .serve_connection(stream, service).await.unwrap();\n                                    }\n                                });\n                            }\n                            _ = &mut shutdown_rx => {\n                                break;\n                            }\n                        }\n                    }\n                })\n            })\n            .expect(\"thread spawn\");\n\n        let addr = addr_rx.recv().expect(\"server addr rx\");\n\n        Serve {\n            msg_rx,\n            trailers_rx,\n            reply_tx: Mutex::new(reply_tx),\n            addr,\n            shutdown_signal: Some(shutdown_tx),\n            thread: Some(thread),\n        }\n    }\n}\n\nfn s(buf: &[u8]) -> &str {\n    std::str::from_utf8(buf).unwrap()\n}\n\nfn has_header(msg: &str, name: &str) -> bool {\n    let n = msg.find(\"\\r\\n\\r\\n\").unwrap_or(msg.len());\n\n    msg[..n].contains(name)\n}\n\nfn tcp_bind(addr: &SocketAddr) -> std::io::Result<TcpListener> {\n    let std_listener = StdTcpListener::bind(addr).unwrap();\n    std_listener.set_nonblocking(true).unwrap();\n    TcpListener::from_std(std_listener)\n}\n\nfn read_until<R, F>(io: &mut R, func: F) -> io::Result<Vec<u8>>\nwhere\n    R: Read,\n    F: Fn(&[u8]) -> bool,\n{\n    let mut buf = vec![0; 8192];\n    let mut pos = 0;\n    loop {\n        let n = io.read(&mut buf[pos..])?;\n        pos += n;\n        if func(&buf[..pos]) {\n            break;\n        }\n\n        if pos == buf.len() {\n            return Err(io::Error::new(\n                io::ErrorKind::Other,\n                \"read_until buffer filled\",\n            ));\n        }\n    }\n    buf.truncate(pos);\n    Ok(buf)\n}\n\nstruct DebugStream<T, D> {\n    stream: T,\n    _debug: D,\n}\n\nimpl<T: Unpin, D> Unpin for DebugStream<T, D> {}\n\nimpl<T: Read, D> Read for DebugStream<T, D> {\n    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {\n        self.stream.read(buf)\n    }\n}\n\nimpl<T: Write, D> Write for DebugStream<T, D> {\n    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {\n        self.stream.write(buf)\n    }\n\n    fn flush(&mut self) -> io::Result<()> {\n        self.stream.flush()\n    }\n}\n\nimpl<T: AsyncWrite + Unpin, D> AsyncWrite for DebugStream<T, D> {\n    fn poll_write(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<Result<usize, io::Error>> {\n        Pin::new(&mut self.stream).poll_write(cx, buf)\n    }\n\n    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {\n        Pin::new(&mut self.stream).poll_flush(cx)\n    }\n\n    fn poll_shutdown(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Result<(), io::Error>> {\n        Pin::new(&mut self.stream).poll_shutdown(cx)\n    }\n}\n\nimpl<T: AsyncRead + Unpin, D: Unpin> AsyncRead for DebugStream<T, D> {\n    fn poll_read(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: hyper::rt::ReadBufCursor<'_>,\n    ) -> Poll<io::Result<()>> {\n        Pin::new(&mut self.stream).poll_read(cx, buf)\n    }\n}\n\n#[derive(Clone)]\nstruct Dropped(Arc<AtomicBool>);\n\nimpl Dropped {\n    pub fn new() -> Dropped {\n        Dropped(Arc::new(AtomicBool::new(false)))\n    }\n\n    pub fn load(&self) -> bool {\n        self.0.load(Ordering::SeqCst)\n    }\n}\n\nimpl Drop for Dropped {\n    fn drop(&mut self) {\n        self.0.store(true, Ordering::SeqCst);\n    }\n}\n\nstruct TestClient {\n    http2_only: bool,\n}\n\nimpl TestClient {\n    fn new() -> Self {\n        Self { http2_only: false }\n    }\n\n    fn http2_only(mut self) -> Self {\n        self.http2_only = true;\n        self\n    }\n\n    async fn get(&self, uri: Uri) -> Result<Response<IncomingBody>, hyper::Error> {\n        self.request(\n            Request::builder()\n                .uri(uri)\n                .method(Method::GET)\n                .body(Empty::<Bytes>::new())\n                .unwrap(),\n        )\n        .await\n    }\n\n    async fn request(\n        &self,\n        req: Request<Empty<Bytes>>,\n    ) -> Result<Response<IncomingBody>, hyper::Error> {\n        let host = req.uri().host().expect(\"uri has no host\");\n        let port = req.uri().port_u16().expect(\"uri has no port\");\n\n        let stream = TokioIo::new(\n            TkTcpStream::connect(format!(\"{}:{}\", host, port))\n                .await\n                .unwrap(),\n        );\n\n        if self.http2_only {\n            let (mut sender, conn) = hyper::client::conn::http2::Builder::new(TokioExecutor)\n                .handshake(stream)\n                .await\n                .unwrap();\n            tokio::task::spawn(async move {\n                conn.await.unwrap();\n            });\n\n            sender.send_request(req).await\n        } else {\n            let (mut sender, conn) = hyper::client::conn::http1::Builder::new()\n                .handshake(stream)\n                .await\n                .unwrap();\n            tokio::task::spawn(async move {\n                conn.await.unwrap();\n            });\n\n            sender.send_request(req).await\n        }\n    }\n}\n"
  },
  {
    "path": "tests/support/mod.rs",
    "content": "#![allow(dead_code)]\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::sync::{\n    atomic::{AtomicUsize, Ordering},\n    Arc, Mutex,\n};\n\nuse bytes::Bytes;\nuse http_body_util::{BodyExt, Full};\nuse hyper::server;\nuse tokio::net::{TcpListener, TcpStream};\n\nuse hyper::service::service_fn;\nuse hyper::{body::Incoming as IncomingBody, Request, Response, Version};\n\npub use futures_util::{\n    future, FutureExt as _, StreamExt as _, TryFutureExt as _, TryStreamExt as _,\n};\npub use hyper::HeaderMap;\npub use std::net::SocketAddr;\n\nmod tokiort;\n#[allow(unused)]\npub use tokiort::{TokioExecutor, TokioIo, TokioTimer};\n\npub mod trailers;\n\n#[allow(unused_macros)]\nmacro_rules! t {\n    (\n        $name:ident,\n        parallel: $range:expr\n    ) => (\n        #[test]\n        fn $name() {\n\n            let mut c = vec![];\n            let mut s = vec![];\n\n            for _i in $range {\n                c.push((\n                    __CReq {\n                        uri: \"/\",\n                        body: vec![b'x'; 8192],\n                        ..Default::default()\n                    },\n                    __CRes {\n                        body: vec![b'x'; 8192],\n                        ..Default::default()\n                    },\n                ));\n                s.push((\n                    __SReq {\n                        uri: \"/\",\n                        body: vec![b'x'; 8192],\n                        ..Default::default()\n                    },\n                    __SRes {\n                        body: vec![b'x'; 8192],\n                        ..Default::default()\n                    },\n                ));\n            }\n\n            __run_test(__TestConfig {\n                client_version: 2,\n                client_msgs: c.clone(),\n                server_version: 2,\n                server_msgs: s.clone(),\n                parallel: true,\n                connections: 1,\n                proxy: false,\n            });\n\n            __run_test(__TestConfig {\n                client_version: 2,\n                client_msgs: c,\n                server_version: 2,\n                server_msgs: s,\n                parallel: true,\n                connections: 1,\n                proxy: true,\n            });\n        }\n    );\n    (\n        $name:ident,\n        client: $(\n            request: $(\n                $c_req_prop:ident: $c_req_val:tt,\n            )*;\n            response: $(\n                $c_res_prop:ident: $c_res_val:tt,\n            )*;\n        )*\n        server: $(\n            request: $(\n                $s_req_prop:ident: $s_req_val:tt,\n            )*;\n            response: $(\n                $s_res_prop:ident: $s_res_val:tt,\n            )*;\n        )*\n    ) => (\n        #[test]\n        fn $name() {\n            let c = vec![$((\n                __CReq {\n                    $($c_req_prop: __internal_map_prop!($c_req_prop: $c_req_val),)*\n                    ..Default::default()\n                },\n                __CRes {\n                    $($c_res_prop: __internal_eq_prop!($c_res_prop: $c_res_val),)*\n                    ..Default::default()\n                }\n            ),)*];\n            let s = vec![$((\n                __SReq {\n                    $($s_req_prop: __internal_eq_prop!($s_req_prop: $s_req_val),)*\n                    ..Default::default()\n                },\n                __SRes {\n                    $($s_res_prop: __internal_map_prop!($s_res_prop: $s_res_val),)*\n                    ..Default::default()\n                }\n            ),)*];\n\n            __run_test(__TestConfig {\n                client_version: 1,\n                client_msgs: c.clone(),\n                server_version: 1,\n                server_msgs: s.clone(),\n                parallel: false,\n                connections: 1,\n                proxy: false,\n            });\n\n            __run_test(__TestConfig {\n                client_version: 2,\n                client_msgs: c.clone(),\n                server_version: 2,\n                server_msgs: s.clone(),\n                parallel: false,\n                connections: 1,\n                proxy: false,\n            });\n\n            __run_test(__TestConfig {\n                client_version: 1,\n                client_msgs: c.clone(),\n                server_version: 1,\n                server_msgs: s.clone(),\n                parallel: false,\n                connections: 1,\n                proxy: true,\n            });\n\n            __run_test(__TestConfig {\n                client_version: 2,\n                client_msgs: c,\n                server_version: 2,\n                server_msgs: s,\n                parallel: false,\n                connections: 1,\n                proxy: true,\n            });\n        }\n    );\n}\n\nmacro_rules! __internal_map_prop {\n    (headers: $map:tt) => {{\n        #[allow(unused_mut)]\n        {\n            let mut headers = HeaderMap::new();\n            __internal_headers_map!(headers, $map);\n            headers\n        }\n    }};\n    ($name:tt: $val:tt) => {{\n        __internal_req_res_prop!($name: $val)\n    }};\n}\n\nmacro_rules! __internal_eq_prop {\n    (headers: $map:tt) => {{\n        #[allow(unused_mut)]\n        {\n            let mut headers = Vec::<std::sync::Arc<dyn Fn(&hyper::HeaderMap) + Send + Sync>>::new();\n            __internal_headers_eq!(headers, $map);\n            headers\n        }\n    }};\n    ($name:tt: $val:tt) => {{\n        __internal_req_res_prop!($name: $val)\n    }};\n}\n\nmacro_rules! __internal_req_res_prop {\n    (method: $prop_val:expr) => {\n        $prop_val\n    };\n    (status: $prop_val:expr) => {\n        hyper::StatusCode::from_u16($prop_val).expect(\"status code\")\n    };\n    ($prop_name:ident: $prop_val:expr) => {\n        From::from($prop_val)\n    };\n}\n\nmacro_rules! __internal_headers_map {\n    ($headers:ident, { $($name:expr => $val:expr,)* }) => {\n        $(\n        $headers.insert($name, $val.to_string().parse().expect(\"header value\"));\n        )*\n    }\n}\n\nmacro_rules! __internal_headers_eq {\n    (@pat $name: expr, $pat:pat) => {\n        std::sync::Arc::new(move |__hdrs: &hyper::HeaderMap| {\n            match __hdrs.get($name) {\n                $pat => (),\n                other => panic!(\"headers[{}] was not {}: {:?}\", stringify!($name), stringify!($pat), other),\n            }\n        }) as std::sync::Arc<dyn Fn(&hyper::HeaderMap) + Send + Sync>\n    };\n    (@val $name: expr, NONE) => {{\n        __internal_headers_eq!(@pat $name, None);\n    }};\n    (@val $name: expr, SOME) => {{\n        __internal_headers_eq!(@pat $name, Some(_))\n    }};\n    (@val $name: expr, $val:expr) => ({\n        let __val = Option::from($val);\n        std::sync::Arc::new(move |__hdrs: &hyper::HeaderMap| {\n            if let Some(ref val) = __val {\n                assert_eq!(__hdrs.get($name).expect(stringify!($name)), val.to_string().as_str(), stringify!($name));\n            } else {\n                assert_eq!(__hdrs.get($name), None, stringify!($name));\n            }\n        }) as std::sync::Arc<dyn Fn(&hyper::HeaderMap) + Send + Sync>\n    });\n    ($headers:ident, { $($name:expr => $val:tt,)* }) => {{\n        $(\n        $headers.push(__internal_headers_eq!(@val $name, $val));\n        )*\n    }}\n}\n\n#[derive(Clone, Debug)]\npub struct __CReq {\n    pub method: &'static str,\n    pub uri: &'static str,\n    pub headers: HeaderMap,\n    pub body: Vec<u8>,\n}\n\nimpl Default for __CReq {\n    fn default() -> __CReq {\n        __CReq {\n            method: \"GET\",\n            uri: \"/\",\n            headers: HeaderMap::new(),\n            body: Vec::new(),\n        }\n    }\n}\n\n#[derive(Clone, Default)]\npub struct __CRes {\n    pub status: hyper::StatusCode,\n    pub body: Vec<u8>,\n    pub headers: __HeadersEq,\n}\n\n#[derive(Clone)]\npub struct __SReq {\n    pub method: &'static str,\n    pub uri: &'static str,\n    pub headers: __HeadersEq,\n    pub body: Vec<u8>,\n}\n\nimpl Default for __SReq {\n    fn default() -> __SReq {\n        __SReq {\n            method: \"GET\",\n            uri: \"/\",\n            headers: Vec::new(),\n            body: Vec::new(),\n        }\n    }\n}\n\n#[derive(Clone, Debug, Default)]\npub struct __SRes {\n    pub status: hyper::StatusCode,\n    pub body: Vec<u8>,\n    pub headers: HeaderMap,\n}\n\npub type __HeadersEq = Vec<Arc<dyn Fn(&HeaderMap) + Send + Sync>>;\n\npub struct __TestConfig {\n    pub client_version: usize,\n    pub client_msgs: Vec<(__CReq, __CRes)>,\n\n    pub server_version: usize,\n    pub server_msgs: Vec<(__SReq, __SRes)>,\n\n    pub parallel: bool,\n    pub connections: usize,\n    pub proxy: bool,\n}\n\npub fn runtime() -> tokio::runtime::Runtime {\n    tokio::runtime::Builder::new_current_thread()\n        .enable_all()\n        .build()\n        .expect(\"new rt\")\n}\n\npub fn __run_test(cfg: __TestConfig) {\n    let _ = pretty_env_logger::try_init();\n    runtime().block_on(async_test(cfg));\n}\n\nasync fn async_test(cfg: __TestConfig) {\n    assert_eq!(cfg.client_version, cfg.server_version);\n\n    let version = if cfg.client_version == 2 {\n        Version::HTTP_2\n    } else {\n        Version::HTTP_11\n    };\n\n    let http2_only = cfg.server_version == 2;\n\n    let serve_handles = Arc::new(Mutex::new(cfg.server_msgs));\n\n    let listener = TcpListener::bind(&SocketAddr::from(([127, 0, 0, 1], 0)))\n        .await\n        .unwrap();\n\n    let mut addr = listener.local_addr().unwrap();\n\n    let expected_connections = cfg.connections;\n    tokio::task::spawn(async move {\n        let mut cnt = 0;\n\n        cnt += 1;\n        assert!(\n            cnt <= expected_connections,\n            \"server expected {} connections, received {}\",\n            expected_connections,\n            cnt\n        );\n\n        loop {\n            let (stream, _) = listener.accept().await.expect(\"server error\");\n            let io = TokioIo::new(stream);\n\n            // Move a clone into the service_fn\n            let serve_handles = serve_handles.clone();\n            let service = service_fn(move |req: Request<IncomingBody>| {\n                let (sreq, sres) = serve_handles.lock().unwrap().remove(0);\n\n                assert_eq!(req.uri().path(), sreq.uri, \"client path\");\n                assert_eq!(req.method(), &sreq.method, \"client method\");\n                assert_eq!(req.version(), version, \"client version\");\n                for func in &sreq.headers {\n                    func(req.headers());\n                }\n                let sbody = sreq.body;\n                req.collect().map_ok(move |collected| {\n                    let body = collected.to_bytes();\n                    assert_eq!(body.as_ref(), sbody.as_slice(), \"client body\");\n\n                    let mut res = Response::builder()\n                        .status(sres.status)\n                        .body(Full::new(Bytes::from(sres.body)))\n                        .expect(\"Response::build\");\n                    *res.headers_mut() = sres.headers;\n                    res\n                })\n            });\n\n            tokio::task::spawn(async move {\n                if http2_only {\n                    server::conn::http2::Builder::new(TokioExecutor)\n                        .serve_connection(io, service)\n                        .await\n                        .expect(\"server error\");\n                } else {\n                    server::conn::http1::Builder::new()\n                        .serve_connection(io, service)\n                        .await\n                        .expect(\"server error\");\n                }\n            });\n        }\n    });\n\n    if cfg.proxy {\n        let (proxy_addr, proxy) = naive_proxy(ProxyConfig {\n            connections: cfg.connections,\n            dst: addr,\n            version: cfg.server_version,\n        })\n        .await;\n        tokio::task::spawn(proxy);\n        addr = proxy_addr;\n    }\n\n    let make_request = Arc::new(move |creq: __CReq, cres: __CRes| {\n        let uri = format!(\"http://{}{}\", addr, creq.uri);\n        let mut req = Request::builder()\n            .method(creq.method)\n            .uri(uri)\n            //.headers(creq.headers)\n            .body(Full::new(Bytes::from(creq.body)))\n            .expect(\"Request::build\");\n        *req.headers_mut() = creq.headers;\n        let cstatus = cres.status;\n        let cheaders = cres.headers;\n        let cbody = cres.body;\n\n        async move {\n            let stream = TcpStream::connect(addr).await.unwrap();\n            let io = TokioIo::new(stream);\n\n            let res = if http2_only {\n                let (mut sender, conn) = hyper::client::conn::http2::Builder::new(TokioExecutor)\n                    .handshake(io)\n                    .await\n                    .unwrap();\n\n                tokio::task::spawn(async move {\n                    if let Err(err) = conn.await {\n                        panic!(\"{:?}\", err);\n                    }\n                });\n                sender.send_request(req).await.unwrap()\n            } else {\n                let (mut sender, conn) = hyper::client::conn::http1::Builder::new()\n                    .handshake(io)\n                    .await\n                    .unwrap();\n\n                tokio::task::spawn(async move {\n                    if let Err(err) = conn.await {\n                        panic!(\"{:?}\", err);\n                    }\n                });\n                sender.send_request(req).await.unwrap()\n            };\n\n            assert_eq!(res.status(), cstatus, \"server status\");\n            assert_eq!(res.version(), version, \"server version\");\n            for func in &cheaders {\n                func(res.headers());\n            }\n\n            let body = res.collect().await.unwrap().to_bytes();\n\n            assert_eq!(body.as_ref(), cbody.as_slice(), \"server body\");\n        }\n    });\n\n    let client_futures: Pin<Box<dyn Future<Output = ()> + Send>> = if cfg.parallel {\n        let mut client_futures = vec![];\n        for (creq, cres) in cfg.client_msgs {\n            client_futures.push(make_request(creq, cres));\n        }\n        Box::pin(future::join_all(client_futures).map(|_| ()))\n    } else {\n        let mut client_futures: Pin<Box<dyn Future<Output = ()> + Send>> =\n            Box::pin(future::ready(()));\n        for (creq, cres) in cfg.client_msgs {\n            let mk_request = make_request.clone();\n            client_futures = Box::pin(client_futures.then(move |_| mk_request(creq, cres)));\n        }\n        Box::pin(client_futures.map(|_| ()))\n    };\n\n    client_futures.await;\n}\n\nstruct ProxyConfig {\n    connections: usize,\n    dst: SocketAddr,\n    version: usize,\n}\n\nasync fn naive_proxy(cfg: ProxyConfig) -> (SocketAddr, impl Future<Output = ()>) {\n    let dst_addr = cfg.dst;\n    let max_connections = cfg.connections;\n    let counter = AtomicUsize::new(0);\n    let http2_only = cfg.version == 2;\n\n    let listener = TcpListener::bind(SocketAddr::from(([127, 0, 0, 1], 0)))\n        .await\n        .unwrap();\n\n    let proxy_addr = listener.local_addr().unwrap();\n\n    let fut = async move {\n        tokio::task::spawn(async move {\n            let prev = counter.fetch_add(1, Ordering::Relaxed);\n            assert!(max_connections > prev, \"proxy max connections\");\n\n            loop {\n                let (stream, _) = listener.accept().await.unwrap();\n                let io = TokioIo::new(stream);\n\n                let service = service_fn(move |mut req| {\n                    async move {\n                        let uri = format!(\"http://{}{}\", dst_addr, req.uri().path())\n                            .parse()\n                            .expect(\"proxy new uri parse\");\n                        *req.uri_mut() = uri;\n\n                        // Make the client request\n                        let uri = req.uri().host().expect(\"uri has no host\");\n                        let port = req.uri().port_u16().expect(\"uri has no port\");\n\n                        let stream = TcpStream::connect(format!(\"{}:{}\", uri, port))\n                            .await\n                            .unwrap();\n                        let io = TokioIo::new(stream);\n\n                        let resp = if http2_only {\n                            let (mut sender, conn) =\n                                hyper::client::conn::http2::Builder::new(TokioExecutor)\n                                    .handshake(io)\n                                    .await\n                                    .unwrap();\n\n                            tokio::task::spawn(async move {\n                                if let Err(err) = conn.await {\n                                    panic!(\"{:?}\", err);\n                                }\n                            });\n\n                            sender.send_request(req).await?\n                        } else {\n                            let builder = hyper::client::conn::http1::Builder::new();\n                            let (mut sender, conn) = builder.handshake(io).await.unwrap();\n\n                            tokio::task::spawn(async move {\n                                if let Err(err) = conn.await {\n                                    panic!(\"{:?}\", err);\n                                }\n                            });\n\n                            sender.send_request(req).await?\n                        };\n\n                        let (mut parts, body) = resp.into_parts();\n\n                        // Remove the Connection header for HTTP/1.1 proxy connections.\n                        if !http2_only {\n                            parts.headers.remove(\"Connection\");\n                        }\n\n                        let mut builder = Response::builder().status(parts.status);\n                        *builder.headers_mut().unwrap() = parts.headers;\n\n                        Result::<Response<hyper::body::Incoming>, hyper::Error>::Ok(\n                            builder.body(body).unwrap(),\n                        )\n                    }\n                });\n\n                if http2_only {\n                    server::conn::http2::Builder::new(TokioExecutor)\n                        .serve_connection(io, service)\n                        .await\n                        .unwrap();\n                } else {\n                    server::conn::http1::Builder::new()\n                        .serve_connection(io, service)\n                        .await\n                        .unwrap();\n                }\n            }\n        });\n    };\n\n    (proxy_addr, fut)\n}\n"
  },
  {
    "path": "tests/support/trailers.rs",
    "content": "use bytes::Buf;\nuse futures_util::stream::Stream;\nuse http::header::HeaderMap;\nuse http_body::{Body, Frame};\nuse pin_project_lite::pin_project;\nuse std::{\n    pin::Pin,\n    task::{Context, Poll},\n};\n\npin_project! {\n    /// A body created from a [`Stream`].\n    #[derive(Clone, Debug)]\n    pub struct StreamBodyWithTrailers<S> {\n        #[pin]\n        stream: S,\n        trailers: Option<HeaderMap>,\n    }\n}\n\nimpl<S> StreamBodyWithTrailers<S> {\n    /// Create a new `StreamBodyWithTrailers`.\n    pub fn new(stream: S) -> Self {\n        Self {\n            stream,\n            trailers: None,\n        }\n    }\n\n    pub fn with_trailers(stream: S, trailers: HeaderMap) -> Self {\n        Self {\n            stream,\n            trailers: Some(trailers),\n        }\n    }\n\n    pub fn set_trailers(&mut self, trailers: HeaderMap) {\n        self.trailers = Some(trailers);\n    }\n}\n\nimpl<S, D, E> Body for StreamBodyWithTrailers<S>\nwhere\n    S: Stream<Item = Result<Frame<D>, E>>,\n    D: Buf,\n{\n    type Data = D;\n    type Error = E;\n\n    fn poll_frame(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {\n        let project = self.project();\n        match project.stream.poll_next(cx) {\n            Poll::Ready(Some(result)) => Poll::Ready(Some(result)),\n            Poll::Ready(None) => match project.trailers.take() {\n                Some(trailers) => Poll::Ready(Some(Ok(Frame::trailers(trailers)))),\n                None => Poll::Ready(None),\n            },\n            Poll::Pending => Poll::Pending,\n        }\n    }\n}\n\nimpl<S: Stream> Stream for StreamBodyWithTrailers<S> {\n    type Item = S::Item;\n\n    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        self.project().stream.poll_next(cx)\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.stream.size_hint()\n    }\n}\n"
  }
]