[
  {
    "path": ".github/FUNDING.yml",
    "content": "github: [seanmonstar]\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Version**\nList the versions of all `warp` crates you are using. The easiest way to get\nthis information is using `cargo-tree`.\n\n`cargo install cargo-tree`\n(see install here: https://github.com/sfackler/cargo-tree)\n\nThen:\n\n`cargo tree | grep warp`\n\n**Platform**\nThe output of `uname -a` (UNIX), or version and 32 or 64-bit (Windows)\n\n**Description**\nEnter your issue details here.\nOne way to structure the description:\n\n[short summary of the bug]\n\nI tried this code:\n\n[code sample that causes the bug]\n\nI expected to see this happen: [explanation]\n\nInstead, this happened: [explanation]\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Question\n    url: https://discord.gg/RFsPjyt\n    about: 'Please post your question on the #warp discord channel. You may\n           also be able to find help at https://users.rust-lang.org/.'\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: 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/workflows/ci.yml",
    "content": "name: CI\n\non:\n  pull_request:\n  push:\n    branches:\n      - master\nenv:\n  RUST_BACKTRACE: 1\n\njobs:\n  ci-pass:\n    name: CI is green\n    runs-on: ubuntu-latest\n    needs:\n      - style\n      - test\n      - doc\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@v5\n\n      - name: Install rust\n        uses: dtolnay/rust-toolchain@stable\n        with:\n          components: rustfmt\n\n      - run: cargo fmt --all --check\n\n  test:\n    name: Test\n    needs: [style]\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        build: [stable, beta, nightly, without-test, multipart, websocket, compression]\n\n        include:\n          - build: stable\n            features: \"--features test\"\n          - build: beta\n            rust: beta\n            features: \"--features server\"\n          - build: nightly\n            rust: nightly\n            benches: true\n            features: \"--features test\"\n          - build: compression\n            features: \"--features compression,test\"\n          - build: multipart\n            features: \"--features multipart,test\"\n          - build: websocket\n            features: \"--features websocket,test\"\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v5\n\n      - name: Install rust\n        uses: dtolnay/rust-toolchain@master\n        with:\n          toolchain: ${{ matrix.rust || 'stable' }}\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  doc:\n    name: Build docs\n    needs: [style, test]\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v5\n\n      - name: Install Rust\n        uses: dtolnay/rust-toolchain@nightly\n\n      - name: cargo doc\n        run: cargo doc --all-features --no-deps\n        env:\n          RUSTDOCFLAGS: \"--cfg docsrs -D rustdoc::broken_intra_doc_links\"\n"
  },
  {
    "path": ".gitignore",
    "content": "\n/target\n**/*.rs.bk\nCargo.lock\n.idea/\nwarp.iml\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# CHANGELOG\n\n### v0.4.2 (August 19, 2025)\n\n- **Features**:\n  - Add support for passing `UnixListener` to `incoming(listener)`.\n- **Fixes**:\n  - Reduce some dependencies when `server` is not enabled.\n\n### v0.4.1 (August 6, 2025)\n\n- **Fixes**:\n  - Fix `Server::graceful()` bounds incorrect requiring the filter to be a future.\n  - Enable `tokio/net` when the `server` feature is enabled.\n  - Render `cfg`s in the docs.\n\n## v0.4.0 (August 5, 2025)\n\n- **Changes**:\n  - Upgrade to `hyper`, `http`, and `http-body` to v1.\n  - Remove `multipart` and `websocket` features from being enabled by default.\n  - Put `warp::serve()` behind a `server` feature, not enabled by default.\n  - Put `warp::test` behind a `test` feature, not enabled by default.\n  - Remove `tls` feature and types.\n  - Remove `warp::addr` filters.\n\n### v0.3.7 (April 5, 2024)\n\n- **Features**:\n  - Add ecc private key support to `tls()` config.\n- **Fixes**:\n  - Several dependency upgrades.\n\n### v0.3.6 (September 27, 2023)\n\n- **Features**:\n  - Add ability to pass `None` to `multipart::form().max_length()`.\n  - Implement `Reply` for `Result<impl Reply, impl Reply>`.\n  - Make `multipart::Part::content_type()` return the full mime string.\n  - Add `TlsServer::try_bind_with_graceful_shutdown()`.\n- **Fixes**:\n  - Updated tungstenite and rustls dependencies for security fixes.\n\n### v0.3.5 (April 28, 2023)\n\n- **Fixes**:\n  - `multipart` filters now use `multer` dependency, fixing some streaming bugs.\n  - `Rejection::into_response()` is significantly faster.\n\n### v0.3.4 (March 31, 2023)\n\n- **Fixes**:\n  - `multipart::Part` data is now streamed instead of buffered.\n  - Update dependency used for `multipart` filters.\n\n### v0.3.3 (September 27, 2022)\n\n- **Fixes**:\n  - Fix `fs` filters path sanitization to reject colons on Windows.\n\n### v0.3.2 (November 9, 2021)\n\n- **Features**:\n  - Add `Filter::then()`, which is like `Filter::map()` in that it's infallible, but is async like `Filter::and_then()`.\n  - Add `redirect::found()` reply helper that returns `302 Found`.\n  - Add `compression-brotli` and `compression-gzip` cargo features to enable only the compression you need.\n  - Allow `HEAD` requests to be served to `fs::dir()` filters.\n  - Allow `path!()` with no arguments.\n- **Fixes**:\n  - Update private dependencies Tungstenite and Multipart.\n  - Replaces uses of `futures` with `futures-util`, which is a smaller dependency.\n\n\n### v0.3.1 (March 24, 2021)\n\n- **Features**:\n  - Add `pong` constructor to websocket messages.\n  - Add `redirect::see_other` and `redirect::permanent` helpers.\n- **Fixes**:\n  - Fix `fs` filters sometimes having an off-by-one error with range requests.\n  - Fix CORS to allow spaces when checking `Access-Control-Request-Headers`.\n\n## v0.3.0 (January 19, 2021)\n\n- **Features**:\n  - Add TLS client authentication support.\n  - Add TLS OCSP stapling support.\n  - Add `From<Reject>` for `Rejection`.\n  - Add `close_frame` accessor to `ws::Message`.\n- **Changes**:\n  - Update to Tokio v1.\n  - Update to Bytes v1.\n  - Update to hyper v0.14.\n  - Rework `sse` filter to be more like `ws`, with a single `Event` type and builder.\n  - Change `cookie` filter to extract a generic `FromStr` value.\n\n\n### v0.2.5 (August 31, 2020)\n\n- **Features**:\n  - Add `wrap_fn`, which can be used to create a `Wrap` from a closure. These in turn are used with `Filter::with()`.\n  - Add `warp::host` filters to deal with `Host`/`:authority` headers.\n  - Relax some lifetime bounds on `Server`.\n- **Fixes**:\n  - Fix panic when URI doesn't have a slash (for example, `CONNECT foo.bar`).\n\n### v0.2.4 (July 20, 2020)\n\n- **Features**:\n  - Add `tracing` internals in place of `log` (log is still emitted for backwards compatibility).\n  - Add `warp::trace` module set of filters to customize `tracing` dianostics.\n  - Add `path` method to `warp::fs::File` reply.\n  - Add `source` implementation for `BodyDeserializeError`.\n  - Make `warp::ws::MissingConnectionUpgrade` rejection public.\n\n### v0.2.3 (May 19, 2020)\n\n- **Features**:\n  - Add `warp::compression` filters, which will compress response bodies.\n  - Add `warp::header::value()` filter to get a request `HeaderValue`.\n  - Add `request_headers` method to `warp::log::Info`.\n  - Add `max_frame_size` to `warp::ws::Ws` builder.\n  - Add `remote_addr` to `warp::test::RequestBuilder`.\n  - Add `try_bind_with_graceful_shutdown` to `warp::Server` builder.\n  - Add `serve_incoming_with_graceful_shutdown` to `warp::Server` builder.\n- **Fixes**:\n  - Fix `warp::addr::remote` when used with `Server::tls`.\n  - Fix panic in `warp::path::{peek, tail, full}` filters when the request URI is in authority-form or asterisk-form.\n\n### v0.2.2 (March 3, 2020)\n\n- **Features**:\n  - Implement `Reply` for all `Box<T>` where `T: Reply`.\n  - Add `name` methods to `MissingHeader`, `InvalidHeader`, and `MissingCookie` rejections.\n  - Add `warp::ext::optional()` filter that optionally retrieves an extension from the request.\n- **Fixes**:\n  - Fix the sending of pings when a user sends a `ws::Message::ping()`.\n\n### v0.2.1 (January 23, 2020)\n\n- **Features**:\n  - Add `close` and `close_with` constructors to `warp::ws::Message`.\n- **Fixes**:\n  - Fix `warp::fs` filters using a very small read buffer.\n\n## v0.2.0 (January 16, 2020)\n\n- **Features**:\n  - Update to `std::future`, adding `async`/`await` support!\n  - Add `warp::service()` to convert a `Filter` into a `tower::Service`.\n  - Implement `Reply` for `Box<dyn Reply>`.\n- **Changes**:\n  - Refactored Rejection system (#311).\n  - Change `path!` macro to assume a `path::end()` by default, with explicit `/ ..` to allow building a prefix (#359).\n  - Change `warp::path(str)` to accept any `AsRef<str>` argument.\n  - Rename \"2\"-suffixed filters and types (`get2` to `get`, `ws2` to `ws`, etc).\n  - `Filter::{or, or_else, recover}` now require `Self::Error=Rejection`. This helps catch filters that didn't make sense (like `warp::any().or(warp::get())`).\n  - Change several `warp::body` filters (#345).\n  - Change `warp::cors()` to return a `warp::cors::Builder` which still implements `Wrap`, but can also `build` a cheaper-to-clone wrapper.\n  - Change `warp::multipart` stream API to allow for errors when streaming.\n  - Change `warp::sse` to no longer return a `Filter`, adds `warp::sse::reply` to do what `Sse::reply` did.\n  - Change `Server::tls()` to return a TLS server builder (#340).\n  - Change internal `warp::never::Never` usage with `std::convert::Infallible`.\n  - Remove `warp::ext::set()` function (#222).\n  - Remove deprecated `warp::cookie::optional_value()`.\n\n\n### v0.1.20 (September 17, 2019)\n\n- **Features**:\n  - Implement `Clone` for the `warp::cors` filter.\n  - Add `into_bytes` method for `warp::ws::Message`.\n\n### v0.1.19 (August 16, 2019)\n\n- **Features**:\n  - Make `warp::multipart` and `wrap::ws` support optional, though enabled by default.\n- **Fixes**:\n  - Fix `warp::fs::dir` filter to reject paths containing backslashes.\n\n### v0.1.18 (July 25, 2019)\n\n- **Features**:\n  - Add `warp::multipart` support.\n\n### v0.1.17 (July 8, 2019)\n\n- **Features**:\n  - Export all built-in Rejection causes in the `warp::reject` module.\n  - Add `Server::try_bind` as fallible bind methods.\n\n### v0.1.16 (June 11, 2019)\n\n- **Features**:\n  - Unseal the `Reply` trait: custom types can now implement `Reply`.\n  - Add `warp::sse::keep_alive()` replacement for `warp::sse::keep()` which allows customizing keep-alive behavior.\n  - Add `warp::log::Info::host()` accessor.\n- **Fixes**:\n  - Fix `warp::fs` filters from sending some headers for `304` responses.\n\n### v0.1.15 (April 2, 2019)\n\n- **Features**:\n  - Add more accessors to `warp::log::Info` type for building custom log formats.\n  - Implement `Reply` for `Cow<'static, str>`.\n\n### v0.1.14 (March 19, 2019)\n\n- **Features**:\n  - Add `warp::header::optional` filter.\n\n### v0.1.13 (February 13, 2019)\n\n- **Features**:\n  - Implement `Reply` for `Vec<u8>` and `&'static [u8]`.\n  - Set `content-type` header automatically for string and bytes replies.\n  - Add `expose_headers` to `warp::cors` filter.\n\n### v0.1.12 (January 29, 2019)\n\n- **Features**:\n  - Implement `PartialEq`, `Eq`, and `Clone` for `warp::ws::Message`.\n- **Fixes**:\n  - Fix panic when incoming request URI may not have a path (such as `CONNECT` requests).\n\n### v0.1.11 (January 14, 2019)\n\n- **Features**:\n  - Add `warp::sse` filters for handling Server-Sent-Events.\n  - Add `allow_headers` to `warp::cors` filter.\n- **Fixes**:\n  - Fix TLS handshake to close the connection if handshake fails.\n\n### v0.1.10 (December 17, 2018)\n\n- **Features**:\n  - Add optional TLS support. Enable the `tls` feature, and then use `Server::tls`.\n  - Add `warp::cors` filter for CORS support.\n  - Add `warp::addr::remote` to access the remote address of a request.\n  - Add `warp::log::custom` to support customizing of access logging.\n  - Add `warp::test::ws` to improve testing Websocket filters.\n\n### v0.1.9 (October 30, 2018)\n\n- **Features**:\n  - Add `warp::ext::get` and `warp::ext::set` to set request extensions.\n  - Add `Filter::untuple_one` to unroll nested tuple layers from extractions.\n  - Add `Ws2::max_send_queue` configuration method.\n  - Add `ws::Message::is_ping` method, and yield pings to user code.\n- **Fixes**:\n  - Fix panic in debug mode when receiving a websocket ping.\n\n### v0.1.8 (October 25, 2018)\n\n- **Features**:\n  - Improved flexibility of `Rejection` system.\n    \n    The `Rejection` type can now nest and combine arbitrary rejections,\n    so it is no longer bound to a small set of meanings. The ranking of\n    status codes is still used to determine which rejection gets priority.\n    \n    A different priority can be implemented by handling rejections with\n    a `Filter::recover`, and searching for causes in order via\n    `Rejection::find_cause`.\n    - Adds `warp::reject::custom()` to create a `Rejection` with\n      any `Into<Box<std::error::Error>>`. These rejections should be\n      handled with an eventual `Filter::recover`. Any unhandled\n      custom rejections are considered a server error.\n    - Deprecates `Rejection::with`. Use custom rejections instead.\n    - Deprecates `Rejection::into_cause`, as it can no longer work. Always\n      returns `Err(Rejection)`.\n    - Deprecates `Rejection::json`, since the format needed is too generic.\n      The `errors.rs` example shows how to send custom JSON when recovering\n      from rejections.\n    - Deprecates `warp::reject()`, since it current signals a `400 Bad\n      Request`, but in newer versions, it will signal `404 Not Found`.\n      It's deprecated simply to warn that the semantics are changing,\n      but the function won't actually go away.\n    - Deprecates `reject::bad_request()`, `reject::forbidden()`, and\n      `reject::server_error()`. Uses custom rejections instead.\n  - Renamed `warp::path::index` to `warp::path::end`.\n\n\n### v0.1.7 (October 15, 2018)\n\n- **Features**:\n  - Export the types returned from the `warp::body::stream()` filter, `BodyStream` and `StreamBuf`.\n  - Deprecated `Rejection::into_cause`, since an upcoming Rejection refactor will make it impossible to support.\n\n- **Fixes**:\n  - Fix websocket filters to do a case-insensitive match of the `Connection` header.\n\n### v0.1.6 (October 5, 2018)\n\n- **Features**:\n  - Add Conditional and Range request support for `warp::fs` filters.\n  - Relaxed bounds on `Rejection::with` to no longer need to be `Sized`.\n  - Add `warp::path::peek()` which gets the unmatched tail without adjusting the currently matched path.\n\n### v0.1.5 (October 3, 2018)\n\n- **Features**:\n  - Serve `index.html` automatically with `warp::fs::dir` filter.\n  - Include `last-modified` header with `warp::fs` filters.\n  - Add `warp::redirect` to easily reply with redirections.\n  - Add `warp::reply::{with_status, with_header}` to wrap `impl Reply`s directly with a new status code or header.\n  - Add support for running a warp `Server` with a custom source of incoming connections.\n    - `Server::run_incoming` to have the runtime started automatically.\n    - `Server::serve_incoming` to get a future to run on existing runtime.\n    - These can be used to support Unix Domain Sockets, TLS, and other transports.\n  - Add `Rejection::into_cause()` to retrieve the original error of a rejection back.\n  - Add `Rejection::json()` to convert a rejection into a JSON response.\n\n- **Fixes**\n  - Internal errors in warp that result in rendering a `500 Internal Server Error` are now also logged at the `error` level.\n\n\n### v0.1.4 (September 25, 2018)\n\n- **Features**:\n  - Add `warp::reply::with::headers(HeaderMap)` filter wrapper.\n  - Add `warp::cookie::optional()` to get an optional cookie value.\n  - Add `warp::path::full()` to be able to extract the full request path without affecting route matching.\n  - Add graceful shutdown support to the `Server`.\n  - Allow empty query strings to be treated as for `warp::query()`.\n\n### v0.1.3 (August 28, 2018)\n\n- **Features**:\n  - Add `warp::reject::forbidden()` to represent `403 Forbidden` responses.\n  - Add `Rejection::with(cause)` to customize rejection messages.\n- **Fixes**:\n  - Fix `warp::body::form` to allow charsets in the `content-type` header.\n\n### v0.1.2 (August 14, 2018)\n\n- **Features**:\n  - Implemented `Reply` for `Response<impl Into<hyper::Body>`, allowing streaming response bodies.\n  - Add `warp::body::stream()` filter to access the request body as an `impl Stream`.\n  - Add `warp::ws2()` as a more flexible websocket filter.\n    - This allows passing other extracted values to the upgrade callback, such as a value from a header or path.\n    - Deprecates `warp::ws()`, and `ws2()` will become `ws()` in 0.2.\n  - Add `warp::get2()`, `warp::post2()`, `warp::put2()`, and `warp::delete2()` as more standard method filters that are used via chaining instead of nesting.\n    - `get()`, `post()`, `put()`, and `delete()` are deprecated, and the new versions will become them in 0.2.\n  - Add `Filter::unify()` for when a filter returns `Either<T, T>`, converting the `Either` into the inner `T`, regardless of which variant it was.\n    - This requires that both sides of the `Either` be the same type.\n    - This can be useful when extracting a value that might be present in different places of the request.\n      \n      ```rust\n      // Allow `MyId` to be a path parameter or a header...\n      let id = warp::path::param::<MyId>()\n          .or(warp::header::<MyId>())\n          .unify();\n      \n      // A way of providing default values...\n      let dnt = warp::header::<bool>(\"dnt\")\n          .or(warp::any().map(|| true))\n          .unify();\n      ```\n  - Add `content-type` header automatically to replies from `file` and `dir` filters based on file extension.\n  - Add `warp::head()`, `warp::options()`, and `warp::patch()` as new Method filters.\n  - Try to use OS blocksize in `warp::fs` filters.\n- **Fixes**:\n  - Chaining filters that try to consume the request body will log that the body is already consumed, and return a `500 Internal Server Error` rejection.\n\n### v0.1.1 (August 7, 2018)\n\n- **Features**:\n  - Add `warp::query::raw()` filter to get query as a `String`.\n  - Add `Filter::recover()` to ease customizing of rejected responses.\n  - Add `warp::header::headers_clone()` filter to get a clone of request's `HeaderMap`.\n  - Add `warp::path::tail()` filter to get remaining \"tail\" of the request path.\n- **Fixes**:\n  - URL decode path segments in `warp::fs` filters.\n\n\n## v0.1.0 (August 1, 2018)\n\n- Initial release.\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[package]\nname = \"warp\"\nversion = \"0.4.2\"\ndescription = \"serve the web at warp speeds\"\nauthors = [\"Sean McArthur <sean@seanmonstar.com>\"]\nlicense = \"MIT\"\nreadme = \"README.md\"\ndocumentation = \"https://docs.rs/warp\"\nrepository = \"https://github.com/seanmonstar/warp\"\ncategories = [\"web-programming::http-server\"]\nkeywords = [\"warp\", \"server\", \"http\", \"hyper\"]\nautotests = true\nautoexamples = true\nedition = \"2021\"\n\ninclude = [\n    \"Cargo.toml\",\n    \"LICENSE\",\n    \"src/**/*\",\n]\n\n[package.metadata.docs.rs]\nall-features = true\n\n[dependencies]\nasync-compression = { version = \"0.4.5\", features = [\"tokio\"], optional = true }\nbytes = \"1.0\"\nfutures-util = { version = \"0.3\", default-features = false, features = [\"sink\"] }\nfutures-channel = { version = \"0.3.17\", features = [\"sink\"], optional = true }\nheaders = \"0.4\"\nhttp = \"1\"\nhttp-body = \"1\"\nhttp-body-util = \"0.1.2\"\nhyper = { version = \"1\", optional = true }\nhyper-util = { version = \"0.1.12\", features = [\"server\", \"server-graceful\", \"server-auto\", \"http1\", \"http2\", \"service\", \"tokio\"], optional = true }\nlog = \"0.4\"\nmime = \"0.3\"\nmime_guess = \"2.0.0\"\nmulter = { version = \"3\", optional = true }\nscoped-tls = \"1.0\"\nserde = \"1.0\"\nserde_json = \"1.0\"\nserde_urlencoded = \"0.7.1\"\ntokio = { version = \"1.0\", features = [\"io-util\", \"fs\", \"sync\", \"time\"] }\ntokio-util = { version = \"0.7.1\", features = [\"io\"] }\ntracing = { version = \"0.1.21\", default-features = false, features = [\"log\", \"std\"] }\ntower-service = \"0.3\"\ntokio-tungstenite = { version = \"0.28\", optional = true }\npercent-encoding = \"2.1\"\npin-project = \"1.0\"\n#tokio-rustls = { version = \"0.26\", default-features = false, features = [\"logging\", \"tls12\", \"ring\"], optional = true }\n#rustls-pemfile = { version = \"2.0\", optional = true }\n\n[dev-dependencies]\npretty_env_logger = \"0.5\"\ntracing-subscriber = { version = \"0.3\", features = [\"env-filter\"] }\ntracing-log = \"0.2\"\nserde_derive = \"1.0\"\nhandlebars = \"6.0\"\ntokio = { version = \"1.0\", features = [\"macros\", \"rt-multi-thread\", \"signal\"] }\ntokio-stream = \"0.1.1\"\n\n[features]\ndefault = []\nmultipart = [\"dep:multer\"]\nwebsocket = [\"dep:hyper\", \"dep:tokio-tungstenite\", \"hyper-util/tokio\"]\nserver = [\"dep:hyper\", \"dep:hyper-util\", \"tokio/net\"]\ntest = [\"server\", \"hyper/client\", \"hyper/http1\", \"dep:futures-channel\"]\n# tls might come back, uncertain\n#tls = [\"tokio-rustls\", \"rustls-pemfile\"]\n\n# Enable compression-related filters\ncompression = [\"compression-brotli\", \"compression-gzip\"]\ncompression-brotli = [\"async-compression/brotli\"]\ncompression-gzip = [\"async-compression/deflate\", \"async-compression/gzip\"]\n\n[profile.release]\ncodegen-units = 1\nincremental = false\n\n[profile.bench]\ncodegen-units = 1\nincremental = false\n\n\n[[example]]\nname = \"body\"\nrequired-features = [\"server\"]\n\n[[example]]\nname = \"compression\"\nrequired-features = [\"compression\", \"server\"]\n\n[[example]]\nname = \"dir\"\nrequired-features = [\"server\"]\n\n[[example]]\nname = \"file\"\nrequired-features = [\"server\"]\n\n[[example]]\nname = \"futures\"\nrequired-features = [\"server\"]\n\n[[example]]\nname = \"handlebars_template\"\nrequired-features = [\"server\"]\n\n[[example]]\nname = \"headers\"\nrequired-features = [\"server\"]\n\n[[example]]\nname = \"hello\"\nrequired-features = [\"server\"]\n\n[[example]]\nname = \"multipart\"\nrequired-features = [\"multipart\", \"server\"]\n\n[[example]]\nname = \"query_string\"\nrequired-features = [\"server\"]\n\n[[example]]\nname = \"rejections\"\nrequired-features = [\"server\"]\n\n[[example]]\nname = \"returning\"\nrequired-features = [\"server\"]\n\n[[example]]\nname = \"routing\"\nrequired-features = [\"server\"]\n\n[[example]]\nname = \"sse\"\nrequired-features = [\"server\"]\n\n[[example]]\nname = \"sse_chat\"\nrequired-features = [\"server\"]\n\n[[example]]\nname = \"todos\"\nrequired-features = [\"server\"]\n\n[[example]]\nname = \"tracing\"\nrequired-features = [\"server\"]\n\n[[example]]\nname = \"unix_socket\"\nrequired-features = [\"server\"]\n\n[[example]]\nname = \"websockets\"\nrequired-features = [\"websocket\", \"server\"]\n\n[[example]]\nname = \"websockets_chat\"\nrequired-features = [\"websocket\", \"server\"]\n\n[[test]]\nname = \"addr\"\nrequired-features = [\"test\"]\n\n[[test]]\nname = \"body\"\nrequired-features = [\"test\"]\n\n[[test]]\nname = \"cookie\"\nrequired-features = [\"test\"]\n\n[[test]]\nname = \"cors\"\nrequired-features = [\"test\"]\n\n[[test]]\nname = \"ext\"\nrequired-features = [\"test\"]\n\n[[test]]\nname = \"filter\"\nrequired-features = [\"test\"]\n\n[[test]]\nname = \"fs\"\nrequired-features = [\"test\"]\n\n[[test]]\nname = \"header\"\nrequired-features = [\"test\"]\n\n[[test]]\nname = \"host\"\nrequired-features = [\"test\"]\n\n[[test]]\nname = \"method\"\nrequired-features = [\"test\"]\n\n[[test]]\nname = \"multipart\"\nrequired-features = [\"multipart\", \"test\"]\n\n[[test]]\nname = \"path\"\nrequired-features = [\"test\"]\n\n[[test]]\nname = \"query\"\nrequired-features = [\"test\"]\n\n[[test]]\nname = \"redirect\"\nrequired-features = [\"test\"]\n\n[[test]]\nname = \"reply_with\"\nrequired-features = [\"test\"]\n\n[[test]]\nname = \"tracing\"\nrequired-features = [\"test\"]\n\n[[test]]\nname = \"ws\"\nrequired-features = [\"websocket\", \"test\"]\n\n[lints.rust]\nunexpected_cfgs = { level = \"warn\", check-cfg = ['cfg(feature, values(\"tls\"))'] }\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2018-2025 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\n"
  },
  {
    "path": "README.md",
    "content": "# warp\n\n[![crates.io](https://img.shields.io/crates/v/warp.svg)](https://crates.io/crates/warp)\n[![Released API docs](https://docs.rs/warp/badge.svg)](https://docs.rs/warp)\n[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)\n[![GHA Build Status](https://github.com/seanmonstar/warp/workflows/CI/badge.svg)](https://github.com/seanmonstar/warp/actions?query=workflow%3ACI)\n[![Discord chat][discord-badge]][discord-url]\n\nA super-easy, composable, web server framework for warp speeds.\n\nThe fundamental building block of `warp` is the `Filter`: they can be combined\nand composed to express rich requirements on requests.\n\nThanks to its `Filter` system, warp provides these out of the box:\n\n* Path routing and parameter extraction\n* Header requirements and extraction\n* Query string deserialization\n* JSON and Form bodies\n* Multipart form data\n* Static Files and Directories\n* Websockets\n* Access logging\n* Gzip, Deflate, and Brotli compression\n\nSince it builds on top of [hyper](https://hyper.rs), you automatically get:\n\n- HTTP/1\n- HTTP/2\n- Asynchronous\n- One of the fastest HTTP implementations\n- Tested and **correct**\n\n## Example\n\nAdd warp and Tokio to your dependencies:\n\n```toml\ntokio = { version = \"1\", features = [\"full\"] }\nwarp = { version = \"0.4\", features = [\"server\"] }\n```\n\nAnd then get started in your `main.rs`:\n\n```rust\nuse warp::Filter;\n\n#[tokio::main]\nasync fn main() {\n    // GET /hello/warp => 200 OK with body \"Hello, warp!\"\n    let hello = warp::path!(\"hello\" / String)\n        .map(|name| format!(\"Hello, {}!\", name));\n\n    warp::serve(hello)\n        .run(([127, 0, 0, 1], 3030))\n        .await;\n}\n```\n\nFor more information you can check the [docs](https://docs.rs/warp) or the [examples](https://github.com/seanmonstar/warp/tree/master/examples).\n\n[discord-badge]: https://img.shields.io/discord/500028886025895936.svg?logo=discord\n[discord-url]: https://discord.gg/RFsPjyt\n"
  },
  {
    "path": "examples/README.md",
    "content": "# Examples\n\nWelcome to the examples! These show off `warp`'s functionality and explain how to use it.\n\n## Getting Started\n\nTo get started, run `examples/hello.rs` with:\n\n```bash\n> cargo run --example hello\n```\n\nThis will start a simple \"hello world\" service running on your localhost port 3030.\n\nOpen another terminal and run:\n\n```bash\n> curl http://localhost:3030/hi\nHello, World!%\n```\n\nCongratulations, you have just run your first warp service!\n\nYou can run other examples with `cargo run --example [example name]`:\n\n- [`hello.rs`](./hello.rs) - Just a basic \"Hello World\" API\n- [`routing.rs`](./routing.rs) - Builds up a more complex set of routes and shows how to combine filters\n- [`body.rs`](./body.rs) - What's a good API without parsing data from the request body?\n- [`headers.rs`](./headers.rs) - Parsing data from the request headers\n- [`rejections.rs`](./rejections.rs) - Your APIs are obviously perfect, but for silly others who call them incorrectly you'll want to define errors for them\n- [`futures.rs`](./futures.rs) - Wait, wait! ... Or how to integrate futures into filters\n- [`todos.rs`](./todos.rs) - Putting this all together with a proper app\n\n## Further Use Cases\n\n### Serving HTML and Other Files\n\n- [`file.rs`](./file.rs) - Serving static files\n- [`dir.rs`](./dir.rs) - Or a whole directory of files\n- [`handlebars_template.rs`](./handlebars_template.rs) - Using Handlebars to fill in an HTML template\n\n### Websockets\n\nHooray! `warp` also includes built-in support for WebSockets\n\n- [`websockets.rs`](./websockets.rs) - Basic handling of a WebSocket upgrade\n- [`websockets_chat.rs`](./websockets_chat.rs) - Full WebSocket app\n\n### Server-Side Events\n\n- [`sse.rs`](./sse.rs) - Basic Server-Side Event\n- [`sse_chat.rs`](./sse_chat.rs) - Full SSE app\n\n### TLS\n\n- [`tls.rs`](./tls.rs) - can i haz security?\n\n### Debugging\n\n- [`tracing.rs`](./tracing.rs) - Warp has built-in support for rich diagnostics with [`tracing`](https://docs.rs/tracing)!\n\n## Custom HTTP Methods\n\n- [`custom_methods.rs`](./custom_methods.rs) - It is also possible to use Warp with custom HTTP methods.\n"
  },
  {
    "path": "examples/body.rs",
    "content": "#![deny(warnings)]\n\nuse serde_derive::{Deserialize, Serialize};\n\nuse warp::Filter;\n\n#[derive(Deserialize, Serialize)]\nstruct Employee {\n    name: String,\n    rate: u32,\n}\n\n#[tokio::main]\nasync fn main() {\n    pretty_env_logger::init();\n\n    // POST /employees/:rate  {\"name\":\"Sean\",\"rate\":2}\n    let promote = warp::post()\n        .and(warp::path(\"employees\"))\n        .and(warp::path::param::<u32>())\n        // Only accept bodies smaller than 16kb...\n        .and(warp::body::content_length_limit(1024 * 16))\n        .and(warp::body::json())\n        .map(|rate, mut employee: Employee| {\n            employee.rate = rate;\n            warp::reply::json(&employee)\n        });\n\n    warp::serve(promote).run(([127, 0, 0, 1], 3030)).await\n}\n"
  },
  {
    "path": "examples/compression.rs",
    "content": "#![deny(warnings)]\n\nuse warp::Filter;\n\n#[tokio::main]\nasync fn main() {\n    let file = warp::path(\"todos\").and(warp::fs::file(\"./examples/todos.rs\"));\n    // NOTE: You could double compress something by adding a compression\n    // filter here, a la\n    // ```\n    // let file = warp::path(\"todos\")\n    //     .and(warp::fs::file(\"./examples/todos.rs\"))\n    //     .with(warp::compression::brotli());\n    // ```\n    // This would result in a browser error, or downloading a file whose contents\n    // are compressed\n\n    let dir = warp::path(\"ws_chat\").and(warp::fs::file(\"./examples/websockets_chat.rs\"));\n\n    let file_and_dir = warp::get()\n        .and(file.or(dir))\n        .with(warp::compression::gzip());\n\n    let examples = warp::path(\"ex\")\n        .and(warp::fs::dir(\"./examples/\"))\n        .with(warp::compression::deflate());\n\n    // GET /todos => gzip -> toods.rs\n    // GET /ws_chat => gzip -> ws_chat.rs\n    // GET /ex/... => deflate -> ./examples/...\n    let routes = file_and_dir.or(examples);\n\n    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;\n}\n"
  },
  {
    "path": "examples/dir/another.html",
    "content": "<!DOCTYPE html>\n<html>\n    <head>\n        <title>dir/another.html</title>\n    </head>\n    <body>\n        <h1>Welcome to Another Page</h1>\n        <a href=\"/\">back</a>\n    </body>\n</html>"
  },
  {
    "path": "examples/dir/index.html",
    "content": "<!DOCTYPE html>\n<html>\n    <head>\n        <title>dir/index.html</title>\n    </head>\n    <body>\n        <h1>Welcome to Dir</h1>\n        <a href=\"/another.html\">another page</a>\n    </body>\n</html>"
  },
  {
    "path": "examples/dir.rs",
    "content": "#![deny(warnings)]\n\n#[tokio::main]\nasync fn main() {\n    pretty_env_logger::init();\n\n    warp::serve(warp::fs::dir(\"examples/dir\"))\n        .run(([127, 0, 0, 1], 3030))\n        .await;\n}\n"
  },
  {
    "path": "examples/file.rs",
    "content": "#![deny(warnings)]\n\nuse warp::Filter;\n\n#[tokio::main]\nasync fn main() {\n    pretty_env_logger::init();\n\n    let readme = warp::get()\n        .and(warp::path::end())\n        .and(warp::fs::file(\"./README.md\"));\n\n    // dir already requires GET...\n    let examples = warp::path(\"ex\").and(warp::fs::dir(\"./examples/\"));\n\n    // GET / => README.md\n    // GET /ex/... => ./examples/..\n    let routes = readme.or(examples);\n\n    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;\n}\n"
  },
  {
    "path": "examples/futures.rs",
    "content": "#![deny(warnings)]\n\nuse std::convert::Infallible;\nuse std::str::FromStr;\nuse std::time::Duration;\nuse warp::Filter;\n\n#[tokio::main]\nasync fn main() {\n    // Match `/:Seconds`...\n    let routes = warp::path::param()\n        // and_then create a `Future` that will simply wait N seconds...\n        .and_then(sleepy);\n\n    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;\n}\n\nasync fn sleepy(Seconds(seconds): Seconds) -> Result<impl warp::Reply, Infallible> {\n    tokio::time::sleep(Duration::from_secs(seconds)).await;\n    Ok(format!(\"I waited {} seconds!\", seconds))\n}\n\n/// A newtype to enforce our maximum allowed seconds.\nstruct Seconds(u64);\n\nimpl FromStr for Seconds {\n    type Err = ();\n    fn from_str(src: &str) -> Result<Self, Self::Err> {\n        src.parse::<u64>().map_err(|_| ()).and_then(|num| {\n            if num <= 5 {\n                Ok(Seconds(num))\n            } else {\n                Err(())\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "examples/handlebars_template.rs",
    "content": "#![deny(warnings)]\nuse std::sync::Arc;\n\nuse handlebars::Handlebars;\nuse serde::Serialize;\nuse serde_json::json;\nuse warp::Filter;\n\nstruct WithTemplate<T: Serialize> {\n    name: &'static str,\n    value: T,\n}\n\nfn render<T>(template: WithTemplate<T>, hbs: Arc<Handlebars<'_>>) -> impl warp::Reply\nwhere\n    T: Serialize,\n{\n    let render = hbs\n        .render(template.name, &template.value)\n        .unwrap_or_else(|err| err.to_string());\n    warp::reply::html(render)\n}\n\n#[tokio::main]\nasync fn main() {\n    let template = \"<!DOCTYPE html>\n                    <html>\n                      <head>\n                        <title>Warp Handlebars template example</title>\n                      </head>\n                      <body>\n                        <h1>Hello {{user}}!</h1>\n                      </body>\n                    </html>\";\n\n    let mut hb = Handlebars::new();\n    // register the template\n    hb.register_template_string(\"template.html\", template)\n        .unwrap();\n\n    // Turn Handlebars instance into a Filter so we can combine it\n    // easily with others...\n    let hb = Arc::new(hb);\n\n    // Create a reusable closure to render template\n    let handlebars = move |with_template| render(with_template, hb.clone());\n\n    //GET /\n    let route = warp::get()\n        .and(warp::path::end())\n        .map(|| WithTemplate {\n            name: \"template.html\",\n            value: json!({\"user\" : \"Warp\"}),\n        })\n        .map(handlebars);\n\n    warp::serve(route).run(([127, 0, 0, 1], 3030)).await;\n}\n"
  },
  {
    "path": "examples/headers.rs",
    "content": "#![deny(warnings)]\nuse std::net::SocketAddr;\nuse warp::Filter;\n\n/// Create a server that requires header conditions:\n///\n/// - `Host` is a `SocketAddr`\n/// - `Accept` is exactly `*/*`\n///\n/// If these conditions don't match, a 404 is returned.\n#[tokio::main]\nasync fn main() {\n    pretty_env_logger::init();\n\n    // For this example, we assume no DNS was used,\n    // so the Host header should be an address.\n    let host = warp::header::<SocketAddr>(\"host\");\n\n    // Match when we get `accept: */*` exactly.\n    let accept_stars = warp::header::exact(\"accept\", \"*/*\");\n\n    let routes = host\n        .and(accept_stars)\n        .map(|addr| format!(\"accepting stars on {}\", addr));\n\n    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;\n}\n"
  },
  {
    "path": "examples/hello.rs",
    "content": "#![deny(warnings)]\nuse warp::Filter;\n\n#[tokio::main]\nasync fn main() {\n    // Match any request and return hello world!\n    let routes = warp::any().map(|| \"Hello, World!\");\n\n    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;\n}\n"
  },
  {
    "path": "examples/multipart.rs",
    "content": "use bytes::BufMut;\nuse futures_util::TryStreamExt;\nuse warp::multipart::FormData;\nuse warp::Filter;\n\n#[tokio::main]\nasync fn main() {\n    // Running curl -F file=@.gitignore 'localhost:3030/' should print [(\"file\", \".gitignore\", \"\\n/target\\n**/*.rs.bk\\nCargo.lock\\n.idea/\\nwarp.iml\\n\")]\n    let route = warp::multipart::form().and_then(|form: FormData| async move {\n        let field_names: Vec<_> = form\n            .and_then(|mut field| async move {\n                let mut bytes: Vec<u8> = Vec::new();\n\n                // field.data() only returns a piece of the content, you should call over it until it replies None\n                while let Some(content) = field.data().await {\n                    let content = content.unwrap();\n                    bytes.put(content);\n                }\n                Ok((\n                    field.name().to_string(),\n                    field.filename().unwrap().to_string(),\n                    String::from_utf8_lossy(&*bytes).to_string(),\n                ))\n            })\n            .try_collect()\n            .await\n            .unwrap();\n\n        Ok::<_, warp::Rejection>(format!(\"{:?}\", field_names))\n    });\n    warp::serve(route).run(([127, 0, 0, 1], 3030)).await;\n}\n"
  },
  {
    "path": "examples/query_string.rs",
    "content": "use serde_derive::{Deserialize, Serialize};\nuse std::collections::HashMap;\nuse warp::{\n    http::{Response, StatusCode},\n    Filter,\n};\n\n#[derive(Deserialize, Serialize)]\nstruct MyObject {\n    key1: String,\n    key2: u32,\n}\n\n#[tokio::main]\nasync fn main() {\n    pretty_env_logger::init();\n\n    // get /example1?key=value\n    // demonstrates an optional parameter.\n    let example1 = warp::get()\n        .and(warp::path(\"example1\"))\n        .and(warp::query::<HashMap<String, String>>())\n        .map(|p: HashMap<String, String>| match p.get(\"key\") {\n            Some(key) => Response::builder().body(format!(\"key = {}\", key)),\n            None => Response::builder().body(String::from(\"No \\\"key\\\" param in query.\")),\n        });\n\n    // get /example2?key1=value&key2=42\n    // uses the query string to populate a custom object\n    let example2 = warp::get()\n        .and(warp::path(\"example2\"))\n        .and(warp::query::<MyObject>())\n        .map(|p: MyObject| {\n            Response::builder().body(format!(\"key1 = {}, key2 = {}\", p.key1, p.key2))\n        });\n\n    let opt_query = warp::query::<MyObject>()\n        .map(Some)\n        .or_else(|_| async { Ok::<(Option<MyObject>,), std::convert::Infallible>((None,)) });\n\n    // get /example3?key1=value&key2=42\n    // builds on example2 but adds custom error handling\n    let example3 =\n        warp::get()\n            .and(warp::path(\"example3\"))\n            .and(opt_query)\n            .map(|p: Option<MyObject>| match p {\n                Some(obj) => {\n                    Response::builder().body(format!(\"key1 = {}, key2 = {}\", obj.key1, obj.key2))\n                }\n                None => Response::builder()\n                    .status(StatusCode::BAD_REQUEST)\n                    .body(String::from(\"Failed to decode query param.\")),\n            });\n\n    warp::serve(example1.or(example2).or(example3))\n        .run(([127, 0, 0, 1], 3030))\n        .await\n}\n"
  },
  {
    "path": "examples/rejections.rs",
    "content": "#![deny(warnings)]\n\nuse std::convert::Infallible;\nuse std::error::Error;\nuse std::num::NonZeroU16;\n\nuse serde_derive::{Deserialize, Serialize};\nuse warp::http::StatusCode;\nuse warp::{reject, Filter, Rejection, Reply};\n\n/// Rejections represent cases where a filter should not continue processing\n/// the request, but a different filter *could* process it.\n#[tokio::main]\nasync fn main() {\n    let math = warp::path!(\"math\" / u16);\n    let div_with_header = math\n        .and(warp::get())\n        .and(div_by())\n        .map(|num: u16, denom: NonZeroU16| {\n            warp::reply::json(&Math {\n                op: format!(\"{} / {}\", num, denom),\n                output: num / denom.get(),\n            })\n        });\n\n    let div_with_body =\n        math.and(warp::post())\n            .and(warp::body::json())\n            .map(|num: u16, body: DenomRequest| {\n                warp::reply::json(&Math {\n                    op: format!(\"{} / {}\", num, body.denom),\n                    output: num / body.denom.get(),\n                })\n            });\n\n    let routes = div_with_header.or(div_with_body).recover(handle_rejection);\n\n    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;\n}\n\n/// Extract a denominator from a \"div-by\" header, or reject with DivideByZero.\nfn div_by() -> impl Filter<Extract = (NonZeroU16,), Error = Rejection> + Copy {\n    warp::header::<u16>(\"div-by\").and_then(|n: u16| async move {\n        if let Some(denom) = NonZeroU16::new(n) {\n            Ok(denom)\n        } else {\n            Err(reject::custom(DivideByZero))\n        }\n    })\n}\n\n#[derive(Deserialize)]\nstruct DenomRequest {\n    pub denom: NonZeroU16,\n}\n\n#[derive(Debug)]\nstruct DivideByZero;\n\nimpl reject::Reject for DivideByZero {}\n\n// JSON replies\n\n/// A successful math operation.\n#[derive(Serialize)]\nstruct Math {\n    op: String,\n    output: u16,\n}\n\n/// An API error serializable to JSON.\n#[derive(Serialize)]\nstruct ErrorMessage {\n    code: u16,\n    message: String,\n}\n\n// This function receives a `Rejection` and tries to return a custom\n// value, otherwise simply passes the rejection along.\nasync fn handle_rejection(err: Rejection) -> Result<impl Reply, Infallible> {\n    let code;\n    let message;\n\n    if err.is_not_found() {\n        code = StatusCode::NOT_FOUND;\n        message = \"NOT_FOUND\";\n    } else if let Some(DivideByZero) = err.find() {\n        code = StatusCode::BAD_REQUEST;\n        message = \"DIVIDE_BY_ZERO\";\n    } else if let Some(e) = err.find::<warp::filters::body::BodyDeserializeError>() {\n        // This error happens if the body could not be deserialized correctly\n        // We can use the cause to analyze the error and customize the error message\n        message = match e.source() {\n            Some(cause) => {\n                if cause.to_string().contains(\"denom\") {\n                    \"FIELD_ERROR: denom\"\n                } else {\n                    \"BAD_REQUEST\"\n                }\n            }\n            None => \"BAD_REQUEST\",\n        };\n        code = StatusCode::BAD_REQUEST;\n    } else if let Some(_) = err.find::<warp::reject::MethodNotAllowed>() {\n        // We can handle a specific error, here METHOD_NOT_ALLOWED,\n        // and render it however we want\n        code = StatusCode::METHOD_NOT_ALLOWED;\n        message = \"METHOD_NOT_ALLOWED\";\n    } else {\n        // We should have expected this... Just log and say its a 500\n        eprintln!(\"unhandled rejection: {:?}\", err);\n        code = StatusCode::INTERNAL_SERVER_ERROR;\n        message = \"UNHANDLED_REJECTION\";\n    }\n\n    let json = warp::reply::json(&ErrorMessage {\n        code: code.as_u16(),\n        message: message.into(),\n    });\n\n    Ok(warp::reply::with_status(json, code))\n}\n"
  },
  {
    "path": "examples/returning.rs",
    "content": "use warp::{filters::BoxedFilter, Filter, Rejection, Reply};\n\n// Option 1: BoxedFilter\n// Note that this may be useful for shortening compile times when you are composing many filters.\n// Boxing the filters will use dynamic dispatch and speed up compilation while\n// making it slightly slower at runtime.\npub fn assets_filter() -> BoxedFilter<(impl Reply,)> {\n    warp::path(\"assets\").and(warp::fs::dir(\"./assets\")).boxed()\n}\n\n// Option 2: impl Filter + Clone\npub fn index_filter() -> impl Filter<Extract = (&'static str,), Error = Rejection> + Clone {\n    warp::path::end().map(|| \"Index page\")\n}\n\n#[tokio::main]\nasync fn main() {\n    let routes = index_filter().or(assets_filter());\n    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;\n}\n"
  },
  {
    "path": "examples/routing.rs",
    "content": "#![deny(warnings)]\n\nuse warp::Filter;\n\n#[tokio::main]\nasync fn main() {\n    pretty_env_logger::init();\n\n    // We'll start simple, and gradually show how you combine these powers\n    // into super powers!\n\n    // GET /\n    let hello_world = warp::path::end().map(|| \"Hello, World at root!\");\n\n    // GET /hi\n    let hi = warp::path(\"hi\").map(|| \"Hello, World!\");\n\n    // How about multiple segments? First, we could use the `path!` macro:\n    //\n    // GET /hello/from/warp\n    let hello_from_warp = warp::path!(\"hello\" / \"from\" / \"warp\").map(|| \"Hello from warp!\");\n\n    // Fine, but how do I handle parameters in paths?\n    //\n    // GET /sum/:u32/:u32\n    let sum = warp::path!(\"sum\" / u32 / u32).map(|a, b| format!(\"{} + {} = {}\", a, b, a + b));\n\n    // Any type that implements FromStr can be used, and in any order:\n    //\n    // GET /:u16/times/:u16\n    let times =\n        warp::path!(u16 / \"times\" / u16).map(|a, b| format!(\"{} times {} = {}\", a, b, a * b));\n\n    // Oh shoot, those math routes should be mounted at a different path,\n    // is that possible? Yep.\n    //\n    // GET /math/sum/:u32/:u32\n    // GET /math/:u16/times/:u16\n    let math = warp::path(\"math\");\n    let _sum = math.and(sum);\n    let _times = math.and(times);\n\n    // What! And? What's that do?\n    //\n    // It combines the filters in a sort of \"this and then that\" order. In\n    // fact, it's exactly what the `path!` macro has been doing internally.\n    //\n    // GET /bye/:string\n    let bye = warp::path(\"bye\")\n        .and(warp::path::param())\n        .map(|name: String| format!(\"Good bye, {}!\", name));\n\n    // Ah, can filters do things besides `and`?\n    //\n    // Why, yes they can! They can also `or`! As you might expect, `or` creates\n    // a \"this or else that\" chain of filters. If the first doesn't succeed,\n    // then it tries the other.\n    //\n    // So, those `math` routes could have been mounted all as one, with `or`.\n    //\n    // GET /math/sum/:u32/:u32\n    // GET /math/:u16/times/:u16\n    let math = warp::path(\"math\").and(sum.or(times));\n\n    // We can use the end() filter to match a shorter path\n    let help = warp::path(\"math\")\n        // Careful! Omitting the following line would make this filter match\n        // requests to /math/sum/:u32/:u32 and /math/:u16/times/:u16\n        .and(warp::path::end())\n        .map(|| \"This is the Math API. Try calling /math/sum/:u32/:u32 or /math/:u16/times/:u16\");\n    let math = help.or(math);\n\n    // Let's let people know that the `sum` and `times` routes are under `math`.\n    let sum = sum.map(|output| format!(\"(This route has moved to /math/sum/:u16/:u16) {}\", output));\n    let times =\n        times.map(|output| format!(\"(This route has moved to /math/:u16/times/:u16) {}\", output));\n\n    // It turns out, using `or` is how you combine everything together into\n    // a single API. (We also actually haven't been enforcing that the\n    // method is GET, so we'll do that too!)\n    //\n    // GET /\n    // GET /hi\n    // GET /hello/from/warp\n    // GET /bye/:string\n    // GET /math/sum/:u32/:u32\n    // GET /math/:u16/times/:u16\n\n    let routes = warp::get().and(\n        hello_world\n            .or(hi)\n            .or(hello_from_warp)\n            .or(bye)\n            .or(math)\n            .or(sum)\n            .or(times),\n    );\n\n    // Note that composing filters for many routes may increase compile times (because it uses a lot of generics).\n    // If you wish to use dynamic dispatch instead and speed up compile times while\n    // making it slightly slower at runtime, you can use Filter::boxed().\n\n    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;\n}\n"
  },
  {
    "path": "examples/sse.rs",
    "content": "use futures_util::StreamExt;\nuse std::convert::Infallible;\nuse std::time::Duration;\nuse tokio::time::interval;\nuse tokio_stream::wrappers::IntervalStream;\nuse warp::{sse::Event, Filter};\n\n// create server-sent event\nfn sse_counter(counter: u64) -> Result<Event, Infallible> {\n    Ok(warp::sse::Event::default().data(counter.to_string()))\n}\n\n#[tokio::main]\nasync fn main() {\n    pretty_env_logger::init();\n\n    let routes = warp::path(\"ticks\").and(warp::get()).map(|| {\n        let mut counter: u64 = 0;\n        // create server event source\n        let interval = interval(Duration::from_secs(1));\n        let stream = IntervalStream::new(interval);\n        let event_stream = stream.map(move |_| {\n            counter += 1;\n            sse_counter(counter)\n        });\n        // reply using server-sent events\n        warp::sse::reply(event_stream)\n    });\n\n    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;\n}\n"
  },
  {
    "path": "examples/sse_chat.rs",
    "content": "use futures_util::{Stream, StreamExt};\nuse std::collections::HashMap;\nuse std::sync::{\n    atomic::{AtomicUsize, Ordering},\n    Arc, Mutex,\n};\nuse tokio::sync::mpsc;\nuse tokio_stream::wrappers::UnboundedReceiverStream;\nuse warp::{sse::Event, Filter};\n\n#[tokio::main]\nasync fn main() {\n    pretty_env_logger::init();\n\n    // Keep track of all connected users, key is usize, value\n    // is an event stream sender.\n    let users = Arc::new(Mutex::new(HashMap::new()));\n    // Turn our \"state\" into a new Filter...\n    let users = warp::any().map(move || users.clone());\n\n    // POST /chat -> send message\n    let chat_send = warp::path(\"chat\")\n        .and(warp::post())\n        .and(warp::path::param::<usize>())\n        .and(warp::body::content_length_limit(500))\n        .and(\n            warp::body::bytes().and_then(|body: bytes::Bytes| async move {\n                std::str::from_utf8(&body)\n                    .map(String::from)\n                    .map_err(|_e| warp::reject::custom(NotUtf8))\n            }),\n        )\n        .and(users.clone())\n        .map(|my_id, msg, users| {\n            user_message(my_id, msg, &users);\n            warp::reply()\n        });\n\n    // GET /chat -> messages stream\n    let chat_recv = warp::path(\"chat\").and(warp::get()).and(users).map(|users| {\n        // reply using server-sent events\n        let stream = user_connected(users);\n        warp::sse::reply(warp::sse::keep_alive().stream(stream))\n    });\n\n    // GET / -> index html\n    let index = warp::path::end().map(|| {\n        warp::http::Response::builder()\n            .header(\"content-type\", \"text/html; charset=utf-8\")\n            .body(INDEX_HTML)\n    });\n\n    let routes = index.or(chat_recv).or(chat_send);\n\n    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;\n}\n\n/// Our global unique user id counter.\nstatic NEXT_USER_ID: AtomicUsize = AtomicUsize::new(1);\n\n/// Message variants.\n#[derive(Debug)]\nenum Message {\n    UserId(usize),\n    Reply(String),\n}\n\n#[derive(Debug)]\nstruct NotUtf8;\nimpl warp::reject::Reject for NotUtf8 {}\n\n/// Our state of currently connected users.\n///\n/// - Key is their id\n/// - Value is a sender of `Message`\ntype Users = Arc<Mutex<HashMap<usize, mpsc::UnboundedSender<Message>>>>;\n\nfn user_connected(users: Users) -> impl Stream<Item = Result<Event, warp::Error>> + Send + 'static {\n    // Use a counter to assign a new unique ID for this user.\n    let my_id = NEXT_USER_ID.fetch_add(1, Ordering::Relaxed);\n\n    eprintln!(\"new chat user: {}\", my_id);\n\n    // Use an unbounded channel to handle buffering and flushing of messages\n    // to the event source...\n    let (tx, rx) = mpsc::unbounded_channel();\n    let rx = UnboundedReceiverStream::new(rx);\n\n    tx.send(Message::UserId(my_id))\n        // rx is right above, so this cannot fail\n        .unwrap();\n\n    // Save the sender in our list of connected users.\n    users.lock().unwrap().insert(my_id, tx);\n\n    // Convert messages into Server-Sent Events and return resulting stream.\n    rx.map(|msg| match msg {\n        Message::UserId(my_id) => Ok(Event::default().event(\"user\").data(my_id.to_string())),\n        Message::Reply(reply) => Ok(Event::default().data(reply)),\n    })\n}\n\nfn user_message(my_id: usize, msg: String, users: &Users) {\n    let new_msg = format!(\"<User#{}>: {}\", my_id, msg);\n\n    // New message from this user, send it to everyone else (except same uid)...\n    //\n    // We use `retain` instead of a for loop so that we can reap any user that\n    // appears to have disconnected.\n    users.lock().unwrap().retain(|uid, tx| {\n        if my_id == *uid {\n            // don't send to same user, but do retain\n            true\n        } else {\n            // If not `is_ok`, the SSE stream is gone, and so don't retain\n            tx.send(Message::Reply(new_msg.clone())).is_ok()\n        }\n    });\n}\n\nstatic INDEX_HTML: &str = r#\"\n<!DOCTYPE html>\n<html>\n    <head>\n        <title>Warp Chat</title>\n    </head>\n    <body>\n        <h1>warp chat</h1>\n        <div id=\"chat\">\n            <p><em>Connecting...</em></p>\n        </div>\n        <input type=\"text\" id=\"text\" />\n        <button type=\"button\" id=\"send\">Send</button>\n        <script type=\"text/javascript\">\n        var uri = 'http://' + location.host + '/chat';\n        var sse = new EventSource(uri);\n        function message(data) {\n            var line = document.createElement('p');\n            line.innerText = data;\n            chat.appendChild(line);\n        }\n        sse.onopen = function() {\n            chat.innerHTML = \"<p><em>Connected!</em></p>\";\n        }\n        var user_id;\n        sse.addEventListener(\"user\", function(msg) {\n            user_id = msg.data;\n        });\n        sse.onmessage = function(msg) {\n            message(msg.data);\n        };\n        send.onclick = function() {\n            var msg = text.value;\n            var xhr = new XMLHttpRequest();\n            xhr.open(\"POST\", uri + '/' + user_id, true);\n            xhr.send(msg);\n            text.value = '';\n            message('<You>: ' + msg);\n        };\n        </script>\n    </body>\n</html>\n\"#;\n"
  },
  {
    "path": "examples/tls/cert.ecc.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIICGjCCAb+gAwIBAgIUEbF3/5NuJeGvIywbwta91AkJxTgwCgYIKoZIzj0EAwIw\nYjELMAkGA1UEBhMCREUxEDAOBgNVBAgMB0dlcm1hbnkxEDAOBgNVBAcMB0xlaXB6\naWcxEjAQBgNVBAMMCWxvY2FsLmRldjEbMBkGCSqGSIb3DQEJARYMaGlAbG9jYWwu\nZGV2MB4XDTI0MDcyMzA3MDMzOFoXDTI3MDcyMzA3MDMzOFowYjELMAkGA1UEBhMC\nREUxEDAOBgNVBAgMB0dlcm1hbnkxEDAOBgNVBAcMB0xlaXB6aWcxEjAQBgNVBAMM\nCWxvY2FsLmRldjEbMBkGCSqGSIb3DQEJARYMaGlAbG9jYWwuZGV2MFkwEwYHKoZI\nzj0CAQYIKoZIzj0DAQcDQgAE2UeBetF/oh43g+pMkmX15YzXJA29tkGEO+k7OBhW\nFpHQ7LVOsnocchEfjGVrJlJ0xPxst5p6UpjM6EgX6CkZh6NTMFEwHQYDVR0OBBYE\nFFERjkqZLloI4V6XcrsutHi0oiwtMB8GA1UdIwQYMBaAFFERjkqZLloI4V6Xcrsu\ntHi0oiwtMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDSQAwRgIhAM3fWlv0\n5OW660apTKBgNxtQQ/JW4mdeuqBuI1+Jea6DAiEAhb1Kpcksg1iyMLJ4uMQvUePY\nsmRQQ67YgoLE+W5JAuw=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "examples/tls/cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEADCCAmigAwIBAgICAcgwDQYJKoZIhvcNAQELBQAwLDEqMCgGA1UEAwwhcG9u\neXRvd24gUlNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTE2MDgxMzE2MDcwNFoX\nDTIyMDIwMzE2MDcwNFowGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wggEiMA0G\nCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpVhh1/FNP2qvWenbZSghari/UThwe\ndynfnHG7gc3JmygkEdErWBO/CHzHgsx7biVE5b8sZYNEDKFojyoPHGWK2bQM/FTy\nniJCgNCLdn6hUqqxLAml3cxGW77hAWu94THDGB1qFe+eFiAUnDmob8gNZtAzT6Ky\nb/JGJdrEU0wj+Rd7wUb4kpLInNH/Jc+oz2ii2AjNbGOZXnRz7h7Kv3sO9vABByYe\nLcCj3qnhejHMqVhbAT1MD6zQ2+YKBjE52MsQKU/xhUpu9KkUyLh0cxkh3zrFiKh4\nVuvtc+n7aeOv2jJmOl1dr0XLlSHBlmoKqH6dCTSbddQLmlK7dms8vE01AgMBAAGj\ngb4wgbswDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBsAwHQYDVR0OBBYEFMeUzGYV\nbXwJNQVbY1+A8YXYZY8pMEIGA1UdIwQ7MDmAFJvEsUi7+D8vp8xcWvnEdVBGkpoW\noR6kHDAaMRgwFgYDVQQDDA9wb255dG93biBSU0EgQ0GCAXswOwYDVR0RBDQwMoIO\ndGVzdHNlcnZlci5jb22CFXNlY29uZC50ZXN0c2VydmVyLmNvbYIJbG9jYWxob3N0\nMA0GCSqGSIb3DQEBCwUAA4IBgQBsk5ivAaRAcNgjc7LEiWXFkMg703AqDDNx7kB1\nRDgLalLvrjOfOp2jsDfST7N1tKLBSQ9bMw9X4Jve+j7XXRUthcwuoYTeeo+Cy0/T\n1Q78ctoX74E2nB958zwmtRykGrgE/6JAJDwGcgpY9kBPycGxTlCN926uGxHsDwVs\n98cL6ZXptMLTR6T2XP36dAJZuOICSqmCSbFR8knc/gjUO36rXTxhwci8iDbmEVaf\nBHpgBXGU5+SQ+QM++v6bHGf4LNQC5NZ4e4xvGax8ioYu/BRsB/T3Lx+RlItz4zdU\nXuxCNcm3nhQV2ZHquRdbSdoyIxV5kJXel4wCmOhWIq7A2OBKdu5fQzIAzzLi65EN\nRPAKsKB4h7hGgvciZQ7dsMrlGw0DLdJ6UrFyiR5Io7dXYT/+JP91lP5xsl6Lhg9O\nFgALt7GSYRm2cZdgi9pO9rRr83Br1VjQT1vHz6yoZMXSqc4A2zcN2a2ZVq//rHvc\nFZygs8miAhWPzqnpmgTj1cPiU1M=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "examples/tls/key.ecc",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIPwp3LAnLEyWe2lLz66Y3QCCJ/BEMJheTM0shZnnSw6toAoGCCqGSM49\nAwEHoUQDQgAE2UeBetF/oh43g+pMkmX15YzXJA29tkGEO+k7OBhWFpHQ7LVOsnoc\nchEfjGVrJlJ0xPxst5p6UpjM6EgX6CkZhw==\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "examples/tls/key.rsa",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAqVYYdfxTT9qr1np22UoIWq4v1E4cHncp35xxu4HNyZsoJBHR\nK1gTvwh8x4LMe24lROW/LGWDRAyhaI8qDxxlitm0DPxU8p4iQoDQi3Z+oVKqsSwJ\npd3MRlu+4QFrveExwxgdahXvnhYgFJw5qG/IDWbQM0+ism/yRiXaxFNMI/kXe8FG\n+JKSyJzR/yXPqM9ootgIzWxjmV50c+4eyr97DvbwAQcmHi3Ao96p4XoxzKlYWwE9\nTA+s0NvmCgYxOdjLEClP8YVKbvSpFMi4dHMZId86xYioeFbr7XPp+2njr9oyZjpd\nXa9Fy5UhwZZqCqh+nQk0m3XUC5pSu3ZrPLxNNQIDAQABAoIBAFKtZJgGsK6md4vq\nkyiYSufrcBLaaEQ/rkQtYCJKyC0NAlZKFLRy9oEpJbNLm4cQSkYPXn3Qunx5Jj2k\n2MYz+SgIDy7f7KHgr52Ew020dzNQ52JFvBgt6NTZaqL1TKOS1fcJSSNIvouTBerK\nNCSXHzfb4P+MfEVe/w1c4ilE+kH9SzdEo2jK/sRbzHIY8TX0JbmQ4SCLLayr22YG\nusIxtIYcWt3MMP/G2luRnYzzBCje5MXdpAhlHLi4TB6x4h5PmBKYc57uOVNngKLd\nYyrQKcszW4Nx5v0a4HG3A5EtUXNCco1+5asXOg2lYphQYVh2R+1wgu5WiDjDVu+6\nEYgjFSkCgYEA0NBk6FDoxE/4L/4iJ4zIhu9BptN8Je/uS5c6wRejNC/VqQyw7SHb\nhRFNrXPvq5Y+2bI/DxtdzZLKAMXOMjDjj0XEgfOIn2aveOo3uE7zf1i+njxwQhPu\nuSYA9AlBZiKGr2PCYSDPnViHOspVJjxRuAgyWM1Qf+CTC0D95aj0oz8CgYEAz5n4\nCb3/WfUHxMJLljJ7PlVmlQpF5Hk3AOR9+vtqTtdxRjuxW6DH2uAHBDdC3OgppUN4\nCFj55kzc2HUuiHtmPtx8mK6G+otT7Lww+nLSFL4PvZ6CYxqcio5MPnoYd+pCxrXY\nJFo2W7e4FkBOxb5PF5So5plg+d0z/QiA7aFP1osCgYEAtgi1rwC5qkm8prn4tFm6\nhkcVCIXc+IWNS0Bu693bXKdGr7RsmIynff1zpf4ntYGpEMaeymClCY0ppDrMYlzU\nRBYiFNdlBvDRj6s/H+FTzHRk2DT/99rAhY9nzVY0OQFoQIXK8jlURGrkmI/CYy66\nXqBmo5t4zcHM7kaeEBOWEKkCgYAYnO6VaRtPNQfYwhhoFFAcUc+5t+AVeHGW/4AY\nM5qlAlIBu64JaQSI5KqwS0T4H+ZgG6Gti68FKPO+DhaYQ9kZdtam23pRVhd7J8y+\nxMI3h1kiaBqZWVxZ6QkNFzizbui/2mtn0/JB6YQ/zxwHwcpqx0tHG8Qtm5ZAV7PB\neLCYhQKBgQDALJxU/6hMTdytEU5CLOBSMby45YD/RrfQrl2gl/vA0etPrto4RkVq\nUrkDO/9W4mZORClN3knxEFSTlYi8YOboxdlynpFfhcs82wFChs+Ydp1eEsVHAqtu\nT+uzn0sroycBiBfVB949LExnzGDFUkhG0i2c2InarQYLTsIyHCIDEA==\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "examples/tls.rs",
    "content": "#![deny(warnings)]\n\n// Don't copy this `cfg`, it's only needed because this file is within\n// the warp repository.\n// Instead, specify the \"tls\" feature in your warp dependency declaration.\n#[cfg(feature = \"tls\")]\n#[tokio::main]\nasync fn main() {\n    use warp::Filter;\n\n    // Match any request and return hello world!\n    let routes = warp::any().map(|| \"Hello, World!\");\n\n    warp::serve(routes)\n        .tls()\n        // RSA\n        .cert_path(\"examples/tls/cert.pem\")\n        .key_path(\"examples/tls/key.rsa\")\n        // ECC\n        // .cert_path(\"examples/tls/cert.ecc.pem\")\n        // .key_path(\"examples/tls/key.ecc\")\n        .run(([127, 0, 0, 1], 3030))\n        .await;\n}\n\n#[cfg(not(feature = \"tls\"))]\nfn main() {\n    eprintln!(\"Requires the `tls` feature.\");\n}\n"
  },
  {
    "path": "examples/todos.rs",
    "content": "#![deny(warnings)]\n\nuse std::env;\nuse warp::Filter;\n\n/// Provides a RESTful web server managing some Todos.\n///\n/// API will be:\n///\n/// - `GET /todos`: return a JSON list of Todos.\n/// - `POST /todos`: create a new Todo.\n/// - `PUT /todos/:id`: update a specific Todo.\n/// - `DELETE /todos/:id`: delete a specific Todo.\n#[tokio::main]\nasync fn main() {\n    if env::var_os(\"RUST_LOG\").is_none() {\n        // Set `RUST_LOG=todos=debug` to see debug logs,\n        // this only shows access logs.\n        env::set_var(\"RUST_LOG\", \"todos=info\");\n    }\n    pretty_env_logger::init();\n\n    let db = models::blank_db();\n\n    let api = filters::todos(db);\n\n    // View access logs by setting `RUST_LOG=todos`.\n    let routes = api.with(warp::log(\"todos\"));\n    // Start up the server...\n    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;\n}\n\nmod filters {\n    use super::handlers;\n    use super::models::{Db, ListOptions, Todo};\n    use warp::Filter;\n\n    /// The 4 TODOs filters combined.\n    pub fn todos(\n        db: Db,\n    ) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {\n        todos_list(db.clone())\n            .or(todos_create(db.clone()))\n            .or(todos_update(db.clone()))\n            .or(todos_delete(db))\n    }\n\n    /// GET /todos?offset=3&limit=5\n    pub fn todos_list(\n        db: Db,\n    ) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {\n        warp::path!(\"todos\")\n            .and(warp::get())\n            .and(warp::query::<ListOptions>())\n            .and(with_db(db))\n            .and_then(handlers::list_todos)\n    }\n\n    /// POST /todos with JSON body\n    pub fn todos_create(\n        db: Db,\n    ) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {\n        warp::path!(\"todos\")\n            .and(warp::post())\n            .and(json_body())\n            .and(with_db(db))\n            .and_then(handlers::create_todo)\n    }\n\n    /// PUT /todos/:id with JSON body\n    pub fn todos_update(\n        db: Db,\n    ) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {\n        warp::path!(\"todos\" / u64)\n            .and(warp::put())\n            .and(json_body())\n            .and(with_db(db))\n            .and_then(handlers::update_todo)\n    }\n\n    /// DELETE /todos/:id\n    pub fn todos_delete(\n        db: Db,\n    ) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {\n        // We'll make one of our endpoints admin-only to show how authentication filters are used\n        let admin_only = warp::header::exact(\"authorization\", \"Bearer admin\");\n\n        warp::path!(\"todos\" / u64)\n            // It is important to put the auth check _after_ the path filters.\n            // If we put the auth check before, the request `PUT /todos/invalid-string`\n            // would try this filter and reject because the authorization header doesn't match,\n            // rather because the param is wrong for that other path.\n            .and(admin_only)\n            .and(warp::delete())\n            .and(with_db(db))\n            .and_then(handlers::delete_todo)\n    }\n\n    fn with_db(db: Db) -> impl Filter<Extract = (Db,), Error = std::convert::Infallible> + Clone {\n        warp::any().map(move || db.clone())\n    }\n\n    fn json_body() -> impl Filter<Extract = (Todo,), Error = warp::Rejection> + Clone {\n        // When accepting a body, we want a JSON body\n        // (and to reject huge payloads)...\n        warp::body::content_length_limit(1024 * 16).and(warp::body::json())\n    }\n}\n\n/// These are our API handlers, the ends of each filter chain.\n/// Notice how thanks to using `Filter::and`, we can define a function\n/// with the exact arguments we'd expect from each filter in the chain.\n/// No tuples are needed, it's auto flattened for the functions.\nmod handlers {\n    use super::models::{Db, ListOptions, Todo};\n    use std::convert::Infallible;\n    use warp::http::StatusCode;\n\n    pub async fn list_todos(opts: ListOptions, db: Db) -> Result<impl warp::Reply, Infallible> {\n        // Just return a JSON array of todos, applying the limit and offset.\n        let todos = db.lock().await;\n        let todos: Vec<Todo> = todos\n            .clone()\n            .into_iter()\n            .skip(opts.offset.unwrap_or(0))\n            .take(opts.limit.unwrap_or(std::usize::MAX))\n            .collect();\n        Ok(warp::reply::json(&todos))\n    }\n\n    pub async fn create_todo(create: Todo, db: Db) -> Result<impl warp::Reply, Infallible> {\n        log::debug!(\"create_todo: {:?}\", create);\n\n        let mut vec = db.lock().await;\n\n        for todo in vec.iter() {\n            if todo.id == create.id {\n                log::debug!(\"    -> id already exists: {}\", create.id);\n                // Todo with id already exists, return `400 BadRequest`.\n                return Ok(StatusCode::BAD_REQUEST);\n            }\n        }\n\n        // No existing Todo with id, so insert and return `201 Created`.\n        vec.push(create);\n\n        Ok(StatusCode::CREATED)\n    }\n\n    pub async fn update_todo(\n        id: u64,\n        update: Todo,\n        db: Db,\n    ) -> Result<impl warp::Reply, Infallible> {\n        log::debug!(\"update_todo: id={}, todo={:?}\", id, update);\n        let mut vec = db.lock().await;\n\n        // Look for the specified Todo...\n        for todo in vec.iter_mut() {\n            if todo.id == id {\n                *todo = update;\n                return Ok(StatusCode::OK);\n            }\n        }\n\n        log::debug!(\"    -> todo id not found!\");\n\n        // If the for loop didn't return OK, then the ID doesn't exist...\n        Ok(StatusCode::NOT_FOUND)\n    }\n\n    pub async fn delete_todo(id: u64, db: Db) -> Result<impl warp::Reply, Infallible> {\n        log::debug!(\"delete_todo: id={}\", id);\n\n        let mut vec = db.lock().await;\n\n        let len = vec.len();\n        vec.retain(|todo| {\n            // Retain all Todos that aren't this id...\n            // In other words, remove all that *are* this id...\n            todo.id != id\n        });\n\n        // If the vec is smaller, we found and deleted a Todo!\n        let deleted = vec.len() != len;\n\n        if deleted {\n            // respond with a `204 No Content`, which means successful,\n            // yet no body expected...\n            Ok(StatusCode::NO_CONTENT)\n        } else {\n            log::debug!(\"    -> todo id not found!\");\n            Ok(StatusCode::NOT_FOUND)\n        }\n    }\n}\n\nmod models {\n    use serde_derive::{Deserialize, Serialize};\n    use std::sync::Arc;\n    use tokio::sync::Mutex;\n\n    /// So we don't have to tackle how different database work, we'll just use\n    /// a simple in-memory DB, a vector synchronized by a mutex.\n    pub type Db = Arc<Mutex<Vec<Todo>>>;\n\n    pub fn blank_db() -> Db {\n        Arc::new(Mutex::new(Vec::new()))\n    }\n\n    #[derive(Debug, Deserialize, Serialize, Clone)]\n    pub struct Todo {\n        pub id: u64,\n        pub text: String,\n        pub completed: bool,\n    }\n\n    // The query parameters for list_todos.\n    #[derive(Debug, Deserialize)]\n    pub struct ListOptions {\n        pub offset: Option<usize>,\n        pub limit: Option<usize>,\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use warp::http::StatusCode;\n    use warp::test::request;\n\n    use super::{\n        filters,\n        models::{self, Todo},\n    };\n\n    #[tokio::test]\n    async fn test_post() {\n        let db = models::blank_db();\n        let api = filters::todos(db);\n\n        let resp = request()\n            .method(\"POST\")\n            .path(\"/todos\")\n            .json(&todo1())\n            .reply(&api)\n            .await;\n\n        assert_eq!(resp.status(), StatusCode::CREATED);\n    }\n\n    #[tokio::test]\n    async fn test_post_conflict() {\n        let db = models::blank_db();\n        db.lock().await.push(todo1());\n        let api = filters::todos(db);\n\n        let resp = request()\n            .method(\"POST\")\n            .path(\"/todos\")\n            .json(&todo1())\n            .reply(&api)\n            .await;\n\n        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);\n    }\n\n    #[tokio::test]\n    async fn test_put_unknown() {\n        let _ = pretty_env_logger::try_init();\n        let db = models::blank_db();\n        let api = filters::todos(db);\n\n        let resp = request()\n            .method(\"PUT\")\n            .path(\"/todos/1\")\n            .header(\"authorization\", \"Bearer admin\")\n            .json(&todo1())\n            .reply(&api)\n            .await;\n\n        assert_eq!(resp.status(), StatusCode::NOT_FOUND);\n    }\n\n    fn todo1() -> Todo {\n        Todo {\n            id: 1,\n            text: \"test 1\".into(),\n            completed: false,\n        }\n    }\n}\n"
  },
  {
    "path": "examples/tracing.rs",
    "content": "//! [`tracing`] is a framework for instrumenting Rust programs to\n//! collect scoped, structured, and async-aware diagnostics. This example\n//! demonstrates how the `warp::trace` module can be used to instrument `warp`\n//! applications with `tracing`.\n//!\n//! [`tracing`]: https://crates.io/crates/tracing\n#![deny(warnings)]\nuse tracing_subscriber::fmt::format::FmtSpan;\nuse warp::Filter;\n\n#[tokio::main]\nasync fn main() {\n    // Filter traces based on the RUST_LOG env var, or, if it's not set,\n    // default to show the output of the example.\n    let filter = std::env::var(\"RUST_LOG\").unwrap_or_else(|_| \"tracing=info,warp=debug\".to_owned());\n\n    // Configure the default `tracing` subscriber.\n    // The `fmt` subscriber from the `tracing-subscriber` crate logs `tracing`\n    // events to stdout. Other subscribers are available for integrating with\n    // distributed tracing systems such as OpenTelemetry.\n    tracing_subscriber::fmt()\n        // Use the filter we built above to determine which traces to record.\n        .with_env_filter(filter)\n        // Record an event when each span closes. This can be used to time our\n        // routes' durations!\n        .with_span_events(FmtSpan::CLOSE)\n        .init();\n\n    let hello = warp::path(\"hello\")\n        .and(warp::get())\n        // When the `hello` route is called, emit a `tracing` event.\n        .map(|| {\n            tracing::info!(\"saying hello...\");\n            \"Hello, World!\"\n        })\n        // Wrap the route in a `tracing` span to add the route's name as context\n        // to any events that occur inside it.\n        .with(warp::trace::named(\"hello\"));\n\n    let goodbye = warp::path(\"goodbye\")\n        .and(warp::get())\n        .map(|| {\n            tracing::info!(\"saying goodbye...\");\n            \"So long and thanks for all the fish!\"\n        })\n        // We can also provide our own custom `tracing` spans to wrap a route.\n        .with(warp::trace(|info| {\n            // Construct our own custom span for this route.\n            tracing::info_span!(\"goodbye\", req.path = ?info.path())\n        }));\n\n    let routes = hello\n        .or(goodbye)\n        // Wrap all the routes with a filter that creates a `tracing` span for\n        // each request we receive, including data about the request.\n        .with(warp::trace::request());\n\n    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;\n}\n"
  },
  {
    "path": "examples/unix_socket.rs",
    "content": "#![deny(warnings)]\n\n#[cfg(unix)]\n#[tokio::main]\nasync fn main() {\n    use tokio::net::UnixListener;\n\n    pretty_env_logger::init();\n\n    let socket = \"/tmp/warp.sock\";\n\n    let listener = UnixListener::bind(socket).unwrap();\n    warp::serve(warp::fs::dir(\"examples/dir\"))\n        .incoming(listener)\n        .graceful(async { tokio::signal::ctrl_c().await.unwrap() })\n        .run()\n        .await;\n\n    std::fs::remove_file(socket).unwrap();\n}\n\n#[cfg(not(unix))]\n#[tokio::main]\nasync fn main() {\n    panic!(\"Must run under Unix-like platform!\");\n}\n"
  },
  {
    "path": "examples/websockets.rs",
    "content": "#![deny(warnings)]\n\nuse futures_util::{FutureExt, StreamExt};\nuse warp::Filter;\n\n#[tokio::main]\nasync fn main() {\n    pretty_env_logger::init();\n\n    let routes = warp::path(\"echo\")\n        // The `ws()` filter will prepare the Websocket handshake.\n        .and(warp::ws())\n        .map(|ws: warp::ws::Ws| {\n            // And then our closure will be called when it completes...\n            ws.on_upgrade(|websocket| {\n                // Just echo all messages back...\n                let (tx, rx) = websocket.split();\n                rx.forward(tx).map(|result| {\n                    if let Err(e) = result {\n                        eprintln!(\"websocket error: {:?}\", e);\n                    }\n                })\n            })\n        });\n\n    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;\n}\n"
  },
  {
    "path": "examples/websockets_chat.rs",
    "content": "// #![deny(warnings)]\nuse std::collections::HashMap;\nuse std::sync::{\n    atomic::{AtomicUsize, Ordering},\n    Arc,\n};\n\nuse futures_util::{SinkExt, StreamExt, TryFutureExt};\nuse tokio::sync::{mpsc, RwLock};\nuse tokio_stream::wrappers::UnboundedReceiverStream;\nuse warp::ws::{Message, WebSocket};\nuse warp::Filter;\n\n/// Our global unique user id counter.\nstatic NEXT_USER_ID: AtomicUsize = AtomicUsize::new(1);\n\n/// Our state of currently connected users.\n///\n/// - Key is their id\n/// - Value is a sender of `warp::ws::Message`\ntype Users = Arc<RwLock<HashMap<usize, mpsc::UnboundedSender<Message>>>>;\n\n#[tokio::main]\nasync fn main() {\n    pretty_env_logger::init();\n\n    // Keep track of all connected users, key is usize, value\n    // is a websocket sender.\n    let users = Users::default();\n    // Turn our \"state\" into a new Filter...\n    let users = warp::any().map(move || users.clone());\n\n    // GET /chat -> websocket upgrade\n    let chat = warp::path(\"chat\")\n        // The `ws()` filter will prepare Websocket handshake...\n        .and(warp::ws())\n        .and(users)\n        .map(|ws: warp::ws::Ws, users| {\n            // This will call our function if the handshake succeeds.\n            ws.on_upgrade(move |socket| user_connected(socket, users))\n        });\n\n    // GET / -> index html\n    let index = warp::path::end().map(|| warp::reply::html(INDEX_HTML));\n\n    let routes = index.or(chat);\n\n    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;\n}\n\nasync fn user_connected(ws: WebSocket, users: Users) {\n    // Use a counter to assign a new unique ID for this user.\n    let my_id = NEXT_USER_ID.fetch_add(1, Ordering::Relaxed);\n\n    eprintln!(\"new chat user: {}\", my_id);\n\n    // Split the socket into a sender and receive of messages.\n    let (mut user_ws_tx, mut user_ws_rx) = ws.split();\n\n    // Use an unbounded channel to handle buffering and flushing of messages\n    // to the websocket...\n    let (tx, rx) = mpsc::unbounded_channel();\n    let mut rx = UnboundedReceiverStream::new(rx);\n\n    tokio::task::spawn(async move {\n        while let Some(message) = rx.next().await {\n            user_ws_tx\n                .send(message)\n                .unwrap_or_else(|e| {\n                    eprintln!(\"websocket send error: {}\", e);\n                })\n                .await;\n        }\n    });\n\n    // Save the sender in our list of connected users.\n    users.write().await.insert(my_id, tx);\n\n    // Return a `Future` that is basically a state machine managing\n    // this specific user's connection.\n\n    // Every time the user sends a message, broadcast it to\n    // all other users...\n    while let Some(result) = user_ws_rx.next().await {\n        let msg = match result {\n            Ok(msg) => msg,\n            Err(e) => {\n                eprintln!(\"websocket error(uid={}): {}\", my_id, e);\n                break;\n            }\n        };\n        user_message(my_id, msg, &users).await;\n    }\n\n    // user_ws_rx stream will keep processing as long as the user stays\n    // connected. Once they disconnect, then...\n    user_disconnected(my_id, &users).await;\n}\n\nasync fn user_message(my_id: usize, msg: Message, users: &Users) {\n    // Skip any non-Text messages...\n    let msg = if let Ok(s) = msg.to_str() {\n        s\n    } else {\n        return;\n    };\n\n    let new_msg = format!(\"<User#{}>: {}\", my_id, msg);\n\n    // New message from this user, send it to everyone else (except same uid)...\n    for (&uid, tx) in users.read().await.iter() {\n        if my_id != uid {\n            if let Err(_disconnected) = tx.send(Message::text(new_msg.clone())) {\n                // The tx is disconnected, our `user_disconnected` code\n                // should be happening in another task, nothing more to\n                // do here.\n            }\n        }\n    }\n}\n\nasync fn user_disconnected(my_id: usize, users: &Users) {\n    eprintln!(\"good bye user: {}\", my_id);\n\n    // Stream closed up, so remove from the user list\n    users.write().await.remove(&my_id);\n}\n\nstatic INDEX_HTML: &str = r#\"<!DOCTYPE html>\n<html lang=\"en\">\n    <head>\n        <title>Warp Chat</title>\n    </head>\n    <body>\n        <h1>Warp chat</h1>\n        <div id=\"chat\">\n            <p><em>Connecting...</em></p>\n        </div>\n        <input type=\"text\" id=\"text\" />\n        <button type=\"button\" id=\"send\">Send</button>\n        <script type=\"text/javascript\">\n        const chat = document.getElementById('chat');\n        const text = document.getElementById('text');\n        const uri = 'ws://' + location.host + '/chat';\n        const ws = new WebSocket(uri);\n\n        function message(data) {\n            const line = document.createElement('p');\n            line.innerText = data;\n            chat.appendChild(line);\n        }\n\n        ws.onopen = function() {\n            chat.innerHTML = '<p><em>Connected!</em></p>';\n        };\n\n        ws.onmessage = function(msg) {\n            message(msg.data);\n        };\n\n        ws.onclose = function() {\n            chat.getElementsByTagName('em')[0].innerText = 'Disconnected!';\n        };\n\n        send.onclick = function() {\n            const msg = text.value;\n            ws.send(msg);\n            text.value = '';\n\n            message('<You>: ' + msg);\n        };\n        </script>\n    </body>\n</html>\n\"#;\n"
  },
  {
    "path": "src/bodyt.rs",
    "content": "use std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse bytes::Buf;\nuse bytes::Bytes;\nuse futures_util::StreamExt;\nuse http_body::Frame;\nuse http_body_util::{combinators::BoxBody, BodyExt};\n\n#[derive(Debug)]\npub struct Body(BoxBody<Bytes, crate::Error>);\n\nimpl Default for Body {\n    fn default() -> Self {\n        Body::empty()\n    }\n}\n\nimpl http_body::Body for Body {\n    type Data = Bytes;\n    type Error = crate::Error;\n\n    fn poll_frame(\n        mut self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {\n        Pin::new(&mut self.0).poll_frame(cx)\n    }\n\n    fn is_end_stream(&self) -> bool {\n        self.0.is_end_stream()\n    }\n\n    fn size_hint(&self) -> http_body::SizeHint {\n        self.0.size_hint()\n    }\n}\n\nimpl Body {\n    pub(crate) fn empty() -> Self {\n        Body(\n            http_body_util::Empty::<Bytes>::new()\n                .map_err(crate::Error::new)\n                .boxed(),\n        )\n    }\n\n    pub(crate) fn wrap<B>(body: B) -> Self\n    where\n        B: http_body::Body + Send + Sync + 'static,\n        B::Error: Into<Box<dyn std::error::Error + Send + Sync>>,\n    {\n        let body = body\n            .map_frame(|f| f.map_data(|mut buf| buf.copy_to_bytes(buf.remaining())))\n            .map_err(crate::Error::new);\n        Body(http_body_util::BodyExt::boxed(body))\n    }\n\n    pub(crate) fn wrap_stream<S, B, E>(stream: S) -> Self\n    where\n        S: futures_util::Stream<Item = Result<B, E>> + Send + Sync + 'static,\n        B: Into<Bytes>,\n        E: Into<Box<dyn std::error::Error + Send + Sync>> + Send + 'static,\n    {\n        let body = http_body_util::StreamBody::new(stream.map(|item| {\n            item.map(|buf| Frame::data(buf.into()))\n                .map_err(crate::Error::new)\n        }));\n        Body(http_body_util::BodyExt::boxed(body))\n    }\n}\n\nimpl From<Bytes> for Body {\n    fn from(b: Bytes) -> Self {\n        Body(\n            http_body_util::Full::new(b)\n                .map_err(crate::Error::new)\n                .boxed(),\n        )\n    }\n}\n\nimpl From<&'static str> for Body {\n    fn from(s: &'static str) -> Self {\n        Bytes::from(s).into()\n    }\n}\n\nimpl From<String> for Body {\n    fn from(s: String) -> Self {\n        Bytes::from(s).into()\n    }\n}\n\nimpl From<&'static [u8]> for Body {\n    fn from(v: &'static [u8]) -> Self {\n        Bytes::from(v).into()\n    }\n}\n\nimpl From<Vec<u8>> for Body {\n    fn from(v: Vec<u8>) -> Self {\n        Bytes::from(v).into()\n    }\n}\n\nimpl From<Option<Bytes>> for Body {\n    fn from(opt: Option<Bytes>) -> Self {\n        match opt {\n            Some(b) => b.into(),\n            None => Body::empty(),\n        }\n    }\n}\n"
  },
  {
    "path": "src/error.rs",
    "content": "use std::convert::Infallible;\nuse std::error::Error as StdError;\nuse std::fmt;\n\ntype BoxError = Box<dyn std::error::Error + Send + Sync>;\n\n/// Errors that can happen inside warp.\npub struct Error {\n    inner: BoxError,\n}\n\nimpl Error {\n    pub(crate) fn new<E: Into<BoxError>>(err: E) -> Error {\n        Error { inner: err.into() }\n    }\n}\n\nimpl fmt::Debug for Error {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        // Skip showing worthless `Error { .. }` wrapper.\n        fmt::Debug::fmt(&self.inner, f)\n    }\n}\n\nimpl fmt::Display for Error {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        fmt::Display::fmt(&self.inner, f)\n    }\n}\n\nimpl StdError for Error {\n    fn source(&self) -> Option<&(dyn StdError + 'static)> {\n        Some(self.inner.as_ref())\n    }\n}\n\nimpl From<Infallible> for Error {\n    fn from(infallible: Infallible) -> Error {\n        match infallible {}\n    }\n}\n\n#[test]\nfn error_size_of() {\n    assert_eq!(\n        ::std::mem::size_of::<Error>(),\n        ::std::mem::size_of::<usize>() * 2\n    );\n}\n\n#[test]\nfn error_source() {\n    let e = Error::new(std::fmt::Error {});\n    assert!(e.source().unwrap().is::<std::fmt::Error>());\n}\n\nmacro_rules! unit_error {\n    (\n        $(#[$docs:meta])*\n        $pub:vis $typ:ident: $display:literal\n    ) => (\n        $(#[$docs])*\n        $pub struct $typ { _p: (), }\n\n        impl ::std::fmt::Debug for $typ {\n            fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {\n                f.debug_struct(stringify!($typ)).finish()\n            }\n        }\n\n        impl ::std::fmt::Display for $typ {\n            fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {\n                f.write_str($display)\n            }\n        }\n\n        impl ::std::error::Error for $typ {}\n    )\n}\n"
  },
  {
    "path": "src/filter/and.rs",
    "content": "use std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse futures_util::ready;\nuse pin_project::pin_project;\n\nuse super::{Combine, Filter, FilterBase, Internal, Tuple};\nuse crate::generic::CombinedTuples;\nuse crate::reject::CombineRejection;\n\n#[derive(Clone, Copy, Debug)]\npub struct And<T, U> {\n    pub(super) first: T,\n    pub(super) second: U,\n}\n\nimpl<T, U> FilterBase for And<T, U>\nwhere\n    T: Filter,\n    T::Extract: Send,\n    U: Filter + Clone + Send,\n    <T::Extract as Tuple>::HList: Combine<<U::Extract as Tuple>::HList> + Send,\n    CombinedTuples<T::Extract, U::Extract>: Send,\n    U::Error: CombineRejection<T::Error>,\n{\n    type Extract = CombinedTuples<T::Extract, U::Extract>;\n    type Error = <U::Error as CombineRejection<T::Error>>::One;\n    type Future = AndFuture<T, U>;\n\n    fn filter(&self, _: Internal) -> Self::Future {\n        AndFuture {\n            state: State::First(self.first.filter(Internal), self.second.clone()),\n        }\n    }\n}\n\n#[allow(missing_debug_implementations)]\n#[pin_project]\npub struct AndFuture<T: Filter, U: Filter> {\n    #[pin]\n    state: State<T::Future, T::Extract, U>,\n}\n\n#[pin_project(project = StateProj)]\nenum State<T, TE, U: Filter> {\n    First(#[pin] T, U),\n    Second(Option<TE>, #[pin] U::Future),\n    Done,\n}\n\nimpl<T, U> Future for AndFuture<T, U>\nwhere\n    T: Filter,\n    U: Filter,\n    <T::Extract as Tuple>::HList: Combine<<U::Extract as Tuple>::HList> + Send,\n    U::Error: CombineRejection<T::Error>,\n{\n    type Output = Result<\n        CombinedTuples<T::Extract, U::Extract>,\n        <U::Error as CombineRejection<T::Error>>::One,\n    >;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        self.project().state.poll(cx)\n    }\n}\n\nimpl<T, TE, U, E> Future for State<T, TE, U>\nwhere\n    T: Future<Output = Result<TE, E>>,\n    U: Filter,\n    TE: Tuple,\n    TE::HList: Combine<<U::Extract as Tuple>::HList> + Send,\n    U::Error: CombineRejection<E>,\n{\n    type Output = Result<CombinedTuples<TE, U::Extract>, <U::Error as CombineRejection<E>>::One>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        loop {\n            match self.as_mut().project() {\n                StateProj::First(first, second) => {\n                    let ex1 = ready!(first.poll(cx))?;\n                    let fut2 = second.filter(Internal);\n                    self.set(State::Second(Some(ex1), fut2));\n                }\n                StateProj::Second(ex1, second) => {\n                    let ex2 = ready!(second.poll(cx))?;\n                    let ex3 = ex1.take().unwrap().combine(ex2);\n                    self.set(State::Done);\n                    return Poll::Ready(Ok(ex3));\n                }\n                StateProj::Done => panic!(\"polled after complete\"),\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/filter/and_then.rs",
    "content": "use std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse futures_util::{ready, TryFuture};\nuse pin_project::pin_project;\n\nuse super::{Filter, FilterBase, Func, Internal};\nuse crate::reject::CombineRejection;\n\n#[derive(Clone, Copy, Debug)]\npub struct AndThen<T, F> {\n    pub(super) filter: T,\n    pub(super) callback: F,\n}\n\nimpl<T, F> FilterBase for AndThen<T, F>\nwhere\n    T: Filter,\n    F: Func<T::Extract> + Clone + Send,\n    F::Output: TryFuture + Send,\n    <F::Output as TryFuture>::Error: CombineRejection<T::Error>,\n{\n    type Extract = (<F::Output as TryFuture>::Ok,);\n    type Error = <<F::Output as TryFuture>::Error as CombineRejection<T::Error>>::One;\n    type Future = AndThenFuture<T, F>;\n    #[inline]\n    fn filter(&self, _: Internal) -> Self::Future {\n        AndThenFuture {\n            state: State::First(self.filter.filter(Internal), self.callback.clone()),\n        }\n    }\n}\n\n#[allow(missing_debug_implementations)]\n#[pin_project]\npub struct AndThenFuture<T, F>\nwhere\n    T: Filter,\n    F: Func<T::Extract>,\n    F::Output: TryFuture + Send,\n    <F::Output as TryFuture>::Error: CombineRejection<T::Error>,\n{\n    #[pin]\n    state: State<T::Future, F>,\n}\n\n#[pin_project(project = StateProj)]\nenum State<T, F>\nwhere\n    T: TryFuture,\n    F: Func<T::Ok>,\n    F::Output: TryFuture + Send,\n    <F::Output as TryFuture>::Error: CombineRejection<T::Error>,\n{\n    First(#[pin] T, F),\n    Second(#[pin] F::Output),\n    Done,\n}\n\nimpl<T, F> Future for AndThenFuture<T, F>\nwhere\n    T: Filter,\n    F: Func<T::Extract>,\n    F::Output: TryFuture + Send,\n    <F::Output as TryFuture>::Error: CombineRejection<T::Error>,\n{\n    type Output = Result<\n        (<F::Output as TryFuture>::Ok,),\n        <<F::Output as TryFuture>::Error as CombineRejection<T::Error>>::One,\n    >;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        self.project().state.poll(cx)\n    }\n}\n\nimpl<T, F> Future for State<T, F>\nwhere\n    T: TryFuture,\n    F: Func<T::Ok>,\n    F::Output: TryFuture + Send,\n    <F::Output as TryFuture>::Error: CombineRejection<T::Error>,\n{\n    type Output = Result<\n        (<F::Output as TryFuture>::Ok,),\n        <<F::Output as TryFuture>::Error as CombineRejection<T::Error>>::One,\n    >;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        loop {\n            match self.as_mut().project() {\n                StateProj::First(first, second) => {\n                    let ex1 = ready!(first.try_poll(cx))?;\n                    let fut2 = second.call(ex1);\n                    self.set(State::Second(fut2));\n                }\n                StateProj::Second(second) => {\n                    let ex2 = match ready!(second.try_poll(cx)) {\n                        Ok(item) => Ok((item,)),\n                        Err(err) => Err(From::from(err)),\n                    };\n                    self.set(State::Done);\n                    return Poll::Ready(ex2);\n                }\n                StateProj::Done => panic!(\"polled after complete\"),\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/filter/boxed.rs",
    "content": "use std::fmt;\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::sync::Arc;\n\nuse futures_util::TryFutureExt;\n\nuse super::{Filter, FilterBase, Internal, Tuple};\nuse crate::reject::Rejection;\n\n/// A type representing a boxed [`Filter`](crate::Filter) trait object.\n///\n/// The filter inside is a dynamic trait object. The purpose of this type is\n/// to ease returning `Filter`s from other functions.\n///\n/// To create one, call `Filter::boxed` on any filter.\n///\n/// # Examples\n///\n/// ```\n/// use warp::{Filter, filters::BoxedFilter, Reply};\n///\n/// pub fn assets_filter() -> BoxedFilter<(impl Reply,)> {\n///     warp::path(\"assets\")\n///         .and(warp::fs::dir(\"./assets\"))\n///         .boxed()\n/// }\n/// ```\n///\npub struct BoxedFilter<T: Tuple> {\n    filter: Arc<\n        dyn Filter<\n                Extract = T,\n                Error = Rejection,\n                Future = Pin<Box<dyn Future<Output = Result<T, Rejection>> + Send>>,\n            > + Send\n            + Sync,\n    >,\n}\n\nimpl<T: Tuple + Send> BoxedFilter<T> {\n    pub(super) fn new<F>(filter: F) -> BoxedFilter<T>\n    where\n        F: Filter<Extract = T> + Send + Sync + 'static,\n        F::Error: Into<Rejection>,\n    {\n        BoxedFilter {\n            filter: Arc::new(BoxingFilter {\n                filter: filter.map_err(super::Internal, Into::into),\n            }),\n        }\n    }\n}\n\nimpl<T: Tuple> Clone for BoxedFilter<T> {\n    fn clone(&self) -> BoxedFilter<T> {\n        BoxedFilter {\n            filter: self.filter.clone(),\n        }\n    }\n}\n\nimpl<T: Tuple> fmt::Debug for BoxedFilter<T> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"BoxedFilter\").finish()\n    }\n}\n\nfn _assert_send() {\n    fn _assert<T: Send>() {}\n    _assert::<BoxedFilter<()>>();\n}\n\nimpl<T: Tuple + Send> FilterBase for BoxedFilter<T> {\n    type Extract = T;\n    type Error = Rejection;\n    type Future = Pin<Box<dyn Future<Output = Result<T, Rejection>> + Send>>;\n\n    fn filter(&self, _: Internal) -> Self::Future {\n        self.filter.filter(Internal)\n    }\n}\n\nstruct BoxingFilter<F> {\n    filter: F,\n}\n\nimpl<F> FilterBase for BoxingFilter<F>\nwhere\n    F: Filter,\n    F::Future: Send + 'static,\n{\n    type Extract = F::Extract;\n    type Error = F::Error;\n    type Future = Pin<Box<dyn Future<Output = Result<Self::Extract, Self::Error>> + Send>>;\n\n    fn filter(&self, _: Internal) -> Self::Future {\n        Box::pin(self.filter.filter(Internal).into_future())\n    }\n}\n"
  },
  {
    "path": "src/filter/map.rs",
    "content": "use std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse futures_util::{ready, TryFuture};\nuse pin_project::pin_project;\n\nuse super::{Filter, FilterBase, Func, Internal};\n\n#[derive(Clone, Copy, Debug)]\npub struct Map<T, F> {\n    pub(super) filter: T,\n    pub(super) callback: F,\n}\n\nimpl<T, F> FilterBase for Map<T, F>\nwhere\n    T: Filter,\n    F: Func<T::Extract> + Clone + Send,\n{\n    type Extract = (F::Output,);\n    type Error = T::Error;\n    type Future = MapFuture<T, F>;\n    #[inline]\n    fn filter(&self, _: Internal) -> Self::Future {\n        MapFuture {\n            extract: self.filter.filter(Internal),\n            callback: self.callback.clone(),\n        }\n    }\n}\n\n#[allow(missing_debug_implementations)]\n#[pin_project]\npub struct MapFuture<T: Filter, F> {\n    #[pin]\n    extract: T::Future,\n    callback: F,\n}\n\nimpl<T, F> Future for MapFuture<T, F>\nwhere\n    T: Filter,\n    F: Func<T::Extract>,\n{\n    type Output = Result<(F::Output,), T::Error>;\n\n    #[inline]\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let pin = self.project();\n        match ready!(pin.extract.try_poll(cx)) {\n            Ok(ex) => {\n                let ex = (pin.callback.call(ex),);\n                Poll::Ready(Ok(ex))\n            }\n            Err(err) => Poll::Ready(Err(err)),\n        }\n    }\n}\n"
  },
  {
    "path": "src/filter/map_err.rs",
    "content": "use std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse futures_util::TryFuture;\nuse pin_project::pin_project;\n\nuse super::{Filter, FilterBase, Internal};\nuse crate::reject::IsReject;\n\n#[derive(Clone, Copy, Debug)]\npub struct MapErr<T, F> {\n    pub(super) filter: T,\n    pub(super) callback: F,\n}\n\nimpl<T, F, E> FilterBase for MapErr<T, F>\nwhere\n    T: Filter,\n    F: Fn(T::Error) -> E + Clone + Send,\n    E: IsReject,\n{\n    type Extract = T::Extract;\n    type Error = E;\n    type Future = MapErrFuture<T, F>;\n    #[inline]\n    fn filter(&self, _: Internal) -> Self::Future {\n        MapErrFuture {\n            extract: self.filter.filter(Internal),\n            callback: self.callback.clone(),\n        }\n    }\n}\n\n#[allow(missing_debug_implementations)]\n#[pin_project]\npub struct MapErrFuture<T: Filter, F> {\n    #[pin]\n    extract: T::Future,\n    callback: F,\n}\n\nimpl<T, F, E> Future for MapErrFuture<T, F>\nwhere\n    T: Filter,\n    F: Fn(T::Error) -> E,\n{\n    type Output = Result<T::Extract, E>;\n\n    #[inline]\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        self.as_mut()\n            .project()\n            .extract\n            .try_poll(cx)\n            .map_err(|err| (self.callback)(err))\n    }\n}\n"
  },
  {
    "path": "src/filter/mod.rs",
    "content": "mod and;\nmod and_then;\nmod boxed;\nmod map;\nmod map_err;\nmod or;\nmod or_else;\nmod recover;\npub(crate) mod service;\nmod then;\nmod unify;\nmod untuple_one;\nmod wrap;\n\nuse std::future::Future;\n\nuse futures_util::{future, TryFuture, TryFutureExt};\n\npub(crate) use crate::generic::{one, Combine, Either, Func, One, Tuple};\nuse crate::reject::{CombineRejection, IsReject, Rejection};\nuse crate::route::{self, Route};\n\npub(crate) use self::and::And;\nuse self::and_then::AndThen;\npub use self::boxed::BoxedFilter;\npub(crate) use self::map::Map;\npub(crate) use self::map_err::MapErr;\npub(crate) use self::or::Or;\nuse self::or_else::OrElse;\nuse self::recover::Recover;\nuse self::then::Then;\nuse self::unify::Unify;\nuse self::untuple_one::UntupleOne;\npub use self::wrap::wrap_fn;\npub(crate) use self::wrap::{Wrap, WrapSealed};\n\n// A crate-private base trait, allowing the actual `filter` method to change\n// signatures without it being a breaking change.\npub trait FilterBase {\n    type Extract: Tuple; // + Send;\n    type Error: IsReject;\n    type Future: Future<Output = Result<Self::Extract, Self::Error>> + Send;\n\n    fn filter(&self, internal: Internal) -> Self::Future;\n\n    fn map_err<F, E>(self, _internal: Internal, fun: F) -> MapErr<Self, F>\n    where\n        Self: Sized,\n        F: Fn(Self::Error) -> E + Clone,\n        E: ::std::fmt::Debug + Send,\n    {\n        MapErr {\n            filter: self,\n            callback: fun,\n        }\n    }\n}\n\n// A crate-private argument to prevent users from calling methods on\n// the `FilterBase` trait.\n//\n// For instance, this innocent user code could otherwise call `filter`:\n//\n// ```\n// async fn with_filter<F: Filter>(f: F) -> Result<F::Extract, F::Error> {\n//     f.filter().await\n// }\n// ```\n#[allow(missing_debug_implementations)]\npub struct Internal;\n\n/// Composable request filters.\n///\n/// A `Filter` can optionally extract some data from a request, combine\n/// it with others, mutate it, and return back some value as a reply. The\n/// power of `Filter`s come from being able to isolate small subsets, and then\n/// chain and reuse them in various parts of your app.\n///\n/// # Extracting Tuples\n///\n/// You may notice that several of these filters extract some tuple, often\n/// times a tuple of just 1 item! Why?\n///\n/// If a filter extracts a `(String,)`, that simply means that it\n/// extracts a `String`. If you were to `map` the filter, the argument type\n/// would be exactly that, just a `String`.\n///\n/// What is it? It's just some type magic that allows for automatic combining\n/// and flattening of tuples. Without it, combining two filters together with\n/// `and`, where one extracted `()`, and another `String`, would mean the\n/// `map` would be given a single argument of `((), String,)`, which is just\n/// no fun.\npub trait Filter: FilterBase {\n    /// Composes a new `Filter` that requires both this and the other to filter a request.\n    ///\n    /// Additionally, this will join together the extracted values of both\n    /// filters, so that `map` and `and_then` receive them as separate arguments.\n    ///\n    /// If a `Filter` extracts nothing (so, `()`), combining with any other\n    /// filter will simply discard the `()`. If a `Filter` extracts one or\n    /// more items, combining will mean it extracts the values of itself\n    /// combined with the other.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use warp::Filter;\n    ///\n    /// // Match `/hello/:name`...\n    /// warp::path(\"hello\")\n    ///     .and(warp::path::param::<String>());\n    /// ```\n    fn and<F>(self, other: F) -> And<Self, F>\n    where\n        Self: Sized,\n        <Self::Extract as Tuple>::HList: Combine<<F::Extract as Tuple>::HList>,\n        F: Filter + Clone,\n        F::Error: CombineRejection<Self::Error>,\n    {\n        And {\n            first: self,\n            second: other,\n        }\n    }\n\n    /// Composes a new `Filter` of either this or the other filter.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use std::net::SocketAddr;\n    /// use warp::Filter;\n    ///\n    /// // Match either `/:u32` or `/:socketaddr`\n    /// warp::path::param::<u32>()\n    ///     .or(warp::path::param::<SocketAddr>());\n    /// ```\n    fn or<F>(self, other: F) -> Or<Self, F>\n    where\n        Self: Filter<Error = Rejection> + Sized,\n        F: Filter,\n        F::Error: CombineRejection<Self::Error>,\n    {\n        Or {\n            first: self,\n            second: other,\n        }\n    }\n\n    /// Composes this `Filter` with a function receiving the extracted value.\n    ///\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use warp::Filter;\n    ///\n    /// // Map `/:id`\n    /// warp::path::param().map(|id: u64| {\n    ///   format!(\"Hello #{}\", id)\n    /// });\n    /// ```\n    ///\n    /// # `Func`\n    ///\n    /// The generic `Func` trait is implemented for any function that receives\n    /// the same arguments as this `Filter` extracts. In practice, this\n    /// shouldn't ever bother you, and simply makes things feel more natural.\n    ///\n    /// For example, if three `Filter`s were combined together, suppose one\n    /// extracts nothing (so `()`), and the other two extract two integers,\n    /// a function that accepts exactly two integer arguments is allowed.\n    /// Specifically, any `Fn(u32, u32)`.\n    ///\n    /// Without `Product` and `Func`, this would be a lot messier. First of\n    /// all, the `()`s couldn't be discarded, and the tuples would be nested.\n    /// So, instead, you'd need to pass an `Fn(((), (u32, u32)))`. That's just\n    /// a single argument. Bleck!\n    ///\n    /// Even worse, the tuples would shuffle the types around depending on\n    /// the exact invocation of `and`s. So, `unit.and(int).and(int)` would\n    /// result in a different extracted type from `unit.and(int.and(int))`,\n    /// or from `int.and(unit).and(int)`. If you changed around the order\n    /// of filters, while still having them be semantically equivalent, you'd\n    /// need to update all your `map`s as well.\n    ///\n    /// `Product`, `HList`, and `Func` do all the heavy work so that none of\n    /// this is a bother to you. What's more, the types are enforced at\n    /// compile-time, and tuple flattening is optimized away to nothing by\n    /// LLVM.\n    fn map<F>(self, fun: F) -> Map<Self, F>\n    where\n        Self: Sized,\n        F: Func<Self::Extract> + Clone,\n    {\n        Map {\n            filter: self,\n            callback: fun,\n        }\n    }\n\n    /// Composes this `Filter` with an async function receiving\n    /// the extracted value.\n    ///\n    /// The function should return some `Future` type.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use warp::Filter;\n    ///\n    /// // Map `/:id`\n    /// warp::path::param().then(|id: u64| async move {\n    ///   format!(\"Hello #{}\", id)\n    /// });\n    /// ```\n    fn then<F>(self, fun: F) -> Then<Self, F>\n    where\n        Self: Sized,\n        F: Func<Self::Extract> + Clone,\n        F::Output: Future + Send,\n    {\n        Then {\n            filter: self,\n            callback: fun,\n        }\n    }\n\n    /// Composes this `Filter` with a fallible async function receiving\n    /// the extracted value.\n    ///\n    /// The function should return some `TryFuture` type.\n    ///\n    /// The `Error` type of the return `Future` needs be a `Rejection`, which\n    /// means most futures will need to have their error mapped into one.\n    ///\n    /// Rejections are meant to say \"this filter didn't accept the request,\n    /// maybe another can\". So for application-level errors, consider using\n    /// [`Filter::then`] instead.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use warp::Filter;\n    ///\n    /// // Validate after `/:id`\n    /// warp::path::param().and_then(|id: u64| async move {\n    ///     if id != 0 {\n    ///         Ok(format!(\"Hello #{}\", id))\n    ///     } else {\n    ///         Err(warp::reject::not_found())\n    ///     }\n    /// });\n    /// ```\n    fn and_then<F>(self, fun: F) -> AndThen<Self, F>\n    where\n        Self: Sized,\n        F: Func<Self::Extract> + Clone,\n        F::Output: TryFuture + Send,\n        <F::Output as TryFuture>::Error: CombineRejection<Self::Error>,\n    {\n        AndThen {\n            filter: self,\n            callback: fun,\n        }\n    }\n\n    /// Compose this `Filter` with a function receiving an error.\n    ///\n    /// The function should return some `TryFuture` type yielding the\n    /// same item and error types.\n    fn or_else<F>(self, fun: F) -> OrElse<Self, F>\n    where\n        Self: Filter<Error = Rejection> + Sized,\n        F: Func<Rejection>,\n        F::Output: TryFuture<Ok = Self::Extract> + Send,\n        <F::Output as TryFuture>::Error: IsReject,\n    {\n        OrElse {\n            filter: self,\n            callback: fun,\n        }\n    }\n\n    /// Compose this `Filter` with a function receiving an error and\n    /// returning a *new* type, instead of the *same* type.\n    ///\n    /// This is useful for \"customizing\" rejections into new response types.\n    /// See also the [rejections example][ex].\n    ///\n    /// [ex]: https://github.com/seanmonstar/warp/blob/master/examples/rejections.rs\n    fn recover<F>(self, fun: F) -> Recover<Self, F>\n    where\n        Self: Filter<Error = Rejection> + Sized,\n        F: Func<Rejection>,\n        F::Output: TryFuture + Send,\n        <F::Output as TryFuture>::Error: IsReject,\n    {\n        Recover {\n            filter: self,\n            callback: fun,\n        }\n    }\n\n    /// Unifies the extracted value of `Filter`s composed with `or`.\n    ///\n    /// When a `Filter` extracts some `Either<T, T>`, where both sides\n    /// are the same type, this combinator can be used to grab the\n    /// inner value, regardless of which side of `Either` it was. This\n    /// is useful for values that could be extracted from multiple parts\n    /// of a request, and the exact place isn't important.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// use std::net::SocketAddr;\n    /// use warp::Filter;\n    ///\n    /// let client_ip = warp::header(\"x-real-ip\")\n    ///     .or(warp::header(\"x-forwarded-for\"))\n    ///     .unify()\n    ///     .map(|ip: SocketAddr| {\n    ///         // Get the IP from either header,\n    ///         // and unify into the inner type.\n    ///     });\n    /// ```\n    fn unify<T>(self) -> Unify<Self>\n    where\n        Self: Filter<Extract = (Either<T, T>,)> + Sized,\n        T: Tuple,\n    {\n        Unify { filter: self }\n    }\n\n    /// Convenience method to remove one layer of tupling.\n    ///\n    /// This is useful for when things like `map` don't return a new value,\n    /// but just `()`, since warp will wrap it up into a `((),)`.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use warp::Filter;\n    ///\n    /// let route = warp::path::param()\n    ///     .map(|num: u64| {\n    ///         println!(\"just logging: {}\", num);\n    ///         // returning \"nothing\"\n    ///     })\n    ///     .untuple_one()\n    ///     .map(|| {\n    ///         println!(\"the ((),) was removed\");\n    ///         warp::reply()\n    ///     });\n    /// ```\n    ///\n    /// ```\n    /// use warp::Filter;\n    ///\n    /// let route = warp::any()\n    ///     .map(|| {\n    ///         // wanting to return a tuple\n    ///         (true, 33)\n    ///     })\n    ///     .untuple_one()\n    ///     .map(|is_enabled: bool, count: i32| {\n    ///         println!(\"untupled: ({}, {})\", is_enabled, count);\n    ///     });\n    /// ```\n    fn untuple_one<T>(self) -> UntupleOne<Self>\n    where\n        Self: Filter<Extract = (T,)> + Sized,\n        T: Tuple,\n    {\n        UntupleOne { filter: self }\n    }\n\n    /// Wraps the current filter with some wrapper.\n    ///\n    /// The wrapper may do some preparation work before starting this filter,\n    /// and may do post-processing after the filter completes.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use warp::Filter;\n    ///\n    /// let route = warp::any()\n    ///     .map(warp::reply);\n    ///\n    /// // Wrap the route with a log wrapper.\n    /// let route = route.with(warp::log(\"example\"));\n    /// ```\n    fn with<W>(self, wrapper: W) -> W::Wrapped\n    where\n        Self: Sized,\n        W: Wrap<Self>,\n    {\n        wrapper.wrap(self)\n    }\n\n    /// Boxes this filter into a trait object, making it easier to name the type.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use warp::Filter;\n    ///\n    /// fn impl_reply() -> warp::filters::BoxedFilter<(impl warp::Reply,)> {\n    ///     warp::any()\n    ///         .map(warp::reply)\n    ///         .boxed()\n    /// }\n    ///\n    /// fn named_i32() -> warp::filters::BoxedFilter<(i32,)> {\n    ///     warp::path::param::<i32>()\n    ///         .boxed()\n    /// }\n    ///\n    /// fn named_and() -> warp::filters::BoxedFilter<(i32, String)> {\n    ///     warp::path::param::<i32>()\n    ///         .and(warp::header::<String>(\"host\"))\n    ///         .boxed()\n    /// }\n    /// ```\n    fn boxed(self) -> BoxedFilter<Self::Extract>\n    where\n        Self: Sized + Send + Sync + 'static,\n        Self::Extract: Send,\n        Self::Error: Into<Rejection>,\n    {\n        BoxedFilter::new(self)\n    }\n}\n\nimpl<T: FilterBase> Filter for T {}\n\npub trait FilterClone: Filter + Clone {}\n\nimpl<T: Filter + Clone> FilterClone for T {}\n\nfn _assert_object_safe() {\n    fn _assert(_f: &dyn Filter<Extract = (), Error = (), Future = future::Ready<()>>) {}\n}\n\n// ===== FilterFn =====\n\npub(crate) fn filter_fn<F, U>(func: F) -> FilterFn<F>\nwhere\n    F: Fn(&mut Route) -> U,\n    U: TryFuture,\n    U::Ok: Tuple,\n    U::Error: IsReject,\n{\n    FilterFn { func }\n}\n\npub(crate) fn filter_fn_one<F, U>(\n    func: F,\n) -> impl Filter<Extract = (U::Ok,), Error = U::Error> + Copy\nwhere\n    F: Fn(&mut Route) -> U + Copy,\n    U: TryFuture + Send + 'static,\n    U::Ok: Send,\n    U::Error: IsReject,\n{\n    filter_fn(move |route| func(route).map_ok(|item| (item,)))\n}\n\n#[derive(Copy, Clone)]\n#[allow(missing_debug_implementations)]\npub(crate) struct FilterFn<F> {\n    // TODO: could include a `debug_str: &'static str` to be used in Debug impl\n    func: F,\n}\n\nimpl<F, U> FilterBase for FilterFn<F>\nwhere\n    F: Fn(&mut Route) -> U,\n    U: TryFuture + Send + 'static,\n    U::Ok: Tuple + Send,\n    U::Error: IsReject,\n{\n    type Extract = U::Ok;\n    type Error = U::Error;\n    type Future = future::IntoFuture<U>;\n\n    #[inline]\n    fn filter(&self, _: Internal) -> Self::Future {\n        route::with(|route| (self.func)(route)).into_future()\n    }\n}\n"
  },
  {
    "path": "src/filter/or.rs",
    "content": "use std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse futures_util::{ready, TryFuture};\nuse pin_project::pin_project;\n\nuse super::{Filter, FilterBase, Internal};\nuse crate::generic::Either;\nuse crate::reject::CombineRejection;\nuse crate::route;\n\ntype Combined<E1, E2> = <E1 as CombineRejection<E2>>::Combined;\n\n#[derive(Clone, Copy, Debug)]\npub struct Or<T, U> {\n    pub(super) first: T,\n    pub(super) second: U,\n}\n\nimpl<T, U> FilterBase for Or<T, U>\nwhere\n    T: Filter,\n    U: Filter + Clone + Send,\n    U::Error: CombineRejection<T::Error>,\n{\n    type Extract = (Either<T::Extract, U::Extract>,);\n    //type Error = <U::Error as CombineRejection<T::Error>>::Combined;\n    type Error = Combined<U::Error, T::Error>;\n    type Future = EitherFuture<T, U>;\n\n    fn filter(&self, _: Internal) -> Self::Future {\n        let idx = route::with(|route| route.matched_path_index());\n        EitherFuture {\n            state: State::First(self.first.filter(Internal), self.second.clone()),\n            original_path_index: PathIndex(idx),\n        }\n    }\n}\n\n#[allow(missing_debug_implementations)]\n#[pin_project]\npub struct EitherFuture<T: Filter, U: Filter> {\n    #[pin]\n    state: State<T, U>,\n    original_path_index: PathIndex,\n}\n\n#[pin_project(project = StateProj)]\nenum State<T: Filter, U: Filter> {\n    First(#[pin] T::Future, U),\n    Second(Option<T::Error>, #[pin] U::Future),\n    Done,\n}\n\n#[derive(Copy, Clone)]\nstruct PathIndex(usize);\n\nimpl PathIndex {\n    fn reset_path(&self) {\n        route::with(|route| route.reset_matched_path_index(self.0));\n    }\n}\n\nimpl<T, U> Future for EitherFuture<T, U>\nwhere\n    T: Filter,\n    U: Filter,\n    U::Error: CombineRejection<T::Error>,\n{\n    type Output = Result<(Either<T::Extract, U::Extract>,), Combined<U::Error, T::Error>>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        loop {\n            let pin = self.as_mut().project();\n            let (err1, fut2) = match pin.state.project() {\n                StateProj::First(first, second) => match ready!(first.try_poll(cx)) {\n                    Ok(ex1) => {\n                        return Poll::Ready(Ok((Either::A(ex1),)));\n                    }\n                    Err(e) => {\n                        pin.original_path_index.reset_path();\n                        (e, second.filter(Internal))\n                    }\n                },\n                StateProj::Second(err1, second) => {\n                    let ex2 = match ready!(second.try_poll(cx)) {\n                        Ok(ex2) => Ok((Either::B(ex2),)),\n                        Err(e) => {\n                            pin.original_path_index.reset_path();\n                            let err1 = err1.take().expect(\"polled after complete\");\n                            Err(e.combine(err1))\n                        }\n                    };\n                    self.set(EitherFuture {\n                        state: State::Done,\n                        ..*self\n                    });\n                    return Poll::Ready(ex2);\n                }\n                StateProj::Done => panic!(\"polled after complete\"),\n            };\n\n            self.set(EitherFuture {\n                state: State::Second(Some(err1), fut2),\n                ..*self\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/filter/or_else.rs",
    "content": "use std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse futures_util::{ready, TryFuture};\nuse pin_project::pin_project;\n\nuse super::{Filter, FilterBase, Func, Internal};\nuse crate::reject::IsReject;\nuse crate::route;\n\n#[derive(Clone, Copy, Debug)]\npub struct OrElse<T, F> {\n    pub(super) filter: T,\n    pub(super) callback: F,\n}\n\nimpl<T, F> FilterBase for OrElse<T, F>\nwhere\n    T: Filter,\n    F: Func<T::Error> + Clone + Send,\n    F::Output: TryFuture<Ok = T::Extract> + Send,\n    <F::Output as TryFuture>::Error: IsReject,\n{\n    type Extract = <F::Output as TryFuture>::Ok;\n    type Error = <F::Output as TryFuture>::Error;\n    type Future = OrElseFuture<T, F>;\n    #[inline]\n    fn filter(&self, _: Internal) -> Self::Future {\n        let idx = route::with(|route| route.matched_path_index());\n        OrElseFuture {\n            state: State::First(self.filter.filter(Internal), self.callback.clone()),\n            original_path_index: PathIndex(idx),\n        }\n    }\n}\n\n#[allow(missing_debug_implementations)]\n#[pin_project]\npub struct OrElseFuture<T: Filter, F>\nwhere\n    T: Filter,\n    F: Func<T::Error>,\n    F::Output: TryFuture<Ok = T::Extract> + Send,\n{\n    #[pin]\n    state: State<T, F>,\n    original_path_index: PathIndex,\n}\n\n#[pin_project(project = StateProj)]\nenum State<T, F>\nwhere\n    T: Filter,\n    F: Func<T::Error>,\n    F::Output: TryFuture<Ok = T::Extract> + Send,\n{\n    First(#[pin] T::Future, F),\n    Second(#[pin] F::Output),\n    Done,\n}\n\n#[derive(Copy, Clone)]\nstruct PathIndex(usize);\n\nimpl PathIndex {\n    fn reset_path(&self) {\n        route::with(|route| route.reset_matched_path_index(self.0));\n    }\n}\n\nimpl<T, F> Future for OrElseFuture<T, F>\nwhere\n    T: Filter,\n    F: Func<T::Error>,\n    F::Output: TryFuture<Ok = T::Extract> + Send,\n{\n    type Output = Result<<F::Output as TryFuture>::Ok, <F::Output as TryFuture>::Error>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        loop {\n            let pin = self.as_mut().project();\n            let (err, second) = match pin.state.project() {\n                StateProj::First(first, second) => match ready!(first.try_poll(cx)) {\n                    Ok(ex) => return Poll::Ready(Ok(ex)),\n                    Err(err) => (err, second),\n                },\n                StateProj::Second(second) => {\n                    let ex2 = ready!(second.try_poll(cx));\n                    self.set(OrElseFuture {\n                        state: State::Done,\n                        ..*self\n                    });\n                    return Poll::Ready(ex2);\n                }\n                StateProj::Done => panic!(\"polled after complete\"),\n            };\n\n            pin.original_path_index.reset_path();\n            let fut2 = second.call(err);\n            self.set(OrElseFuture {\n                state: State::Second(fut2),\n                ..*self\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/filter/recover.rs",
    "content": "use std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse futures_util::{ready, TryFuture};\nuse pin_project::pin_project;\n\nuse super::{Filter, FilterBase, Func, Internal};\nuse crate::generic::Either;\nuse crate::reject::IsReject;\nuse crate::route;\n\n#[derive(Clone, Copy, Debug)]\npub struct Recover<T, F> {\n    pub(super) filter: T,\n    pub(super) callback: F,\n}\n\nimpl<T, F> FilterBase for Recover<T, F>\nwhere\n    T: Filter,\n    F: Func<T::Error> + Clone + Send,\n    F::Output: TryFuture + Send,\n    <F::Output as TryFuture>::Error: IsReject,\n{\n    type Extract = (Either<T::Extract, (<F::Output as TryFuture>::Ok,)>,);\n    type Error = <F::Output as TryFuture>::Error;\n    type Future = RecoverFuture<T, F>;\n    #[inline]\n    fn filter(&self, _: Internal) -> Self::Future {\n        let idx = route::with(|route| route.matched_path_index());\n        RecoverFuture {\n            state: State::First(self.filter.filter(Internal), self.callback.clone()),\n            original_path_index: PathIndex(idx),\n        }\n    }\n}\n\n#[allow(missing_debug_implementations)]\n#[pin_project]\npub struct RecoverFuture<T: Filter, F>\nwhere\n    T: Filter,\n    F: Func<T::Error>,\n    F::Output: TryFuture + Send,\n    <F::Output as TryFuture>::Error: IsReject,\n{\n    #[pin]\n    state: State<T, F>,\n    original_path_index: PathIndex,\n}\n\n#[pin_project(project = StateProj)]\nenum State<T, F>\nwhere\n    T: Filter,\n    F: Func<T::Error>,\n    F::Output: TryFuture + Send,\n    <F::Output as TryFuture>::Error: IsReject,\n{\n    First(#[pin] T::Future, F),\n    Second(#[pin] F::Output),\n    Done,\n}\n\n#[derive(Copy, Clone)]\nstruct PathIndex(usize);\n\nimpl PathIndex {\n    fn reset_path(&self) {\n        route::with(|route| route.reset_matched_path_index(self.0));\n    }\n}\n\nimpl<T, F> Future for RecoverFuture<T, F>\nwhere\n    T: Filter,\n    F: Func<T::Error>,\n    F::Output: TryFuture + Send,\n    <F::Output as TryFuture>::Error: IsReject,\n{\n    type Output = Result<\n        (Either<T::Extract, (<F::Output as TryFuture>::Ok,)>,),\n        <F::Output as TryFuture>::Error,\n    >;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        loop {\n            let pin = self.as_mut().project();\n            let (err, second) = match pin.state.project() {\n                StateProj::First(first, second) => match ready!(first.try_poll(cx)) {\n                    Ok(ex) => return Poll::Ready(Ok((Either::A(ex),))),\n                    Err(err) => (err, second),\n                },\n                StateProj::Second(second) => {\n                    let ex2 = match ready!(second.try_poll(cx)) {\n                        Ok(ex2) => Ok((Either::B((ex2,)),)),\n                        Err(e) => Err(e),\n                    };\n                    self.set(RecoverFuture {\n                        state: State::Done,\n                        ..*self\n                    });\n                    return Poll::Ready(ex2);\n                }\n                StateProj::Done => panic!(\"polled after complete\"),\n            };\n\n            pin.original_path_index.reset_path();\n            let fut2 = second.call(err);\n            self.set(RecoverFuture {\n                state: State::Second(fut2),\n                ..*self\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "src/filter/service.rs",
    "content": "use std::convert::Infallible;\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse futures_util::future::TryFuture;\nuse pin_project::pin_project;\nuse tower_service::Service;\n\nuse crate::reject::IsReject;\nuse crate::reply::{Reply, Response};\nuse crate::route::{self, Route};\nuse crate::{Filter, Request};\n\n/// Convert a `Filter` into a `Service`.\n///\n/// Filters are normally what APIs are built on in warp. However, it can be\n/// useful to convert a `Filter` into a [`Service`][Service], such as if\n/// further customizing a `hyper::Service`, or if wanting to make use of\n/// the greater [Tower][tower] set of middleware.\n///\n/// # Example\n///\n/// Running a `warp::Filter` on a regular `hyper::Server`:\n///\n/// ```\n/// # async fn run() -> Result<(), Box<dyn std::error::Error>> {\n/// use std::convert::Infallible;\n/// use warp::Filter;\n///\n/// // Our Filter...\n/// let route = warp::any().map(|| \"Hello From Warp!\");\n///\n/// // Convert it into a `Service`...\n/// let svc = warp::service(route);\n/// # drop(svc);\n/// # Ok(())\n/// # }\n/// ```\n///\n/// [Service]: https://docs.rs/tower_service/latest/tower_service/trait.Service.html\n/// [tower]: https://docs.rs/tower\npub fn service<F>(filter: F) -> FilteredService<F>\nwhere\n    F: Filter,\n    <F::Future as TryFuture>::Ok: Reply,\n    <F::Future as TryFuture>::Error: IsReject,\n{\n    FilteredService { filter }\n}\n\n#[derive(Copy, Clone, Debug)]\npub struct FilteredService<F> {\n    filter: F,\n}\n\nimpl<F> FilteredService<F>\nwhere\n    F: Filter,\n    <F::Future as TryFuture>::Ok: Reply,\n    <F::Future as TryFuture>::Error: IsReject,\n{\n    #[inline]\n    pub(crate) fn call_route(&self, req: Request) -> FilteredFuture<F::Future> {\n        debug_assert!(!route::is_set(), \"nested route::set calls\");\n\n        let route = Route::new(req);\n        let fut = route::set(&route, || self.filter.filter(super::Internal));\n        FilteredFuture { future: fut, route }\n    }\n}\n\nimpl<F, B> Service<http::Request<B>> for FilteredService<F>\nwhere\n    F: Filter,\n    <F::Future as TryFuture>::Ok: Reply,\n    <F::Future as TryFuture>::Error: IsReject,\n    B: http_body::Body + Send + Sync + 'static,\n    B::Error: Into<Box<dyn std::error::Error + Send + Sync>>,\n{\n    type Response = Response;\n    type Error = Infallible;\n    type Future = FilteredFuture<F::Future>;\n\n    fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        Poll::Ready(Ok(()))\n    }\n\n    #[inline]\n    fn call(&mut self, req: http::Request<B>) -> Self::Future {\n        let req = req.map(crate::bodyt::Body::wrap);\n        self.call_route(req)\n    }\n}\n\n#[pin_project]\n#[derive(Debug)]\npub struct FilteredFuture<F> {\n    #[pin]\n    future: F,\n    route: ::std::cell::RefCell<Route>,\n}\n\nimpl<F> Future for FilteredFuture<F>\nwhere\n    F: TryFuture,\n    F::Ok: Reply,\n    F::Error: IsReject,\n{\n    type Output = Result<Response, Infallible>;\n\n    #[inline]\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        debug_assert!(!route::is_set(), \"nested route::set calls\");\n\n        let pin = self.project();\n        let fut = pin.future;\n        match route::set(pin.route, || fut.try_poll(cx)) {\n            Poll::Ready(Ok(ok)) => Poll::Ready(Ok(ok.into_response())),\n            Poll::Pending => Poll::Pending,\n            Poll::Ready(Err(err)) => {\n                tracing::debug!(\"rejected: {:?}\", err);\n                Poll::Ready(Ok(err.into_response()))\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/filter/then.rs",
    "content": "use std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse futures_util::{ready, TryFuture};\nuse pin_project::pin_project;\n\nuse super::{Filter, FilterBase, Func, Internal};\n\n#[derive(Clone, Copy, Debug)]\npub struct Then<T, F> {\n    pub(super) filter: T,\n    pub(super) callback: F,\n}\n\nimpl<T, F> FilterBase for Then<T, F>\nwhere\n    T: Filter,\n    F: Func<T::Extract> + Clone + Send,\n    F::Output: Future + Send,\n{\n    type Extract = (<F::Output as Future>::Output,);\n    type Error = T::Error;\n    type Future = ThenFuture<T, F>;\n    #[inline]\n    fn filter(&self, _: Internal) -> Self::Future {\n        ThenFuture {\n            state: State::First(self.filter.filter(Internal), self.callback.clone()),\n        }\n    }\n}\n\n#[allow(missing_debug_implementations)]\n#[pin_project]\npub struct ThenFuture<T, F>\nwhere\n    T: Filter,\n    F: Func<T::Extract>,\n    F::Output: Future + Send,\n{\n    #[pin]\n    state: State<T::Future, F>,\n}\n\n#[pin_project(project = StateProj)]\nenum State<T, F>\nwhere\n    T: TryFuture,\n    F: Func<T::Ok>,\n    F::Output: Future + Send,\n{\n    First(#[pin] T, F),\n    Second(#[pin] F::Output),\n    Done,\n}\n\nimpl<T, F> Future for ThenFuture<T, F>\nwhere\n    T: Filter,\n    F: Func<T::Extract>,\n    F::Output: Future + Send,\n{\n    type Output = Result<(<F::Output as Future>::Output,), T::Error>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        self.project().state.poll(cx)\n    }\n}\n\nimpl<T, F> Future for State<T, F>\nwhere\n    T: TryFuture,\n    F: Func<T::Ok>,\n    F::Output: Future + Send,\n{\n    type Output = Result<(<F::Output as Future>::Output,), T::Error>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        loop {\n            match self.as_mut().project() {\n                StateProj::First(first, second) => {\n                    let ex1 = ready!(first.try_poll(cx))?;\n                    let fut2 = second.call(ex1);\n                    self.set(State::Second(fut2));\n                }\n                StateProj::Second(second) => {\n                    let ex2 = (ready!(second.poll(cx)),);\n                    self.set(State::Done);\n                    return Poll::Ready(Ok(ex2));\n                }\n                StateProj::Done => panic!(\"polled after complete\"),\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/filter/unify.rs",
    "content": "use std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse futures_util::{ready, TryFuture};\nuse pin_project::pin_project;\n\nuse super::{Either, Filter, FilterBase, Internal, Tuple};\n\n#[derive(Clone, Copy, Debug)]\npub struct Unify<F> {\n    pub(super) filter: F,\n}\n\nimpl<F, T> FilterBase for Unify<F>\nwhere\n    F: Filter<Extract = (Either<T, T>,)>,\n    T: Tuple,\n{\n    type Extract = T;\n    type Error = F::Error;\n    type Future = UnifyFuture<F::Future>;\n    #[inline]\n    fn filter(&self, _: Internal) -> Self::Future {\n        UnifyFuture {\n            inner: self.filter.filter(Internal),\n        }\n    }\n}\n\n#[allow(missing_debug_implementations)]\n#[pin_project]\npub struct UnifyFuture<F> {\n    #[pin]\n    inner: F,\n}\n\nimpl<F, T> Future for UnifyFuture<F>\nwhere\n    F: TryFuture<Ok = (Either<T, T>,)>,\n{\n    type Output = Result<T, F::Error>;\n\n    #[inline]\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        Poll::Ready(match ready!(self.project().inner.try_poll(cx))? {\n            (Either::A(x),) | (Either::B(x),) => Ok(x),\n        })\n    }\n}\n"
  },
  {
    "path": "src/filter/untuple_one.rs",
    "content": "use std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse futures_util::{ready, TryFuture};\nuse pin_project::pin_project;\n\nuse super::{Filter, FilterBase, Internal, Tuple};\n\n#[derive(Clone, Copy, Debug)]\npub struct UntupleOne<F> {\n    pub(super) filter: F,\n}\n\nimpl<F, T> FilterBase for UntupleOne<F>\nwhere\n    F: Filter<Extract = (T,)>,\n    T: Tuple,\n{\n    type Extract = T;\n    type Error = F::Error;\n    type Future = UntupleOneFuture<F>;\n    #[inline]\n    fn filter(&self, _: Internal) -> Self::Future {\n        UntupleOneFuture {\n            extract: self.filter.filter(Internal),\n        }\n    }\n}\n\n#[allow(missing_debug_implementations)]\n#[pin_project]\npub struct UntupleOneFuture<F: Filter> {\n    #[pin]\n    extract: F::Future,\n}\n\nimpl<F, T> Future for UntupleOneFuture<F>\nwhere\n    F: Filter<Extract = (T,)>,\n    T: Tuple,\n{\n    type Output = Result<T, F::Error>;\n\n    #[inline]\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        match ready!(self.project().extract.try_poll(cx)) {\n            Ok((t,)) => Poll::Ready(Ok(t)),\n            Err(err) => Poll::Ready(Err(err)),\n        }\n    }\n}\n"
  },
  {
    "path": "src/filter/wrap.rs",
    "content": "use super::Filter;\n\npub trait WrapSealed<F: Filter> {\n    type Wrapped: Filter;\n\n    fn wrap(&self, filter: F) -> Self::Wrapped;\n}\n\nimpl<'a, T, F> WrapSealed<F> for &'a T\nwhere\n    T: WrapSealed<F>,\n    F: Filter,\n{\n    type Wrapped = T::Wrapped;\n    fn wrap(&self, filter: F) -> Self::Wrapped {\n        (*self).wrap(filter)\n    }\n}\n\npub trait Wrap<F: Filter>: WrapSealed<F> {}\n\nimpl<T, F> Wrap<F> for T\nwhere\n    T: WrapSealed<F>,\n    F: Filter,\n{\n}\n\n/// Combines received filter with pre and after filters\n///\n/// # Example\n///\n/// ```\n/// use crate::warp::Filter;\n///\n/// let route = warp::any()\n///     .map(|| \"hello world\")\n///     .with(warp::wrap_fn(|filter| filter));\n/// ```\n///\n/// You can find the full example in the [usage example](https://github.com/seanmonstar/warp/blob/master/examples/wrapping.rs).\npub fn wrap_fn<F, T, U>(func: F) -> WrapFn<F>\nwhere\n    F: Fn(T) -> U,\n    T: Filter,\n    U: Filter,\n{\n    WrapFn { func }\n}\n\n#[derive(Debug)]\npub struct WrapFn<F> {\n    func: F,\n}\n\nimpl<F, T, U> WrapSealed<T> for WrapFn<F>\nwhere\n    F: Fn(T) -> U,\n    T: Filter,\n    U: Filter,\n{\n    type Wrapped = U;\n\n    fn wrap(&self, filter: T) -> Self::Wrapped {\n        (self.func)(filter)\n    }\n}\n"
  },
  {
    "path": "src/filters/addr.rs",
    "content": "//! Socket Address filters.\n\nuse std::convert::Infallible;\nuse std::net::SocketAddr;\n\nuse futures_util::future;\n\nuse crate::filter::{filter_fn_one, Filter};\n\n/// Creates a `Filter` to get the remote address of the connection.\n///\n/// If the underlying transport doesn't use socket addresses, this will yield\n/// `None`.\n///\n/// # Example\n///\n/// ```\n/// use std::net::SocketAddr;\n/// use warp::Filter;\n///\n/// let route = warp::addr::remote()\n///     .map(|addr: Option<SocketAddr>| {\n///         println!(\"remote address = {:?}\", addr);\n///     });\n/// ```\npub fn remote() -> impl Filter<Extract = (Option<SocketAddr>,), Error = Infallible> + Copy {\n    filter_fn_one(|route| {\n        future::ok(\n            route\n                .extensions()\n                .get::<RemoteAddr>()\n                .map(|RemoteAddr(addr)| *addr),\n        )\n    })\n}\n\n#[derive(Debug, Clone, Copy)]\npub(crate) struct RemoteAddr(pub(crate) SocketAddr);\n"
  },
  {
    "path": "src/filters/any.rs",
    "content": "//! A filter that matches any route.\nuse std::convert::Infallible;\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse crate::filter::{Filter, FilterBase, Internal};\n\n/// A [`Filter`] that matches any route.\n///\n/// This can be a useful building block to build new filters from,\n/// since [`Filter`] is otherwise a sealed trait.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let route = warp::any()\n///     .map(|| {\n///         \"I always return this string!\"\n///     });\n/// ```\n///\n/// This could allow creating a single `impl Filter` returning a specific\n/// reply, that can then be used as the end of several different filter\n/// chains.\n///\n/// Another use case is turning some clone-able resource into a `Filter`,\n/// thus allowing to easily `and` it together with others.\n///\n/// ```\n/// use std::sync::Arc;\n/// use warp::Filter;\n///\n/// let state = Arc::new(vec![33, 41]);\n/// let with_state = warp::any().map(move || state.clone());\n///\n/// // Now we could `and` with any other filter:\n///\n/// let route = warp::path::param()\n///     .and(with_state)\n///     .map(|param_id: u32, db: Arc<Vec<u32>>| {\n///         db.contains(&param_id)\n///     });\n/// ```\npub fn any() -> impl Filter<Extract = (), Error = Infallible> + Copy {\n    Any\n}\n\n#[derive(Copy, Clone)]\n#[allow(missing_debug_implementations)]\nstruct Any;\n\nimpl FilterBase for Any {\n    type Extract = ();\n    type Error = Infallible;\n    type Future = AnyFut;\n\n    #[inline]\n    fn filter(&self, _: Internal) -> Self::Future {\n        AnyFut\n    }\n}\n\n#[allow(missing_debug_implementations)]\nstruct AnyFut;\n\nimpl Future for AnyFut {\n    type Output = Result<(), Infallible>;\n\n    #[inline]\n    fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {\n        Poll::Ready(Ok(()))\n    }\n}\n"
  },
  {
    "path": "src/filters/body.rs",
    "content": "//! Body filters\n//!\n//! Filters that extract a body for a route.\n\nuse std::error::Error as StdError;\nuse std::fmt;\n\nuse crate::bodyt::Body;\nuse bytes::{Buf, Bytes};\nuse futures_util::future;\nuse futures_util::Stream;\nuse headers::ContentLength;\nuse http::header::CONTENT_TYPE;\nuse http_body_util::BodyDataStream;\nuse http_body_util::BodyExt;\nuse mime;\nuse serde::de::DeserializeOwned;\n\nuse crate::filter::{filter_fn, filter_fn_one, Filter, FilterBase};\nuse crate::reject::{self, Rejection};\n\ntype BoxError = Box<dyn StdError + Send + Sync>;\n\n// Extracts the `Body` Stream from the route.\n//\n// Does not consume any of it.\npub(crate) fn body() -> impl Filter<Extract = (Body,), Error = Rejection> + Copy {\n    filter_fn_one(|route| {\n        future::ready(route.take_body().ok_or_else(|| {\n            tracing::error!(\"request body already taken in previous filter\");\n            reject::known(BodyConsumedMultipleTimes { _p: () })\n        }))\n    })\n}\n\n/// Require a `content-length` header to have a value no greater than some limit.\n///\n/// Rejects if `content-length` header is missing, is invalid, or has a number\n/// larger than the limit provided.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// // Limit the upload to 4kb...\n/// let upload = warp::body::content_length_limit(4096)\n///     .and(warp::body::aggregate());\n/// ```\npub fn content_length_limit(limit: u64) -> impl Filter<Extract = (), Error = Rejection> + Copy {\n    crate::filters::header::header2()\n        .map_err(crate::filter::Internal, |_| {\n            tracing::debug!(\"content-length missing\");\n            reject::length_required()\n        })\n        .and_then(move |ContentLength(length)| {\n            if length <= limit {\n                future::ok(())\n            } else {\n                tracing::debug!(\"content-length: {} is over limit {}\", length, limit);\n                future::err(reject::payload_too_large())\n            }\n        })\n        .untuple_one()\n}\n\n/// Create a `Filter` that extracts the request body as a `futures::Stream`.\n///\n/// If other filters have already extracted the body, this filter will reject\n/// with a `500 Internal Server Error`.\n///\n/// For example usage, please take a look at [examples/stream.rs](https://github.com/seanmonstar/warp/blob/master/examples/stream.rs).\n///\n/// # Warning\n///\n/// This does not have a default size limit, it would be wise to use one to\n/// prevent a overly large request from using too much memory.\npub fn stream(\n) -> impl Filter<Extract = (impl Stream<Item = Result<impl Buf, crate::Error>>,), Error = Rejection> + Copy\n{\n    body().map(|body| BodyDataStream::new(body))\n}\n\n/// Returns a `Filter` that matches any request and extracts a `Future` of a\n/// concatenated body.\n///\n/// The contents of the body will be flattened into a single contiguous\n/// `Bytes`, which may require memory copies. If you don't require a\n/// contiguous buffer, using `aggregate` can be give better performance.\n///\n/// # Warning\n///\n/// This does not have a default size limit, it would be wise to use one to\n/// prevent a overly large request from using too much memory.\n///\n/// # Example\n///\n/// ```\n/// use warp::{Buf, Filter};\n///\n/// let route = warp::body::content_length_limit(1024 * 32)\n///     .and(warp::body::bytes())\n///     .map(|bytes: bytes::Bytes| {\n///         println!(\"bytes = {:?}\", bytes);\n///     });\n/// ```\npub fn bytes() -> impl Filter<Extract = (Bytes,), Error = Rejection> + Copy {\n    body().and_then(|mut body| async move {\n        BodyExt::collect(&mut body)\n            .await\n            .map(|b| b.to_bytes())\n            .map_err(|err| {\n                tracing::debug!(\"to_bytes error: {}\", err);\n                reject::known(BodyReadError(err))\n            })\n    })\n}\n\n/// Returns a `Filter` that matches any request and extracts a `Future` of an\n/// aggregated body.\n///\n/// The `Buf` may contain multiple, non-contiguous buffers. This can be more\n/// performant (by reducing copies) when receiving large bodies.\n///\n/// # Warning\n///\n/// This does not have a default size limit, it would be wise to use one to\n/// prevent a overly large request from using too much memory.\n///\n/// # Example\n///\n/// ```\n/// use warp::{Buf, Filter};\n///\n/// fn full_body(mut body: impl Buf) {\n///     // It could have several non-contiguous slices of memory...\n///     while body.has_remaining() {\n///         println!(\"slice = {:?}\", body.chunk());\n///         let cnt = body.chunk().len();\n///         body.advance(cnt);\n///     }\n/// }\n///\n/// let route = warp::body::content_length_limit(1024 * 32)\n///     .and(warp::body::aggregate())\n///     .map(full_body);\n/// ```\npub fn aggregate() -> impl Filter<Extract = (impl Buf,), Error = Rejection> + Copy {\n    body().and_then(|mut body: crate::bodyt::Body| async move {\n        http_body_util::BodyExt::collect(&mut body)\n            .await\n            .map(|collected| collected.aggregate())\n            .map_err(|err| {\n                tracing::debug!(\"aggregate error: {}\", err);\n                reject::known(BodyReadError(err))\n            })\n    })\n}\n\n/// Returns a `Filter` that matches any request and extracts a `Future` of a\n/// JSON-decoded body.\n///\n/// # Warning\n///\n/// This does not have a default size limit, it would be wise to use one to\n/// prevent a overly large request from using too much memory.\n///\n/// # Example\n///\n/// ```\n/// use std::collections::HashMap;\n/// use warp::Filter;\n///\n/// let route = warp::body::content_length_limit(1024 * 32)\n///     .and(warp::body::json())\n///     .map(|simple_map: HashMap<String, String>| {\n///         \"Got a JSON body!\"\n///     });\n/// ```\npub fn json<T: DeserializeOwned + Send>() -> impl Filter<Extract = (T,), Error = Rejection> + Copy {\n    is_content_type::<Json>()\n        .and(bytes())\n        .and_then(|buf| async move {\n            Json::decode(buf).map_err(|err| {\n                tracing::debug!(\"request json body error: {}\", err);\n                reject::known(BodyDeserializeError { cause: err })\n            })\n        })\n}\n\n/// Returns a `Filter` that matches any request and extracts a\n/// `Future` of a form encoded body.\n///\n/// # Note\n///\n/// This filter is for the simpler `application/x-www-form-urlencoded` format,\n/// not `multipart/form-data`.\n///\n/// # Warning\n///\n/// This does not have a default size limit, it would be wise to use one to\n/// prevent a overly large request from using too much memory.\n///\n///\n/// ```\n/// use std::collections::HashMap;\n/// use warp::Filter;\n///\n/// let route = warp::body::content_length_limit(1024 * 32)\n///     .and(warp::body::form())\n///     .map(|simple_map: HashMap<String, String>| {\n///         \"Got a urlencoded body!\"\n///     });\n/// ```\npub fn form<T: DeserializeOwned + Send>() -> impl Filter<Extract = (T,), Error = Rejection> + Copy {\n    is_content_type::<Form>()\n        .and(aggregate())\n        .and_then(|buf| async move {\n            Form::decode(buf).map_err(|err| {\n                tracing::debug!(\"request form body error: {}\", err);\n                reject::known(BodyDeserializeError { cause: err })\n            })\n        })\n}\n\n// ===== Decoders =====\n\ntrait Decode {\n    const MIME: (mime::Name<'static>, mime::Name<'static>);\n    const WITH_NO_CONTENT_TYPE: bool;\n\n    fn decode<B: Buf, T: DeserializeOwned>(buf: B) -> Result<T, BoxError>;\n}\n\nstruct Json;\n\nimpl Decode for Json {\n    const MIME: (mime::Name<'static>, mime::Name<'static>) = (mime::APPLICATION, mime::JSON);\n    const WITH_NO_CONTENT_TYPE: bool = true;\n\n    fn decode<B: Buf, T: DeserializeOwned>(mut buf: B) -> Result<T, BoxError> {\n        serde_json::from_slice(&buf.copy_to_bytes(buf.remaining())).map_err(Into::into)\n    }\n}\n\nstruct Form;\n\nimpl Decode for Form {\n    const MIME: (mime::Name<'static>, mime::Name<'static>) =\n        (mime::APPLICATION, mime::WWW_FORM_URLENCODED);\n    const WITH_NO_CONTENT_TYPE: bool = true;\n\n    fn decode<B: Buf, T: DeserializeOwned>(buf: B) -> Result<T, BoxError> {\n        serde_urlencoded::from_reader(buf.reader()).map_err(Into::into)\n    }\n}\n\n// Require the `content-type` header to be this type (or, if there's no `content-type`\n// header at all, optimistically hope it's the right type).\nfn is_content_type<D: Decode>() -> impl Filter<Extract = (), Error = Rejection> + Copy {\n    filter_fn(move |route| {\n        let (type_, subtype) = D::MIME;\n        if let Some(value) = route.headers().get(CONTENT_TYPE) {\n            tracing::trace!(\"is_content_type {}/{}? {:?}\", type_, subtype, value);\n            let ct = value\n                .to_str()\n                .ok()\n                .and_then(|s| s.parse::<mime::Mime>().ok());\n            if let Some(ct) = ct {\n                if ct.type_() == type_ && ct.subtype() == subtype {\n                    future::ok(())\n                } else {\n                    tracing::debug!(\n                        \"content-type {:?} doesn't match {}/{}\",\n                        value,\n                        type_,\n                        subtype\n                    );\n                    future::err(reject::unsupported_media_type())\n                }\n            } else {\n                tracing::debug!(\"content-type {:?} couldn't be parsed\", value);\n                future::err(reject::unsupported_media_type())\n            }\n        } else if D::WITH_NO_CONTENT_TYPE {\n            // Optimistically assume its correct!\n            tracing::trace!(\"no content-type header, assuming {}/{}\", type_, subtype);\n            future::ok(())\n        } else {\n            tracing::debug!(\"no content-type found\");\n            future::err(reject::unsupported_media_type())\n        }\n    })\n}\n\n// ===== Rejections =====\n\n/// An error used in rejections when deserializing a request body fails.\n#[derive(Debug)]\npub struct BodyDeserializeError {\n    cause: BoxError,\n}\n\nimpl fmt::Display for BodyDeserializeError {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"Request body deserialize error: {}\", self.cause)\n    }\n}\n\nimpl StdError for BodyDeserializeError {\n    fn source(&self) -> Option<&(dyn StdError + 'static)> {\n        Some(self.cause.as_ref())\n    }\n}\n\n#[derive(Debug)]\npub(crate) struct BodyReadError(crate::Error);\n\nimpl fmt::Display for BodyReadError {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"Request body read error: {}\", self.0)\n    }\n}\n\nimpl StdError for BodyReadError {}\n\nunit_error! {\n    pub(crate) BodyConsumedMultipleTimes: \"Request body consumed multiple times\"\n}\n"
  },
  {
    "path": "src/filters/compression.rs",
    "content": "//! Compression Filters\n//!\n//! Filters that compress the body of a response.\n\n#[cfg(feature = \"compression-brotli\")]\nuse async_compression::tokio::bufread::BrotliEncoder;\n\n#[cfg(feature = \"compression-gzip\")]\nuse async_compression::tokio::bufread::{DeflateEncoder, GzipEncoder};\n\nuse crate::bodyt::Body;\nuse http::header::{HeaderValue, CONTENT_ENCODING, CONTENT_LENGTH};\nuse tokio_util::io::{ReaderStream, StreamReader};\n\nuse crate::filter::{Filter, WrapSealed};\nuse crate::reject::IsReject;\nuse crate::reply::{Reply, Response};\n\nuse self::internal::{CompressionProps, WithCompression};\n\nenum CompressionAlgo {\n    #[cfg(feature = \"compression-brotli\")]\n    BR,\n    #[cfg(feature = \"compression-gzip\")]\n    DEFLATE,\n    #[cfg(feature = \"compression-gzip\")]\n    GZIP,\n}\n\nimpl From<CompressionAlgo> for HeaderValue {\n    #[inline]\n    fn from(algo: CompressionAlgo) -> Self {\n        HeaderValue::from_static(match algo {\n            #[cfg(feature = \"compression-brotli\")]\n            CompressionAlgo::BR => \"br\",\n            #[cfg(feature = \"compression-gzip\")]\n            CompressionAlgo::DEFLATE => \"deflate\",\n            #[cfg(feature = \"compression-gzip\")]\n            CompressionAlgo::GZIP => \"gzip\",\n        })\n    }\n}\n\n/// Compression\n#[derive(Clone, Copy, Debug)]\npub struct Compression<F> {\n    func: F,\n}\n\n// TODO: The implementation of `gzip()`, `deflate()`, and `brotli()` could be replaced with\n// generics or a macro\n\n/// Create a wrapping filter that compresses the Body of a [`Response`](crate::reply::Response)\n/// using gzip, adding `content-encoding: gzip` to the Response's [`HeaderMap`](hyper::HeaderMap)\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let route = warp::get()\n///     .and(warp::path::end())\n///     .and(warp::fs::file(\"./README.md\"))\n///     .with(warp::compression::gzip());\n/// ```\n#[cfg(feature = \"compression-gzip\")]\npub fn gzip() -> Compression<impl Fn(CompressionProps) -> Response + Copy> {\n    let func = move |mut props: CompressionProps| {\n        let body = Body::wrap_stream(ReaderStream::new(GzipEncoder::new(StreamReader::new(\n            props.body,\n        ))));\n        props\n            .head\n            .headers\n            .append(CONTENT_ENCODING, CompressionAlgo::GZIP.into());\n        props.head.headers.remove(CONTENT_LENGTH);\n        Response::from_parts(props.head, body)\n    };\n    Compression { func }\n}\n\n/// Create a wrapping filter that compresses the Body of a [`Response`](crate::reply::Response)\n/// using deflate, adding `content-encoding: deflate` to the Response's [`HeaderMap`](hyper::HeaderMap)\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let route = warp::get()\n///     .and(warp::path::end())\n///     .and(warp::fs::file(\"./README.md\"))\n///     .with(warp::compression::deflate());\n/// ```\n#[cfg(feature = \"compression-gzip\")]\npub fn deflate() -> Compression<impl Fn(CompressionProps) -> Response + Copy> {\n    let func = move |mut props: CompressionProps| {\n        let body = Body::wrap_stream(ReaderStream::new(DeflateEncoder::new(StreamReader::new(\n            props.body,\n        ))));\n        props\n            .head\n            .headers\n            .append(CONTENT_ENCODING, CompressionAlgo::DEFLATE.into());\n        props.head.headers.remove(CONTENT_LENGTH);\n        Response::from_parts(props.head, body)\n    };\n    Compression { func }\n}\n\n/// Create a wrapping filter that compresses the Body of a [`Response`](crate::reply::Response)\n/// using brotli, adding `content-encoding: br` to the Response's [`HeaderMap`](hyper::HeaderMap)\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let route = warp::get()\n///     .and(warp::path::end())\n///     .and(warp::fs::file(\"./README.md\"))\n///     .with(warp::compression::brotli());\n/// ```\n#[cfg(feature = \"compression-brotli\")]\npub fn brotli() -> Compression<impl Fn(CompressionProps) -> Response + Copy> {\n    let func = move |mut props: CompressionProps| {\n        let body = Body::wrap_stream(ReaderStream::new(BrotliEncoder::new(StreamReader::new(\n            props.body,\n        ))));\n        props\n            .head\n            .headers\n            .append(CONTENT_ENCODING, CompressionAlgo::BR.into());\n        props.head.headers.remove(CONTENT_LENGTH);\n        Response::from_parts(props.head, body)\n    };\n    Compression { func }\n}\n\nimpl<FN, F> WrapSealed<F> for Compression<FN>\nwhere\n    FN: Fn(CompressionProps) -> Response + Clone + Send,\n    F: Filter + Clone + Send,\n    F::Extract: Reply,\n    F::Error: IsReject,\n{\n    type Wrapped = WithCompression<FN, F>;\n\n    fn wrap(&self, filter: F) -> Self::Wrapped {\n        WithCompression {\n            filter,\n            compress: self.clone(),\n        }\n    }\n}\n\nmod internal {\n    use std::future::Future;\n    use std::pin::Pin;\n    use std::task::{Context, Poll};\n\n    use bytes::Bytes;\n    use futures_util::{ready, Stream, TryFuture};\n    use http_body_util::BodyDataStream;\n    use pin_project::pin_project;\n\n    use crate::bodyt::Body;\n    use crate::filter::{Filter, FilterBase, Internal};\n    use crate::reject::IsReject;\n    use crate::reply::{Reply, Response};\n\n    use super::Compression;\n\n    /// A wrapper around any type that implements [`Stream`](futures::Stream) to be\n    /// compatible with async_compression's Stream based encoders\n    #[pin_project]\n    #[derive(Debug)]\n    pub struct CompressableBody<S, E>\n    where\n        E: std::error::Error,\n        S: Stream<Item = Result<Bytes, E>>,\n    {\n        #[pin]\n        body: S,\n    }\n\n    impl<S, E> Stream for CompressableBody<S, E>\n    where\n        E: std::error::Error,\n        S: Stream<Item = Result<Bytes, E>>,\n    {\n        type Item = std::io::Result<Bytes>;\n\n        fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n            use std::io::{Error, ErrorKind};\n\n            let pin = self.project();\n            S::poll_next(pin.body, cx).map_err(|_| Error::from(ErrorKind::InvalidData))\n        }\n    }\n\n    impl From<Body> for CompressableBody<BodyDataStream<Body>, crate::Error> {\n        fn from(body: Body) -> Self {\n            CompressableBody {\n                body: BodyDataStream::new(body),\n            }\n        }\n    }\n\n    /// Compression Props\n    #[derive(Debug)]\n    pub struct CompressionProps {\n        pub(super) body: CompressableBody<BodyDataStream<Body>, crate::Error>,\n        pub(super) head: http::response::Parts,\n    }\n\n    impl From<http::Response<Body>> for CompressionProps {\n        fn from(resp: http::Response<Body>) -> Self {\n            let (head, body) = resp.into_parts();\n            CompressionProps {\n                body: body.into(),\n                head,\n            }\n        }\n    }\n\n    #[allow(missing_debug_implementations)]\n    pub struct Compressed(pub(super) Response);\n\n    impl Reply for Compressed {\n        #[inline]\n        fn into_response(self) -> Response {\n            self.0\n        }\n    }\n\n    #[allow(missing_debug_implementations)]\n    #[derive(Clone, Copy)]\n    pub struct WithCompression<FN, F> {\n        pub(super) compress: Compression<FN>,\n        pub(super) filter: F,\n    }\n\n    impl<FN, F> FilterBase for WithCompression<FN, F>\n    where\n        FN: Fn(CompressionProps) -> Response + Clone + Send,\n        F: Filter + Clone + Send,\n        F::Extract: Reply,\n        F::Error: IsReject,\n    {\n        type Extract = (Compressed,);\n        type Error = F::Error;\n        type Future = WithCompressionFuture<FN, F::Future>;\n\n        fn filter(&self, _: Internal) -> Self::Future {\n            WithCompressionFuture {\n                compress: self.compress.clone(),\n                future: self.filter.filter(Internal),\n            }\n        }\n    }\n\n    #[allow(missing_debug_implementations)]\n    #[pin_project]\n    pub struct WithCompressionFuture<FN, F> {\n        compress: Compression<FN>,\n        #[pin]\n        future: F,\n    }\n\n    impl<FN, F> Future for WithCompressionFuture<FN, F>\n    where\n        FN: Fn(CompressionProps) -> Response,\n        F: TryFuture,\n        F::Ok: Reply,\n        F::Error: IsReject,\n    {\n        type Output = Result<(Compressed,), F::Error>;\n\n        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n            let pin = self.as_mut().project();\n            let result = ready!(pin.future.try_poll(cx));\n            match result {\n                Ok(reply) => {\n                    let resp = (self.compress.func)(reply.into_response().into());\n                    Poll::Ready(Ok((Compressed(resp),)))\n                }\n                Err(reject) => Poll::Ready(Err(reject)),\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/filters/cookie.rs",
    "content": "//! Cookie Filters\n\nuse futures_util::future;\nuse headers::Cookie;\n\nuse super::header;\nuse crate::filter::{Filter, One};\nuse crate::reject::Rejection;\nuse std::convert::Infallible;\nuse std::str::FromStr;\n\n/// Creates a `Filter` that requires a cookie by name.\n///\n/// If found, extracts the value of the cookie, otherwise rejects.\npub fn cookie<T>(name: &'static str) -> impl Filter<Extract = One<T>, Error = Rejection> + Copy\nwhere\n    T: FromStr + Send + 'static,\n{\n    header::header2().and_then(move |cookie: Cookie| {\n        let cookie = cookie\n            .get(name)\n            .ok_or_else(|| crate::reject::missing_cookie(name))\n            .and_then(|s| T::from_str(s).map_err(|_| crate::reject::missing_cookie(name)));\n        future::ready(cookie)\n    })\n}\n\n/// Creates a `Filter` that looks for an optional cookie by name.\n///\n/// If found, extracts the value of the cookie, otherwise continues\n/// the request, extracting `None`.\npub fn optional<T>(\n    name: &'static str,\n) -> impl Filter<Extract = One<Option<T>>, Error = Infallible> + Copy\nwhere\n    T: FromStr + Send + 'static,\n{\n    header::optional2().map(move |opt: Option<Cookie>| {\n        let cookie = opt.and_then(|cookie| cookie.get(name).map(|x| T::from_str(x)));\n        match cookie {\n            Some(Ok(t)) => Some(t),\n            Some(Err(_)) => None,\n            None => None,\n        }\n    })\n}\n"
  },
  {
    "path": "src/filters/cors.rs",
    "content": "//! CORS Filters\n\nuse std::collections::HashSet;\nuse std::convert::TryFrom;\nuse std::error::Error as StdError;\nuse std::fmt;\nuse std::sync::Arc;\n\nuse headers::{\n    AccessControlAllowHeaders, AccessControlAllowMethods, AccessControlExposeHeaders, HeaderMapExt,\n};\nuse http::header::{self, HeaderName, HeaderValue};\n\nuse crate::filter::{Filter, WrapSealed};\nuse crate::reject::{CombineRejection, Rejection};\nuse crate::reply::Reply;\n\nuse self::internal::{CorsFilter, IntoOrigin, Seconds};\n\n/// Create a wrapping [`Filter`] that exposes [CORS][] behavior for a wrapped\n/// filter.\n///\n/// [CORS]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let cors = warp::cors()\n///     .allow_origin(\"https://hyper.rs\")\n///     .allow_methods(vec![\"GET\", \"POST\", \"DELETE\"]);\n///\n/// let route = warp::any()\n///     .map(warp::reply)\n///     .with(cors);\n/// ```\n/// If you want to allow any route:\n/// ```\n/// use warp::Filter;\n/// let cors = warp::cors()\n///     .allow_any_origin();\n/// ```\n/// You can find more usage examples [here](https://github.com/seanmonstar/warp/blob/7fa54eaecd0fe12687137372791ff22fc7995766/tests/cors.rs).\npub fn cors() -> Builder {\n    Builder {\n        credentials: false,\n        allowed_headers: HashSet::new(),\n        exposed_headers: HashSet::new(),\n        max_age: None,\n        methods: HashSet::new(),\n        origins: None,\n    }\n}\n\n/// A wrapping [`Filter`] constructed via [`cors()`].\n#[derive(Clone, Debug)]\npub struct Cors {\n    config: Arc<Configured>,\n}\n\n/// A constructed via `warp::cors()`.\n#[derive(Clone, Debug)]\npub struct Builder {\n    credentials: bool,\n    allowed_headers: HashSet<HeaderName>,\n    exposed_headers: HashSet<HeaderName>,\n    max_age: Option<u64>,\n    methods: HashSet<http::Method>,\n    origins: Option<HashSet<HeaderValue>>,\n}\n\nimpl Builder {\n    /// Sets whether to add the `Access-Control-Allow-Credentials` header.\n    pub fn allow_credentials(mut self, allow: bool) -> Self {\n        self.credentials = allow;\n        self\n    }\n\n    /// Adds a method to the existing list of allowed request methods.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the provided argument is not a valid `http::Method`.\n    pub fn allow_method<M>(mut self, method: M) -> Self\n    where\n        http::Method: TryFrom<M>,\n    {\n        let method = match TryFrom::try_from(method) {\n            Ok(m) => m,\n            Err(_) => panic!(\"illegal Method\"),\n        };\n        self.methods.insert(method);\n        self\n    }\n\n    /// Adds multiple methods to the existing list of allowed request methods.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the provided argument is not a valid `http::Method`.\n    pub fn allow_methods<I>(mut self, methods: I) -> Self\n    where\n        I: IntoIterator,\n        http::Method: TryFrom<I::Item>,\n    {\n        let iter = methods.into_iter().map(|m| match TryFrom::try_from(m) {\n            Ok(m) => m,\n            Err(_) => panic!(\"illegal Method\"),\n        });\n        self.methods.extend(iter);\n        self\n    }\n\n    /// Adds a header to the list of allowed request headers.\n    ///\n    /// **Note**: These should match the values the browser sends via `Access-Control-Request-Headers`, e.g. `content-type`.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the provided argument is not a valid `http::header::HeaderName`.\n    pub fn allow_header<H>(mut self, header: H) -> Self\n    where\n        HeaderName: TryFrom<H>,\n    {\n        let header = match TryFrom::try_from(header) {\n            Ok(m) => m,\n            Err(_) => panic!(\"illegal Header\"),\n        };\n        self.allowed_headers.insert(header);\n        self\n    }\n\n    /// Adds multiple headers to the list of allowed request headers.\n    ///\n    /// **Note**: These should match the values the browser sends via `Access-Control-Request-Headers`, e.g.`content-type`.\n    ///\n    /// # Panics\n    ///\n    /// Panics if any of the headers are not a valid `http::header::HeaderName`.\n    pub fn allow_headers<I>(mut self, headers: I) -> Self\n    where\n        I: IntoIterator,\n        HeaderName: TryFrom<I::Item>,\n    {\n        let iter = headers.into_iter().map(|h| match TryFrom::try_from(h) {\n            Ok(h) => h,\n            Err(_) => panic!(\"illegal Header\"),\n        });\n        self.allowed_headers.extend(iter);\n        self\n    }\n\n    /// Adds a header to the list of exposed headers.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the provided argument is not a valid `http::header::HeaderName`.\n    pub fn expose_header<H>(mut self, header: H) -> Self\n    where\n        HeaderName: TryFrom<H>,\n    {\n        let header = match TryFrom::try_from(header) {\n            Ok(m) => m,\n            Err(_) => panic!(\"illegal Header\"),\n        };\n        self.exposed_headers.insert(header);\n        self\n    }\n\n    /// Adds multiple headers to the list of exposed headers.\n    ///\n    /// # Panics\n    ///\n    /// Panics if any of the headers are not a valid `http::header::HeaderName`.\n    pub fn expose_headers<I>(mut self, headers: I) -> Self\n    where\n        I: IntoIterator,\n        HeaderName: TryFrom<I::Item>,\n    {\n        let iter = headers.into_iter().map(|h| match TryFrom::try_from(h) {\n            Ok(h) => h,\n            Err(_) => panic!(\"illegal Header\"),\n        });\n        self.exposed_headers.extend(iter);\n        self\n    }\n\n    /// Sets that *any* `Origin` header is allowed.\n    ///\n    /// # Warning\n    ///\n    /// This can allow websites you didn't intend to access this resource,\n    /// it is usually better to set an explicit list.\n    pub fn allow_any_origin(mut self) -> Self {\n        self.origins = None;\n        self\n    }\n\n    /// Add an origin to the existing list of allowed `Origin`s.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the provided argument is not a valid `Origin`.\n    pub fn allow_origin(self, origin: impl IntoOrigin) -> Self {\n        self.allow_origins(Some(origin))\n    }\n\n    /// Add multiple origins to the existing list of allowed `Origin`s.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the provided argument is not a valid `Origin`.\n    pub fn allow_origins<I>(mut self, origins: I) -> Self\n    where\n        I: IntoIterator,\n        I::Item: IntoOrigin,\n    {\n        let iter = origins\n            .into_iter()\n            .map(IntoOrigin::into_origin)\n            .map(|origin| {\n                origin\n                    .to_string()\n                    .parse()\n                    .expect(\"Origin is always a valid HeaderValue\")\n            });\n\n        self.origins.get_or_insert_with(HashSet::new).extend(iter);\n\n        self\n    }\n\n    /// Sets the `Access-Control-Max-Age` header.\n    ///\n    /// # Example\n    ///\n    ///\n    /// ```\n    /// use std::time::Duration;\n    /// use warp::Filter;\n    ///\n    /// let cors = warp::cors()\n    ///     .max_age(30) // 30u32 seconds\n    ///     .max_age(Duration::from_secs(30)); // or a Duration\n    /// ```\n    pub fn max_age(mut self, seconds: impl Seconds) -> Self {\n        self.max_age = Some(seconds.seconds());\n        self\n    }\n\n    /// Builds the `Cors` wrapper from the configured settings.\n    ///\n    /// This step isn't *required*, as the `Builder` itself can be passed\n    /// to `Filter::with`. This just allows constructing once, thus not needing\n    /// to pay the cost of \"building\" every time.\n    pub fn build(self) -> Cors {\n        let expose_headers_header = if self.exposed_headers.is_empty() {\n            None\n        } else {\n            Some(self.exposed_headers.iter().cloned().collect())\n        };\n        let allowed_headers_header = self.allowed_headers.iter().cloned().collect();\n        let methods_header = self.methods.iter().cloned().collect();\n\n        let config = Arc::new(Configured {\n            cors: self,\n            allowed_headers_header,\n            expose_headers_header,\n            methods_header,\n        });\n\n        Cors { config }\n    }\n}\n\nimpl<F> WrapSealed<F> for Builder\nwhere\n    F: Filter + Clone + Send + Sync + 'static,\n    F::Extract: Reply,\n    F::Error: CombineRejection<Rejection>,\n    <F::Error as CombineRejection<Rejection>>::One: CombineRejection<Rejection>,\n{\n    type Wrapped = CorsFilter<F>;\n\n    fn wrap(&self, inner: F) -> Self::Wrapped {\n        let Cors { config } = self.clone().build();\n\n        CorsFilter { config, inner }\n    }\n}\n\nimpl<F> WrapSealed<F> for Cors\nwhere\n    F: Filter + Clone + Send + Sync + 'static,\n    F::Extract: Reply,\n    F::Error: CombineRejection<Rejection>,\n    <F::Error as CombineRejection<Rejection>>::One: CombineRejection<Rejection>,\n{\n    type Wrapped = CorsFilter<F>;\n\n    fn wrap(&self, inner: F) -> Self::Wrapped {\n        let config = self.config.clone();\n\n        CorsFilter { config, inner }\n    }\n}\n\n/// An error used to reject requests that are forbidden by a `cors` filter.\npub struct CorsForbidden {\n    kind: Forbidden,\n}\n\n#[derive(Debug)]\nenum Forbidden {\n    OriginNotAllowed,\n    MethodNotAllowed,\n    HeaderNotAllowed,\n}\n\nimpl fmt::Debug for CorsForbidden {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_tuple(\"CorsForbidden\").field(&self.kind).finish()\n    }\n}\n\nimpl fmt::Display for CorsForbidden {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let detail = match self.kind {\n            Forbidden::OriginNotAllowed => \"origin not allowed\",\n            Forbidden::MethodNotAllowed => \"request-method not allowed\",\n            Forbidden::HeaderNotAllowed => \"header not allowed\",\n        };\n        write!(f, \"CORS request forbidden: {}\", detail)\n    }\n}\n\nimpl StdError for CorsForbidden {}\n\n#[derive(Clone, Debug)]\nstruct Configured {\n    cors: Builder,\n    allowed_headers_header: AccessControlAllowHeaders,\n    expose_headers_header: Option<AccessControlExposeHeaders>,\n    methods_header: AccessControlAllowMethods,\n}\n\nenum Validated {\n    Preflight(HeaderValue),\n    Simple(HeaderValue),\n    NotCors,\n}\n\nimpl Configured {\n    fn check_request(\n        &self,\n        method: &http::Method,\n        headers: &http::HeaderMap,\n    ) -> Result<Validated, Forbidden> {\n        match (headers.get(header::ORIGIN), method) {\n            (Some(origin), &http::Method::OPTIONS) => {\n                // OPTIONS requests are preflight CORS requests...\n\n                if !self.is_origin_allowed(origin) {\n                    return Err(Forbidden::OriginNotAllowed);\n                }\n\n                if let Some(req_method) = headers.get(header::ACCESS_CONTROL_REQUEST_METHOD) {\n                    if !self.is_method_allowed(req_method) {\n                        return Err(Forbidden::MethodNotAllowed);\n                    }\n                } else {\n                    tracing::trace!(\n                        \"preflight request missing access-control-request-method header\"\n                    );\n                    return Err(Forbidden::MethodNotAllowed);\n                }\n\n                if let Some(req_headers) = headers.get(header::ACCESS_CONTROL_REQUEST_HEADERS) {\n                    let headers = req_headers\n                        .to_str()\n                        .map_err(|_| Forbidden::HeaderNotAllowed)?;\n                    for header in headers.split(',') {\n                        if !self.is_header_allowed(header.trim()) {\n                            return Err(Forbidden::HeaderNotAllowed);\n                        }\n                    }\n                }\n\n                Ok(Validated::Preflight(origin.clone()))\n            }\n            (Some(origin), _) => {\n                // Any other method, simply check for a valid origin...\n\n                tracing::trace!(\"origin header: {:?}\", origin);\n                if self.is_origin_allowed(origin) {\n                    Ok(Validated::Simple(origin.clone()))\n                } else {\n                    Err(Forbidden::OriginNotAllowed)\n                }\n            }\n            (None, _) => {\n                // No `ORIGIN` header means this isn't CORS!\n                Ok(Validated::NotCors)\n            }\n        }\n    }\n\n    fn is_method_allowed(&self, header: &HeaderValue) -> bool {\n        http::Method::from_bytes(header.as_bytes())\n            .map(|method| self.cors.methods.contains(&method))\n            .unwrap_or(false)\n    }\n\n    fn is_header_allowed(&self, header: &str) -> bool {\n        HeaderName::from_bytes(header.as_bytes())\n            .map(|header| self.cors.allowed_headers.contains(&header))\n            .unwrap_or(false)\n    }\n\n    fn is_origin_allowed(&self, origin: &HeaderValue) -> bool {\n        if let Some(ref allowed) = self.cors.origins {\n            allowed.contains(origin)\n        } else {\n            true\n        }\n    }\n\n    fn append_preflight_headers(&self, headers: &mut http::HeaderMap) {\n        self.append_common_headers(headers);\n\n        headers.typed_insert(self.allowed_headers_header.clone());\n        headers.typed_insert(self.methods_header.clone());\n\n        if let Some(max_age) = self.cors.max_age {\n            headers.insert(header::ACCESS_CONTROL_MAX_AGE, max_age.into());\n        }\n    }\n\n    fn append_common_headers(&self, headers: &mut http::HeaderMap) {\n        if self.cors.credentials {\n            headers.insert(\n                header::ACCESS_CONTROL_ALLOW_CREDENTIALS,\n                HeaderValue::from_static(\"true\"),\n            );\n        }\n        if let Some(expose_headers_header) = &self.expose_headers_header {\n            headers.typed_insert(expose_headers_header.clone())\n        }\n    }\n}\n\nmod internal {\n    use std::future::Future;\n    use std::pin::Pin;\n    use std::sync::Arc;\n    use std::task::{Context, Poll};\n\n    use futures_util::{future, ready, TryFuture};\n    use headers::Origin;\n    use http::header;\n    use pin_project::pin_project;\n\n    use super::{Configured, CorsForbidden, Validated};\n    use crate::filter::{Filter, FilterBase, Internal, One};\n    use crate::generic::Either;\n    use crate::reject::{CombineRejection, Rejection};\n    use crate::route;\n\n    #[derive(Clone, Debug)]\n    pub struct CorsFilter<F> {\n        pub(super) config: Arc<Configured>,\n        pub(super) inner: F,\n    }\n\n    impl<F> FilterBase for CorsFilter<F>\n    where\n        F: Filter,\n        F::Extract: Send,\n        F::Future: Future,\n        F::Error: CombineRejection<Rejection>,\n    {\n        type Extract =\n            One<Either<One<Preflight>, One<Either<One<Wrapped<F::Extract>>, F::Extract>>>>;\n        type Error = <F::Error as CombineRejection<Rejection>>::One;\n        type Future = future::Either<\n            future::Ready<Result<Self::Extract, Self::Error>>,\n            WrappedFuture<F::Future>,\n        >;\n\n        fn filter(&self, _: Internal) -> Self::Future {\n            let validated =\n                route::with(|route| self.config.check_request(route.method(), route.headers()));\n\n            match validated {\n                Ok(Validated::Preflight(origin)) => {\n                    let preflight = Preflight {\n                        config: self.config.clone(),\n                        origin,\n                    };\n                    future::Either::Left(future::ok((Either::A((preflight,)),)))\n                }\n                Ok(Validated::Simple(origin)) => future::Either::Right(WrappedFuture {\n                    inner: self.inner.filter(Internal),\n                    wrapped: Some((self.config.clone(), origin)),\n                }),\n                Ok(Validated::NotCors) => future::Either::Right(WrappedFuture {\n                    inner: self.inner.filter(Internal),\n                    wrapped: None,\n                }),\n                Err(err) => {\n                    let rejection = crate::reject::known(CorsForbidden { kind: err });\n                    future::Either::Left(future::err(rejection.into()))\n                }\n            }\n        }\n    }\n\n    #[derive(Debug)]\n    pub struct Preflight {\n        config: Arc<Configured>,\n        origin: header::HeaderValue,\n    }\n\n    impl crate::reply::Reply for Preflight {\n        fn into_response(self) -> crate::reply::Response {\n            let mut res = crate::reply::Response::default();\n            self.config.append_preflight_headers(res.headers_mut());\n            res.headers_mut()\n                .insert(header::ACCESS_CONTROL_ALLOW_ORIGIN, self.origin);\n            res\n        }\n    }\n\n    #[derive(Debug)]\n    pub struct Wrapped<R> {\n        config: Arc<Configured>,\n        inner: R,\n        origin: header::HeaderValue,\n    }\n\n    impl<R> crate::reply::Reply for Wrapped<R>\n    where\n        R: crate::reply::Reply,\n    {\n        fn into_response(self) -> crate::reply::Response {\n            let mut res = self.inner.into_response();\n            self.config.append_common_headers(res.headers_mut());\n            res.headers_mut()\n                .insert(header::ACCESS_CONTROL_ALLOW_ORIGIN, self.origin);\n            res\n        }\n    }\n\n    #[pin_project]\n    #[derive(Debug)]\n    pub struct WrappedFuture<F> {\n        #[pin]\n        inner: F,\n        wrapped: Option<(Arc<Configured>, header::HeaderValue)>,\n    }\n\n    impl<F> Future for WrappedFuture<F>\n    where\n        F: TryFuture,\n        F::Error: CombineRejection<Rejection>,\n    {\n        type Output = Result<\n            One<Either<One<Preflight>, One<Either<One<Wrapped<F::Ok>>, F::Ok>>>>,\n            <F::Error as CombineRejection<Rejection>>::One,\n        >;\n\n        fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n            let pin = self.project();\n            match ready!(pin.inner.try_poll(cx)) {\n                Ok(inner) => {\n                    let item = if let Some((config, origin)) = pin.wrapped.take() {\n                        (Either::A((Wrapped {\n                            config,\n                            inner,\n                            origin,\n                        },)),)\n                    } else {\n                        (Either::B(inner),)\n                    };\n                    let item = (Either::B(item),);\n                    Poll::Ready(Ok(item))\n                }\n                Err(err) => Poll::Ready(Err(err.into())),\n            }\n        }\n    }\n\n    pub trait Seconds {\n        fn seconds(self) -> u64;\n    }\n\n    impl Seconds for u32 {\n        fn seconds(self) -> u64 {\n            self.into()\n        }\n    }\n\n    impl Seconds for ::std::time::Duration {\n        fn seconds(self) -> u64 {\n            self.as_secs()\n        }\n    }\n\n    pub trait IntoOrigin {\n        fn into_origin(self) -> Origin;\n    }\n\n    impl<'a> IntoOrigin for &'a str {\n        fn into_origin(self) -> Origin {\n            let mut parts = self.splitn(2, \"://\");\n            let scheme = parts.next().expect(\"missing scheme\");\n            let rest = parts.next().expect(\"missing scheme\");\n\n            Origin::try_from_parts(scheme, rest, None).expect(\"invalid Origin\")\n        }\n    }\n}\n"
  },
  {
    "path": "src/filters/ext.rs",
    "content": "//! Request Extensions\n\nuse std::convert::Infallible;\n\nuse futures_util::future;\n\nuse crate::filter::{filter_fn_one, Filter};\nuse crate::reject::{self, Rejection};\n\n/// Get a previously set extension of the current route.\n///\n/// If the extension doesn't exist, this rejects with a `MissingExtension`.\npub fn get<T: Clone + Send + Sync + 'static>(\n) -> impl Filter<Extract = (T,), Error = Rejection> + Copy {\n    filter_fn_one(|route| {\n        let route = route\n            .extensions()\n            .get::<T>()\n            .cloned()\n            .ok_or_else(|| reject::known(MissingExtension { _p: () }));\n        future::ready(route)\n    })\n}\n\n/// Get a previously set extension of the current route.\n///\n/// If the extension doesn't exist, it yields `None`.\npub fn optional<T: Clone + Send + Sync + 'static>(\n) -> impl Filter<Extract = (Option<T>,), Error = Infallible> + Copy {\n    filter_fn_one(|route| future::ok(route.extensions().get::<T>().cloned()))\n}\n\nunit_error! {\n    /// An error used to reject if `get` cannot find the extension.\n    pub MissingExtension: \"Missing request extension\"\n}\n"
  },
  {
    "path": "src/filters/fs.rs",
    "content": "//! File System Filters\n\nuse std::cmp;\nuse std::convert::Infallible;\nuse std::fs::Metadata;\nuse std::future::Future;\nuse std::io;\nuse std::path::{Path, PathBuf};\nuse std::pin::Pin;\nuse std::sync::Arc;\nuse std::task::Poll;\n\nuse bytes::{Bytes, BytesMut};\nuse futures_util::future::Either;\nuse futures_util::{future, ready, stream, FutureExt, Stream, StreamExt, TryFutureExt};\nuse headers::{\n    AcceptRanges, ContentLength, ContentRange, ContentType, HeaderMapExt, IfModifiedSince, IfRange,\n    IfUnmodifiedSince, LastModified, Range,\n};\nuse http::StatusCode;\nuse mime_guess;\nuse percent_encoding::percent_decode_str;\nuse tokio::fs::File as TkFile;\nuse tokio::io::AsyncSeekExt;\nuse tokio_util::io::poll_read_buf;\n\nuse crate::bodyt::Body;\nuse crate::filter::{Filter, FilterClone, One};\nuse crate::reject::{self, Rejection};\nuse crate::reply::{Reply, Response};\n\n/// Creates a `Filter` that serves a File at the `path`.\n///\n/// Does not filter out based on any information of the request. Always serves\n/// the file at the exact `path` provided. Thus, this can be used to serve a\n/// single file with `GET`s, but could also be used in combination with other\n/// filters, such as after validating in `POST` request, wanting to return a\n/// specific file as the body.\n///\n/// For serving a directory, see [dir].\n///\n/// # Example\n///\n/// ```\n/// // Always serves this file from the file system.\n/// let route = warp::fs::file(\"/www/static/app.js\");\n/// ```\npub fn file(path: impl Into<PathBuf>) -> impl FilterClone<Extract = One<File>, Error = Rejection> {\n    let path = Arc::new(path.into());\n    crate::any()\n        .map(move || {\n            tracing::trace!(\"file: {:?}\", path);\n            ArcPath(path.clone())\n        })\n        .and(conditionals())\n        .and_then(file_reply)\n}\n\n/// Creates a `Filter` that serves a directory at the base `path` joined\n/// by the request path.\n///\n/// This can be used to serve \"static files\" from a directory. By far the most\n/// common pattern of serving static files is for `GET` requests, so this\n/// filter automatically includes a `GET` check.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// // Matches requests that start with `/static`,\n/// // and then uses the rest of that path to lookup\n/// // and serve a file from `/www/static`.\n/// let route = warp::path(\"static\")\n///     .and(warp::fs::dir(\"/www/static\"));\n///\n/// // For example:\n/// // - `GET /static/app.js` would serve the file `/www/static/app.js`\n/// // - `GET /static/css/app.css` would serve the file `/www/static/css/app.css`\n/// ```\npub fn dir(path: impl Into<PathBuf>) -> impl FilterClone<Extract = One<File>, Error = Rejection> {\n    let base = Arc::new(path.into());\n    crate::get()\n        .or(crate::head())\n        .unify()\n        .and(path_from_tail(base))\n        .and(conditionals())\n        .and_then(file_reply)\n}\n\nfn path_from_tail(\n    base: Arc<PathBuf>,\n) -> impl FilterClone<Extract = One<ArcPath>, Error = Rejection> {\n    crate::path::tail().and_then(move |tail: crate::path::Tail| {\n        future::ready(sanitize_path(base.as_ref(), tail.as_str())).and_then(|mut buf| async {\n            let is_dir = tokio::fs::metadata(buf.clone())\n                .await\n                .map(|m| m.is_dir())\n                .unwrap_or(false);\n\n            if is_dir {\n                tracing::debug!(\"dir: appending index.html to directory path\");\n                buf.push(\"index.html\");\n            }\n            tracing::trace!(\"dir: {:?}\", buf);\n            Ok(ArcPath(Arc::new(buf)))\n        })\n    })\n}\n\nfn sanitize_path(base: impl AsRef<Path>, tail: &str) -> Result<PathBuf, Rejection> {\n    let mut buf = PathBuf::from(base.as_ref());\n    let p = match percent_decode_str(tail).decode_utf8() {\n        Ok(p) => p,\n        Err(err) => {\n            tracing::debug!(\"dir: failed to decode route={:?}: {:?}\", tail, err);\n            return Err(reject::not_found());\n        }\n    };\n    tracing::trace!(\"dir? base={:?}, route={:?}\", base.as_ref(), p);\n    for seg in p.split('/') {\n        if seg.starts_with(\"..\") {\n            tracing::warn!(\"dir: rejecting segment starting with '..'\");\n            return Err(reject::not_found());\n        } else if seg.contains('\\\\') {\n            tracing::warn!(\"dir: rejecting segment containing backslash (\\\\)\");\n            return Err(reject::not_found());\n        } else if cfg!(windows) && seg.contains(':') {\n            tracing::warn!(\"dir: rejecting segment containing colon (:)\");\n            return Err(reject::not_found());\n        } else {\n            buf.push(seg);\n        }\n    }\n    Ok(buf)\n}\n\n#[derive(Debug)]\nstruct Conditionals {\n    if_modified_since: Option<IfModifiedSince>,\n    if_unmodified_since: Option<IfUnmodifiedSince>,\n    if_range: Option<IfRange>,\n    range: Option<Range>,\n}\n\nenum Cond {\n    NoBody(Response),\n    WithBody(Option<Range>),\n}\n\nimpl Conditionals {\n    fn check(self, last_modified: Option<LastModified>) -> Cond {\n        if let Some(since) = self.if_unmodified_since {\n            let precondition = last_modified\n                .map(|time| since.precondition_passes(time.into()))\n                .unwrap_or(false);\n\n            tracing::trace!(\n                \"if-unmodified-since? {:?} vs {:?} = {}\",\n                since,\n                last_modified,\n                precondition\n            );\n            if !precondition {\n                let mut res = Response::new(Body::empty());\n                *res.status_mut() = StatusCode::PRECONDITION_FAILED;\n                return Cond::NoBody(res);\n            }\n        }\n\n        if let Some(since) = self.if_modified_since {\n            tracing::trace!(\n                \"if-modified-since? header = {:?}, file = {:?}\",\n                since,\n                last_modified\n            );\n            let unmodified = last_modified\n                .map(|time| !since.is_modified(time.into()))\n                // no last_modified means its always modified\n                .unwrap_or(false);\n            if unmodified {\n                let mut res = Response::new(Body::empty());\n                *res.status_mut() = StatusCode::NOT_MODIFIED;\n                return Cond::NoBody(res);\n            }\n        }\n\n        if let Some(if_range) = self.if_range {\n            tracing::trace!(\"if-range? {:?} vs {:?}\", if_range, last_modified);\n            let can_range = !if_range.is_modified(None, last_modified.as_ref());\n\n            if !can_range {\n                return Cond::WithBody(None);\n            }\n        }\n\n        Cond::WithBody(self.range)\n    }\n}\n\nfn conditionals() -> impl Filter<Extract = One<Conditionals>, Error = Infallible> + Copy {\n    crate::header::optional2()\n        .and(crate::header::optional2())\n        .and(crate::header::optional2())\n        .and(crate::header::optional2())\n        .map(\n            |if_modified_since, if_unmodified_since, if_range, range| Conditionals {\n                if_modified_since,\n                if_unmodified_since,\n                if_range,\n                range,\n            },\n        )\n}\n\n/// A file response.\n#[derive(Debug)]\npub struct File {\n    resp: Response,\n    path: ArcPath,\n}\n\nimpl File {\n    /// Extract the `&Path` of the file this `Response` delivers.\n    ///\n    /// # Example\n    ///\n    /// The example below changes the Content-Type response header for every file called `video.mp4`.\n    ///\n    /// ```\n    /// use warp::{Filter, reply::Reply};\n    ///\n    /// let route = warp::path(\"static\")\n    ///     .and(warp::fs::dir(\"/www/static\"))\n    ///     .map(|reply: warp::filters::fs::File| {\n    ///         if reply.path().ends_with(\"video.mp4\") {\n    ///             warp::reply::with_header(reply, \"Content-Type\", \"video/mp4\").into_response()\n    ///         } else {\n    ///             reply.into_response()\n    ///         }\n    ///     });\n    /// ```\n    pub fn path(&self) -> &Path {\n        self.path.as_ref()\n    }\n}\n\n// Silly wrapper since Arc<PathBuf> doesn't implement AsRef<Path> ;_;\n#[derive(Clone, Debug)]\nstruct ArcPath(Arc<PathBuf>);\n\nimpl AsRef<Path> for ArcPath {\n    fn as_ref(&self) -> &Path {\n        (*self.0).as_ref()\n    }\n}\n\nimpl Reply for File {\n    fn into_response(self) -> Response {\n        self.resp\n    }\n}\n\nfn file_reply(\n    path: ArcPath,\n    conditionals: Conditionals,\n) -> impl Future<Output = Result<File, Rejection>> + Send {\n    TkFile::open(path.clone()).then(move |res| match res {\n        Ok(f) => Either::Left(file_conditional(f, path, conditionals)),\n        Err(err) => {\n            let rej = match err.kind() {\n                io::ErrorKind::NotFound => {\n                    tracing::debug!(\"file not found: {:?}\", path.as_ref().display());\n                    reject::not_found()\n                }\n                io::ErrorKind::PermissionDenied => {\n                    tracing::warn!(\"file permission denied: {:?}\", path.as_ref().display());\n                    reject::known(FilePermissionError { _p: () })\n                }\n                _ => {\n                    tracing::error!(\n                        \"file open error (path={:?}): {} \",\n                        path.as_ref().display(),\n                        err\n                    );\n                    reject::known(FileOpenError { _p: () })\n                }\n            };\n            Either::Right(future::err(rej))\n        }\n    })\n}\n\nasync fn file_metadata(f: TkFile) -> Result<(TkFile, Metadata), Rejection> {\n    match f.metadata().await {\n        Ok(meta) => Ok((f, meta)),\n        Err(err) => {\n            tracing::debug!(\"file metadata error: {}\", err);\n            Err(reject::not_found())\n        }\n    }\n}\n\nfn file_conditional(\n    f: TkFile,\n    path: ArcPath,\n    conditionals: Conditionals,\n) -> impl Future<Output = Result<File, Rejection>> + Send {\n    file_metadata(f).map_ok(move |(file, meta)| {\n        let mut len = meta.len();\n        let modified = meta.modified().ok().map(LastModified::from);\n\n        let resp = match conditionals.check(modified) {\n            Cond::NoBody(resp) => resp,\n            Cond::WithBody(range) => {\n                bytes_range(range, len)\n                    .map(|(start, end)| {\n                        let sub_len = end - start;\n                        let buf_size = optimal_buf_size(&meta);\n                        let stream = file_stream(file, buf_size, (start, end));\n                        let body = Body::wrap_stream(stream);\n\n                        let mut resp = Response::new(body);\n\n                        if sub_len != len {\n                            *resp.status_mut() = StatusCode::PARTIAL_CONTENT;\n                            resp.headers_mut().typed_insert(\n                                ContentRange::bytes(start..end, len).expect(\"valid ContentRange\"),\n                            );\n\n                            len = sub_len;\n                        }\n\n                        let mime = mime_guess::from_path(path.as_ref()).first_or_octet_stream();\n\n                        resp.headers_mut().typed_insert(ContentLength(len));\n                        resp.headers_mut().typed_insert(ContentType::from(mime));\n                        resp.headers_mut().typed_insert(AcceptRanges::bytes());\n\n                        if let Some(last_modified) = modified {\n                            resp.headers_mut().typed_insert(last_modified);\n                        }\n\n                        resp\n                    })\n                    .unwrap_or_else(|BadRange| {\n                        // bad byte range\n                        let mut resp = Response::new(Body::empty());\n                        *resp.status_mut() = StatusCode::RANGE_NOT_SATISFIABLE;\n                        resp.headers_mut()\n                            .typed_insert(ContentRange::unsatisfied_bytes(len));\n                        resp\n                    })\n            }\n        };\n\n        File { resp, path }\n    })\n}\n\nstruct BadRange;\n\nfn bytes_range(range: Option<Range>, max_len: u64) -> Result<(u64, u64), BadRange> {\n    use std::ops::Bound;\n\n    let range = if let Some(range) = range {\n        range\n    } else {\n        return Ok((0, max_len));\n    };\n\n    let ret = range\n        .satisfiable_ranges(max_len)\n        .map(|(start, end)| {\n            let start = match start {\n                Bound::Unbounded => 0,\n                Bound::Included(s) => s,\n                Bound::Excluded(s) => s + 1,\n            };\n\n            let end = match end {\n                Bound::Unbounded => max_len,\n                Bound::Included(s) => {\n                    // For the special case where s == the file size\n                    if s == max_len {\n                        s\n                    } else {\n                        s + 1\n                    }\n                }\n                Bound::Excluded(s) => s,\n            };\n\n            if start < end && end <= max_len {\n                Ok((start, end))\n            } else {\n                tracing::trace!(\"unsatisfiable byte range: {}-{}/{}\", start, end, max_len);\n                Err(BadRange)\n            }\n        })\n        .next()\n        .unwrap_or(Ok((0, max_len)));\n    ret\n}\n\nfn file_stream(\n    mut file: TkFile,\n    buf_size: usize,\n    (start, end): (u64, u64),\n) -> impl Stream<Item = Result<Bytes, io::Error>> + Send {\n    use std::io::SeekFrom;\n\n    let seek = async move {\n        if start != 0 {\n            file.seek(SeekFrom::Start(start)).await?;\n        }\n        Ok(file)\n    };\n\n    seek.into_stream()\n        .map(move |result| {\n            let mut buf = BytesMut::new();\n            let mut len = end - start;\n            let mut f = match result {\n                Ok(f) => f,\n                Err(f) => return Either::Left(stream::once(future::err(f))),\n            };\n\n            Either::Right(stream::poll_fn(move |cx| {\n                if len == 0 {\n                    return Poll::Ready(None);\n                }\n                reserve_at_least(&mut buf, buf_size);\n\n                let n = match ready!(poll_read_buf(Pin::new(&mut f), cx, &mut buf)) {\n                    Ok(n) => n as u64,\n                    Err(err) => {\n                        tracing::debug!(\"file read error: {}\", err);\n                        return Poll::Ready(Some(Err(err)));\n                    }\n                };\n\n                if n == 0 {\n                    tracing::debug!(\"file read found EOF before expected length\");\n                    return Poll::Ready(None);\n                }\n\n                let mut chunk = buf.split().freeze();\n                if n > len {\n                    chunk = chunk.split_to(len as usize);\n                    len = 0;\n                } else {\n                    len -= n;\n                }\n\n                Poll::Ready(Some(Ok(chunk)))\n            }))\n        })\n        .flatten()\n}\n\nfn reserve_at_least(buf: &mut BytesMut, cap: usize) {\n    if buf.capacity() - buf.len() < cap {\n        buf.reserve(cap);\n    }\n}\n\nconst DEFAULT_READ_BUF_SIZE: usize = 8_192;\n\nfn optimal_buf_size(metadata: &Metadata) -> usize {\n    let block_size = get_block_size(metadata);\n\n    // If file length is smaller than block size, don't waste space\n    // reserving a bigger-than-needed buffer.\n    cmp::min(block_size as u64, metadata.len()) as usize\n}\n\n#[cfg(unix)]\nfn get_block_size(metadata: &Metadata) -> usize {\n    use std::os::unix::fs::MetadataExt;\n    //TODO: blksize() returns u64, should handle bad cast...\n    //(really, a block size bigger than 4gb?)\n\n    // Use device blocksize unless it's really small.\n    cmp::max(metadata.blksize() as usize, DEFAULT_READ_BUF_SIZE)\n}\n\n#[cfg(not(unix))]\nfn get_block_size(_metadata: &Metadata) -> usize {\n    DEFAULT_READ_BUF_SIZE\n}\n\n// ===== Rejections =====\n\nunit_error! {\n    pub(crate) FileOpenError: \"file open error\"\n}\n\nunit_error! {\n    pub(crate) FilePermissionError: \"file perimission error\"\n}\n\n#[cfg(test)]\nmod tests {\n    use super::sanitize_path;\n    use bytes::BytesMut;\n\n    #[test]\n    fn test_sanitize_path() {\n        let base = \"/var/www\";\n\n        fn p(s: &str) -> &::std::path::Path {\n            s.as_ref()\n        }\n\n        assert_eq!(\n            sanitize_path(base, \"/foo.html\").unwrap(),\n            p(\"/var/www/foo.html\")\n        );\n\n        // bad paths\n        sanitize_path(base, \"/../foo.html\").expect_err(\"dot dot\");\n\n        sanitize_path(base, \"/C:\\\\/foo.html\").expect_err(\"C:\\\\\");\n    }\n\n    #[test]\n    fn test_reserve_at_least() {\n        let mut buf = BytesMut::new();\n        let cap = 8_192;\n\n        assert_eq!(buf.len(), 0);\n        assert_eq!(buf.capacity(), 0);\n\n        super::reserve_at_least(&mut buf, cap);\n        assert_eq!(buf.len(), 0);\n        assert_eq!(buf.capacity(), cap);\n    }\n}\n"
  },
  {
    "path": "src/filters/header.rs",
    "content": "//! Header Filters\n//!\n//! These filters are used to interact with the Request HTTP headers. Some\n//! of them, like `exact` and `exact_ignore_case`, are just predicates,\n//! they don't extract any values. The `header` filter allows parsing\n//! a type from any header.\nuse std::convert::Infallible;\nuse std::str::FromStr;\n\nuse futures_util::future;\nuse headers::{Header, HeaderMapExt};\nuse http::header::HeaderValue;\nuse http::HeaderMap;\n\nuse crate::filter::{filter_fn, filter_fn_one, Filter, One};\nuse crate::reject::{self, Rejection};\n\n/// Create a `Filter` that tries to parse the specified header.\n///\n/// This `Filter` will look for a header with supplied name, and try to\n/// parse to a `T`, otherwise rejects the request.\n///\n/// # Example\n///\n/// ```\n/// use std::net::SocketAddr;\n///\n/// // Parse `content-length: 100` as a `u64`\n/// let content_length = warp::header::<u64>(\"content-length\");\n///\n/// // Parse `host: 127.0.0.1:8080` as a `SocketAddr\n/// let local_host = warp::header::<SocketAddr>(\"host\");\n///\n/// // Parse `foo: bar` into a `String`\n/// let foo = warp::header::<String>(\"foo\");\n/// ```\npub fn header<T: FromStr + Send + 'static>(\n    name: &'static str,\n) -> impl Filter<Extract = One<T>, Error = Rejection> + Copy {\n    filter_fn_one(move |route| {\n        tracing::trace!(\"header({:?})\", name);\n        let route = route\n            .headers()\n            .get(name)\n            .ok_or_else(|| reject::missing_header(name))\n            .and_then(|value| value.to_str().map_err(|_| reject::invalid_header(name)))\n            .and_then(|s| T::from_str(s).map_err(|_| reject::invalid_header(name)));\n        future::ready(route)\n    })\n}\n\npub(crate) fn header2<T: Header + Send + 'static>(\n) -> impl Filter<Extract = One<T>, Error = Rejection> + Copy {\n    filter_fn_one(move |route| {\n        tracing::trace!(\"header2({:?})\", T::name());\n        let route = route\n            .headers()\n            .typed_get()\n            .ok_or_else(|| reject::invalid_header(T::name().as_str()));\n        future::ready(route)\n    })\n}\n\n/// Create a `Filter` that tries to parse the specified header, if it exists.\n///\n/// If the header does not exist, it yields `None`. Otherwise, it will try to\n/// parse as a `T`, and if it fails, a invalid header rejection is return. If\n/// successful, the filter yields `Some(T)`.\n///\n/// # Example\n///\n/// ```\n/// // Grab the `authorization` header if it exists.\n/// let opt_auth = warp::header::optional::<String>(\"authorization\");\n/// ```\npub fn optional<T>(\n    name: &'static str,\n) -> impl Filter<Extract = One<Option<T>>, Error = Rejection> + Copy\nwhere\n    T: FromStr + Send + 'static,\n{\n    filter_fn_one(move |route| {\n        tracing::trace!(\"optional({:?})\", name);\n        let result = route.headers().get(name).map(|value| {\n            value\n                .to_str()\n                .map_err(|_| reject::invalid_header(name))?\n                .parse::<T>()\n                .map_err(|_| reject::invalid_header(name))\n        });\n\n        match result {\n            Some(Ok(t)) => future::ok(Some(t)),\n            Some(Err(e)) => future::err(e),\n            None => future::ok(None),\n        }\n    })\n}\n\npub(crate) fn optional2<T>() -> impl Filter<Extract = One<Option<T>>, Error = Infallible> + Copy\nwhere\n    T: Header + Send + 'static,\n{\n    filter_fn_one(move |route| future::ready(Ok(route.headers().typed_get())))\n}\n\n/* TODO\npub fn exact2<T>(header: T) -> impl FilterClone<Extract=(), Error=Rejection>\nwhere\n    T: Header + PartialEq + Clone + Send,\n{\n    filter_fn(move |route| {\n        tracing::trace!(\"exact2({:?})\", T::NAME);\n        route.headers()\n            .typed_get::<T>()\n            .and_then(|val| if val == header {\n                Some(())\n            } else {\n                None\n            })\n            .ok_or_else(|| reject::bad_request())\n    })\n}\n*/\n\n/// Create a `Filter` that requires a header to match the value exactly.\n///\n/// This `Filter` will look for a header with supplied name and the exact\n/// value, otherwise rejects the request.\n///\n/// # Example\n///\n/// ```\n/// // Require `dnt: 1` header to be set.\n/// let must_dnt = warp::header::exact(\"dnt\", \"1\");\n/// ```\npub fn exact(\n    name: &'static str,\n    value: &'static str,\n) -> impl Filter<Extract = (), Error = Rejection> + Copy {\n    filter_fn(move |route| {\n        tracing::trace!(\"exact?({:?}, {:?})\", name, value);\n        let route = route\n            .headers()\n            .get(name)\n            .ok_or_else(|| reject::missing_header(name))\n            .and_then(|val| {\n                if val == value {\n                    Ok(())\n                } else {\n                    Err(reject::invalid_header(name))\n                }\n            });\n        future::ready(route)\n    })\n}\n\n/// Create a `Filter` that requires a header to match the value exactly.\n///\n/// This `Filter` will look for a header with supplied name and the exact\n/// value, ignoring ASCII case, otherwise rejects the request.\n///\n/// # Example\n///\n/// ```\n/// // Require `connection: keep-alive` header to be set.\n/// let keep_alive = warp::header::exact_ignore_case(\"connection\", \"keep-alive\");\n/// ```\npub fn exact_ignore_case(\n    name: &'static str,\n    value: &'static str,\n) -> impl Filter<Extract = (), Error = Rejection> + Copy {\n    filter_fn(move |route| {\n        tracing::trace!(\"exact_ignore_case({:?}, {:?})\", name, value);\n        let route = route\n            .headers()\n            .get(name)\n            .ok_or_else(|| reject::missing_header(name))\n            .and_then(|val| {\n                if val.as_bytes().eq_ignore_ascii_case(value.as_bytes()) {\n                    Ok(())\n                } else {\n                    Err(reject::invalid_header(name))\n                }\n            });\n        future::ready(route)\n    })\n}\n\n/// Create a `Filter` that gets a `HeaderValue` for the name.\n///\n/// # Example\n///\n/// ```\n/// use warp::{Filter, http::header::HeaderValue};\n///\n/// let filter = warp::header::value(\"x-token\")\n///     .map(|value: HeaderValue| {\n///         format!(\"header value bytes: {:?}\", value)\n///     });\n/// ```\npub fn value(\n    name: &'static str,\n) -> impl Filter<Extract = One<HeaderValue>, Error = Rejection> + Copy {\n    filter_fn_one(move |route| {\n        tracing::trace!(\"value({:?})\", name);\n        let route = route\n            .headers()\n            .get(name)\n            .cloned()\n            .ok_or_else(|| reject::missing_header(name));\n        future::ready(route)\n    })\n}\n\n/// Create a `Filter` that returns a clone of the request's `HeaderMap`.\n///\n/// # Example\n///\n/// ```\n/// use warp::{Filter, http::HeaderMap};\n///\n/// let headers = warp::header::headers_cloned()\n///     .map(|headers: HeaderMap| {\n///         format!(\"header count: {}\", headers.len())\n///     });\n/// ```\npub fn headers_cloned() -> impl Filter<Extract = One<HeaderMap>, Error = Infallible> + Copy {\n    filter_fn_one(|route| future::ok(route.headers().clone()))\n}\n"
  },
  {
    "path": "src/filters/host.rs",
    "content": "//! Host (\"authority\") filter\n//!\nuse crate::filter::{filter_fn_one, Filter, One};\nuse crate::reject::{self, Rejection};\nuse futures_util::future;\npub use http::uri::Authority;\nuse std::str::FromStr;\n\n/// Creates a `Filter` that requires a specific authority (target server's\n/// host and port) in the request.\n///\n/// Authority is specified either in the `Host` header or in the target URI.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let multihost =\n///     warp::host::exact(\"foo.com\").map(|| \"you've reached foo.com\")\n///     .or(warp::host::exact(\"bar.com\").map(|| \"you've reached bar.com\"));\n/// ```\npub fn exact(expected: &str) -> impl Filter<Extract = (), Error = Rejection> + Clone {\n    let expected = Authority::from_str(expected).expect(\"invalid host/authority\");\n    optional()\n        .and_then(move |option: Option<Authority>| match option {\n            Some(authority) if authority == expected => future::ok(()),\n            _ => future::err(reject::not_found()),\n        })\n        .untuple_one()\n}\n\n/// Creates a `Filter` that looks for an authority (target server's host\n/// and port) in the request.\n///\n/// Authority is specified either in the `Host` header or in the target URI.\n///\n/// If found, extracts the `Authority`, otherwise continues the request,\n/// extracting `None`.\n///\n/// Rejects with `400 Bad Request` if the `Host` header is malformed or if there\n/// is a mismatch between the `Host` header and the target URI.\n///\n/// # Example\n///\n/// ```\n/// use warp::{Filter, host::Authority};\n///\n/// let host = warp::host::optional()\n///     .map(|authority: Option<Authority>| {\n///         if let Some(a) = authority {\n///             format!(\"{} is currently not at home\", a.host())\n///         } else {\n///             \"please state who you're trying to reach\".to_owned()\n///         }\n///     });\n/// ```\npub fn optional() -> impl Filter<Extract = One<Option<Authority>>, Error = Rejection> + Copy {\n    filter_fn_one(move |route| {\n        // The authority can be sent by clients in various ways:\n        //\n        //  1) in the \"target URI\"\n        //    a) serialized in the start line (HTTP/1.1 proxy requests)\n        //    b) serialized in `:authority` pseudo-header (HTTP/2 generated - \"SHOULD\")\n        //  2) in the `Host` header (HTTP/1.1 origin requests, HTTP/2 converted)\n        //\n        // Hyper transparently handles 1a/1b, but not 2, so we must look at both.\n\n        let from_uri = route.uri().authority();\n\n        let name = \"host\";\n        let from_header = route.headers()\n            .get(name)\n            .map(|value|\n                // Header present, parse it\n                value.to_str().map_err(|_| reject::invalid_header(name))\n                    .and_then(|value| Authority::from_str(value).map_err(|_| reject::invalid_header(name)))\n            );\n\n        future::ready(match (from_uri, from_header) {\n            // no authority in the request (HTTP/1.0 or non-conforming)\n            (None, None) => Ok(None),\n\n            // authority specified in either or both matching\n            (Some(a), None) => Ok(Some(a.clone())),\n            (None, Some(Ok(a))) => Ok(Some(a)),\n            (Some(a), Some(Ok(b))) if *a == b => Ok(Some(b)),\n\n            // mismatch\n            (Some(_), Some(Ok(_))) => Err(reject::invalid_header(name)),\n\n            // parse error\n            (_, Some(Err(r))) => Err(r),\n        })\n    })\n}\n"
  },
  {
    "path": "src/filters/log.rs",
    "content": "//! Logger Filters\n\nuse std::fmt;\nuse std::net::SocketAddr;\nuse std::time::{Duration, Instant};\n\nuse http::{header, StatusCode};\n\nuse crate::filter::{Filter, WrapSealed};\nuse crate::reject::IsReject;\nuse crate::reply::Reply;\nuse crate::route::Route;\n\nuse self::internal::WithLog;\n\n/// Create a wrapping [`Filter`] with the specified `name` as the `target`.\n///\n/// This uses the default access logging format, and log records produced\n/// will have their `target` set to `name`.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// // If using something like `pretty_env_logger`,\n/// // view logs by setting `RUST_LOG=example::api`.\n/// let log = warp::log(\"example::api\");\n/// let route = warp::any()\n///     .map(warp::reply)\n///     .with(log);\n/// ```\npub fn log(name: &'static str) -> Log<impl Fn(Info<'_>) + Copy> {\n    let func = move |info: Info<'_>| {\n        // TODO?\n        // - response content length?\n        log::info!(\n            target: name,\n            \"{} \\\"{} {} {:?}\\\" {} \\\"{}\\\" \\\"{}\\\" {:?}\",\n            OptFmt(info.route.remote_addr()),\n            info.method(),\n            info.path(),\n            info.route.version(),\n            info.status().as_u16(),\n            OptFmt(info.referer()),\n            OptFmt(info.user_agent()),\n            info.elapsed(),\n        );\n    };\n    Log { func }\n}\n\n/// Create a wrapping [`Filter`](crate::Filter) that receives `warp::log::Info`.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let log = warp::log::custom(|info| {\n///     // Use a log macro, or slog, or println, or whatever!\n///     eprintln!(\n///         \"{} {} {}\",\n///         info.method(),\n///         info.path(),\n///         info.status(),\n///     );\n/// });\n/// let route = warp::any()\n///     .map(warp::reply)\n///     .with(log);\n/// ```\npub fn custom<F>(func: F) -> Log<F>\nwhere\n    F: Fn(Info<'_>),\n{\n    Log { func }\n}\n\n/// Decorates a [`Filter`] to log requests and responses.\n#[derive(Clone, Copy, Debug)]\npub struct Log<F> {\n    func: F,\n}\n\n/// Information about the request/response that can be used to prepare log lines.\n#[allow(missing_debug_implementations)]\npub struct Info<'a> {\n    route: &'a Route,\n    start: Instant,\n    status: StatusCode,\n}\n\nimpl<FN, F> WrapSealed<F> for Log<FN>\nwhere\n    FN: Fn(Info<'_>) + Clone + Send,\n    F: Filter + Clone + Send,\n    F::Extract: Reply,\n    F::Error: IsReject,\n{\n    type Wrapped = WithLog<FN, F>;\n\n    fn wrap(&self, filter: F) -> Self::Wrapped {\n        WithLog {\n            filter,\n            log: self.clone(),\n        }\n    }\n}\n\nimpl<'a> Info<'a> {\n    /// View the remote `SocketAddr` of the request.\n    pub fn remote_addr(&self) -> Option<SocketAddr> {\n        self.route.remote_addr()\n    }\n\n    /// View the `http::Method` of the request.\n    pub fn method(&self) -> &http::Method {\n        self.route.method()\n    }\n\n    /// View the URI path of the request.\n    pub fn path(&self) -> &str {\n        self.route.full_path()\n    }\n\n    /// View the `http::Version` of the request.\n    pub fn version(&self) -> http::Version {\n        self.route.version()\n    }\n\n    /// View the `http::StatusCode` of the response.\n    pub fn status(&self) -> http::StatusCode {\n        self.status\n    }\n\n    /// View the referer of the request.\n    pub fn referer(&self) -> Option<&str> {\n        self.route\n            .headers()\n            .get(header::REFERER)\n            .and_then(|v| v.to_str().ok())\n    }\n\n    /// View the user agent of the request.\n    pub fn user_agent(&self) -> Option<&str> {\n        self.route\n            .headers()\n            .get(header::USER_AGENT)\n            .and_then(|v| v.to_str().ok())\n    }\n\n    /// View the `Duration` that elapsed for the request.\n    pub fn elapsed(&self) -> Duration {\n        tokio::time::Instant::now().into_std() - self.start\n    }\n\n    /// View the host of the request\n    pub fn host(&self) -> Option<&str> {\n        self.route\n            .headers()\n            .get(header::HOST)\n            .and_then(|v| v.to_str().ok())\n    }\n\n    /// Access the full headers of the request\n    pub fn request_headers(&self) -> &http::HeaderMap {\n        self.route.headers()\n    }\n}\n\nstruct OptFmt<T>(Option<T>);\n\nimpl<T: fmt::Display> fmt::Display for OptFmt<T> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        if let Some(ref t) = self.0 {\n            fmt::Display::fmt(t, f)\n        } else {\n            f.write_str(\"-\")\n        }\n    }\n}\n\nmod internal {\n    use std::future::Future;\n    use std::pin::Pin;\n    use std::task::{Context, Poll};\n    use std::time::Instant;\n\n    use futures_util::{ready, TryFuture};\n    use pin_project::pin_project;\n\n    use super::{Info, Log};\n    use crate::filter::{Filter, FilterBase, Internal};\n    use crate::reject::IsReject;\n    use crate::reply::{Reply, Response};\n    use crate::route;\n\n    #[allow(missing_debug_implementations)]\n    pub struct Logged(pub(super) Response);\n\n    impl Reply for Logged {\n        #[inline]\n        fn into_response(self) -> Response {\n            self.0\n        }\n    }\n\n    #[allow(missing_debug_implementations)]\n    #[derive(Clone, Copy)]\n    pub struct WithLog<FN, F> {\n        pub(super) filter: F,\n        pub(super) log: Log<FN>,\n    }\n\n    impl<FN, F> FilterBase for WithLog<FN, F>\n    where\n        FN: Fn(Info<'_>) + Clone + Send,\n        F: Filter + Clone + Send,\n        F::Extract: Reply,\n        F::Error: IsReject,\n    {\n        type Extract = (Logged,);\n        type Error = F::Error;\n        type Future = WithLogFuture<FN, F::Future>;\n\n        fn filter(&self, _: Internal) -> Self::Future {\n            let started = tokio::time::Instant::now().into_std();\n            WithLogFuture {\n                log: self.log.clone(),\n                future: self.filter.filter(Internal),\n                started,\n            }\n        }\n    }\n\n    #[allow(missing_debug_implementations)]\n    #[pin_project]\n    pub struct WithLogFuture<FN, F> {\n        log: Log<FN>,\n        #[pin]\n        future: F,\n        started: Instant,\n    }\n\n    impl<FN, F> Future for WithLogFuture<FN, F>\n    where\n        FN: Fn(Info<'_>),\n        F: TryFuture,\n        F::Ok: Reply,\n        F::Error: IsReject,\n    {\n        type Output = Result<(Logged,), F::Error>;\n\n        fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n            let pin = self.as_mut().project();\n            let (result, status) = match ready!(pin.future.try_poll(cx)) {\n                Ok(reply) => {\n                    let resp = reply.into_response();\n                    let status = resp.status();\n                    (Poll::Ready(Ok((Logged(resp),))), status)\n                }\n                Err(reject) => {\n                    let status = reject.status();\n                    (Poll::Ready(Err(reject)), status)\n                }\n            };\n\n            route::with(|route| {\n                (self.log.func)(Info {\n                    route,\n                    start: self.started,\n                    status,\n                });\n            });\n\n            result\n        }\n    }\n}\n"
  },
  {
    "path": "src/filters/method.rs",
    "content": "//! HTTP Method filters.\n//!\n//! The filters deal with the HTTP Method part of a request. Several here will\n//! match the request `Method`, and if not matched, will reject the request\n//! with a `405 Method Not Allowed`.\n//!\n//! There is also [`warp::method()`](method), which never rejects\n//! a request, and just extracts the method to be used in your filter chains.\nuse futures_util::future;\nuse http::Method;\n\nuse crate::filter::{filter_fn, filter_fn_one, Filter, One};\nuse crate::reject::Rejection;\nuse std::convert::Infallible;\n\n/// Create a `Filter` that requires the request method to be `GET`.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let get_only = warp::get().map(warp::reply);\n/// ```\npub fn get() -> impl Filter<Extract = (), Error = Rejection> + Copy {\n    method_is(|| &Method::GET)\n}\n\n/// Create a `Filter` that requires the request method to be `POST`.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let post_only = warp::post().map(warp::reply);\n/// ```\npub fn post() -> impl Filter<Extract = (), Error = Rejection> + Copy {\n    method_is(|| &Method::POST)\n}\n\n/// Create a `Filter` that requires the request method to be `PUT`.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let put_only = warp::put().map(warp::reply);\n/// ```\npub fn put() -> impl Filter<Extract = (), Error = Rejection> + Copy {\n    method_is(|| &Method::PUT)\n}\n\n/// Create a `Filter` that requires the request method to be `DELETE`.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let delete_only = warp::delete().map(warp::reply);\n/// ```\npub fn delete() -> impl Filter<Extract = (), Error = Rejection> + Copy {\n    method_is(|| &Method::DELETE)\n}\n\n/// Create a `Filter` that requires the request method to be `HEAD`.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let head_only = warp::head().map(warp::reply);\n/// ```\npub fn head() -> impl Filter<Extract = (), Error = Rejection> + Copy {\n    method_is(|| &Method::HEAD)\n}\n\n/// Create a `Filter` that requires the request method to be `OPTIONS`.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let options_only = warp::options().map(warp::reply);\n/// ```\npub fn options() -> impl Filter<Extract = (), Error = Rejection> + Copy {\n    method_is(|| &Method::OPTIONS)\n}\n\n/// Create a `Filter` that requires the request method to be `PATCH`.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let patch_only = warp::patch().map(warp::reply);\n/// ```\npub fn patch() -> impl Filter<Extract = (), Error = Rejection> + Copy {\n    method_is(|| &Method::PATCH)\n}\n\n/// Extract the `Method` from the request.\n///\n/// This never rejects a request.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let route = warp::method()\n///     .map(|method| {\n///         format!(\"You sent a {} request!\", method)\n///     });\n/// ```\npub fn method() -> impl Filter<Extract = One<Method>, Error = Infallible> + Copy {\n    filter_fn_one(|route| future::ok::<_, Infallible>(route.method().clone()))\n}\n\n// NOTE: This takes a static function instead of `&'static Method` directly\n// so that the `impl Filter` can be zero-sized. Moving it around should be\n// cheaper than holding a single static pointer (which would make it 1 word).\nfn method_is<F>(func: F) -> impl Filter<Extract = (), Error = Rejection> + Copy\nwhere\n    F: Fn() -> &'static Method + Copy,\n{\n    filter_fn(move |route| {\n        let method = func();\n        tracing::trace!(\"method::{:?}?: {:?}\", method, route.method());\n        if route.method() == method {\n            future::ok(())\n        } else {\n            future::err(crate::reject::method_not_allowed())\n        }\n    })\n}\n\n#[cfg(test)]\nmod tests {\n    #[test]\n    fn method_size_of() {\n        // See comment on `method_is` function.\n        assert_eq!(std::mem::size_of_val(&super::get()), 0,);\n    }\n}\n"
  },
  {
    "path": "src/filters/mod.rs",
    "content": "//! Built-in Filters\n//!\n//! This module mostly serves as documentation to group together the list of\n//! built-in filters. Most of these are available at more convenient paths.\n\npub mod addr;\npub mod any;\npub mod body;\n#[cfg(any(feature = \"compression-brotli\", feature = \"compression-gzip\"))]\npub mod compression;\npub mod cookie;\npub mod cors;\npub mod ext;\npub mod fs;\npub mod header;\npub mod host;\npub mod log;\npub mod method;\n#[cfg(feature = \"multipart\")]\npub mod multipart;\npub mod path;\npub mod query;\npub mod reply;\npub mod sse;\npub mod trace;\n#[cfg(feature = \"websocket\")]\npub mod ws;\n\npub use crate::filter::BoxedFilter;\n"
  },
  {
    "path": "src/filters/multipart.rs",
    "content": "//! Multipart body filters\n//!\n//! [`Filter`](crate::Filter)s that extract a multipart body for a route.\n\nuse std::error::Error as StdError;\nuse std::fmt::{Display, Formatter};\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\nuse std::{fmt, io};\n\nuse bytes::{Buf, Bytes};\nuse futures_util::{future, Stream};\nuse headers::ContentType;\nuse http_body_util::BodyDataStream;\nuse mime::Mime;\nuse multer::{Field as PartInner, Multipart as FormDataInner};\n\nuse crate::bodyt::Body;\nuse crate::filter::{Filter, FilterBase, Internal};\nuse crate::reject::{self, Rejection};\n\n// If not otherwise configured, default to 2MB.\nconst DEFAULT_FORM_DATA_MAX_LENGTH: u64 = 1024 * 1024 * 2;\n\n/// A [`Filter`](crate::Filter) to extract a `multipart/form-data` body from a request.\n///\n/// Create with the `warp::multipart::form()` function.\n#[derive(Debug, Clone)]\npub struct FormOptions {\n    max_length: Option<u64>,\n}\n\n/// A `Stream` of multipart/form-data `Part`s.\n///\n/// Extracted with a `warp::multipart::form` filter.\npub struct FormData {\n    inner: FormDataInner<'static>,\n}\n\n/// A single \"part\" of a multipart/form-data body.\n///\n/// Yielded from the `FormData` stream.\npub struct Part {\n    part: PartInner<'static>,\n}\n\n/// Create a [`Filter`](crate::Filter) to extract a `multipart/form-data` body from a request.\n///\n/// The extracted `FormData` type is a `Stream` of `Part`s, and each `Part`\n/// in turn is a `Stream` of bytes.\npub fn form() -> FormOptions {\n    FormOptions {\n        max_length: Some(DEFAULT_FORM_DATA_MAX_LENGTH),\n    }\n}\n\n// ===== impl Form =====\n\nimpl FormOptions {\n    /// Set the maximum byte length allowed for this body.\n    ///\n    /// `max_length(None)` means that maximum byte length is not checked.\n    /// Defaults to 2MB.\n    pub fn max_length(mut self, max: impl Into<Option<u64>>) -> Self {\n        self.max_length = max.into();\n        self\n    }\n}\n\ntype FormFut = Pin<Box<dyn Future<Output = Result<(FormData,), Rejection>> + Send>>;\n\nimpl FilterBase for FormOptions {\n    type Extract = (FormData,);\n    type Error = Rejection;\n    type Future = FormFut;\n\n    fn filter(&self, _: Internal) -> Self::Future {\n        let boundary = super::header::header2::<ContentType>().and_then(|ct| {\n            let mime = Mime::from(ct);\n            let mime = mime\n                .get_param(\"boundary\")\n                .map(|v| v.to_string())\n                .ok_or_else(|| reject::invalid_header(\"content-type\"));\n            future::ready(mime)\n        });\n\n        let filt = boundary\n            .and(super::body::body())\n            .map(|boundary: String, body| {\n                let body = BodyIoError(BodyDataStream::new(body));\n                FormData {\n                    inner: FormDataInner::new(body, &boundary),\n                }\n            });\n\n        if let Some(max_length) = self.max_length {\n            Box::pin(\n                super::body::content_length_limit(max_length)\n                    .and(filt)\n                    .filter(Internal),\n            )\n        } else {\n            Box::pin(filt.filter(Internal))\n        }\n    }\n}\n\n// ===== impl FormData =====\n\nimpl fmt::Debug for FormData {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"FormData\").finish()\n    }\n}\n\nimpl Stream for FormData {\n    type Item = Result<Part, crate::Error>;\n\n    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        match self.inner.poll_next_field(cx) {\n            Poll::Pending => Poll::Pending,\n            Poll::Ready(Ok(Some(part))) => {\n                if part.name().is_some() || part.file_name().is_some() {\n                    Poll::Ready(Some(Ok(Part { part })))\n                } else {\n                    Poll::Ready(Some(Err(crate::Error::new(MultipartFieldMissingName))))\n                }\n            }\n            Poll::Ready(Ok(None)) => Poll::Ready(None),\n            Poll::Ready(Err(err)) => Poll::Ready(Some(Err(crate::Error::new(err)))),\n        }\n    }\n}\n\n// ===== impl Part =====\n\nimpl Part {\n    /// Get the name of this part.\n    pub fn name(&self) -> &str {\n        self.part\n            .name()\n            .unwrap_or_else(|| self.part.file_name().expect(\"checked for name previously\"))\n    }\n\n    /// Get the filename of this part, if present.\n    pub fn filename(&self) -> Option<&str> {\n        self.part.file_name()\n    }\n\n    /// Get the content-type of this part, if present.\n    pub fn content_type(&self) -> Option<&str> {\n        let content_type = self.part.content_type();\n        content_type.map(|t| t.as_ref())\n    }\n\n    /// Asynchronously get some of the data for this `Part`.\n    pub async fn data(&mut self) -> Option<Result<impl Buf, crate::Error>> {\n        future::poll_fn(|cx| self.poll_next(cx)).await\n    }\n\n    /// Convert this `Part` into a `Stream` of `Buf`s.\n    pub fn stream(self) -> impl Stream<Item = Result<impl Buf, crate::Error>> {\n        PartStream(self)\n    }\n\n    fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Bytes, crate::Error>>> {\n        match Pin::new(&mut self.part).poll_next(cx) {\n            Poll::Pending => Poll::Pending,\n            Poll::Ready(Some(Ok(bytes))) => Poll::Ready(Some(Ok(bytes))),\n            Poll::Ready(None) => Poll::Ready(None),\n            Poll::Ready(Some(Err(err))) => Poll::Ready(Some(Err(crate::Error::new(err)))),\n        }\n    }\n}\n\nimpl fmt::Debug for Part {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let mut builder = f.debug_struct(\"Part\");\n        builder.field(\"name\", &self.name());\n\n        if let Some(ref filename) = self.part.file_name() {\n            builder.field(\"filename\", filename);\n        }\n\n        if let Some(ref mime) = self.part.content_type() {\n            builder.field(\"content_type\", mime);\n        }\n\n        builder.finish()\n    }\n}\n\nstruct PartStream(Part);\n\nimpl Stream for PartStream {\n    type Item = Result<Bytes, crate::Error>;\n\n    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        self.0.poll_next(cx)\n    }\n}\n\nstruct BodyIoError(BodyDataStream<Body>);\n\nimpl Stream for BodyIoError {\n    type Item = io::Result<Bytes>;\n\n    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        match Pin::new(&mut self.0).poll_next(cx) {\n            Poll::Pending => Poll::Pending,\n            Poll::Ready(Some(Ok(bytes))) => Poll::Ready(Some(Ok(bytes))),\n            Poll::Ready(None) => Poll::Ready(None),\n            Poll::Ready(Some(Err(err))) => {\n                Poll::Ready(Some(Err(io::Error::new(io::ErrorKind::Other, err))))\n            }\n        }\n    }\n}\n\n/// An error used when a multipart field is missing a name.\n#[derive(Debug)]\nstruct MultipartFieldMissingName;\n\nimpl Display for MultipartFieldMissingName {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        write!(f, \"Multipart field is missing a name\")\n    }\n}\n\nimpl StdError for MultipartFieldMissingName {}\n"
  },
  {
    "path": "src/filters/path.rs",
    "content": "//! Path Filters\n//!\n//! The [`Filter`]s here work on the \"path\" of requests.\n//!\n//! - [`path`](./fn.path.html) matches a specific segment, like `/foo`.\n//! - [`param`](./fn.param.html) tries to parse a segment into a type, like `/:u16`.\n//! - [`end`](./fn.end.html) matches when the path end is found.\n//! - [`path!`](../../macro.path.html) eases combining multiple `path` and `param` filters.\n//!\n//! # Routing\n//!\n//! Routing in warp is simple yet powerful.\n//!\n//! First up, matching a single segment:\n//!\n//! ```\n//! use warp::Filter;\n//!\n//! // GET /hi\n//! let hi = warp::path(\"hi\").map(|| {\n//!     \"Hello, World!\"\n//! });\n//! ```\n//!\n//! How about multiple segments? It's easiest with the `path!` macro:\n//!\n//! ```\n//! # use warp::Filter;\n//! // GET /hello/from/warp\n//! let hello_from_warp = warp::path!(\"hello\" / \"from\" / \"warp\").map(|| {\n//!     \"Hello from warp!\"\n//! });\n//! ```\n//!\n//! Neat! But how do I handle **parameters** in paths?\n//!\n//! ```\n//! # use warp::Filter;\n//! // GET /sum/:u32/:u32\n//! let sum = warp::path!(\"sum\" / u32 / u32).map(|a, b| {\n//!     format!(\"{} + {} = {}\", a, b, a + b)\n//! });\n//! ```\n//!\n//! In fact, any type that implements `FromStr` can be used, in any order:\n//!\n//! ```\n//! # use warp::Filter;\n//! // GET /:u16/times/:u16\n//! let times = warp::path!(u16 / \"times\" / u16).map(|a, b| {\n//!     format!(\"{} times {} = {}\", a, b, a * b)\n//! });\n//! ```\n//!\n//! Oh shoot, those math routes should be **mounted** at a different path,\n//! is that possible? Yep!\n//!\n//! ```\n//! # use warp::Filter;\n//! # let sum = warp::any().map(warp::reply);\n//! # let times = sum.clone();\n//! // GET /math/sum/:u32/:u32\n//! // GET /math/:u16/times/:u16\n//! let math = warp::path(\"math\");\n//! let math_sum = math.and(sum);\n//! let math_times = math.and(times);\n//! ```\n//!\n//! What! `and`? What's that do?\n//!\n//! It combines the filters in a sort of \"this and then that\" order. In fact,\n//! it's exactly what the `path!` macro has been doing internally.\n//!\n//! ```\n//! # use warp::Filter;\n//! // GET /bye/:string\n//! let bye = warp::path(\"bye\")\n//!     .and(warp::path::param())\n//!     .map(|name: String| {\n//!         format!(\"Good bye, {}!\", name)\n//!     });\n//! ```\n//!\n//! Ah, so, can filters do things besides `and`?\n//!\n//! Why, yes they can! They can also `or`! As you might expect, `or` creates a\n//! \"this or else that\" chain of filters. If the first doesn't succeed, then\n//! it tries the other.\n//!\n//! So, those `math` routes could have been **mounted** all as one, with `or`.\n//!\n//!\n//! ```\n//! # use warp::Filter;\n//! # let sum = warp::path(\"sum\");\n//! # let times = warp::path(\"times\");\n//! // GET /math/sum/:u32/:u32\n//! // GET /math/:u16/times/:u16\n//! let math = warp::path(\"math\")\n//!     .and(sum.or(times));\n//! ```\n//!\n//! It turns out, using `or` is how you combine everything together into a\n//! single API.\n//!\n//! ```\n//! # use warp::Filter;\n//! # let hi = warp::path(\"hi\");\n//! # let hello_from_warp = hi.clone();\n//! # let bye = hi.clone();\n//! # let math = hi.clone();\n//! // GET /hi\n//! // GET /hello/from/warp\n//! // GET /bye/:string\n//! // GET /math/sum/:u32/:u32\n//! // GET /math/:u16/times/:u16\n//! let routes = hi\n//!     .or(hello_from_warp)\n//!     .or(bye)\n//!     .or(math);\n//! ```\n//!\n//! Note that you will generally want path filters to come **before** other filters\n//! like `body` or `headers`. If a different type of filter comes first, a request\n//! with an invalid body for route `/right-path-wrong-body` may try matching against `/wrong-path`\n//! and return the error from `/wrong-path` instead of the correct body-related error.\n\nuse std::convert::Infallible;\nuse std::fmt;\nuse std::str::FromStr;\n\nuse futures_util::future;\nuse http::uri::PathAndQuery;\n\nuse self::internal::Opaque;\nuse crate::filter::{filter_fn, one, Filter, FilterBase, Internal, One, Tuple};\nuse crate::reject::{self, Rejection};\nuse crate::route::{self, Route};\n\n/// Create an exact match path segment [`Filter`].\n///\n/// This will try to match exactly to the current request path segment.\n///\n/// # Note\n///\n/// - [`end()`](./fn.end.html) should be used to match the end of a path to avoid having\n///   filters for shorter paths like `/math` unintentionally match a longer\n///   path such as `/math/sum`\n/// - Path-related filters should generally come **before** other types of filters, such\n///   as those checking headers or body types. Including those other filters before\n///   the path checks may result in strange errors being returned because a given request\n///   does not match the parameters for a completely separate route.\n///\n/// # Panics\n///\n/// Exact path filters cannot be empty, or contain slashes.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// // Matches '/hello'\n/// let hello = warp::path(\"hello\")\n///     .map(|| \"Hello, World!\");\n/// ```\npub fn path<P>(p: P) -> Exact<Opaque<P>>\nwhere\n    P: AsRef<str>,\n{\n    let s = p.as_ref();\n    assert!(!s.is_empty(), \"exact path segments should not be empty\");\n    assert!(\n        !s.contains('/'),\n        \"exact path segments should not contain a slash: {:?}\",\n        s\n    );\n\n    Exact(Opaque(p))\n    /*\n    segment(move |seg| {\n        tracing::trace!(\"{:?}?: {:?}\", p, seg);\n        if seg == p {\n            Ok(())\n        } else {\n            Err(reject::not_found())\n        }\n    })\n    */\n}\n\n/// A [`Filter`] matching an exact path segment.\n///\n/// Constructed from `path()` or `path!()`.\n#[allow(missing_debug_implementations)]\n#[derive(Clone, Copy)]\npub struct Exact<P>(P);\n\nimpl<P> FilterBase for Exact<P>\nwhere\n    P: AsRef<str>,\n{\n    type Extract = ();\n    type Error = Rejection;\n    type Future = future::Ready<Result<Self::Extract, Self::Error>>;\n\n    #[inline]\n    fn filter(&self, _: Internal) -> Self::Future {\n        route::with(|route| {\n            let p = self.0.as_ref();\n            future::ready(with_segment(route, |seg| {\n                tracing::trace!(\"{:?}?: {:?}\", p, seg);\n\n                if seg == p {\n                    Ok(())\n                } else {\n                    Err(reject::not_found())\n                }\n            }))\n        })\n    }\n}\n\n/// Matches the end of a route.\n///\n/// Note that _not_ including `end()` may result in shorter paths like\n/// `/math` unintentionally matching `/math/sum`.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// // Matches '/'\n/// let hello = warp::path::end()\n///     .map(|| \"Hello, World!\");\n/// ```\npub fn end() -> impl Filter<Extract = (), Error = Rejection> + Copy {\n    filter_fn(move |route| {\n        if route.path().is_empty() {\n            future::ok(())\n        } else {\n            future::err(reject::not_found())\n        }\n    })\n}\n\n/// Extract a parameter from a path segment.\n///\n/// This will try to parse a value from the current request path\n/// segment, and if successful, the value is returned as the `Filter`'s\n/// \"extracted\" value.\n///\n/// If the value could not be parsed, rejects with a `404 Not Found`.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let route = warp::path::param()\n///     .map(|id: u32| {\n///         format!(\"You asked for /{}\", id)\n///     });\n/// ```\npub fn param<T: FromStr + Send + 'static>(\n) -> impl Filter<Extract = One<T>, Error = Rejection> + Copy {\n    filter_segment(|seg| {\n        tracing::trace!(\"param?: {:?}\", seg);\n        if seg.is_empty() {\n            return Err(reject::not_found());\n        }\n        T::from_str(seg).map(one).map_err(|_| reject::not_found())\n    })\n}\n\n/// Extract the unmatched tail of the path.\n///\n/// This will return a `Tail`, which allows access to the rest of the path\n/// that previous filters have not already matched.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let route = warp::path(\"foo\")\n///     .and(warp::path::tail())\n///     .map(|tail| {\n///         // GET /foo/bar/baz would return \"bar/baz\".\n///         format!(\"The tail after foo is {:?}\", tail)\n///     });\n/// ```\npub fn tail() -> impl Filter<Extract = One<Tail>, Error = Infallible> + Copy {\n    filter_fn(move |route| {\n        let path = path_and_query(route);\n        let idx = route.matched_path_index();\n\n        // Giving the user the full tail means we assume the full path\n        // has been matched now.\n        let end = path.path().len() - idx;\n        route.set_unmatched_path(end);\n\n        future::ok(one(Tail {\n            path,\n            start_index: idx,\n        }))\n    })\n}\n\n/// Represents the tail part of a request path, returned by the [`tail()`] filter.\npub struct Tail {\n    path: PathAndQuery,\n    start_index: usize,\n}\n\nimpl Tail {\n    /// Get the `&str` representation of the remaining path.\n    pub fn as_str(&self) -> &str {\n        &self.path.path()[self.start_index..]\n    }\n}\n\nimpl fmt::Debug for Tail {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        fmt::Debug::fmt(self.as_str(), f)\n    }\n}\n\n/// Peek at the unmatched tail of the path, without affecting the matched path.\n///\n/// This will return a `Peek`, which allows access to the rest of the path\n/// that previous filters have not already matched. This differs from `tail`\n/// in that `peek` will **not** set the entire path as matched.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let route = warp::path(\"foo\")\n///     .and(warp::path::peek())\n///     .map(|peek| {\n///         // GET /foo/bar/baz would return \"bar/baz\".\n///         format!(\"The path after foo is {:?}\", peek)\n///     });\n/// ```\npub fn peek() -> impl Filter<Extract = One<Peek>, Error = Infallible> + Copy {\n    filter_fn(move |route| {\n        let path = path_and_query(route);\n        let idx = route.matched_path_index();\n\n        future::ok(one(Peek {\n            path,\n            start_index: idx,\n        }))\n    })\n}\n\n/// Represents the tail part of a request path, returned by the [`peek()`] filter.\npub struct Peek {\n    path: PathAndQuery,\n    start_index: usize,\n}\n\nimpl Peek {\n    /// Get the `&str` representation of the remaining path.\n    pub fn as_str(&self) -> &str {\n        &self.path.path()[self.start_index..]\n    }\n\n    /// Get an iterator over the segments of the peeked path.\n    pub fn segments(&self) -> impl Iterator<Item = &str> {\n        self.as_str().split('/').filter(|seg| !seg.is_empty())\n    }\n}\n\nimpl fmt::Debug for Peek {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        fmt::Debug::fmt(self.as_str(), f)\n    }\n}\n\n/// Returns the full request path, irrespective of other filters.\n///\n/// This will return a `FullPath`, which can be stringified to return the\n/// full path of the request.\n///\n/// This is more useful in generic pre/post-processing filters, and should\n/// probably not be used for request matching/routing.\n///\n/// # Example\n///\n/// ```\n/// use warp::{Filter, path::FullPath};\n/// use std::{collections::HashMap, sync::{Arc, Mutex}};\n///\n/// let counts = Arc::new(Mutex::new(HashMap::new()));\n/// let access_counter = warp::path::full()\n///     .map(move |path: FullPath| {\n///         let mut counts = counts.lock().unwrap();\n///\n///         *counts.entry(path.as_str().to_string())\n///             .and_modify(|c| *c += 1)\n///             .or_insert(0)\n///     });\n///\n/// let route = warp::path(\"foo\")\n///     .and(warp::path(\"bar\"))\n///     .and(access_counter)\n///     .map(|count| {\n///         format!(\"This is the {}th visit to this URL!\", count)\n///     });\n/// ```\npub fn full() -> impl Filter<Extract = One<FullPath>, Error = Infallible> + Copy {\n    filter_fn(move |route| future::ok(one(FullPath(path_and_query(route)))))\n}\n\n/// Represents the full request path, returned by the [`full()`] filter.\npub struct FullPath(PathAndQuery);\n\nimpl FullPath {\n    /// Get the `&str` representation of the request path.\n    pub fn as_str(&self) -> &str {\n        self.0.path()\n    }\n}\n\nimpl fmt::Debug for FullPath {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        fmt::Debug::fmt(self.as_str(), f)\n    }\n}\n\nfn filter_segment<F, U>(func: F) -> impl Filter<Extract = U, Error = Rejection> + Copy\nwhere\n    F: Fn(&str) -> Result<U, Rejection> + Copy,\n    U: Tuple + Send + 'static,\n{\n    filter_fn(move |route| future::ready(with_segment(route, func)))\n}\n\nfn with_segment<F, U>(route: &mut Route, func: F) -> Result<U, Rejection>\nwhere\n    F: Fn(&str) -> Result<U, Rejection>,\n{\n    let seg = segment(route);\n    let ret = func(seg);\n    if ret.is_ok() {\n        let idx = seg.len();\n        route.set_unmatched_path(idx);\n    }\n    ret\n}\n\nfn segment(route: &Route) -> &str {\n    route\n        .path()\n        .splitn(2, '/')\n        .next()\n        .expect(\"split always has at least 1\")\n}\n\nfn path_and_query(route: &Route) -> PathAndQuery {\n    route\n        .uri()\n        .path_and_query()\n        .cloned()\n        .unwrap_or_else(|| PathAndQuery::from_static(\"\"))\n}\n\n/// Convenient way to chain multiple path filters together.\n///\n/// Any number of either type identifiers or string expressions can be passed,\n/// each separated by a forward slash (`/`). Strings will be used to match\n/// path segments exactly, and type identifiers are used just like\n/// [`param`](crate::path::param) filters.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// // Match `/sum/:a/:b`\n/// let route = warp::path!(\"sum\" / u32 / u32)\n///     .map(|a, b| {\n///         format!(\"{} + {} = {}\", a, b, a + b)\n///     });\n/// ```\n///\n/// The equivalent filter chain without using the `path!` macro looks this:\n///\n/// ```\n/// use warp::Filter;\n///\n/// let route = warp::path(\"sum\")\n///     .and(warp::path::param::<u32>())\n///     .and(warp::path::param::<u32>())\n///     .and(warp::path::end())\n///     .map(|a, b| {\n///         format!(\"{} + {} = {}\", a, b, a + b)\n///     });\n/// ```\n///\n/// # Path Prefixes\n///\n/// The `path!` macro automatically assumes the path should include an `end()`\n/// filter. To build up a path filter *prefix*, such that the `end()` isn't\n/// included, use the `/ ..` syntax.\n///\n///\n/// ```\n/// use warp::Filter;\n///\n/// let prefix = warp::path!(\"math\" / \"sum\" / ..);\n///\n/// let sum = warp::path!(u32 / u32)\n///     .map(|a, b| {\n///         format!(\"{} + {} = {}\", a, b, a + b)\n///     });\n///\n/// let help = warp::path::end()\n///     .map(|| \"This API returns the sum of two u32's\");\n///\n/// let api = prefix.and(sum.or(help));\n/// ```\n#[macro_export]\nmacro_rules! path {\n    ($($pieces:tt)*) => ({\n        $crate::__internal_path!(@start $($pieces)*)\n    });\n}\n\n#[doc(hidden)]\n#[macro_export]\n// not public API\nmacro_rules! __internal_path {\n    (@start) => (\n        $crate::path::end()\n    );\n    (@start ..) => ({\n        compile_error!(\"'..' cannot be the only segment\")\n    });\n    (@start $first:tt $(/ $tail:tt)*) => ({\n        $crate::__internal_path!(@munch $crate::any(); [$first] [$(/ $tail)*])\n    });\n\n    (@munch $sum:expr; [$cur:tt] [/ $next:tt $(/ $tail:tt)*]) => ({\n        $crate::__internal_path!(@munch $crate::Filter::and($sum, $crate::__internal_path!(@segment $cur)); [$next] [$(/ $tail)*])\n    });\n    (@munch $sum:expr; [$cur:tt] []) => ({\n        $crate::__internal_path!(@last $sum; $cur)\n    });\n\n    (@last $sum:expr; ..) => (\n        $sum\n    );\n    (@last $sum:expr; $end:tt) => (\n        $crate::Filter::and(\n            $crate::Filter::and($sum, $crate::__internal_path!(@segment $end)),\n            $crate::path::end()\n        )\n    );\n\n    (@segment ..) => (\n        compile_error!(\"'..' must be the last segment\")\n    );\n    (@segment $param:ty) => (\n        $crate::path::param::<$param>()\n    );\n    // Constructs a unique ZST so the &'static str pointer doesn't need to\n    // be carried around.\n    (@segment $s:literal) => ({\n        #[derive(Clone, Copy)]\n        struct __StaticPath;\n        impl ::std::convert::AsRef<str> for __StaticPath {\n            fn as_ref(&self) -> &str {\n                static S: &str = $s;\n                S\n            }\n        }\n        $crate::path(__StaticPath)\n    });\n}\n\n// path! compile fail tests\n\n/// ```compile_fail\n/// warp::path!(\"foo\" / .. / \"bar\");\n/// ```\n///\n/// ```compile_fail\n/// warp::path!(.. / \"bar\");\n/// ```\n///\n/// ```compile_fail\n/// warp::path!(\"foo\" ..);\n/// ```\n///\n/// ```compile_fail\n/// warp::path!(\"foo\" / .. /);\n/// ```\n///\n/// ```compile_fail\n/// warp::path!(..);\n/// ```\nfn _path_macro_compile_fail() {}\n\nmod internal {\n    // Used to prevent users from naming this type.\n    //\n    // For instance, `Exact<Opaque<String>>` means a user cannot depend\n    // on it being `Exact<String>`.\n    #[allow(missing_debug_implementations)]\n    #[derive(Clone, Copy)]\n    pub struct Opaque<T>(pub(super) T);\n\n    impl<T: AsRef<str>> AsRef<str> for Opaque<T> {\n        #[inline]\n        fn as_ref(&self) -> &str {\n            self.0.as_ref()\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_path_exact_size() {\n        use std::mem::{size_of, size_of_val};\n\n        assert_eq!(\n            size_of_val(&path(\"hello\")),\n            size_of::<&str>(),\n            \"exact(&str) is size of &str\"\n        );\n\n        assert_eq!(\n            size_of_val(&path(String::from(\"world\"))),\n            size_of::<String>(),\n            \"exact(String) is size of String\"\n        );\n\n        assert_eq!(\n            size_of_val(&path!(\"zst\")),\n            size_of::<()>(),\n            \"path!(&str) is ZST\"\n        );\n    }\n}\n"
  },
  {
    "path": "src/filters/query.rs",
    "content": "//! Query Filters\n\nuse futures_util::future;\nuse serde::de::DeserializeOwned;\n\nuse crate::filter::{filter_fn_one, Filter, One};\nuse crate::reject::{self, Rejection};\n\n/// Creates a `Filter` that decodes query parameters to the type `T`.\n///\n/// If cannot decode into a `T`, the request is rejected with a `400 Bad Request`.\n///\n/// # Example\n///\n/// ```\n/// use std::collections::HashMap;\n/// use warp::{\n///     http::Response,\n///     Filter,\n/// };\n///\n/// let route = warp::any()\n///     .and(warp::query::<HashMap<String, String>>())\n///     .map(|map: HashMap<String, String>| {\n///         let mut response: Vec<String> = Vec::new();\n///         for (key, value) in map.into_iter() {\n///             response.push(format!(\"{}={}\", key, value))\n///         }\n///         Response::builder().body(response.join(\";\"))\n///     });\n/// ```\n///\n/// You can define your custom query object and deserialize with [Serde][Serde]. Ensure to include\n/// the crate in your dependencies before usage.\n///\n/// ```\n/// use serde_derive::{Deserialize, Serialize};\n/// use std::collections::HashMap;\n/// use warp::{\n///     http::Response,\n///     Filter,\n/// };\n///\n/// #[derive(Serialize, Deserialize)]\n/// struct FooQuery {\n///     foo: Option<String>,\n///     bar: u8,\n/// }\n///\n/// let route = warp::any()\n///     .and(warp::query::<FooQuery>())\n///     .map(|q: FooQuery| {\n///         if let Some(foo) = q.foo {\n///             Response::builder().body(format!(\"foo={}\", foo))\n///         } else {\n///             Response::builder().body(format!(\"bar={}\", q.bar))\n///         }\n///     });\n/// ```\n///\n/// For more examples, please take a look at [examples/query_string.rs](https://github.com/seanmonstar/warp/blob/master/examples/query_string.rs).\n///\n/// [Serde]: https://docs.rs/serde\npub fn query<T: DeserializeOwned + Send + 'static>(\n) -> impl Filter<Extract = One<T>, Error = Rejection> + Copy {\n    filter_fn_one(|route| {\n        let query_string = route.query().unwrap_or_else(|| {\n            tracing::debug!(\"route was called without a query string, defaulting to empty\");\n            \"\"\n        });\n\n        let query_encoded = serde_urlencoded::from_str(query_string).map_err(|e| {\n            tracing::debug!(\"failed to decode query string '{}': {:?}\", query_string, e);\n            reject::invalid_query()\n        });\n        future::ready(query_encoded)\n    })\n}\n\n/// Creates a `Filter` that returns the raw query string as type String.\npub fn raw() -> impl Filter<Extract = One<String>, Error = Rejection> + Copy {\n    filter_fn_one(|route| {\n        let route = route\n            .query()\n            .map(|q| q.to_owned())\n            .map(Ok)\n            .unwrap_or_else(|| Err(reject::invalid_query()));\n        future::ready(route)\n    })\n}\n"
  },
  {
    "path": "src/filters/reply.rs",
    "content": "//! Reply Filters\n//!\n//! These \"filters\" behave a little differently than the rest. Instead of\n//! being used directly on requests, these filters \"wrap\" other filters.\n//!\n//!\n//! ## Wrapping a `Filter` (`with`)\n//!\n//! ```\n//! use warp::Filter;\n//!\n//! let with_server = warp::reply::with::header(\"server\", \"warp\");\n//!\n//! let route = warp::any()\n//!     .map(warp::reply)\n//!     .with(with_server);\n//! ```\n//!\n//! Wrapping allows adding in conditional logic *before* the request enters\n//! the inner filter (though the `with::header` wrapper does not).\n\nuse std::convert::TryFrom;\nuse std::sync::Arc;\n\nuse http::header::{HeaderMap, HeaderName, HeaderValue};\n\nuse self::sealed::{WithDefaultHeader_, WithHeader_, WithHeaders_};\nuse crate::filter::{Filter, Map, WrapSealed};\nuse crate::reply::Reply;\n\n/// Wrap a [`Filter`] that adds a header to the reply.\n///\n/// # Note\n///\n/// This **only** adds a header if the underlying filter is successful, and\n/// returns a [`Reply`] If the underlying filter was rejected, the\n/// header is not added.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// // Always set `foo: bar` header.\n/// let route = warp::any()\n///     .map(warp::reply)\n///     .with(warp::reply::with::header(\"foo\", \"bar\"));\n/// ```\npub fn header<K, V>(name: K, value: V) -> WithHeader\nwhere\n    HeaderName: TryFrom<K>,\n    <HeaderName as TryFrom<K>>::Error: Into<http::Error>,\n    HeaderValue: TryFrom<V>,\n    <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,\n{\n    let (name, value) = assert_name_and_value(name, value);\n    WithHeader { name, value }\n}\n\n/// Wrap a [`Filter`] that adds multiple headers to the reply.\n///\n/// # Note\n///\n/// This **only** adds a header if the underlying filter is successful, and\n/// returns a [`Reply`] If the underlying filter was rejected, the\n/// header is not added.\n///\n/// # Example\n///\n/// ```\n/// use warp::http::header::{HeaderMap, HeaderValue};\n/// use warp::Filter;\n///\n/// let mut headers = HeaderMap::new();\n/// headers.insert(\"server\", HeaderValue::from_static(\"wee/0\"));\n/// headers.insert(\"foo\", HeaderValue::from_static(\"bar\"));\n///\n/// // Always set `server: wee/0` and `foo: bar` headers.\n/// let route = warp::any()\n///     .map(warp::reply)\n///     .with(warp::reply::with::headers(headers));\n/// ```\npub fn headers(headers: HeaderMap) -> WithHeaders {\n    WithHeaders {\n        headers: Arc::new(headers),\n    }\n}\n\n// pub fn headers?\n\n/// Wrap a [`Filter`] that adds a header to the reply, if they\n/// aren't already set.\n///\n/// # Note\n///\n/// This **only** adds a header if the underlying filter is successful, and\n/// returns a [`Reply`] If the underlying filter was rejected, the\n/// header is not added.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// // Set `server: warp` if not already set.\n/// let route = warp::any()\n///     .map(warp::reply)\n///     .with(warp::reply::with::default_header(\"server\", \"warp\"));\n/// ```\npub fn default_header<K, V>(name: K, value: V) -> WithDefaultHeader\nwhere\n    HeaderName: TryFrom<K>,\n    <HeaderName as TryFrom<K>>::Error: Into<http::Error>,\n    HeaderValue: TryFrom<V>,\n    <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,\n{\n    let (name, value) = assert_name_and_value(name, value);\n    WithDefaultHeader { name, value }\n}\n\n/// Wrap a `Filter` to always set a header.\n#[derive(Clone, Debug)]\npub struct WithHeader {\n    name: HeaderName,\n    value: HeaderValue,\n}\n\nimpl<F, R> WrapSealed<F> for WithHeader\nwhere\n    F: Filter<Extract = (R,)>,\n    R: Reply,\n{\n    type Wrapped = Map<F, WithHeader_>;\n\n    fn wrap(&self, filter: F) -> Self::Wrapped {\n        let with = WithHeader_ { with: self.clone() };\n        filter.map(with)\n    }\n}\n\n/// Wrap a `Filter` to always set multiple headers.\n#[derive(Clone, Debug)]\npub struct WithHeaders {\n    headers: Arc<HeaderMap>,\n}\n\nimpl<F, R> WrapSealed<F> for WithHeaders\nwhere\n    F: Filter<Extract = (R,)>,\n    R: Reply,\n{\n    type Wrapped = Map<F, WithHeaders_>;\n\n    fn wrap(&self, filter: F) -> Self::Wrapped {\n        let with = WithHeaders_ { with: self.clone() };\n        filter.map(with)\n    }\n}\n\n/// Wrap a `Filter` to set a header if it is not already set.\n#[derive(Clone, Debug)]\npub struct WithDefaultHeader {\n    name: HeaderName,\n    value: HeaderValue,\n}\n\nimpl<F, R> WrapSealed<F> for WithDefaultHeader\nwhere\n    F: Filter<Extract = (R,)>,\n    R: Reply,\n{\n    type Wrapped = Map<F, WithDefaultHeader_>;\n\n    fn wrap(&self, filter: F) -> Self::Wrapped {\n        let with = WithDefaultHeader_ { with: self.clone() };\n        filter.map(with)\n    }\n}\n\nfn assert_name_and_value<K, V>(name: K, value: V) -> (HeaderName, HeaderValue)\nwhere\n    HeaderName: TryFrom<K>,\n    <HeaderName as TryFrom<K>>::Error: Into<http::Error>,\n    HeaderValue: TryFrom<V>,\n    <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,\n{\n    let name = <HeaderName as TryFrom<K>>::try_from(name)\n        .map_err(Into::into)\n        .unwrap_or_else(|_| panic!(\"invalid header name\"));\n\n    let value = <HeaderValue as TryFrom<V>>::try_from(value)\n        .map_err(Into::into)\n        .unwrap_or_else(|_| panic!(\"invalid header value\"));\n\n    (name, value)\n}\n\nmod sealed {\n    use super::{WithDefaultHeader, WithHeader, WithHeaders};\n    use crate::generic::{Func, One};\n    use crate::reply::{Reply, Reply_};\n\n    #[derive(Clone)]\n    #[allow(missing_debug_implementations)]\n    pub struct WithHeader_ {\n        pub(super) with: WithHeader,\n    }\n\n    impl<R: Reply> Func<One<R>> for WithHeader_ {\n        type Output = Reply_;\n\n        fn call(&self, args: One<R>) -> Self::Output {\n            let mut resp = args.0.into_response();\n            // Use \"insert\" to replace any set header...\n            resp.headers_mut()\n                .insert(&self.with.name, self.with.value.clone());\n            Reply_(resp)\n        }\n    }\n\n    #[derive(Clone)]\n    #[allow(missing_debug_implementations)]\n    pub struct WithHeaders_ {\n        pub(super) with: WithHeaders,\n    }\n\n    impl<R: Reply> Func<One<R>> for WithHeaders_ {\n        type Output = Reply_;\n\n        fn call(&self, args: One<R>) -> Self::Output {\n            let mut resp = args.0.into_response();\n            for (name, value) in &*self.with.headers {\n                resp.headers_mut().insert(name, value.clone());\n            }\n            Reply_(resp)\n        }\n    }\n\n    #[derive(Clone)]\n    #[allow(missing_debug_implementations)]\n    pub struct WithDefaultHeader_ {\n        pub(super) with: WithDefaultHeader,\n    }\n\n    impl<R: Reply> Func<One<R>> for WithDefaultHeader_ {\n        type Output = Reply_;\n\n        fn call(&self, args: One<R>) -> Self::Output {\n            let mut resp = args.0.into_response();\n            resp.headers_mut()\n                .entry(&self.with.name)\n                .or_insert_with(|| self.with.value.clone());\n\n            Reply_(resp)\n        }\n    }\n}\n"
  },
  {
    "path": "src/filters/sse.rs",
    "content": "//! Server-Sent Events (SSE)\n//!\n//! # Example\n//!\n//! ```\n//!\n//! use std::time::Duration;\n//! use std::convert::Infallible;\n//! use warp::{Filter, sse::Event};\n//! use futures_util::{stream::iter, Stream};\n//!\n//! fn sse_events() -> impl Stream<Item = Result<Event, Infallible>> {\n//!     iter(vec![\n//!         Ok(Event::default().data(\"unnamed event\")),\n//!         Ok(\n//!             Event::default().event(\"chat\")\n//!             .data(\"chat message\")\n//!         ),\n//!         Ok(\n//!             Event::default().id(13.to_string())\n//!             .event(\"chat\")\n//!             .data(\"other chat message\\nwith next line\")\n//!             .retry(Duration::from_millis(5000))\n//!         )\n//!     ])\n//! }\n//!\n//! let app = warp::path(\"push-notifications\")\n//!     .and(warp::get())\n//!     .map(|| {\n//!         warp::sse::reply(warp::sse::keep_alive().stream(sse_events()))\n//!     });\n//! ```\n//!\n//! Each field already is event which can be sent to client.\n//! The events with multiple fields can be created by combining fields using tuples.\n//!\n//! See also the [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) API,\n//! which specifies the expected behavior of Server Sent Events.\n//!\n\n#![allow(rustdoc::invalid_html_tags)]\n\nuse serde::Serialize;\nuse std::borrow::Cow;\nuse std::error::Error as StdError;\nuse std::fmt::{self, Write};\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::str::FromStr;\nuse std::task::{Context, Poll};\nuse std::time::Duration;\n\nuse crate::bodyt::Body;\nuse futures_util::{future, Stream, TryStream, TryStreamExt};\nuse http::header::{HeaderValue, CACHE_CONTROL, CONTENT_TYPE};\nuse pin_project::pin_project;\nuse serde_json::Error;\nuse tokio::time::{self, Sleep};\n\nuse self::sealed::SseError;\nuse super::header;\nuse crate::filter::One;\nuse crate::reply::Response;\nuse crate::{Filter, Rejection, Reply};\n\n// Server-sent event data type\n#[derive(Debug)]\nenum DataType {\n    Text(String),\n    Json(String),\n}\n\n/// Server-sent event\n#[derive(Default, Debug)]\npub struct Event {\n    id: Option<String>,\n    data: Option<DataType>,\n    event: Option<String>,\n    comment: Option<String>,\n    retry: Option<Duration>,\n}\n\nimpl Event {\n    /// Set Server-sent event data\n    /// data field(s) (\"data:<content>\")\n    pub fn data<T: Into<String>>(mut self, data: T) -> Event {\n        self.data = Some(DataType::Text(data.into()));\n        self\n    }\n\n    /// Set Server-sent event data\n    /// data field(s) (\"data:<content>\")\n    pub fn json_data<T: Serialize>(mut self, data: T) -> Result<Event, Error> {\n        self.data = Some(DataType::Json(serde_json::to_string(&data)?));\n        Ok(self)\n    }\n\n    /// Set Server-sent event comment\n    /// Comment field (\":<comment-text>\")\n    pub fn comment<T: Into<String>>(mut self, comment: T) -> Event {\n        self.comment = Some(comment.into());\n        self\n    }\n\n    /// Set Server-sent event event\n    /// Event name field (\"event:<event-name>\")\n    pub fn event<T: Into<String>>(mut self, event: T) -> Event {\n        self.event = Some(event.into());\n        self\n    }\n\n    /// Set Server-sent event retry\n    /// Retry timeout field (\"retry:<timeout>\")\n    pub fn retry(mut self, duration: Duration) -> Event {\n        self.retry = Some(duration);\n        self\n    }\n\n    /// Set Server-sent event id\n    /// Identifier field (\"id:<identifier>\")\n    pub fn id<T: Into<String>>(mut self, id: T) -> Event {\n        self.id = Some(id.into());\n        self\n    }\n}\n\nimpl fmt::Display for Event {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        if let Some(ref comment) = &self.comment {\n            \":\".fmt(f)?;\n            comment.fmt(f)?;\n            f.write_char('\\n')?;\n        }\n\n        if let Some(ref event) = &self.event {\n            \"event:\".fmt(f)?;\n            event.fmt(f)?;\n            f.write_char('\\n')?;\n        }\n\n        match self.data {\n            Some(DataType::Text(ref data)) => {\n                for line in data.split('\\n') {\n                    \"data:\".fmt(f)?;\n                    line.fmt(f)?;\n                    f.write_char('\\n')?;\n                }\n            }\n            Some(DataType::Json(ref data)) => {\n                \"data:\".fmt(f)?;\n                data.fmt(f)?;\n                f.write_char('\\n')?;\n            }\n            None => {}\n        }\n\n        if let Some(ref id) = &self.id {\n            \"id:\".fmt(f)?;\n            id.fmt(f)?;\n            f.write_char('\\n')?;\n        }\n\n        if let Some(ref duration) = &self.retry {\n            \"retry:\".fmt(f)?;\n\n            let secs = duration.as_secs();\n            let millis = duration.subsec_millis();\n\n            if secs > 0 {\n                // format seconds\n                secs.fmt(f)?;\n\n                // pad milliseconds\n                if millis < 10 {\n                    f.write_str(\"00\")?;\n                } else if millis < 100 {\n                    f.write_char('0')?;\n                }\n            }\n\n            // format milliseconds\n            millis.fmt(f)?;\n\n            f.write_char('\\n')?;\n        }\n\n        f.write_char('\\n')?;\n        Ok(())\n    }\n}\n\n/// Gets the optional last event id from request.\n/// Typically this identifier represented as number or string.\n///\n/// ```\n/// let app = warp::sse::last_event_id::<u32>();\n///\n/// // The identifier is present\n/// # #[cfg(feature = \"test\")]\n/// async {\n///     assert_eq!(\n///         warp::test::request()\n///            .header(\"Last-Event-ID\", \"12\")\n///            .filter(&app)\n///            .await\n///            .unwrap(),\n///         Some(12)\n///     );\n///\n///     // The identifier is missing\n///     assert_eq!(\n///        warp::test::request()\n///            .filter(&app)\n///            .await\n///            .unwrap(),\n///         None\n///     );\n///\n///     // The identifier is not a valid\n///     assert!(\n///        warp::test::request()\n///            .header(\"Last-Event-ID\", \"abc\")\n///            .filter(&app)\n///            .await\n///            .is_err(),\n///     );\n///};\n/// ```\npub fn last_event_id<T>() -> impl Filter<Extract = One<Option<T>>, Error = Rejection> + Copy\nwhere\n    T: FromStr + Send + Sync + 'static,\n{\n    header::optional(\"last-event-id\")\n}\n\n/// Server-sent events reply\n///\n/// This function converts stream of server events into a `Reply` with:\n///\n/// - Status of `200 OK`\n/// - Header `content-type: text/event-stream`\n/// - Header `cache-control: no-cache`.\n///\n/// # Example\n///\n/// ```\n/// use std::time::Duration;\n/// use futures_util::Stream;\n/// use futures_util::stream::iter;\n/// use std::convert::Infallible;\n/// use warp::{Filter, sse::Event};\n/// use serde_derive::Serialize;\n///\n/// #[derive(Serialize)]\n/// struct Msg {\n///     from: u32,\n///     text: String,\n/// }\n///\n/// fn event_stream() -> impl Stream<Item = Result<Event, Infallible>> {\n///         iter(vec![\n///             // Unnamed event with data only\n///             Ok(Event::default().data(\"payload\")),\n///             // Named event with ID and retry timeout\n///             Ok(\n///                 Event::default().data(\"other message\\nwith next line\")\n///                 .event(\"chat\")\n///                 .id(1.to_string())\n///                 .retry(Duration::from_millis(15000))\n///             ),\n///             // Event with JSON data\n///             Ok(\n///                 Event::default().id(2.to_string())\n///                 .json_data(Msg {\n///                     from: 2,\n///                     text: \"hello\".into(),\n///                 }).unwrap(),\n///             )\n///         ])\n/// }\n///\n/// # #[cfg(feature = \"test\")]\n/// async {\n///     let app = warp::path(\"sse\").and(warp::get()).map(|| {\n///        warp::sse::reply(event_stream())\n///     });\n///\n///     let res = warp::test::request()\n///         .method(\"GET\")\n///         .header(\"Connection\", \"Keep-Alive\")\n///         .path(\"/sse\")\n///         .reply(&app)\n///         .await\n///         .into_body();\n///\n///     assert_eq!(\n///         res,\n///         r#\"data:payload\n///\n/// event:chat\n/// data:other message\n/// data:with next line\n/// id:1\n/// retry:15000\n///\n/// data:{\"from\":2,\"text\":\"hello\"}\n/// id:2\n///\n/// \"#\n///     );\n/// };\n/// ```\npub fn reply<S>(event_stream: S) -> impl Reply\nwhere\n    S: TryStream<Ok = Event> + Send + Sync + 'static,\n    S::Error: StdError + Send + Sync + 'static,\n{\n    SseReply { event_stream }\n}\n\n#[allow(missing_debug_implementations)]\nstruct SseReply<S> {\n    event_stream: S,\n}\n\nimpl<S> Reply for SseReply<S>\nwhere\n    S: TryStream<Ok = Event> + Send + Sync + 'static,\n    S::Error: StdError + Send + Sync + 'static,\n{\n    #[inline]\n    fn into_response(self) -> Response {\n        let body_stream = self\n            .event_stream\n            .map_err(|error| {\n                // FIXME: error logging\n                log::error!(\"sse stream error: {}\", error);\n                SseError\n            })\n            .into_stream()\n            .and_then(|event| future::ready(Ok(event.to_string())));\n\n        let mut res = Response::new(Body::wrap_stream(body_stream));\n        // Set appropriate content type\n        res.headers_mut()\n            .insert(CONTENT_TYPE, HeaderValue::from_static(\"text/event-stream\"));\n        // Disable response body caching\n        res.headers_mut()\n            .insert(CACHE_CONTROL, HeaderValue::from_static(\"no-cache\"));\n        res\n    }\n}\n\n/// Configure the interval between keep-alive messages, the content\n/// of each message, and the associated stream.\n#[derive(Debug)]\npub struct KeepAlive {\n    comment_text: Cow<'static, str>,\n    max_interval: Duration,\n}\n\nimpl KeepAlive {\n    /// Customize the interval between keep-alive messages.\n    ///\n    /// Default is 15 seconds.\n    pub fn interval(mut self, time: Duration) -> Self {\n        self.max_interval = time;\n        self\n    }\n\n    /// Customize the text of the keep-alive message.\n    ///\n    /// Default is an empty comment.\n    pub fn text(mut self, text: impl Into<Cow<'static, str>>) -> Self {\n        self.comment_text = text.into();\n        self\n    }\n\n    /// Wrap an event stream with keep-alive functionality.\n    ///\n    /// See [`keep_alive`] for more.\n    pub fn stream<S>(\n        self,\n        event_stream: S,\n    ) -> impl TryStream<Ok = Event, Error = impl StdError + Send + Sync + 'static> + Send + 'static\n    where\n        S: TryStream<Ok = Event> + Send + 'static,\n        S::Error: StdError + Send + Sync + 'static,\n    {\n        let alive_timer = time::sleep(self.max_interval);\n        SseKeepAlive {\n            event_stream,\n            comment_text: self.comment_text,\n            max_interval: self.max_interval,\n            alive_timer,\n        }\n    }\n}\n\n#[allow(missing_debug_implementations)]\n#[pin_project]\nstruct SseKeepAlive<S> {\n    #[pin]\n    event_stream: S,\n    comment_text: Cow<'static, str>,\n    max_interval: Duration,\n    #[pin]\n    alive_timer: Sleep,\n}\n\n/// Keeps event source connection alive when no events sent over a some time.\n///\n/// Some proxy servers may drop HTTP connection after a some timeout of inactivity.\n/// This function helps to prevent such behavior by sending comment events every\n/// `keep_interval` of inactivity.\n///\n/// By default the comment is `:` (an empty comment) and the time interval between\n/// events is 15 seconds. Both may be customized using the builder pattern\n/// as shown below.\n///\n/// ```\n/// use std::time::Duration;\n/// use std::convert::Infallible;\n/// use futures_util::StreamExt;\n/// use tokio::time::interval;\n/// use tokio_stream::wrappers::IntervalStream;\n/// use warp::{Filter, Stream, sse::Event};\n///\n/// // create server-sent event\n/// fn sse_counter(counter: u64) ->  Result<Event, Infallible> {\n///     Ok(Event::default().data(counter.to_string()))\n/// }\n///\n/// fn main() {\n///     let routes = warp::path(\"ticks\")\n///         .and(warp::get())\n///         .map(|| {\n///             let mut counter: u64 = 0;\n///             let interval = interval(Duration::from_secs(15));\n///             let stream = IntervalStream::new(interval);\n///             let event_stream = stream.map(move |_| {\n///                 counter += 1;\n///                 sse_counter(counter)\n///             });\n///             // reply using server-sent events\n///             let stream = warp::sse::keep_alive()\n///                 .interval(Duration::from_secs(5))\n///                 .text(\"thump\".to_string())\n///                 .stream(event_stream);\n///             warp::sse::reply(stream)\n///         });\n/// }\n/// ```\n///\n/// See [notes](https://www.w3.org/TR/2009/WD-eventsource-20090421/#notes).\npub fn keep_alive() -> KeepAlive {\n    KeepAlive {\n        comment_text: Cow::Borrowed(\"\"),\n        max_interval: Duration::from_secs(15),\n    }\n}\n\nimpl<S> Stream for SseKeepAlive<S>\nwhere\n    S: TryStream<Ok = Event> + Send + 'static,\n    S::Error: StdError + Send + Sync + 'static,\n{\n    type Item = Result<Event, SseError>;\n\n    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        let mut pin = self.project();\n        match pin.event_stream.try_poll_next(cx) {\n            Poll::Pending => match Pin::new(&mut pin.alive_timer).poll(cx) {\n                Poll::Pending => Poll::Pending,\n                Poll::Ready(_) => {\n                    // restart timer\n                    pin.alive_timer\n                        .reset(tokio::time::Instant::now() + *pin.max_interval);\n                    let comment_str = pin.comment_text.clone();\n                    let event = Event::default().comment(comment_str);\n                    Poll::Ready(Some(Ok(event)))\n                }\n            },\n            Poll::Ready(Some(Ok(event))) => {\n                // restart timer\n                pin.alive_timer\n                    .reset(tokio::time::Instant::now() + *pin.max_interval);\n                Poll::Ready(Some(Ok(event)))\n            }\n            Poll::Ready(None) => Poll::Ready(None),\n            Poll::Ready(Some(Err(error))) => {\n                log::error!(\"sse::keep error: {}\", error);\n                Poll::Ready(Some(Err(SseError)))\n            }\n        }\n    }\n}\n\nmod sealed {\n    use super::*;\n\n    /// SSE error type\n    #[derive(Debug)]\n    pub struct SseError;\n\n    impl fmt::Display for SseError {\n        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n            write!(f, \"sse error\")\n        }\n    }\n\n    impl StdError for SseError {}\n}\n"
  },
  {
    "path": "src/filters/trace.rs",
    "content": "//! [`tracing`] filters.\n//!\n//! [`tracing`] is a framework for instrumenting Rust programs to\n//! collect scoped, structured, and async-aware diagnostics. This module\n//! provides a set of filters for instrumenting Warp applications with `tracing`\n//! spans. [`Spans`] can be used to associate individual events  with a request,\n//! and track contexts through the application.\n//!\n//! [`tracing`]: https://crates.io/crates/tracing\n//! [`Spans`]: https://docs.rs/tracing/latest/tracing/#spans\nuse tracing::Span;\n\nuse http::header;\n\nuse crate::filter::{Filter, WrapSealed};\nuse crate::reject::IsReject;\nuse crate::reply::Reply;\nuse crate::route::Route;\n\nuse self::internal::WithTrace;\n\n/// Create a wrapping filter that instruments every request with a `tracing`\n/// [`Span`] at the [`INFO`] level, containing a summary of the request.\n/// Additionally, if the [`DEBUG`] level is enabled, the span will contain an\n/// event recording the request's headers.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let route = warp::any()\n///     .map(warp::reply)\n///     .with(warp::trace::request());\n/// ```\n///\n/// [`Span`]: https://docs.rs/tracing/latest/tracing/#spans\n/// [`INFO`]: https://docs.rs/tracing/0.1.16/tracing/struct.Level.html#associatedconstant.INFO\n/// [`DEBUG`]: https://docs.rs/tracing/0.1.16/tracing/struct.Level.html#associatedconstant.DEBUG\npub fn request() -> Trace<impl Fn(Info<'_>) -> Span + Clone> {\n    use tracing::field::{display, Empty};\n    trace(|info: Info<'_>| {\n        let span = tracing::info_span!(\n            \"request\",\n            remote.addr = Empty,\n            method = %info.method(),\n            path = %info.path(),\n            version = ?info.route.version(),\n            referer = Empty,\n        );\n\n        // Record optional fields.\n        if let Some(referer) = info.referer() {\n            span.record(\"referer\", &display(referer));\n        }\n\n        tracing::debug!(parent: &span, \"received request\");\n\n        span\n    })\n}\n\n/// Create a wrapping filter that instruments every request with a custom\n/// `tracing` [`Span`] provided by a function.\n///\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let route = warp::any()\n///     .map(warp::reply)\n///     .with(warp::trace(|info| {\n///         // Create a span using tracing macros\n///         tracing::info_span!(\n///             \"request\",\n///             method = %info.method(),\n///             path = %info.path(),\n///         )\n///     }));\n/// ```\n///\n/// [`Span`]: https://docs.rs/tracing/latest/tracing/#spans\npub fn trace<F>(func: F) -> Trace<F>\nwhere\n    F: Fn(Info<'_>) -> Span + Clone,\n{\n    Trace { func }\n}\n\n/// Create a wrapping filter that instruments every request with a `tracing`\n/// [`Span`] at the [`DEBUG`] level representing a named context.\n///\n/// This can be used to instrument multiple routes with their own sub-spans in a\n/// per-request trace.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let hello = warp::path(\"hello\")\n///     .map(warp::reply)\n///     .with(warp::trace::named(\"hello\"));\n///\n/// let goodbye = warp::path(\"goodbye\")\n///     .map(warp::reply)\n///     .with(warp::trace::named(\"goodbye\"));\n///\n/// let routes = hello.or(goodbye);\n/// ```\n///\n/// [`Span`]: https://docs.rs/tracing/latest/tracing/#spans\n/// [`DEBUG`]: https://docs.rs/tracing/0.1.16/tracing/struct.Level.html#associatedconstant.DEBUG\npub fn named(name: &'static str) -> Trace<impl Fn(Info<'_>) -> Span + Copy> {\n    trace(move |_| tracing::debug_span!(\"context\", \"{}\", name,))\n}\n\n/// Decorates a [`Filter`] to create a [`tracing`] [span] for\n/// requests and responses.\n///\n/// [`tracing`]: https://crates.io/crates/tracing\n/// [span]: https://docs.rs/tracing/latest/tracing/#spans\n#[derive(Clone, Copy, Debug)]\npub struct Trace<F> {\n    func: F,\n}\n\n/// Information about the request/response that can be used to prepare log lines.\n#[allow(missing_debug_implementations)]\npub struct Info<'a> {\n    route: &'a Route,\n}\n\nimpl<FN, F> WrapSealed<F> for Trace<FN>\nwhere\n    FN: Fn(Info<'_>) -> Span + Clone + Send,\n    F: Filter + Clone + Send,\n    F::Extract: Reply,\n    F::Error: IsReject,\n{\n    type Wrapped = WithTrace<FN, F>;\n\n    fn wrap(&self, filter: F) -> Self::Wrapped {\n        WithTrace {\n            filter,\n            trace: self.clone(),\n        }\n    }\n}\n\nimpl<'a> Info<'a> {\n    /// View the `http::Method` of the request.\n    pub fn method(&self) -> &http::Method {\n        self.route.method()\n    }\n\n    /// View the URI path of the request.\n    pub fn path(&self) -> &str {\n        self.route.full_path()\n    }\n\n    /// View the `http::Version` of the request.\n    pub fn version(&self) -> http::Version {\n        self.route.version()\n    }\n\n    /// View the referer of the request.\n    pub fn referer(&self) -> Option<&str> {\n        self.route\n            .headers()\n            .get(header::REFERER)\n            .and_then(|v| v.to_str().ok())\n    }\n\n    /// View the user agent of the request.\n    pub fn user_agent(&self) -> Option<&str> {\n        self.route\n            .headers()\n            .get(header::USER_AGENT)\n            .and_then(|v| v.to_str().ok())\n    }\n\n    /// View the host of the request\n    pub fn host(&self) -> Option<&str> {\n        self.route\n            .headers()\n            .get(header::HOST)\n            .and_then(|v| v.to_str().ok())\n    }\n\n    /// View the request headers.\n    pub fn request_headers(&self) -> &http::HeaderMap {\n        self.route.headers()\n    }\n}\n\nmod internal {\n    use futures_util::{future::Inspect, future::MapOk, FutureExt, TryFutureExt};\n\n    use super::{Info, Trace};\n    use crate::filter::{Filter, FilterBase, Internal};\n    use crate::reject::IsReject;\n    use crate::reply::Reply;\n    use crate::reply::Response;\n    use crate::route;\n\n    #[allow(missing_debug_implementations)]\n    pub struct Traced(pub(super) Response);\n\n    impl Reply for Traced {\n        #[inline]\n        fn into_response(self) -> Response {\n            self.0\n        }\n    }\n\n    #[allow(missing_debug_implementations)]\n    #[derive(Clone, Copy)]\n    pub struct WithTrace<FN, F> {\n        pub(super) filter: F,\n        pub(super) trace: Trace<FN>,\n    }\n\n    use tracing::instrument::{Instrument, Instrumented};\n    use tracing::Span;\n\n    fn finished_logger<E: IsReject>(reply: &Result<(Traced,), E>) {\n        let (status, error) = match reply {\n            Ok((Traced(resp),)) => (resp.status(), None),\n            Err(error) => (error.status(), Some(error)),\n        };\n\n        if status.is_success() {\n            tracing::info!(\n                target: \"warp::filters::trace\",\n                status = status.as_u16(),\n                \"finished processing with success\"\n            );\n        } else if status.is_server_error() {\n            tracing::error!(\n                target: \"warp::filters::trace\",\n                status = status.as_u16(),\n                error = ?error,\n                \"unable to process request (internal error)\"\n            );\n        } else if status.is_client_error() {\n            tracing::warn!(\n                target: \"warp::filters::trace\",\n                status = status.as_u16(),\n                error = ?error,\n                \"unable to serve request (client error)\"\n            );\n        } else {\n            // Either informational or redirect\n            tracing::info!(\n                target: \"warp::filters::trace\",\n                status = status.as_u16(),\n                error = ?error,\n                    \"finished processing with status\"\n            );\n        }\n    }\n\n    fn convert_reply<R: Reply>(reply: R) -> (Traced,) {\n        (Traced(reply.into_response()),)\n    }\n\n    impl<FN, F> FilterBase for WithTrace<FN, F>\n    where\n        FN: Fn(Info<'_>) -> Span + Clone + Send,\n        F: Filter + Clone + Send,\n        F::Extract: Reply,\n        F::Error: IsReject,\n    {\n        type Extract = (Traced,);\n        type Error = F::Error;\n        type Future = Instrumented<\n            Inspect<\n                MapOk<F::Future, fn(F::Extract) -> Self::Extract>,\n                fn(&Result<Self::Extract, F::Error>),\n            >,\n        >;\n\n        fn filter(&self, _: Internal) -> Self::Future {\n            let span = route::with(|route| (self.trace.func)(Info { route }));\n            let _entered = span.enter();\n\n            tracing::info!(target: \"warp::filters::trace\", \"processing request\");\n            self.filter\n                .filter(Internal)\n                .map_ok(convert_reply as fn(F::Extract) -> Self::Extract)\n                .inspect(finished_logger as fn(&Result<Self::Extract, F::Error>))\n                .instrument(span.clone())\n        }\n    }\n}\n"
  },
  {
    "path": "src/filters/ws.rs",
    "content": "//! Websockets Filters\n\nuse std::borrow::Cow;\nuse std::fmt;\nuse std::future::Future;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse bytes::Bytes;\nuse futures_util::{future, ready, FutureExt, Sink, Stream, TryFutureExt};\nuse headers::{Connection, HeaderMapExt, SecWebsocketAccept, SecWebsocketKey, Upgrade};\nuse hyper::upgrade::OnUpgrade;\nuse tokio_tungstenite::{\n    tungstenite::protocol::{self, frame::Utf8Bytes, WebSocketConfig},\n    WebSocketStream,\n};\n\nuse super::header;\nuse crate::filter::{filter_fn_one, Filter, One};\nuse crate::reject::Rejection;\nuse crate::reply::{Reply, Response};\n\n/// Creates a Websocket Filter.\n///\n/// The yielded `Ws` is used to finish the websocket upgrade.\n///\n/// # Note\n///\n/// This filter combines multiple filters internally, so you don't need them:\n///\n/// - Method must be `GET`\n/// - Header `connection` must be `upgrade`\n/// - Header `upgrade` must be `websocket`\n/// - Header `sec-websocket-version` must be `13`\n/// - Header `sec-websocket-key` must be set.\n///\n/// If the filters are met, yields a `Ws`. Calling `Ws::on_upgrade` will\n/// return a reply with:\n///\n/// - Status of `101 Switching Protocols`\n/// - Header `connection: upgrade`\n/// - Header `upgrade: websocket`\n/// - Header `sec-websocket-accept` with the hash value of the received key.\npub fn ws() -> impl Filter<Extract = One<Ws>, Error = Rejection> + Copy {\n    let connection_has_upgrade = header::header2()\n        .and_then(|conn: ::headers::Connection| {\n            if conn.contains(\"upgrade\") {\n                future::ok(())\n            } else {\n                future::err(crate::reject::known(MissingConnectionUpgrade))\n            }\n        })\n        .untuple_one();\n\n    crate::get()\n        .and(connection_has_upgrade)\n        .and(header::exact_ignore_case(\"upgrade\", \"websocket\"))\n        .and(header::exact(\"sec-websocket-version\", \"13\"))\n        //.and(header::exact2(Upgrade::websocket()))\n        //.and(header::exact2(SecWebsocketVersion::V13))\n        .and(header::header2::<SecWebsocketKey>())\n        .and(on_upgrade())\n        .map(\n            move |key: SecWebsocketKey, on_upgrade: Option<OnUpgrade>| Ws {\n                config: None,\n                key,\n                on_upgrade,\n            },\n        )\n}\n\n/// Extracted by the [`ws`] filter, and used to finish an upgrade.\npub struct Ws {\n    config: Option<WebSocketConfig>,\n    key: SecWebsocketKey,\n    on_upgrade: Option<OnUpgrade>,\n}\n\nimpl Ws {\n    /// Finish the upgrade, passing a function to handle the `WebSocket`.\n    ///\n    /// The passed function must return a `Future`.\n    pub fn on_upgrade<F, U>(self, func: F) -> impl Reply\n    where\n        F: FnOnce(WebSocket) -> U + Send + 'static,\n        U: Future<Output = ()> + Send + 'static,\n    {\n        WsReply {\n            ws: self,\n            on_upgrade: func,\n        }\n    }\n\n    // config\n\n    /// Does nothing.\n    ///\n    /// # Deprecated\n    ///\n    /// Use `max_write_buffer_size()` instead.\n    #[deprecated = \"use max_write_buffer_size instead\"]\n    pub fn max_send_queue(self, _max: usize) -> Self {\n        self\n    }\n\n    /// The max size of the write buffer, in bytes.\n    pub fn max_write_buffer_size(mut self, max: usize) -> Self {\n        self.config\n            .get_or_insert_with(WebSocketConfig::default)\n            .max_write_buffer_size = max;\n        self\n    }\n\n    /// Set the maximum message size (defaults to 64 megabytes)\n    pub fn max_message_size(mut self, max: usize) -> Self {\n        self.config\n            .get_or_insert_with(WebSocketConfig::default)\n            .max_message_size = Some(max);\n        self\n    }\n\n    /// Set the maximum frame size (defaults to 16 megabytes)\n    pub fn max_frame_size(mut self, max: usize) -> Self {\n        self.config\n            .get_or_insert_with(WebSocketConfig::default)\n            .max_frame_size = Some(max);\n        self\n    }\n}\n\nimpl fmt::Debug for Ws {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Ws\").finish()\n    }\n}\n\n#[allow(missing_debug_implementations)]\nstruct WsReply<F> {\n    ws: Ws,\n    on_upgrade: F,\n}\n\nimpl<F, U> Reply for WsReply<F>\nwhere\n    F: FnOnce(WebSocket) -> U + Send + 'static,\n    U: Future<Output = ()> + Send + 'static,\n{\n    fn into_response(self) -> Response {\n        if let Some(on_upgrade) = self.ws.on_upgrade {\n            let on_upgrade_cb = self.on_upgrade;\n            let config = self.ws.config;\n            let fut = on_upgrade\n                .and_then(move |upgraded| {\n                    tracing::trace!(\"websocket upgrade complete\");\n                    WebSocket::from_raw_socket(upgraded, protocol::Role::Server, config).map(Ok)\n                })\n                .and_then(move |socket| on_upgrade_cb(socket).map(Ok))\n                .map(|result| {\n                    if let Err(err) = result {\n                        tracing::debug!(\"ws upgrade error: {}\", err);\n                    }\n                });\n            ::tokio::task::spawn(fut);\n        } else {\n            tracing::debug!(\"ws couldn't be upgraded since no upgrade state was present\");\n        }\n\n        let mut res = http::Response::default();\n\n        *res.status_mut() = http::StatusCode::SWITCHING_PROTOCOLS;\n\n        res.headers_mut().typed_insert(Connection::upgrade());\n        res.headers_mut().typed_insert(Upgrade::websocket());\n        res.headers_mut()\n            .typed_insert(SecWebsocketAccept::from(self.ws.key));\n\n        res\n    }\n}\n\n// Extracts OnUpgrade state from the route.\nfn on_upgrade() -> impl Filter<Extract = (Option<OnUpgrade>,), Error = Rejection> + Copy {\n    filter_fn_one(|route| future::ready(Ok(route.extensions_mut().remove::<OnUpgrade>())))\n}\n\n/// A websocket `Stream` and `Sink`, provided to `ws` filters.\n///\n/// Ping messages sent from the client will be handled internally by replying with a Pong message.\n/// Close messages need to be handled explicitly: usually by closing the `Sink` end of the\n/// `WebSocket`.\n///\n/// **Note!**\n/// Due to rust futures nature, pings won't be handled until read part of `WebSocket` is polled\npub struct WebSocket {\n    inner: WebSocketStream<hyper_util::rt::TokioIo<hyper::upgrade::Upgraded>>,\n}\n\nimpl WebSocket {\n    pub(crate) async fn from_raw_socket(\n        upgraded: hyper::upgrade::Upgraded,\n        role: protocol::Role,\n        config: Option<protocol::WebSocketConfig>,\n    ) -> Self {\n        let upgraded = hyper_util::rt::TokioIo::new(upgraded);\n        WebSocketStream::from_raw_socket(upgraded, role, config)\n            .map(|inner| WebSocket { inner })\n            .await\n    }\n\n    /// Gracefully close this websocket.\n    pub async fn close(mut self) -> Result<(), crate::Error> {\n        future::poll_fn(|cx| Pin::new(&mut self).poll_close(cx)).await\n    }\n}\n\nimpl Stream for WebSocket {\n    type Item = Result<Message, crate::Error>;\n\n    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        match ready!(Pin::new(&mut self.inner).poll_next(cx)) {\n            Some(Ok(item)) => Poll::Ready(Some(Ok(Message { inner: item }))),\n            Some(Err(e)) => {\n                tracing::debug!(\"websocket poll error: {}\", e);\n                Poll::Ready(Some(Err(crate::Error::new(e))))\n            }\n            None => {\n                tracing::trace!(\"websocket closed\");\n                Poll::Ready(None)\n            }\n        }\n    }\n}\n\nimpl Sink<Message> for WebSocket {\n    type Error = crate::Error;\n\n    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        match ready!(Pin::new(&mut self.inner).poll_ready(cx)) {\n            Ok(()) => Poll::Ready(Ok(())),\n            Err(e) => Poll::Ready(Err(crate::Error::new(e))),\n        }\n    }\n\n    fn start_send(mut self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> {\n        match Pin::new(&mut self.inner).start_send(item.inner) {\n            Ok(()) => Ok(()),\n            Err(e) => {\n                tracing::debug!(\"websocket start_send error: {}\", e);\n                Err(crate::Error::new(e))\n            }\n        }\n    }\n\n    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        match ready!(Pin::new(&mut self.inner).poll_flush(cx)) {\n            Ok(()) => Poll::Ready(Ok(())),\n            Err(e) => Poll::Ready(Err(crate::Error::new(e))),\n        }\n    }\n\n    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        match ready!(Pin::new(&mut self.inner).poll_close(cx)) {\n            Ok(()) => Poll::Ready(Ok(())),\n            Err(err) => {\n                tracing::debug!(\"websocket close error: {}\", err);\n                Poll::Ready(Err(crate::Error::new(err)))\n            }\n        }\n    }\n}\n\nimpl fmt::Debug for WebSocket {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"WebSocket\").finish()\n    }\n}\n\n/// A WebSocket message.\n///\n/// This will likely become a `non-exhaustive` enum in the future, once that\n/// language feature has stabilized.\n#[derive(Eq, PartialEq, Clone)]\npub struct Message {\n    inner: protocol::Message,\n}\n\nimpl Message {\n    /// Construct a new Text `Message`.\n    pub fn text<B: Into<String>>(bytes: B) -> Message {\n        Message {\n            inner: protocol::Message::text(bytes.into()),\n        }\n    }\n\n    /// Construct a new Binary `Message`.\n    pub fn binary<B: Into<Bytes>>(bytes: B) -> Message {\n        Message {\n            inner: protocol::Message::binary(bytes),\n        }\n    }\n\n    /// Construct a new Ping `Message`.\n    pub fn ping<B: Into<Bytes>>(bytes: B) -> Message {\n        Message {\n            inner: protocol::Message::Ping(bytes.into()),\n        }\n    }\n\n    /// Construct a new Pong `Message`.\n    ///\n    /// Note that one rarely needs to manually construct a Pong message because the underlying tungstenite socket\n    /// automatically responds to the Ping messages it receives. Manual construction might still be useful in some cases\n    /// like in tests or to send unidirectional heartbeats.\n    pub fn pong<B: Into<Bytes>>(bytes: B) -> Message {\n        Message {\n            inner: protocol::Message::Pong(bytes.into()),\n        }\n    }\n\n    /// Construct the default Close `Message`.\n    pub fn close() -> Message {\n        Message {\n            inner: protocol::Message::Close(None),\n        }\n    }\n\n    /// Construct a Close `Message` with a code and reason.\n    pub fn close_with(code: impl Into<u16>, reason: impl Into<Cow<'static, str>>) -> Message {\n        Message {\n            inner: protocol::Message::Close(Some(protocol::frame::CloseFrame {\n                code: protocol::frame::coding::CloseCode::from(code.into()),\n                reason: match reason.into() {\n                    Cow::Borrowed(s) => Utf8Bytes::from_static(s),\n                    Cow::Owned(s) => s.into(),\n                },\n            })),\n        }\n    }\n\n    /// Returns true if this message is a Text message.\n    pub fn is_text(&self) -> bool {\n        self.inner.is_text()\n    }\n\n    /// Returns true if this message is a Binary message.\n    pub fn is_binary(&self) -> bool {\n        self.inner.is_binary()\n    }\n\n    /// Returns true if this message a is a Close message.\n    pub fn is_close(&self) -> bool {\n        self.inner.is_close()\n    }\n\n    /// Returns true if this message is a Ping message.\n    pub fn is_ping(&self) -> bool {\n        self.inner.is_ping()\n    }\n\n    /// Returns true if this message is a Pong message.\n    pub fn is_pong(&self) -> bool {\n        self.inner.is_pong()\n    }\n\n    /// Try to get the close frame (close code and reason)\n    pub fn close_frame(&self) -> Option<(u16, &str)> {\n        if let protocol::Message::Close(Some(ref close_frame)) = self.inner {\n            Some((close_frame.code.into(), close_frame.reason.as_ref()))\n        } else {\n            None\n        }\n    }\n\n    /// Try to get a reference to the string text, if this is a Text message.\n    pub fn to_str(&self) -> Result<&str, ()> {\n        match self.inner {\n            protocol::Message::Text(ref s) => Ok(s),\n            _ => Err(()),\n        }\n    }\n\n    /// Return the bytes of this message, if the message can contain data.\n    pub fn as_bytes(&self) -> &[u8] {\n        match self.inner {\n            protocol::Message::Text(ref s) => s.as_bytes(),\n            protocol::Message::Binary(ref v) => v,\n            protocol::Message::Ping(ref v) => v,\n            protocol::Message::Pong(ref v) => v,\n            protocol::Message::Close(_) => &[],\n            protocol::Message::Frame(ref frame) => frame.payload(),\n        }\n    }\n\n    /// Destructure this message into binary data.\n    pub fn into_bytes(self) -> Bytes {\n        self.inner.into_data()\n    }\n}\n\nimpl fmt::Debug for Message {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        fmt::Debug::fmt(&self.inner, f)\n    }\n}\n\nimpl From<Message> for Bytes {\n    fn from(m: Message) -> Self {\n        m.into_bytes()\n    }\n}\n\n// ===== Rejections =====\n\n/// Connection header did not include 'upgrade'\n#[derive(Debug)]\npub struct MissingConnectionUpgrade;\n\nimpl fmt::Display for MissingConnectionUpgrade {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"Connection header did not include 'upgrade'\")\n    }\n}\n\nimpl ::std::error::Error for MissingConnectionUpgrade {}\n"
  },
  {
    "path": "src/generic.rs",
    "content": "#[derive(Debug)]\npub struct Product<H, T: HList>(pub(crate) H, pub(crate) T);\n\npub type One<T> = (T,);\n\n#[inline]\npub(crate) fn one<T>(val: T) -> One<T> {\n    (val,)\n}\n\n#[derive(Debug)]\npub enum Either<T, U> {\n    A(T),\n    B(U),\n}\n\n// Converts Product (and ()) into tuples.\npub trait HList: Sized {\n    type Tuple: Tuple<HList = Self>;\n\n    fn flatten(self) -> Self::Tuple;\n}\n\n// Typeclass that tuples can be converted into a Product (or unit ()).\npub trait Tuple: Sized {\n    type HList: HList<Tuple = Self>;\n\n    fn hlist(self) -> Self::HList;\n\n    #[inline]\n    fn combine<T>(self, other: T) -> CombinedTuples<Self, T>\n    where\n        Self: Sized,\n        T: Tuple,\n        Self::HList: Combine<T::HList>,\n    {\n        self.hlist().combine(other.hlist()).flatten()\n    }\n}\n\npub type CombinedTuples<T, U> =\n    <<<T as Tuple>::HList as Combine<<U as Tuple>::HList>>::Output as HList>::Tuple;\n\n// Combines Product together.\npub trait Combine<T: HList> {\n    type Output: HList;\n\n    fn combine(self, other: T) -> Self::Output;\n}\n\npub trait Func<Args> {\n    type Output;\n\n    fn call(&self, args: Args) -> Self::Output;\n}\n\n// ===== impl Combine =====\n\nimpl<T: HList> Combine<T> for () {\n    type Output = T;\n    #[inline]\n    fn combine(self, other: T) -> Self::Output {\n        other\n    }\n}\n\nimpl<H, T: HList, U: HList> Combine<U> for Product<H, T>\nwhere\n    T: Combine<U>,\n    Product<H, <T as Combine<U>>::Output>: HList,\n{\n    type Output = Product<H, <T as Combine<U>>::Output>;\n\n    #[inline]\n    fn combine(self, other: U) -> Self::Output {\n        Product(self.0, self.1.combine(other))\n    }\n}\n\nimpl HList for () {\n    type Tuple = ();\n    #[inline]\n    fn flatten(self) -> Self::Tuple {}\n}\n\nimpl Tuple for () {\n    type HList = ();\n\n    #[inline]\n    fn hlist(self) -> Self::HList {}\n}\n\nimpl<F, R> Func<()> for F\nwhere\n    F: Fn() -> R,\n{\n    type Output = R;\n\n    #[inline]\n    fn call(&self, _args: ()) -> Self::Output {\n        (*self)()\n    }\n}\n\nimpl<F, R> Func<crate::Rejection> for F\nwhere\n    F: Fn(crate::Rejection) -> R,\n{\n    type Output = R;\n\n    #[inline]\n    fn call(&self, arg: crate::Rejection) -> Self::Output {\n        (*self)(arg)\n    }\n}\n\nmacro_rules! product {\n    ($H:expr) => { Product($H, ()) };\n    ($H:expr, $($T:expr),*) => { Product($H, product!($($T),*)) };\n}\n\nmacro_rules! Product {\n    ($H:ty) => { Product<$H, ()> };\n    ($H:ty, $($T:ty),*) => { Product<$H, Product!($($T),*)> };\n}\n\nmacro_rules! product_pat {\n    ($H:pat) => { Product($H, ()) };\n    ($H:pat, $($T:pat),*) => { Product($H, product_pat!($($T),*)) };\n}\n\nmacro_rules! generics {\n    ($type:ident) => {\n        impl<$type> HList for Product!($type) {\n            type Tuple = ($type,);\n\n            #[inline]\n            fn flatten(self) -> Self::Tuple {\n                (self.0,)\n            }\n        }\n\n        impl<$type> Tuple for ($type,) {\n            type HList = Product!($type);\n            #[inline]\n            fn hlist(self) -> Self::HList {\n                product!(self.0)\n            }\n        }\n\n        impl<F, R, $type> Func<Product!($type)> for F\n        where\n            F: Fn($type) -> R,\n        {\n            type Output = R;\n\n            #[inline]\n            fn call(&self, args: Product!($type)) -> Self::Output {\n                (*self)(args.0)\n            }\n\n        }\n\n        impl<F, R, $type> Func<($type,)> for F\n        where\n            F: Fn($type) -> R,\n        {\n            type Output = R;\n\n            #[inline]\n            fn call(&self, args: ($type,)) -> Self::Output {\n                (*self)(args.0)\n            }\n        }\n\n    };\n\n    ($type1:ident, $( $type:ident ),*) => {\n        generics!($( $type ),*);\n\n        impl<$type1, $( $type ),*> HList for Product!($type1, $($type),*) {\n            type Tuple = ($type1, $( $type ),*);\n\n            #[inline]\n            fn flatten(self) -> Self::Tuple {\n                #[allow(non_snake_case)]\n                let product_pat!($type1, $( $type ),*) = self;\n                ($type1, $( $type ),*)\n            }\n        }\n\n        impl<$type1, $( $type ),*> Tuple for ($type1, $($type),*) {\n            type HList = Product!($type1, $( $type ),*);\n\n            #[inline]\n            fn hlist(self) -> Self::HList {\n                #[allow(non_snake_case)]\n                let ($type1, $( $type ),*) = self;\n                product!($type1, $( $type ),*)\n            }\n        }\n\n        impl<F, R, $type1, $( $type ),*> Func<Product!($type1, $($type),*)> for F\n        where\n            F: Fn($type1, $( $type ),*) -> R,\n        {\n            type Output = R;\n\n            #[inline]\n            fn call(&self, args: Product!($type1, $($type),*)) -> Self::Output {\n                #[allow(non_snake_case)]\n                let product_pat!($type1, $( $type ),*) = args;\n                (*self)($type1, $( $type ),*)\n            }\n        }\n\n        impl<F, R, $type1, $( $type ),*> Func<($type1, $($type),*)> for F\n        where\n            F: Fn($type1, $( $type ),*) -> R,\n        {\n            type Output = R;\n\n            #[inline]\n            fn call(&self, args: ($type1, $($type),*)) -> Self::Output {\n                #[allow(non_snake_case)]\n                let ($type1, $( $type ),*) = args;\n                (*self)($type1, $( $type ),*)\n            }\n        }\n    };\n}\n\ngenerics! {\n    T1,\n    T2,\n    T3,\n    T4,\n    T5,\n    T6,\n    T7,\n    T8,\n    T9,\n    T10,\n    T11,\n    T12,\n    T13,\n    T14,\n    T15,\n    T16\n}\n"
  },
  {
    "path": "src/lib.rs",
    "content": "#![deny(missing_docs)]\n#![deny(missing_debug_implementations)]\n#![deny(rust_2018_idioms)]\n#![cfg_attr(test, deny(warnings))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n//! # warp\n//!\n//! warp is a super-easy, composable, web server framework for warp speeds.\n//!\n//! Thanks to its [`Filter`][Filter] system, warp provides these out of the box:\n//!\n//! - Path routing and parameter extraction\n//! - Header requirements and extraction\n//! - Query string deserialization\n//! - JSON and Form bodies\n//! - Multipart form data\n//! - Static Files and Directories\n//! - Websockets\n//! - Access logging\n//! - Etc\n//!\n//! Since it builds on top of [hyper](https://hyper.rs), you automatically get:\n//!\n//! - HTTP/1\n//! - HTTP/2\n//! - Asynchronous\n//! - One of the fastest HTTP implementations\n//! - Tested and **correct**\n//!\n//! ## Filters\n//!\n//! The main concept in warp is the [`Filter`][Filter], which allows composition\n//! to describe various endpoints in your web service. Besides this powerful\n//! trait, warp comes with several built in [filters](filters/index.html), which\n//! can be combined for your specific needs.\n//!\n//! As a small example, consider an endpoint that has path and header requirements:\n//!\n//! ```\n//! use warp::Filter;\n//!\n//! let hi = warp::path(\"hello\")\n//!     .and(warp::path::param())\n//!     .and(warp::header(\"user-agent\"))\n//!     .map(|param: String, agent: String| {\n//!         format!(\"Hello {}, whose agent is {}\", param, agent)\n//!     });\n//! ```\n//!\n//! This example composes several [`Filter`s][Filter] together using `and`:\n//!\n//! - A path prefix of \"hello\"\n//! - A path parameter of a `String`\n//! - The `user-agent` header parsed as a `String`\n//!\n//! These specific filters will [`reject`][reject] requests that don't match\n//! their requirements.\n//!\n//! This ends up matching requests like:\n//!\n//! ```notrust\n//! GET /hello/sean HTTP/1.1\n//! Host: hyper.rs\n//! User-Agent: reqwest/v0.8.6\n//!\n//! ```\n//! And it returns a response similar to this:\n//!\n//! ```notrust\n//! HTTP/1.1 200 OK\n//! Content-Length: 41\n//! Date: ...\n//!\n//! Hello sean, whose agent is reqwest/v0.8.6\n//! ```\n//!\n//! Take a look at the full list of [`filters`](filters/index.html) to see what\n//! you can build.\n//!\n//! ## Testing\n//!\n//! Testing your web services easily is extremely important, and warp provides\n//! a [`test`](mod@self::test) module to help send mocked requests through your service.\n//!\n//! [Filter]: trait.Filter.html\n//! [reject]: reject/index.html\n\nmod bodyt;\n#[macro_use]\nmod error;\nmod filter;\npub mod filters;\nmod generic;\npub mod redirect;\npub mod reject;\npub mod reply;\nmod route;\n#[cfg(feature = \"server\")]\nmod server;\nmod service;\n#[cfg(feature = \"test\")]\npub mod test;\n#[cfg(feature = \"tls\")]\nmod tls;\n\npub use self::error::Error;\npub use self::filter::Filter;\n// This otherwise shows a big dump of re-exports in the doc homepage,\n// with zero context, so just hide it from the docs. Doc examples\n// on each can show that a convenient import exists.\n#[cfg(feature = \"compression\")]\n#[doc(hidden)]\npub use self::filters::compression;\n#[cfg(feature = \"multipart\")]\n#[doc(hidden)]\npub use self::filters::multipart;\n#[cfg(feature = \"websocket\")]\n#[doc(hidden)]\npub use self::filters::ws;\n#[doc(hidden)]\npub use self::filters::{\n    addr,\n    // any() function\n    any::any,\n    body,\n    cookie,\n    // cookie() function\n    cookie::cookie,\n    cors,\n    // cors() function\n    cors::cors,\n    ext,\n    fs,\n    header,\n    // header() function\n    header::header,\n    host,\n    log,\n    // log() function\n    log::log,\n    method::{delete, get, head, method, options, patch, post, put},\n    path,\n    // path() function and macro\n    path::path,\n    query,\n    // query() function\n    query::query,\n    sse,\n    trace,\n    // trace() function\n    trace::trace,\n};\n// ws() function\npub use self::filter::wrap_fn;\n#[cfg(feature = \"websocket\")]\n#[doc(hidden)]\npub use self::filters::ws::ws;\n#[doc(hidden)]\npub use self::redirect::redirect;\n#[doc(hidden)]\n#[allow(deprecated)]\npub use self::reject::{reject, Rejection};\n#[doc(hidden)]\npub use self::reply::{reply, Reply};\n#[cfg(feature = \"server\")]\npub use self::server::serve;\n#[cfg(docsrs)]\n#[cfg(feature = \"server\")]\npub use self::server::Server;\npub use self::service::service;\n#[doc(hidden)]\npub use http;\n#[cfg(any(feature = \"server\", feature = \"websocket\"))]\n#[doc(hidden)]\npub use hyper;\n\n#[doc(hidden)]\npub use bytes::Buf;\n#[doc(hidden)]\npub use futures_util::{Future, Sink, Stream};\n#[doc(hidden)]\n\npub(crate) type Request = http::Request<crate::bodyt::Body>;\n"
  },
  {
    "path": "src/redirect.rs",
    "content": "//! Redirect requests to a new location.\n//!\n//! The types in this module are helpers that implement [`Reply`], and easy\n//! to use in order to setup redirects.\n\nuse http::{header, StatusCode};\n\npub use self::sealed::AsLocation;\nuse crate::reply::{self, Reply};\n\n/// HTTP 301 Moved Permanently\n/// Description: The requested resource has been permanently moved to a new URL.\n/// Usage: It is used when a URL has permanently moved to a new location. Search engines will update their index to the new URL. Browsers and clients will automatically cache this redirect, so subsequent requests for the old URL will automatically go to the new URL without making a request to the old URL.\n/// Common Use Case: Changing domain names, restructuring website URLs.\n///\n/// # Example\n///\n/// ```\n/// use warp::{http::Uri, Filter};\n///\n/// let route = warp::path(\"v1\")\n///     .map(|| {\n///         warp::redirect(Uri::from_static(\"/v2\"))\n///     });\n/// ```\npub fn redirect(uri: impl AsLocation) -> impl Reply {\n    reply::with_header(\n        StatusCode::MOVED_PERMANENTLY,\n        header::LOCATION,\n        uri.header_value(),\n    )\n}\n\n/// HTTP 302 Found (or Temporary Redirect)\n/// Description: The requested resource can be found at a different URL temporarily.\n/// Usage: Historically, this status code was used for temporary redirects. However, its meaning was often misunderstood, and different clients treated it differently. As a result, it is recommended to use 307 (or 303) for temporary redirects instead.\n/// Common Use Case: Rarely used directly due to ambiguity; replaced by 307 or 303.\n///\n/// # Example\n///\n/// ```\n/// use warp::{http::Uri, Filter};\n///\n/// let route = warp::path(\"v1\")\n///     .map(|| {\n///         warp::redirect::found(Uri::from_static(\"/v2\"))\n///     });\n/// ```\npub fn found(uri: impl AsLocation) -> impl Reply {\n    reply::with_header(StatusCode::FOUND, header::LOCATION, uri.header_value())\n}\n\n/// HTTP 303 See Other\n/// Description: The response to the request can be found at a different URL, and the client should retrieve it using the GET method.\n/// Usage: It is typically used to redirect the client to another URL using a GET request after processing a POST request. It ensures that the client doesn't repeat the POST request if they refresh the page.\n/// Common Use Case: After form submissions or any non-idempotent request.\n///\n/// The HTTP method of the request to the new location will always be `GET`.\n///\n/// # Example\n///\n/// ```\n/// use warp::{http::Uri, Filter};\n///\n/// let route = warp::path(\"v1\")\n///     .map(|| {\n///         warp::redirect::see_other(Uri::from_static(\"/v2\"))\n///     });\n/// ```\npub fn see_other(uri: impl AsLocation) -> impl Reply {\n    reply::with_header(StatusCode::SEE_OTHER, header::LOCATION, uri.header_value())\n}\n\n/// HTTP 307 Temporary Redirect:\n/// Description: The requested resource can be found at a different URL temporarily.\n/// Usage: Similar to 302, but explicitly defined as a temporary redirect. The main difference between 307 and 302 is that 307 preserves the method of the original request when redirecting. If the original request was a POST, the subsequent request to the new URL will also be a POST.\n/// Common Use Case: Temporary redirects that should preserve the original request method.\n///\n/// This is similar to [`see_other`](fn@see_other) but the HTTP method and the body of the request\n/// to the new location will be the same as the method and body of the current request.\n///\n/// # Example\n///\n/// ```\n/// use warp::{http::Uri, Filter};\n///\n/// let route = warp::path(\"v1\")\n///     .map(|| {\n///         warp::redirect::temporary(Uri::from_static(\"/v2\"))\n///     });\n/// ```\npub fn temporary(uri: impl AsLocation) -> impl Reply {\n    reply::with_header(\n        StatusCode::TEMPORARY_REDIRECT,\n        header::LOCATION,\n        uri.header_value(),\n    )\n}\n\n/// HTTP 308 Permanent Redirect\n/// Description: The requested resource has been permanently moved to a new URL, and future requests should use the new URL.\n/// Usage: Similar to 301, but like 307, it preserves the original request method when redirecting. It indicates that the redirection is permanent, and browsers and clients will cache this redirect like they do for 301.\n// Common Use Case: Permanently moving resources to a new URL while maintaining the original request method.\n///\n/// This is similar to [`redirect`](fn@redirect) but the HTTP method of the request to the new\n/// location will be the same as the method of the current request.\n///\n/// # Example\n///\n/// ```\n/// use warp::{http::Uri, Filter};\n///\n/// let route = warp::path(\"v1\")\n///     .map(|| {\n///         warp::redirect::permanent(Uri::from_static(\"/v2\"))\n///     });\n/// ```\npub fn permanent(uri: impl AsLocation) -> impl Reply {\n    reply::with_header(\n        StatusCode::PERMANENT_REDIRECT,\n        header::LOCATION,\n        uri.header_value(),\n    )\n}\n\nmod sealed {\n    use bytes::Bytes;\n    use http::{header::HeaderValue, Uri};\n\n    /// Trait for redirect locations. Currently only a `Uri` can be used in\n    /// redirect.\n    /// This sealed trait exists to allow adding possibly new impls so other\n    /// arguments could be accepted, like maybe just `warp::redirect(\"/v2\")`.\n    pub trait AsLocation: Sealed {}\n    pub trait Sealed {\n        fn header_value(self) -> HeaderValue;\n    }\n\n    impl AsLocation for Uri {}\n\n    impl Sealed for Uri {\n        fn header_value(self) -> HeaderValue {\n            let bytes = Bytes::from(self.to_string());\n            HeaderValue::from_maybe_shared(bytes).expect(\"Uri is a valid HeaderValue\")\n        }\n    }\n}\n"
  },
  {
    "path": "src/reject.rs",
    "content": "//! Rejections\n//!\n//! Part of the power of the [`Filter`](../trait.Filter.html) system is being able to\n//! reject a request from a filter chain. This allows for filters to be\n//! combined with `or`, so that if one side of the chain finds that a request\n//! doesn't fulfill its requirements, the other side can try to process\n//! the request.\n//!\n//! Many of the built-in [`filters`](../filters) will automatically reject\n//! the request with an appropriate rejection. However, you can also build\n//! new custom [`Filter`](../trait.Filter.html)s and still want other routes to be\n//! matchable in the case a predicate doesn't hold.\n//!\n//! As a request is processed by a Filter chain, the rejections are accumulated into\n//! a list contained by the [`Rejection`](struct.Rejection.html) type. Rejections from\n//! filters can be handled using [`Filter::recover`](../trait.Filter.html#method.recover).\n//! This is a convenient way to map rejections into a [`Reply`](../reply/trait.Reply.html).\n//!\n//! For a more complete example see the\n//! [Rejection Example](https://github.com/seanmonstar/warp/blob/master/examples/rejections.rs)\n//! from the repository.\n//!\n//! # Example\n//!\n//! ```\n//! use warp::{reply, Reply, Filter, reject, Rejection, http::StatusCode};\n//!\n//! #[derive(Debug)]\n//! struct InvalidParameter;\n//!\n//! impl reject::Reject for InvalidParameter {}\n//!\n//! // Custom rejection handler that maps rejections into responses.\n//! async fn handle_rejection(err: Rejection) -> Result<impl Reply, std::convert::Infallible> {\n//!     if err.is_not_found() {\n//!         Ok(reply::with_status(\"NOT_FOUND\", StatusCode::NOT_FOUND))\n//!     } else if let Some(e) = err.find::<InvalidParameter>() {\n//!         Ok(reply::with_status(\"BAD_REQUEST\", StatusCode::BAD_REQUEST))\n//!     } else {\n//!         eprintln!(\"unhandled rejection: {:?}\", err);\n//!         Ok(reply::with_status(\"INTERNAL_SERVER_ERROR\", StatusCode::INTERNAL_SERVER_ERROR))\n//!     }\n//! }\n//!\n//!\n//! // Filter on `/:id`, but reject with InvalidParameter if the `id` is `0`.\n//! // Recover from this rejection using a custom rejection handler.\n//! let route = warp::path::param()\n//!     .and_then(|id: u32| async move {\n//!         if id == 0 {\n//!             Err(warp::reject::custom(InvalidParameter))\n//!         } else {\n//!             Ok(\"id is valid\")\n//!         }\n//!     })\n//!     .recover(handle_rejection);\n//! ```\n\nuse std::any::Any;\nuse std::convert::Infallible;\nuse std::error::Error as StdError;\nuse std::fmt;\n\nuse crate::bodyt::Body;\nuse http::{\n    header::{HeaderValue, CONTENT_TYPE},\n    StatusCode,\n};\n\npub(crate) use self::sealed::{CombineRejection, IsReject};\n\n/// Rejects a request with `404 Not Found`.\n#[inline]\npub fn reject() -> Rejection {\n    not_found()\n}\n\n/// Rejects a request with `404 Not Found`.\n#[inline]\npub fn not_found() -> Rejection {\n    Rejection {\n        reason: Reason::NotFound,\n    }\n}\n\n// 400 Bad Request\n#[inline]\npub(crate) fn invalid_query() -> Rejection {\n    known(InvalidQuery { _p: () })\n}\n\n// 400 Bad Request\n#[inline]\npub(crate) fn missing_header(name: &'static str) -> Rejection {\n    known(MissingHeader { name })\n}\n\n// 400 Bad Request\n#[inline]\npub(crate) fn invalid_header(name: &'static str) -> Rejection {\n    known(InvalidHeader { name })\n}\n\n// 400 Bad Request\n#[inline]\npub(crate) fn missing_cookie(name: &'static str) -> Rejection {\n    known(MissingCookie { name })\n}\n\n// 405 Method Not Allowed\n#[inline]\npub(crate) fn method_not_allowed() -> Rejection {\n    known(MethodNotAllowed { _p: () })\n}\n\n// 411 Length Required\n#[inline]\npub(crate) fn length_required() -> Rejection {\n    known(LengthRequired { _p: () })\n}\n\n// 413 Payload Too Large\n#[inline]\npub(crate) fn payload_too_large() -> Rejection {\n    known(PayloadTooLarge { _p: () })\n}\n\n// 415 Unsupported Media Type\n//\n// Used by the body filters if the request payload content-type doesn't match\n// what can be deserialized.\n#[inline]\npub(crate) fn unsupported_media_type() -> Rejection {\n    known(UnsupportedMediaType { _p: () })\n}\n\n/// Rejects a request with a custom cause.\n///\n/// A [`recover`][] filter should convert this `Rejection` into a `Reply`,\n/// or else this will be returned as a `500 Internal Server Error`.\n///\n/// [`recover`]: ../trait.Filter.html#method.recover\npub fn custom<T: Reject>(err: T) -> Rejection {\n    Rejection::custom(Box::new(err))\n}\n\n/// Protect against re-rejecting a rejection.\n///\n/// ```compile_fail\n/// fn with(r: warp::Rejection) {\n///     let _wat = warp::reject::custom(r);\n/// }\n/// ```\nfn __reject_custom_compilefail() {}\n\n/// A marker trait to ensure proper types are used for custom rejections.\n///\n/// Can be converted into Rejection.\n///\n/// # Example\n///\n/// ```\n/// use warp::{Filter, reject::Reject};\n///\n/// #[derive(Debug)]\n/// struct RateLimited;\n///\n/// impl Reject for RateLimited {}\n///\n/// let route = warp::any().and_then(|| async {\n///     Err::<(), _>(warp::reject::custom(RateLimited))\n/// });\n/// ```\n// Require `Sized` for now to prevent passing a `Box<dyn Reject>`, since we\n// would be double-boxing it, and the downcasting wouldn't work as expected.\npub trait Reject: fmt::Debug + Sized + Send + Sync + 'static {}\n\ntrait Cause: fmt::Debug + Send + Sync + 'static {\n    fn as_any(&self) -> &dyn Any;\n}\n\nimpl<T> Cause for T\nwhere\n    T: fmt::Debug + Send + Sync + 'static,\n{\n    fn as_any(&self) -> &dyn Any {\n        self\n    }\n}\n\nimpl dyn Cause {\n    fn downcast_ref<T: Any>(&self) -> Option<&T> {\n        self.as_any().downcast_ref::<T>()\n    }\n}\n\npub(crate) fn known<T: Into<Known>>(err: T) -> Rejection {\n    Rejection::known(err.into())\n}\n\n/// Rejection of a request by a [`Filter`](crate::Filter).\n///\n/// See the [`reject`](module@crate::reject) documentation for more.\npub struct Rejection {\n    reason: Reason,\n}\n\nenum Reason {\n    NotFound,\n    Other(Box<Rejections>),\n}\n\nenum Rejections {\n    Known(Known),\n    Custom(Box<dyn Cause>),\n    Combined(Box<Rejections>, Box<Rejections>),\n}\n\nmacro_rules! enum_known {\n     ($($(#[$attr:meta])* $var:ident($ty:path),)+) => (\n        pub(crate) enum Known {\n            $(\n            $(#[$attr])*\n            $var($ty),\n            )+\n        }\n\n        impl Known {\n            fn inner_as_any(&self) -> &dyn Any {\n                match *self {\n                    $(\n                    $(#[$attr])*\n                    Known::$var(ref t) => t,\n                    )+\n                }\n            }\n        }\n\n        impl fmt::Debug for Known {\n            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n                match *self {\n                    $(\n                    $(#[$attr])*\n                    Known::$var(ref t) => t.fmt(f),\n                    )+\n                }\n            }\n        }\n\n        impl fmt::Display for Known {\n            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n                match *self {\n                    $(\n                    $(#[$attr])*\n                    Known::$var(ref t) => t.fmt(f),\n                    )+\n                }\n            }\n        }\n\n        $(\n        #[doc(hidden)]\n        $(#[$attr])*\n        impl From<$ty> for Known {\n            fn from(ty: $ty) -> Known {\n                Known::$var(ty)\n            }\n        }\n        )+\n    );\n}\n\nenum_known! {\n    MethodNotAllowed(MethodNotAllowed),\n    InvalidHeader(InvalidHeader),\n    MissingHeader(MissingHeader),\n    MissingCookie(MissingCookie),\n    InvalidQuery(InvalidQuery),\n    LengthRequired(LengthRequired),\n    PayloadTooLarge(PayloadTooLarge),\n    UnsupportedMediaType(UnsupportedMediaType),\n    FileOpenError(crate::fs::FileOpenError),\n    FilePermissionError(crate::fs::FilePermissionError),\n    BodyReadError(crate::filters::body::BodyReadError),\n    BodyDeserializeError(crate::filters::body::BodyDeserializeError),\n    CorsForbidden(crate::cors::CorsForbidden),\n    #[cfg(feature = \"websocket\")]\n    MissingConnectionUpgrade(crate::ws::MissingConnectionUpgrade),\n    MissingExtension(crate::ext::MissingExtension),\n    BodyConsumedMultipleTimes(crate::filters::body::BodyConsumedMultipleTimes),\n}\n\nimpl Rejection {\n    fn known(known: Known) -> Self {\n        Rejection {\n            reason: Reason::Other(Box::new(Rejections::Known(known))),\n        }\n    }\n\n    fn custom(other: Box<dyn Cause>) -> Self {\n        Rejection {\n            reason: Reason::Other(Box::new(Rejections::Custom(other))),\n        }\n    }\n\n    /// Searches this `Rejection` for a specific cause.\n    ///\n    /// A `Rejection` will accumulate causes over a `Filter` chain. This method\n    /// can search through them and return the first cause of this type.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// #[derive(Debug)]\n    /// struct Nope;\n    ///\n    /// impl warp::reject::Reject for Nope {}\n    ///\n    /// let reject = warp::reject::custom(Nope);\n    ///\n    /// if let Some(nope) = reject.find::<Nope>() {\n    ///    println!(\"found it: {:?}\", nope);\n    /// }\n    /// ```\n    pub fn find<T: 'static>(&self) -> Option<&T> {\n        if let Reason::Other(ref rejections) = self.reason {\n            return rejections.find();\n        }\n        None\n    }\n\n    /// Returns true if this Rejection was made via `warp::reject::not_found`.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// let rejection = warp::reject();\n    ///\n    /// assert!(rejection.is_not_found());\n    /// ```\n    pub fn is_not_found(&self) -> bool {\n        matches!(self.reason, Reason::NotFound)\n    }\n}\n\nimpl<T: Reject> From<T> for Rejection {\n    #[inline]\n    fn from(err: T) -> Rejection {\n        custom(err)\n    }\n}\n\nimpl From<Infallible> for Rejection {\n    #[inline]\n    fn from(infallible: Infallible) -> Rejection {\n        match infallible {}\n    }\n}\n\nimpl IsReject for Infallible {\n    fn status(&self) -> StatusCode {\n        match *self {}\n    }\n\n    fn into_response(&self) -> crate::reply::Response {\n        match *self {}\n    }\n}\n\nimpl IsReject for Rejection {\n    fn status(&self) -> StatusCode {\n        match self.reason {\n            Reason::NotFound => StatusCode::NOT_FOUND,\n            Reason::Other(ref other) => other.status(),\n        }\n    }\n\n    fn into_response(&self) -> crate::reply::Response {\n        match self.reason {\n            Reason::NotFound => {\n                let mut res = http::Response::default();\n                *res.status_mut() = StatusCode::NOT_FOUND;\n                res\n            }\n            Reason::Other(ref other) => other.into_response(),\n        }\n    }\n}\n\nimpl fmt::Debug for Rejection {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_tuple(\"Rejection\").field(&self.reason).finish()\n    }\n}\n\nimpl fmt::Debug for Reason {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match *self {\n            Reason::NotFound => f.write_str(\"NotFound\"),\n            Reason::Other(ref other) => match **other {\n                Rejections::Known(ref e) => fmt::Debug::fmt(e, f),\n                Rejections::Custom(ref e) => fmt::Debug::fmt(e, f),\n                Rejections::Combined(ref a, ref b) => {\n                    let mut list = f.debug_list();\n                    a.debug_list(&mut list);\n                    b.debug_list(&mut list);\n                    list.finish()\n                }\n            },\n        }\n    }\n}\n\n// ===== Rejections =====\n\nimpl Rejections {\n    fn status(&self) -> StatusCode {\n        match *self {\n            Rejections::Known(ref k) => match *k {\n                Known::MethodNotAllowed(_) => StatusCode::METHOD_NOT_ALLOWED,\n                Known::InvalidHeader(_)\n                | Known::MissingHeader(_)\n                | Known::MissingCookie(_)\n                | Known::InvalidQuery(_)\n                | Known::BodyReadError(_)\n                | Known::BodyDeserializeError(_) => StatusCode::BAD_REQUEST,\n                #[cfg(feature = \"websocket\")]\n                Known::MissingConnectionUpgrade(_) => StatusCode::BAD_REQUEST,\n                Known::LengthRequired(_) => StatusCode::LENGTH_REQUIRED,\n                Known::PayloadTooLarge(_) => StatusCode::PAYLOAD_TOO_LARGE,\n                Known::UnsupportedMediaType(_) => StatusCode::UNSUPPORTED_MEDIA_TYPE,\n                Known::FilePermissionError(_) | Known::CorsForbidden(_) => StatusCode::FORBIDDEN,\n                Known::FileOpenError(_)\n                | Known::MissingExtension(_)\n                | Known::BodyConsumedMultipleTimes(_) => StatusCode::INTERNAL_SERVER_ERROR,\n            },\n            Rejections::Custom(..) => StatusCode::INTERNAL_SERVER_ERROR,\n            Rejections::Combined(..) => self.preferred().status(),\n        }\n    }\n\n    fn into_response(&self) -> crate::reply::Response {\n        match *self {\n            Rejections::Known(ref e) => {\n                let mut res = http::Response::new(Body::from(e.to_string()));\n                *res.status_mut() = self.status();\n                res.headers_mut().insert(\n                    CONTENT_TYPE,\n                    HeaderValue::from_static(\"text/plain; charset=utf-8\"),\n                );\n                res\n            }\n            Rejections::Custom(ref e) => {\n                tracing::error!(\n                    \"unhandled custom rejection, returning 500 response: {:?}\",\n                    e\n                );\n                let body = format!(\"Unhandled rejection: {:?}\", e);\n                let mut res = http::Response::new(Body::from(body));\n                *res.status_mut() = self.status();\n                res.headers_mut().insert(\n                    CONTENT_TYPE,\n                    HeaderValue::from_static(\"text/plain; charset=utf-8\"),\n                );\n                res\n            }\n            Rejections::Combined(..) => self.preferred().into_response(),\n        }\n    }\n\n    fn find<T: 'static>(&self) -> Option<&T> {\n        match *self {\n            Rejections::Known(ref e) => e.inner_as_any().downcast_ref(),\n            Rejections::Custom(ref e) => e.downcast_ref(),\n            Rejections::Combined(ref a, ref b) => a.find().or_else(|| b.find()),\n        }\n    }\n\n    fn debug_list(&self, f: &mut fmt::DebugList<'_, '_>) {\n        match *self {\n            Rejections::Known(ref e) => {\n                f.entry(e);\n            }\n            Rejections::Custom(ref e) => {\n                f.entry(e);\n            }\n            Rejections::Combined(ref a, ref b) => {\n                a.debug_list(f);\n                b.debug_list(f);\n            }\n        }\n    }\n\n    fn preferred(&self) -> &Rejections {\n        match self {\n            Rejections::Known(_) | Rejections::Custom(_) => self,\n            Rejections::Combined(a, b) => {\n                let a = a.preferred();\n                let b = b.preferred();\n                // Now both a and b are known or custom, so it is safe\n                // to get status\n                // Compare status codes, with this priority:\n                // - NOT_FOUND is lowest\n                // - METHOD_NOT_ALLOWED is second\n                // - if one status code is greater than the other\n                // - otherwise, prefer A...\n                match (a.status(), b.status()) {\n                    (_, StatusCode::NOT_FOUND) => a,\n                    (StatusCode::NOT_FOUND, _) => b,\n                    (_, StatusCode::METHOD_NOT_ALLOWED) => a,\n                    (StatusCode::METHOD_NOT_ALLOWED, _) => b,\n                    (sa, sb) if sa < sb => b,\n                    _ => a,\n                }\n            }\n        }\n    }\n}\n\nunit_error! {\n    /// Invalid query\n    pub InvalidQuery: \"Invalid query string\"\n}\n\nunit_error! {\n    /// HTTP method not allowed\n    pub MethodNotAllowed: \"HTTP method not allowed\"\n}\n\nunit_error! {\n    /// A content-length header is required\n    pub LengthRequired: \"A content-length header is required\"\n}\n\nunit_error! {\n    /// The request payload is too large\n    pub PayloadTooLarge: \"The request payload is too large\"\n}\n\nunit_error! {\n    /// The request's content-type is not supported\n    pub UnsupportedMediaType: \"The request's content-type is not supported\"\n}\n\n/// Missing request header\n#[derive(Debug)]\npub struct MissingHeader {\n    name: &'static str,\n}\n\nimpl MissingHeader {\n    /// Retrieve the name of the header that was missing\n    pub fn name(&self) -> &str {\n        self.name\n    }\n}\n\nimpl fmt::Display for MissingHeader {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"Missing request header {:?}\", self.name)\n    }\n}\n\nimpl StdError for MissingHeader {}\n\n/// Invalid request header\n#[derive(Debug)]\npub struct InvalidHeader {\n    name: &'static str,\n}\n\nimpl InvalidHeader {\n    /// Retrieve the name of the header that was invalid\n    pub fn name(&self) -> &str {\n        self.name\n    }\n}\n\nimpl fmt::Display for InvalidHeader {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"Invalid request header {:?}\", self.name)\n    }\n}\n\nimpl StdError for InvalidHeader {}\n\n/// Missing cookie\n#[derive(Debug)]\npub struct MissingCookie {\n    name: &'static str,\n}\n\nimpl MissingCookie {\n    /// Retrieve the name of the cookie that was missing\n    pub fn name(&self) -> &str {\n        self.name\n    }\n}\n\nimpl fmt::Display for MissingCookie {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"Missing request cookie {:?}\", self.name)\n    }\n}\n\nimpl StdError for MissingCookie {}\n\nmod sealed {\n    use super::{Reason, Rejection, Rejections};\n    use http::StatusCode;\n    use std::convert::Infallible;\n    use std::fmt;\n\n    // This sealed trait exists to allow Filters to return either `Rejection`\n    // or `!`. There are no other types that make sense, and so it is sealed.\n    pub trait IsReject: fmt::Debug + Send + Sync {\n        fn status(&self) -> StatusCode;\n        fn into_response(&self) -> crate::reply::Response;\n    }\n\n    fn _assert_object_safe() {\n        fn _assert(_: &dyn IsReject) {}\n    }\n\n    // This weird trait is to allow optimizations of propagating when a\n    // rejection can *never* happen (currently with the `Never` type,\n    // eventually to be replaced with `!`).\n    //\n    // Using this trait means the `Never` gets propagated to chained filters,\n    // allowing LLVM to eliminate more code paths. Without it, such as just\n    // requiring that `Rejection::from(Never)` were used in those filters,\n    // would mean that links later in the chain may assume a rejection *could*\n    // happen, and no longer eliminate those branches.\n    pub trait CombineRejection<E>: Send + Sized {\n        /// The type that should be returned when only 1 of the two\n        /// \"rejections\" occurs.\n        ///\n        /// # For example:\n        ///\n        /// `warp::any().and(warp::path(\"foo\"))` has the following steps:\n        ///\n        /// 1. Since this is `and`, only **one** of the rejections will occur,\n        ///    and as soon as it does, it will be returned.\n        /// 2. `warp::any()` rejects with `Never`. So, it will never return `Never`.\n        /// 3. `warp::path()` rejects with `Rejection`. It may return `Rejection`.\n        ///\n        /// Thus, if the above filter rejects, it will definitely be `Rejection`.\n        type One: IsReject + From<Self> + From<E> + Into<Rejection>;\n\n        /// The type that should be returned when both rejections occur,\n        /// and need to be combined.\n        type Combined: IsReject;\n\n        fn combine(self, other: E) -> Self::Combined;\n    }\n\n    impl CombineRejection<Rejection> for Rejection {\n        type One = Rejection;\n        type Combined = Rejection;\n\n        fn combine(self, other: Rejection) -> Self::Combined {\n            let reason = match (self.reason, other.reason) {\n                (Reason::Other(left), Reason::Other(right)) => {\n                    Reason::Other(Box::new(Rejections::Combined(left, right)))\n                }\n                (Reason::Other(other), Reason::NotFound)\n                | (Reason::NotFound, Reason::Other(other)) => {\n                    // ignore the NotFound\n                    Reason::Other(other)\n                }\n                (Reason::NotFound, Reason::NotFound) => Reason::NotFound,\n            };\n\n            Rejection { reason }\n        }\n    }\n\n    impl CombineRejection<Infallible> for Rejection {\n        type One = Rejection;\n        type Combined = Infallible;\n\n        fn combine(self, other: Infallible) -> Self::Combined {\n            match other {}\n        }\n    }\n\n    impl CombineRejection<Rejection> for Infallible {\n        type One = Rejection;\n        type Combined = Infallible;\n\n        fn combine(self, _: Rejection) -> Self::Combined {\n            match self {}\n        }\n    }\n\n    impl CombineRejection<Infallible> for Infallible {\n        type One = Infallible;\n        type Combined = Infallible;\n\n        fn combine(self, _: Infallible) -> Self::Combined {\n            match self {}\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[derive(Debug, PartialEq)]\n    struct Left;\n\n    #[derive(Debug, PartialEq)]\n    struct Right;\n\n    impl Reject for Left {}\n    impl Reject for Right {}\n\n    #[test]\n    fn rejection_status() {\n        assert_eq!(not_found().status(), StatusCode::NOT_FOUND);\n        assert_eq!(\n            method_not_allowed().status(),\n            StatusCode::METHOD_NOT_ALLOWED\n        );\n        assert_eq!(length_required().status(), StatusCode::LENGTH_REQUIRED);\n        assert_eq!(payload_too_large().status(), StatusCode::PAYLOAD_TOO_LARGE);\n        assert_eq!(\n            unsupported_media_type().status(),\n            StatusCode::UNSUPPORTED_MEDIA_TYPE\n        );\n        assert_eq!(custom(Left).status(), StatusCode::INTERNAL_SERVER_ERROR);\n    }\n\n    #[tokio::test]\n    async fn combine_rejection_causes_with_some_left_and_none_right() {\n        let left = custom(Left);\n        let right = not_found();\n        let reject = left.combine(right);\n        let resp = reject.into_response();\n\n        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);\n        assert_eq!(\n            response_body_string(resp).await,\n            \"Unhandled rejection: Left\"\n        )\n    }\n\n    #[tokio::test]\n    async fn combine_rejection_causes_with_none_left_and_some_right() {\n        let left = not_found();\n        let right = custom(Right);\n        let reject = left.combine(right);\n        let resp = reject.into_response();\n\n        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);\n        assert_eq!(\n            response_body_string(resp).await,\n            \"Unhandled rejection: Right\"\n        )\n    }\n\n    #[tokio::test]\n    async fn unhandled_customs() {\n        let reject = not_found().combine(custom(Right));\n\n        let resp = reject.into_response();\n        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);\n        assert_eq!(\n            response_body_string(resp).await,\n            \"Unhandled rejection: Right\"\n        );\n\n        // There's no real way to determine which is worse, since both are a 500,\n        // so pick the first one.\n        let reject = custom(Left).combine(custom(Right));\n\n        let resp = reject.into_response();\n        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);\n        assert_eq!(\n            response_body_string(resp).await,\n            \"Unhandled rejection: Left\"\n        );\n\n        // With many rejections, custom still is top priority.\n        let reject = not_found()\n            .combine(not_found())\n            .combine(not_found())\n            .combine(custom(Right))\n            .combine(not_found());\n\n        let resp = reject.into_response();\n        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);\n        assert_eq!(\n            response_body_string(resp).await,\n            \"Unhandled rejection: Right\"\n        );\n    }\n\n    async fn response_body_string(resp: crate::reply::Response) -> String {\n        use http_body_util::BodyExt;\n        let (_, body) = resp.into_parts();\n        let body_bytes = body.collect().await.unwrap().to_bytes();\n        String::from_utf8_lossy(&body_bytes).to_string()\n    }\n\n    #[test]\n    fn find_cause() {\n        let rej = custom(Left);\n\n        assert_eq!(rej.find::<Left>(), Some(&Left));\n\n        let rej = rej.combine(method_not_allowed());\n\n        assert_eq!(rej.find::<Left>(), Some(&Left));\n        assert!(rej.find::<MethodNotAllowed>().is_some(), \"MethodNotAllowed\");\n    }\n\n    #[test]\n    fn size_of_rejection() {\n        assert_eq!(\n            ::std::mem::size_of::<Rejection>(),\n            ::std::mem::size_of::<usize>(),\n        );\n    }\n\n    #[derive(Debug)]\n    struct X(#[allow(unused)] u32);\n    impl Reject for X {}\n\n    fn combine_n<F, R>(n: u32, new_reject: F) -> Rejection\n    where\n        F: Fn(u32) -> R,\n        R: Reject,\n    {\n        let mut rej = not_found();\n\n        for i in 0..n {\n            rej = rej.combine(custom(new_reject(i)));\n        }\n\n        rej\n    }\n\n    #[test]\n    fn test_debug() {\n        let rej = combine_n(3, X);\n\n        let s = format!(\"{:?}\", rej);\n        assert_eq!(s, \"Rejection([X(0), X(1), X(2)])\");\n    }\n\n    #[test]\n    fn convert_big_rejections_into_response() {\n        let mut rejections = Rejections::Custom(Box::new(std::io::Error::from_raw_os_error(100)));\n        for _ in 0..50 {\n            rejections = Rejections::Combined(\n                Box::new(Rejections::Known(Known::MethodNotAllowed(\n                    MethodNotAllowed { _p: () },\n                ))),\n                Box::new(rejections),\n            );\n        }\n        let reason = Reason::Other(Box::new(rejections));\n        let rejection = Rejection { reason };\n        assert_eq!(\n            StatusCode::INTERNAL_SERVER_ERROR,\n            rejection.into_response().status()\n        );\n    }\n}\n"
  },
  {
    "path": "src/reply.rs",
    "content": "//! Reply to requests.\n//!\n//! A [`Reply`](./trait.Reply.html) is a type that can be converted into an HTTP\n//! response to be sent to the client. These are typically the successful\n//! counterpart to a [rejection](../reject).\n//!\n//! The functions in this module are helpers for quickly creating a reply.\n//! Besides them, you can return a type that implements [`Reply`](./trait.Reply.html). This\n//! could be any of the following:\n//!\n//! - `String`\n//! - `&'static str`\n//! - `http::StatusCode`\n//!\n//! # Example\n//!\n//! ```\n//! use warp::{Filter, http::Response};\n//!\n//! // Returns an empty `200 OK` response.\n//! let empty_200 = warp::any().map(warp::reply);\n//!\n//! // Returns a `200 OK` response with custom header and body.\n//! let custom = warp::any().map(|| {\n//!     Response::builder()\n//!         .header(\"my-custom-header\", \"some-value\")\n//!         .body(\"and a custom body\")\n//! });\n//!\n//! // GET requests return the empty 200, POST return the custom.\n//! let routes = warp::get().and(empty_200)\n//!     .or(warp::post().and(custom));\n//! ```\n\nuse std::borrow::Cow;\nuse std::convert::TryFrom;\n\nuse http::header::{HeaderName, HeaderValue, CONTENT_TYPE};\nuse http::StatusCode;\nuse serde::Serialize;\n\n// This re-export just looks weird in docs...\npub(crate) use self::sealed::Reply_;\nuse self::sealed::{BoxedReply, Internal};\nuse crate::bodyt::Body;\n#[doc(hidden)]\npub use crate::filters::reply as with;\nuse crate::generic::{Either, One};\n\n/// Response type into which types implementing the `Reply` trait are convertable.\npub type Response = ::http::Response<crate::bodyt::Body>;\n\n/// Returns an empty `Reply` with status code `200 OK`.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// // GET /just-ok returns an empty `200 OK`.\n/// let route = warp::path(\"just-ok\")\n///     .map(|| {\n///         println!(\"got a /just-ok request!\");\n///         warp::reply()\n///     });\n/// ```\n#[inline]\npub fn reply() -> impl Reply {\n    StatusCode::OK\n}\n\n/// Convert the value into a `Reply` with the value encoded as JSON.\n///\n/// The passed value must implement [`Serialize`][ser]. Many\n/// collections do, and custom domain types can have `Serialize` derived.\n///\n/// [ser]: https://serde.rs\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// // GET /ids returns a `200 OK` with a JSON array of ids:\n/// // `[1, 3, 7, 13]`\n/// let route = warp::path(\"ids\")\n///     .map(|| {\n///         let our_ids = vec![1, 3, 7, 13];\n///         warp::reply::json(&our_ids)\n///     });\n/// ```\n///\n/// # Note\n///\n/// If a type fails to be serialized into JSON, the error is logged at the\n/// `error` level, and the returned `impl Reply` will be an empty\n/// `500 Internal Server Error` response.\npub fn json<T>(val: &T) -> Json\nwhere\n    T: Serialize,\n{\n    Json {\n        inner: serde_json::to_vec(val).map_err(|err| {\n            tracing::error!(\"reply::json error: {}\", err);\n        }),\n    }\n}\n\n/// A JSON formatted reply.\n#[allow(missing_debug_implementations)]\npub struct Json {\n    inner: Result<Vec<u8>, ()>,\n}\n\nimpl Reply for Json {\n    #[inline]\n    fn into_response(self) -> Response {\n        match self.inner {\n            Ok(body) => {\n                let mut res = Response::new(body.into());\n                res.headers_mut()\n                    .insert(CONTENT_TYPE, HeaderValue::from_static(\"application/json\"));\n                res\n            }\n            Err(()) => StatusCode::INTERNAL_SERVER_ERROR.into_response(),\n        }\n    }\n}\n\n/// Converts a [`Stream`](futures_util::Stream) of data chunks into a reply.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n/// use futures_util::stream;\n/// use bytes::Bytes;\n///\n/// let route = warp::any().map(|| {\n///     let chunks = vec![Ok::<_, std::io::Error>(Bytes::from(\"hello\"))];\n///     warp::reply::stream(stream::iter(chunks))\n/// });\n/// ```\npub fn stream<S, B, E>(stream: S) -> impl Reply\nwhere\n    S: futures_util::Stream<Item = Result<B, E>> + Send + Sync + 'static,\n    B: Into<bytes::Bytes>,\n    E: Into<Box<dyn std::error::Error + Send + Sync>> + Send + 'static,\n{\n    Response::new(Body::wrap_stream(stream))\n}\n\n/// Reply with a body and `content-type` set to `text/html; charset=utf-8`.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let body = r#\"\n/// <html>\n///     <head>\n///         <title>HTML with warp!</title>\n///     </head>\n///     <body>\n///         <h1>warp + HTML = &hearts;</h1>\n///     </body>\n/// </html>\n/// \"#;\n///\n/// let route = warp::any()\n///     .map(move || {\n///         warp::reply::html(body)\n///     });\n/// ```\npub fn html<T>(body: T) -> Html<T>\nwhere\n    crate::bodyt::Body: From<T>,\n    T: Send,\n{\n    Html { body }\n}\n\n/// An HTML reply.\n#[allow(missing_debug_implementations)]\npub struct Html<T> {\n    body: T,\n}\n\nimpl<T> Reply for Html<T>\nwhere\n    crate::bodyt::Body: From<T>,\n    T: Send,\n{\n    #[inline]\n    fn into_response(self) -> Response {\n        let mut res = Response::new(Body::from(self.body));\n        res.headers_mut().insert(\n            CONTENT_TYPE,\n            HeaderValue::from_static(\"text/html; charset=utf-8\"),\n        );\n        res\n    }\n}\n\n/// Types that can be converted into a `Response`.\n///\n/// This trait is implemented for the following:\n///\n/// - `http::StatusCode`\n/// - `http::Response<impl Into<hyper::Body>>`\n/// - `String`\n/// - `&'static str`\n///\n/// # Example\n///\n/// ```rust\n/// use warp::{Filter, http::Response};\n///\n/// struct Message {\n///     msg: String\n/// }\n///\n/// impl warp::Reply for Message {\n///     fn into_response(self) -> warp::reply::Response {\n///         Response::new(format!(\"message: {}\", self.msg).into())\n///     }\n/// }\n///\n/// fn handler() -> Message {\n///     Message { msg: \"Hello\".to_string() }\n/// }\n///\n/// let route = warp::any().map(handler);\n/// ```\npub trait Reply: BoxedReply + Send {\n    /// Converts the given value into a [`Response`].\n    ///\n    /// [`Response`]: type.Response.html\n    fn into_response(self) -> Response;\n\n    /*\n    TODO: Currently unsure about having trait methods here, as it\n    requires returning an exact type, which I'd rather not commit to.\n    Additionally, it doesn't work great with `Box<Reply>`.\n\n    A possible alternative is to have wrappers, like\n\n    - `WithStatus<R: Reply>(StatusCode, R)`\n\n\n    /// Change the status code of this `Reply`.\n    fn with_status(self, status: StatusCode) -> Reply_\n    where\n        Self: Sized,\n    {\n        let mut res = self.into_response();\n        *res.status_mut() = status;\n        Reply_(res)\n    }\n\n    /// Add a header to this `Reply`.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// use warp::Reply;\n    ///\n    /// let reply = warp::reply()\n    ///     .with_header(\"x-foo\", \"bar\");\n    /// ```\n    fn with_header<K, V>(self, name: K, value: V) -> Reply_\n    where\n        Self: Sized,\n        HeaderName: TryFrom<K>,\n        HeaderValue: TryFrom<V>,\n    {\n        match <HeaderName as TryFrom<K>>::try_from(name) {\n            Ok(name) => match <HeaderValue as TryFrom<V>>::try_from(value) {\n                Ok(value) => {\n                    let mut res = self.into_response();\n                    res.headers_mut().append(name, value);\n                    Reply_(res)\n                },\n                Err(err) => {\n                    tracing::error!(\"with_header value error: {}\", err.into());\n                    Reply_(::reject::server_error()\n                        .into_response())\n                }\n            },\n            Err(err) => {\n                tracing::error!(\"with_header name error: {}\", err.into());\n                Reply_(::reject::server_error()\n                    .into_response())\n            }\n        }\n    }\n    */\n}\n\nimpl<T: Reply + ?Sized> Reply for Box<T> {\n    fn into_response(self) -> Response {\n        self.boxed_into_response(Internal)\n    }\n}\n\nfn _assert_object_safe() {\n    fn _assert(_: &dyn Reply) {}\n}\n\n/// Wrap an `impl Reply` to change its `StatusCode`.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let route = warp::any()\n///     .map(warp::reply)\n///     .map(|reply| {\n///         warp::reply::with_status(reply, warp::http::StatusCode::CREATED)\n///     });\n/// ```\npub fn with_status<T: Reply>(reply: T, status: StatusCode) -> WithStatus<T> {\n    WithStatus { reply, status }\n}\n\n/// Wrap an `impl Reply` to change its `StatusCode`.\n///\n/// Returned by `warp::reply::with_status`.\n#[derive(Debug)]\npub struct WithStatus<T> {\n    reply: T,\n    status: StatusCode,\n}\n\nimpl<T: Reply> Reply for WithStatus<T> {\n    fn into_response(self) -> Response {\n        let mut res = self.reply.into_response();\n        *res.status_mut() = self.status;\n        res\n    }\n}\n\n/// Wrap an `impl Reply` to add a header when rendering.\n///\n/// # Example\n///\n/// ```\n/// use warp::Filter;\n///\n/// let route = warp::any()\n///     .map(warp::reply)\n///     .map(|reply| {\n///         warp::reply::with_header(reply, \"server\", \"warp\")\n///     });\n/// ```\npub fn with_header<T: Reply, K, V>(reply: T, name: K, value: V) -> WithHeader<T>\nwhere\n    HeaderName: TryFrom<K>,\n    <HeaderName as TryFrom<K>>::Error: Into<http::Error>,\n    HeaderValue: TryFrom<V>,\n    <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,\n{\n    let header = match <HeaderName as TryFrom<K>>::try_from(name) {\n        Ok(name) => match <HeaderValue as TryFrom<V>>::try_from(value) {\n            Ok(value) => Some((name, value)),\n            Err(err) => {\n                let err = err.into();\n                tracing::error!(\"with_header value error: {}\", err);\n                None\n            }\n        },\n        Err(err) => {\n            let err = err.into();\n            tracing::error!(\"with_header name error: {}\", err);\n            None\n        }\n    };\n\n    WithHeader { header, reply }\n}\n\n/// Wraps an `impl Reply` and adds a header when rendering.\n///\n/// Returned by `warp::reply::with_header`.\n#[derive(Debug)]\npub struct WithHeader<T> {\n    header: Option<(HeaderName, HeaderValue)>,\n    reply: T,\n}\n\nimpl<T: Reply> Reply for WithHeader<T> {\n    fn into_response(self) -> Response {\n        let mut res = self.reply.into_response();\n        if let Some((name, value)) = self.header {\n            res.headers_mut().insert(name, value);\n        }\n        res\n    }\n}\n\nimpl<T: Send> Reply for ::http::Response<T>\nwhere\n    crate::bodyt::Body: From<T>,\n{\n    #[inline]\n    fn into_response(self) -> Response {\n        self.map(Body::from)\n    }\n}\n\nimpl Reply for ::http::StatusCode {\n    #[inline]\n    fn into_response(self) -> Response {\n        let mut res = Response::default();\n        *res.status_mut() = self;\n        res\n    }\n}\n\nimpl Reply for ::http::Error {\n    #[inline]\n    fn into_response(self) -> Response {\n        tracing::error!(\"reply error: {:?}\", self);\n        StatusCode::INTERNAL_SERVER_ERROR.into_response()\n    }\n}\n\nimpl<T, E> Reply for Result<T, E>\nwhere\n    T: Reply,\n    E: Reply,\n{\n    #[inline]\n    fn into_response(self) -> Response {\n        match self {\n            Ok(t) => t.into_response(),\n            Err(e) => e.into_response(),\n        }\n    }\n}\n\nfn text_plain<T: Into<Body>>(body: T) -> Response {\n    let mut response = ::http::Response::new(body.into());\n    response.headers_mut().insert(\n        CONTENT_TYPE,\n        HeaderValue::from_static(\"text/plain; charset=utf-8\"),\n    );\n    response\n}\n\nimpl Reply for String {\n    #[inline]\n    fn into_response(self) -> Response {\n        text_plain(self)\n    }\n}\n\nimpl Reply for Vec<u8> {\n    #[inline]\n    fn into_response(self) -> Response {\n        ::http::Response::builder()\n            .header(\n                CONTENT_TYPE,\n                HeaderValue::from_static(\"application/octet-stream\"),\n            )\n            .body(Body::from(self))\n            .unwrap()\n    }\n}\n\nimpl Reply for &'static str {\n    #[inline]\n    fn into_response(self) -> Response {\n        text_plain(self)\n    }\n}\n\nimpl Reply for Cow<'static, str> {\n    #[inline]\n    fn into_response(self) -> Response {\n        match self {\n            Cow::Borrowed(s) => s.into_response(),\n            Cow::Owned(s) => s.into_response(),\n        }\n    }\n}\n\nimpl Reply for &'static [u8] {\n    #[inline]\n    fn into_response(self) -> Response {\n        ::http::Response::builder()\n            .header(\n                CONTENT_TYPE,\n                HeaderValue::from_static(\"application/octet-stream\"),\n            )\n            .body(Body::from(bytes::Bytes::from_static(self)))\n            .unwrap()\n    }\n}\n\nimpl<T, U> Reply for Either<T, U>\nwhere\n    T: Reply,\n    U: Reply,\n{\n    #[inline]\n    fn into_response(self) -> Response {\n        match self {\n            Either::A(a) => a.into_response(),\n            Either::B(b) => b.into_response(),\n        }\n    }\n}\n\nimpl<T> Reply for One<T>\nwhere\n    T: Reply,\n{\n    #[inline]\n    fn into_response(self) -> Response {\n        self.0.into_response()\n    }\n}\n\nimpl Reply for std::convert::Infallible {\n    #[inline(always)]\n    fn into_response(self) -> Response {\n        match self {}\n    }\n}\n\nmod sealed {\n    use super::{Reply, Response};\n\n    // An opaque type to return `impl Reply` from trait methods.\n    #[allow(missing_debug_implementations)]\n    pub struct Reply_(pub(crate) Response);\n\n    impl Reply for Reply_ {\n        #[inline]\n        fn into_response(self) -> Response {\n            self.0\n        }\n    }\n\n    #[allow(missing_debug_implementations)]\n    pub struct Internal;\n\n    // Implemented for all types that implement `Reply`.\n    //\n    // A user doesn't need to worry about this, it's just trait\n    // hackery to get `Box<dyn Reply>` working.\n    pub trait BoxedReply {\n        fn boxed_into_response(self: Box<Self>, internal: Internal) -> Response;\n    }\n\n    impl<T: Reply> BoxedReply for T {\n        fn boxed_into_response(self: Box<Self>, _: Internal) -> Response {\n            (*self).into_response()\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use std::collections::HashMap;\n\n    use super::*;\n\n    #[test]\n    fn json_serde_error() {\n        // a HashMap<Vec, _> cannot be serialized to JSON\n        let mut map = HashMap::new();\n        map.insert(vec![1, 2], 45);\n\n        let res = json(&map).into_response();\n        assert_eq!(res.status(), 500);\n    }\n\n    #[test]\n    fn response_builder_error() {\n        let res = ::http::Response::builder()\n            .status(1337)\n            .body(\"woops\")\n            .into_response();\n\n        assert_eq!(res.status(), 500);\n    }\n\n    #[test]\n    fn boxed_reply() {\n        let r: Box<dyn Reply> = Box::new(reply());\n        let resp = r.into_response();\n        assert_eq!(resp.status(), 200);\n    }\n}\n"
  },
  {
    "path": "src/route.rs",
    "content": "use scoped_tls::scoped_thread_local;\nuse std::cell::RefCell;\nuse std::mem;\nuse std::net::SocketAddr;\n\nuse crate::addr::RemoteAddr;\nuse crate::{bodyt::Body, Request};\n\nscoped_thread_local!(static ROUTE: RefCell<Route>);\n\npub(crate) fn set<F, U>(r: &RefCell<Route>, func: F) -> U\nwhere\n    F: FnOnce() -> U,\n{\n    ROUTE.set(r, func)\n}\n\npub(crate) fn is_set() -> bool {\n    ROUTE.is_set()\n}\n\npub(crate) fn with<F, R>(func: F) -> R\nwhere\n    F: FnOnce(&mut Route) -> R,\n{\n    ROUTE.with(move |route| func(&mut *route.borrow_mut()))\n}\n\n#[derive(Debug)]\npub(crate) struct Route {\n    body: BodyState,\n    req: Request,\n    segments_index: usize,\n}\n\n#[derive(Debug)]\nenum BodyState {\n    Ready,\n    Taken,\n}\n\nimpl Route {\n    pub(crate) fn new(req: http::Request<Body>) -> RefCell<Route> {\n        let segments_index = if req.uri().path().starts_with('/') {\n            // Skip the beginning slash.\n            1\n        } else {\n            0\n        };\n\n        RefCell::new(Route {\n            body: BodyState::Ready,\n            req,\n            segments_index,\n        })\n    }\n\n    pub(crate) fn method(&self) -> &http::Method {\n        self.req.method()\n    }\n\n    pub(crate) fn headers(&self) -> &http::HeaderMap {\n        self.req.headers()\n    }\n\n    pub(crate) fn version(&self) -> http::Version {\n        self.req.version()\n    }\n\n    pub(crate) fn extensions(&self) -> &http::Extensions {\n        self.req.extensions()\n    }\n\n    #[cfg(feature = \"websocket\")]\n    pub(crate) fn extensions_mut(&mut self) -> &mut http::Extensions {\n        self.req.extensions_mut()\n    }\n\n    pub(crate) fn uri(&self) -> &http::Uri {\n        self.req.uri()\n    }\n\n    pub(crate) fn path(&self) -> &str {\n        &self.req.uri().path()[self.segments_index..]\n    }\n\n    pub(crate) fn full_path(&self) -> &str {\n        self.req.uri().path()\n    }\n\n    pub(crate) fn set_unmatched_path(&mut self, index: usize) {\n        let index = self.segments_index + index;\n        let path = self.req.uri().path();\n        if path.is_empty() {\n            // malformed path\n            return;\n        } else if path.len() == index {\n            self.segments_index = index;\n        } else {\n            debug_assert_eq!(path.as_bytes()[index], b'/');\n            self.segments_index = index + 1;\n        }\n    }\n\n    pub(crate) fn query(&self) -> Option<&str> {\n        self.req.uri().query()\n    }\n\n    pub(crate) fn matched_path_index(&self) -> usize {\n        self.segments_index\n    }\n\n    pub(crate) fn reset_matched_path_index(&mut self, index: usize) {\n        debug_assert!(\n            index <= self.segments_index,\n            \"reset_match_path_index should not be bigger: current={}, arg={}\",\n            self.segments_index,\n            index,\n        );\n        self.segments_index = index;\n    }\n\n    pub(crate) fn remote_addr(&self) -> Option<SocketAddr> {\n        self.req\n            .extensions()\n            .get::<RemoteAddr>()\n            .map(|RemoteAddr(addr)| *addr)\n    }\n\n    pub(crate) fn take_body(&mut self) -> Option<Body> {\n        match self.body {\n            BodyState::Ready => {\n                let body = mem::replace(self.req.body_mut(), Body::empty());\n                self.body = BodyState::Taken;\n                Some(body)\n            }\n            BodyState::Taken => None,\n        }\n    }\n}\n"
  },
  {
    "path": "src/server.rs",
    "content": "use std::future::Future;\nuse std::net::SocketAddr;\n#[cfg(feature = \"tls\")]\nuse std::path::Path;\n\nuse futures_util::TryFuture;\n\nuse crate::filter::Filter;\nuse crate::reject::IsReject;\nuse crate::reply::Reply;\n#[cfg(feature = \"tls\")]\nuse crate::tls::TlsConfigBuilder;\n\n/// Create a `Server` with the provided `Filter`.\npub fn serve<F>(filter: F) -> Server<F, accept::LazyTcp, run::Standard>\nwhere\n    F: Filter + Clone + Send + Sync + 'static,\n    F::Extract: Reply,\n    F::Error: IsReject,\n{\n    Server {\n        acceptor: accept::LazyTcp,\n        pipeline: false,\n        filter,\n        runner: run::Standard,\n    }\n}\n\n/// A warp Server ready to filter requests.\n///\n/// Construct this type using [`serve()`].\n///\n/// # Unnameable\n///\n/// This type is publicly available in the docs only.\n///\n/// It is not otherwise nameable, since it is a builder type using typestate\n/// to allow for ergonomic configuration.\n#[derive(Debug)]\npub struct Server<F, A, R> {\n    acceptor: A,\n    filter: F,\n    pipeline: bool,\n    runner: R,\n}\n\n// ===== impl Server =====\n\nimpl<F, R> Server<F, accept::LazyTcp, R>\nwhere\n    F: Filter + Clone + Send + Sync + 'static,\n    <F::Future as TryFuture>::Ok: Reply,\n    <F::Future as TryFuture>::Error: IsReject,\n    R: run::Run,\n{\n    /// Binds and runs this server.\n    ///\n    /// # Panics\n    ///\n    /// Panics if we are unable to bind to the provided address.\n    ///\n    /// To handle bind failures, bind a listener and call `incoming()`.\n    pub async fn run(self, addr: impl Into<SocketAddr>) {\n        self.bind(addr).await.run().await;\n    }\n\n    /// Binds this server.\n    ///\n    /// # Panics\n    ///\n    /// Panics if we are unable to bind to the provided address.\n    ///\n    /// To handle bind failures, bind a listener and call `incoming()`.\n    pub async fn bind(self, addr: impl Into<SocketAddr>) -> Server<F, tokio::net::TcpListener, R> {\n        let addr = addr.into();\n        let acceptor = tokio::net::TcpListener::bind(addr)\n            .await\n            .expect(\"failed to bind to address\");\n\n        self.incoming(acceptor)\n    }\n\n    /// Configure the server with an acceptor of incoming connections.\n    pub fn incoming<A>(self, acceptor: A) -> Server<F, A, R> {\n        Server {\n            acceptor,\n            filter: self.filter,\n            pipeline: self.pipeline,\n            runner: self.runner,\n        }\n    }\n\n    // pub fn conn\n}\n\nimpl<F, A, R> Server<F, A, R>\nwhere\n    F: Filter + Clone + Send + Sync + 'static,\n    <F::Future as TryFuture>::Ok: Reply,\n    <F::Future as TryFuture>::Error: IsReject,\n    A: accept::Accept,\n    R: run::Run,\n{\n    #[cfg(feature = \"tls\")]\n    pub fn tls(self) -> Server<F, accept::Tls<A>, R> {}\n\n    /// Add graceful shutdown support to this server.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// # async fn ex(addr: std::net::SocketAddr) {\n    /// # use warp::Filter;\n    /// # let filter = warp::any().map(|| \"ok\");\n    /// warp::serve(filter)\n    ///     .bind(addr).await\n    ///     .graceful(async {\n    ///         // some signal in here, such as ctrl_c\n    ///     })\n    ///     .run().await;\n    /// # }\n    /// ```\n    pub fn graceful<Fut>(self, shutdown_signal: Fut) -> Server<F, A, run::Graceful<Fut>>\n    where\n        Fut: Future<Output = ()> + Send + 'static,\n    {\n        Server {\n            acceptor: self.acceptor,\n            filter: self.filter,\n            pipeline: self.pipeline,\n            runner: run::Graceful(shutdown_signal),\n        }\n    }\n\n    /// Run this server.\n    pub async fn run(self) {\n        R::run(self).await;\n    }\n}\n\n// // ===== impl Tls =====\n\n#[cfg(feature = \"tls\")]\nimpl<F, A, R> Server<F, accept::Tls<A>, R>\nwhere\n    F: Filter + Clone + Send + Sync + 'static,\n    <F::Future as TryFuture>::Ok: Reply,\n    <F::Future as TryFuture>::Error: IsReject,\n    A: accept::Accept,\n    R: run::Run,\n{\n    // TLS config methods\n\n    /// Specify the file path to read the private key.\n    ///\n    /// *This function requires the `\"tls\"` feature.*\n    pub fn key_path(self, path: impl AsRef<Path>) -> Self {\n        self.with_tls(|tls| tls.key_path(path))\n    }\n\n    /// Specify the file path to read the certificate.\n    ///\n    /// *This function requires the `\"tls\"` feature.*\n    pub fn cert_path(self, path: impl AsRef<Path>) -> Self {\n        self.with_tls(|tls| tls.cert_path(path))\n    }\n\n    /// Specify the file path to read the trust anchor for optional client authentication.\n    ///\n    /// Anonymous and authenticated clients will be accepted. If no trust anchor is provided by any\n    /// of the `client_auth_` methods, then client authentication is disabled by default.\n    ///\n    /// *This function requires the `\"tls\"` feature.*\n    pub fn client_auth_optional_path(self, path: impl AsRef<Path>) -> Self {\n        self.with_tls(|tls| tls.client_auth_optional_path(path))\n    }\n\n    /// Specify the file path to read the trust anchor for required client authentication.\n    ///\n    /// Only authenticated clients will be accepted. If no trust anchor is provided by any of the\n    /// `client_auth_` methods, then client authentication is disabled by default.\n    ///\n    /// *This function requires the `\"tls\"` feature.*\n    pub fn client_auth_required_path(self, path: impl AsRef<Path>) -> Self {\n        self.with_tls(|tls| tls.client_auth_required_path(path))\n    }\n\n    /// Specify the in-memory contents of the private key.\n    ///\n    /// *This function requires the `\"tls\"` feature.*\n    pub fn key(self, key: impl AsRef<[u8]>) -> Self {\n        self.with_tls(|tls| tls.key(key.as_ref()))\n    }\n\n    /// Specify the in-memory contents of the certificate.\n    ///\n    /// *This function requires the `\"tls\"` feature.*\n    pub fn cert(self, cert: impl AsRef<[u8]>) -> Self {\n        self.with_tls(|tls| tls.cert(cert.as_ref()))\n    }\n\n    /// Specify the in-memory contents of the trust anchor for optional client authentication.\n    ///\n    /// Anonymous and authenticated clients will be accepted. If no trust anchor is provided by any\n    /// of the `client_auth_` methods, then client authentication is disabled by default.\n    ///\n    /// *This function requires the `\"tls\"` feature.*\n    pub fn client_auth_optional(self, trust_anchor: impl AsRef<[u8]>) -> Self {\n        self.with_tls(|tls| tls.client_auth_optional(trust_anchor.as_ref()))\n    }\n\n    /// Specify the in-memory contents of the trust anchor for required client authentication.\n    ///\n    /// Only authenticated clients will be accepted. If no trust anchor is provided by any of the\n    /// `client_auth_` methods, then client authentication is disabled by default.\n    ///\n    /// *This function requires the `\"tls\"` feature.*\n    pub fn client_auth_required(self, trust_anchor: impl AsRef<[u8]>) -> Self {\n        self.with_tls(|tls| tls.client_auth_required(trust_anchor.as_ref()))\n    }\n\n    /// Specify the DER-encoded OCSP response.\n    ///\n    /// *This function requires the `\"tls\"` feature.*\n    pub fn ocsp_resp(self, resp: impl AsRef<[u8]>) -> Self {\n        self.with_tls(|tls| tls.ocsp_resp(resp.as_ref()))\n    }\n\n    fn with_tls<Func>(self, func: Func) -> Self\n    where\n        Func: FnOnce(TlsConfigBuilder) -> TlsConfigBuilder,\n    {\n        let tls = func(tls);\n    }\n}\n\nmod accept {\n    use std::net::SocketAddr;\n\n    pub trait Accept {\n        type IO: hyper::rt::Read + hyper::rt::Write + Send + Unpin + 'static;\n        type AcceptError: std::fmt::Debug;\n        type Accepting: super::Future<Output = Result<(Self::IO, Option<SocketAddr>), Self::AcceptError>>\n            + Send\n            + 'static;\n        #[allow(async_fn_in_trait)]\n        async fn accept(&mut self) -> Result<Self::Accepting, std::io::Error>;\n    }\n\n    #[derive(Debug)]\n    pub struct LazyTcp;\n\n    impl Accept for tokio::net::TcpListener {\n        type IO = hyper_util::rt::TokioIo<tokio::net::TcpStream>;\n        type AcceptError = std::convert::Infallible;\n        type Accepting =\n            std::future::Ready<Result<(Self::IO, Option<SocketAddr>), Self::AcceptError>>;\n        async fn accept(&mut self) -> Result<Self::Accepting, std::io::Error> {\n            let (io, addr) = <tokio::net::TcpListener>::accept(self).await?;\n            Ok(std::future::ready(Ok((\n                hyper_util::rt::TokioIo::new(io),\n                Some(addr),\n            ))))\n        }\n    }\n\n    #[cfg(unix)]\n    impl Accept for tokio::net::UnixListener {\n        type IO = hyper_util::rt::TokioIo<tokio::net::UnixStream>;\n        type AcceptError = std::convert::Infallible;\n        type Accepting =\n            std::future::Ready<Result<(Self::IO, Option<SocketAddr>), Self::AcceptError>>;\n        async fn accept(&mut self) -> Result<Self::Accepting, std::io::Error> {\n            let (io, _addr) = <tokio::net::UnixListener>::accept(self).await?;\n            Ok(std::future::ready(Ok((\n                hyper_util::rt::TokioIo::new(io),\n                None,\n            ))))\n        }\n    }\n\n    #[cfg(feature = \"tls\")]\n    #[derive(Debug)]\n    pub struct Tls<A>(pub(super) A);\n\n    #[cfg(feature = \"tls\")]\n    impl<A: Accept> Accept for Tls<A> {\n        type IO = hyper_util::rt::TokioIo<tokio::net::TcpStream>;\n        type AcceptError = std::convert::Infallible;\n        type Accepting =\n            std::future::Ready<Result<(Self::IO, Option<SocketAddr>), Self::AcceptError>>;\n        async fn accept(&mut self) -> Result<Self::Accepting, std::io::Error> {\n            let (io, addr) = self.0.accept().await?;\n            Ok(std::future::ready(Ok((\n                hyper_util::rt::TokioIo::new(io),\n                addr,\n            ))))\n        }\n    }\n}\n\nmod middleware {\n    use std::net::SocketAddr;\n    use std::task::{Context, Poll};\n    use tower_service::Service;\n\n    use crate::filters::addr::RemoteAddr;\n\n    #[derive(Clone, Debug)]\n    pub(super) struct RemoteAddrService<S> {\n        inner: S,\n        remote_addr: Option<SocketAddr>,\n    }\n\n    impl<S> RemoteAddrService<S> {\n        pub(super) fn new(inner: S, remote_addr: Option<SocketAddr>) -> Self {\n            Self { inner, remote_addr }\n        }\n    }\n\n    impl<S, B> Service<http::Request<B>> for RemoteAddrService<S>\n    where\n        S: Service<http::Request<B>>,\n    {\n        type Response = S::Response;\n        type Error = S::Error;\n        type Future = S::Future;\n\n        fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n            self.inner.poll_ready(cx)\n        }\n\n        fn call(&mut self, mut req: http::Request<B>) -> Self::Future {\n            if let Some(addr) = self.remote_addr {\n                req.extensions_mut().insert(RemoteAddr(addr));\n            }\n            self.inner.call(req)\n        }\n    }\n}\n\nmod run {\n    pub trait Run {\n        #[allow(async_fn_in_trait)]\n        async fn run<F, A>(server: super::Server<F, A, Self>)\n        where\n            F: super::Filter + Clone + Send + Sync + 'static,\n            <F::Future as super::TryFuture>::Ok: super::Reply,\n            <F::Future as super::TryFuture>::Error: super::IsReject,\n            A: super::accept::Accept,\n            Self: Sized;\n    }\n\n    #[derive(Debug)]\n    pub struct Standard;\n\n    impl Run for Standard {\n        async fn run<F, A>(mut server: super::Server<F, A, Self>)\n        where\n            F: super::Filter + Clone + Send + Sync + 'static,\n            <F::Future as super::TryFuture>::Ok: super::Reply,\n            <F::Future as super::TryFuture>::Error: super::IsReject,\n            A: super::accept::Accept,\n            Self: Sized,\n        {\n            let pipeline = server.pipeline;\n            loop {\n                let accepting = match server.acceptor.accept().await {\n                    Ok(fut) => fut,\n                    Err(err) => {\n                        handle_accept_error(err).await;\n                        continue;\n                    }\n                };\n                let svc = crate::service(server.filter.clone());\n                tokio::spawn(async move {\n                    let (io, remote_addr) = match accepting.await {\n                        Ok(pair) => pair,\n                        Err(err) => {\n                            tracing::debug!(\"server accept error: {:?}\", err);\n                            return;\n                        }\n                    };\n                    let svc = super::middleware::RemoteAddrService::new(svc, remote_addr);\n                    let svc = hyper_util::service::TowerToHyperService::new(svc);\n                    if let Err(err) = hyper_util::server::conn::auto::Builder::new(\n                        hyper_util::rt::TokioExecutor::new(),\n                    )\n                    .http1()\n                    .pipeline_flush(pipeline)\n                    .serve_connection_with_upgrades(io, svc)\n                    .await\n                    {\n                        tracing::error!(\"server connection error: {:?}\", err)\n                    }\n                });\n            }\n        }\n    }\n\n    #[derive(Debug)]\n    pub struct Graceful<Fut>(pub(super) Fut);\n\n    impl<Fut> Run for Graceful<Fut>\n    where\n        Fut: super::Future<Output = ()> + Send + 'static,\n    {\n        async fn run<F, A>(mut server: super::Server<F, A, Self>)\n        where\n            F: super::Filter + Clone + Send + Sync + 'static,\n            <F::Future as super::TryFuture>::Ok: super::Reply,\n            <F::Future as super::TryFuture>::Error: super::IsReject,\n            A: super::accept::Accept,\n            Self: Sized,\n        {\n            use futures_util::future;\n\n            let pipeline = server.pipeline;\n            let graceful_util = hyper_util::server::graceful::GracefulShutdown::new();\n            let mut shutdown_signal = std::pin::pin!(server.runner.0);\n            loop {\n                let accept = std::pin::pin!(server.acceptor.accept());\n                let accepting = match future::select(accept, &mut shutdown_signal).await {\n                    future::Either::Left((Ok(fut), _)) => fut,\n                    future::Either::Left((Err(err), _)) => {\n                        handle_accept_error(err).await;\n                        continue;\n                    }\n                    future::Either::Right(((), _)) => {\n                        tracing::debug!(\"shutdown signal received, starting graceful shutdown\");\n                        break;\n                    }\n                };\n                let svc = crate::service(server.filter.clone());\n                let watcher = graceful_util.watcher();\n                tokio::spawn(async move {\n                    let (io, remote_addr) = match accepting.await {\n                        Ok(pair) => pair,\n                        Err(err) => {\n                            tracing::debug!(\"server accepting error: {:?}\", err);\n                            return;\n                        }\n                    };\n                    let svc = super::middleware::RemoteAddrService::new(svc, remote_addr);\n                    let svc = hyper_util::service::TowerToHyperService::new(svc);\n                    let mut hyper = hyper_util::server::conn::auto::Builder::new(\n                        hyper_util::rt::TokioExecutor::new(),\n                    );\n                    hyper.http1().pipeline_flush(pipeline);\n                    let conn = hyper.serve_connection_with_upgrades(io, svc);\n                    let conn = watcher.watch(conn);\n                    if let Err(err) = conn.await {\n                        tracing::error!(\"server connection error: {:?}\", err)\n                    }\n                });\n            }\n\n            drop(server.acceptor); // close listener\n            graceful_util.shutdown().await;\n        }\n    }\n\n    // TODO: allow providing your own handler\n    async fn handle_accept_error(e: std::io::Error) {\n        if is_connection_error(&e) {\n            return;\n        }\n        // [From `hyper::Server` in 0.14](https://github.com/hyperium/hyper/blob/v0.14.27/src/server/tcp.rs#L186)\n        //\n        // > A possible scenario is that the process has hit the max open files\n        // > allowed, and so trying to accept a new connection will fail with\n        // > `EMFILE`. In some cases, it's preferable to just wait for some time, if\n        // > the application will likely close some files (or connections), and try\n        // > to accept the connection again. If this option is `true`, the error\n        // > will be logged at the `error` level, since it is still a big deal,\n        // > and then the listener will sleep for 1 second.\n        tracing::error!(\"accept error: {:?}\", e);\n        tokio::time::sleep(std::time::Duration::from_secs(1)).await;\n    }\n\n    fn is_connection_error(e: &std::io::Error) -> bool {\n        // some errors that occur on the TCP stream are emitted when\n        // accepting, they can be ignored.\n        matches!(\n            e.kind(),\n            std::io::ErrorKind::ConnectionRefused\n                | std::io::ErrorKind::ConnectionAborted\n                | std::io::ErrorKind::ConnectionReset\n        )\n    }\n}\n"
  },
  {
    "path": "src/service.rs",
    "content": "//! Convert `Filter`s into `Service`s\n\npub use crate::filter::service::service;\n"
  },
  {
    "path": "src/test.rs",
    "content": "//! Test utilities to test your filters.\n//!\n//! [`Filter`](../trait.Filter.html)s can be easily tested without starting up an HTTP\n//! server, by making use of the [`RequestBuilder`](./struct.RequestBuilder.html) in this\n//! module.\n//!\n//! # Testing Filters\n//!\n//! It's easy to test filters, especially if smaller filters are used to build\n//! up your full set. Consider these example filters:\n//!\n//! ```\n//! use warp::Filter;\n//!\n//! fn sum() -> impl Filter<Extract = (u32,), Error = warp::Rejection> + Copy {\n//!     warp::path::param()\n//!         .and(warp::path::param())\n//!         .map(|x: u32, y: u32| {\n//!             x + y\n//!         })\n//! }\n//!\n//! fn math() -> impl Filter<Extract = (String,), Error = warp::Rejection> + Copy {\n//!     warp::post()\n//!         .and(sum())\n//!         .map(|z: u32| {\n//!             format!(\"Sum = {}\", z)\n//!         })\n//! }\n//! ```\n//!\n//! We can test some requests against the `sum` filter like this:\n//!\n//! ```\n//! # use warp::Filter;\n//! #[tokio::test]\n//! async fn test_sum() {\n//! #    let sum = || warp::any().map(|| 3);\n//!     let filter = sum();\n//!\n//!     // Execute `sum` and get the `Extract` back.\n//!     let value = warp::test::request()\n//!         .path(\"/1/2\")\n//!         .filter(&filter)\n//!         .await\n//!         .unwrap();\n//!     assert_eq!(value, 3);\n//!\n//!     // Or simply test if a request matches (doesn't reject).\n//!     assert!(\n//!         warp::test::request()\n//!             .path(\"/1/-5\")\n//!             .matches(&filter)\n//!             .await\n//!     );\n//! }\n//! ```\n//!\n//! If the filter returns something that implements `Reply`, and thus can be\n//! turned into a response sent back to the client, we can test what exact\n//! response is returned. The `math` filter uses the `sum` filter, but returns\n//! a `String` that can be turned into a response.\n//!\n//! ```\n//! # use warp::Filter;\n//! #[test]\n//! fn test_math() {\n//! #    let math = || warp::any().map(warp::reply);\n//!     let filter = math();\n//!\n//!     let res = warp::test::request()\n//!         .path(\"/1/2\")\n//!         .reply(&filter);\n//!     assert_eq!(res.status(), 405, \"GET is not allowed\");\n//!\n//!     let res = warp::test::request()\n//!         .method(\"POST\")\n//!         .path(\"/1/2\")\n//!         .reply(&filter);\n//!     assert_eq!(res.status(), 200);\n//!     assert_eq!(res.body(), \"Sum is 3\");\n//! }\n//! ```\nuse std::convert::TryFrom;\nuse std::error::Error as StdError;\nuse std::fmt;\nuse std::future::Future;\nuse std::net::SocketAddr;\n#[cfg(feature = \"websocket\")]\nuse std::pin::Pin;\n#[cfg(feature = \"websocket\")]\nuse std::task::Context;\n#[cfg(feature = \"websocket\")]\nuse std::task::Poll;\n\nuse bytes::Bytes;\n#[cfg(feature = \"websocket\")]\nuse futures_channel::mpsc;\n#[cfg(feature = \"websocket\")]\nuse futures_util::StreamExt;\nuse futures_util::{future, FutureExt, TryFutureExt};\nuse http::{\n    header::{HeaderName, HeaderValue},\n    Response,\n};\nuse http_body_util::BodyExt;\nuse serde::Serialize;\n#[cfg(feature = \"websocket\")]\nuse tokio::sync::oneshot;\n\nuse crate::filter::Filter;\nuse crate::filters::addr::RemoteAddr;\n#[cfg(feature = \"websocket\")]\nuse crate::filters::ws::Message;\nuse crate::reject::IsReject;\nuse crate::reply::Reply;\nuse crate::route::{self, Route};\nuse crate::Request;\n#[cfg(feature = \"websocket\")]\nuse crate::{Sink, Stream};\n\nuse self::inner::OneOrTuple;\n\n/// Starts a new test `RequestBuilder`.\npub fn request() -> RequestBuilder {\n    RequestBuilder {\n        req: Request::default(),\n    }\n}\n\n/// Starts a new test `WsBuilder`.\n#[cfg(feature = \"websocket\")]\npub fn ws() -> WsBuilder {\n    WsBuilder { req: request() }\n}\n\n/// A request builder for testing filters.\n///\n/// See [module documentation](crate::test) for an overview.\n#[must_use = \"RequestBuilder does nothing on its own\"]\n#[derive(Debug)]\npub struct RequestBuilder {\n    req: Request,\n}\n\n/// A Websocket builder for testing filters.\n///\n/// See [module documentation](crate::test) for an overview.\n#[cfg(feature = \"websocket\")]\n#[must_use = \"WsBuilder does nothing on its own\"]\n#[derive(Debug)]\npub struct WsBuilder {\n    req: RequestBuilder,\n}\n\n/// A test client for Websocket filters.\n#[cfg(feature = \"websocket\")]\npub struct WsClient {\n    tx: mpsc::UnboundedSender<crate::ws::Message>,\n    rx: mpsc::UnboundedReceiver<Result<crate::ws::Message, crate::error::Error>>,\n}\n\n/// An error from Websocket filter tests.\n#[derive(Debug)]\npub struct WsError {\n    cause: Box<dyn StdError + Send + Sync>,\n}\n\nimpl RequestBuilder {\n    /// Sets the method of this builder.\n    ///\n    /// The default if not set is `GET`.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// let req = warp::test::request()\n    ///     .method(\"POST\");\n    /// ```\n    ///\n    /// # Panic\n    ///\n    /// This panics if the passed string is not able to be parsed as a valid\n    /// `Method`.\n    pub fn method(mut self, method: &str) -> Self {\n        *self.req.method_mut() = method.parse().expect(\"valid method\");\n        self\n    }\n\n    /// Sets the request path of this builder.\n    ///\n    /// The default is not set is `/`.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// let req = warp::test::request()\n    ///     .path(\"/todos/33\");\n    /// ```\n    ///\n    /// # Panic\n    ///\n    /// This panics if the passed string is not able to be parsed as a valid\n    /// `Uri`.\n    pub fn path(mut self, p: &str) -> Self {\n        let uri = p.parse().expect(\"test request path invalid\");\n        *self.req.uri_mut() = uri;\n        self\n    }\n\n    /// Set a header for this request.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// let req = warp::test::request()\n    ///     .header(\"accept\", \"application/json\");\n    /// ```\n    ///\n    /// # Panic\n    ///\n    /// This panics if the passed strings are not able to be parsed as a valid\n    /// `HeaderName` and `HeaderValue`.\n    pub fn header<K, V>(mut self, key: K, value: V) -> Self\n    where\n        HeaderName: TryFrom<K>,\n        HeaderValue: TryFrom<V>,\n    {\n        let name: HeaderName = TryFrom::try_from(key)\n            .map_err(|_| ())\n            .expect(\"invalid header name\");\n        let value = TryFrom::try_from(value)\n            .map_err(|_| ())\n            .expect(\"invalid header value\");\n        self.req.headers_mut().insert(name, value);\n        self\n    }\n\n    /// Set the remote address of this request\n    ///\n    /// Default is no remote address.\n    ///\n    /// # Example\n    /// ```\n    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};\n    ///\n    /// let req = warp::test::request()\n    ///     .remote_addr(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080));\n    /// ```\n    pub fn remote_addr(mut self, addr: SocketAddr) -> Self {\n        self.req.extensions_mut().insert(RemoteAddr(addr));\n        self\n    }\n\n    /// Add a type to the request's `http::Extensions`.\n    pub fn extension<T>(mut self, ext: T) -> Self\n    where\n        T: Clone + Send + Sync + 'static,\n    {\n        self.req.extensions_mut().insert(ext);\n        self\n    }\n\n    /// Set the bytes of this request body.\n    ///\n    /// Default is an empty body.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// let req = warp::test::request()\n    ///     .body(\"foo=bar&baz=quux\");\n    /// ```\n    pub fn body(mut self, body: impl AsRef<[u8]>) -> Self {\n        let body = body.as_ref().to_vec();\n        let len = body.len();\n        *self.req.body_mut() = body.into();\n        self.header(\"content-length\", len.to_string())\n    }\n\n    /// Set the bytes of this request body by serializing a value into JSON.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// let req = warp::test::request()\n    ///     .json(&true);\n    /// ```\n    pub fn json(mut self, val: &impl Serialize) -> Self {\n        let vec = serde_json::to_vec(val).expect(\"json() must serialize to JSON\");\n        let len = vec.len();\n        *self.req.body_mut() = vec.into();\n        self.header(\"content-length\", len.to_string())\n            .header(\"content-type\", \"application/json\")\n    }\n\n    /// Tries to apply the `Filter` on this request.\n    ///\n    /// # Example\n    ///\n    /// ```no_run\n    /// async {\n    ///     let param = warp::path::param::<u32>();\n    ///\n    ///     let ex = warp::test::request()\n    ///         .path(\"/41\")\n    ///         .filter(&param)\n    ///         .await\n    ///         .unwrap();\n    ///\n    ///     assert_eq!(ex, 41);\n    ///\n    ///     assert!(\n    ///         warp::test::request()\n    ///             .path(\"/foo\")\n    ///             .filter(&param)\n    ///             .await\n    ///             .is_err()\n    ///     );\n    ///};\n    /// ```\n    pub async fn filter<F>(self, f: &F) -> Result<<F::Extract as OneOrTuple>::Output, F::Error>\n    where\n        F: Filter,\n        F::Future: Send + 'static,\n        F::Extract: OneOrTuple + Send + 'static,\n        F::Error: Send + 'static,\n    {\n        self.apply_filter(f).await.map(|ex| ex.one_or_tuple())\n    }\n\n    /// Returns whether the `Filter` matches this request, or rejects it.\n    ///\n    /// # Example\n    ///\n    /// ```no_run\n    /// async {\n    ///     let get = warp::get();\n    ///     let post = warp::post();\n    ///\n    ///     assert!(\n    ///         warp::test::request()\n    ///             .method(\"GET\")\n    ///             .matches(&get)\n    ///             .await\n    ///     );\n    ///\n    ///     assert!(\n    ///         !warp::test::request()\n    ///             .method(\"GET\")\n    ///             .matches(&post)\n    ///             .await\n    ///     );\n    ///};\n    /// ```\n    pub async fn matches<F>(self, f: &F) -> bool\n    where\n        F: Filter,\n        F::Future: Send + 'static,\n        F::Extract: Send + 'static,\n        F::Error: Send + 'static,\n    {\n        self.apply_filter(f).await.is_ok()\n    }\n\n    /// Returns `Response` provided by applying the `Filter`.\n    ///\n    /// This requires that the supplied `Filter` return a [`Reply`].\n    pub async fn reply<F>(self, f: &F) -> Response<Bytes>\n    where\n        F: Filter + 'static,\n        F::Extract: Reply + Send,\n        F::Error: IsReject + Send,\n    {\n        // TODO: de-duplicate this and apply_filter()\n        assert!(!route::is_set(), \"nested test filter calls\");\n\n        let route = Route::new(self.req);\n        let mut fut = Box::pin(\n            route::set(&route, move || f.filter(crate::filter::Internal)).then(|result| {\n                let res = match result {\n                    Ok(rep) => rep.into_response(),\n                    Err(rej) => {\n                        tracing::debug!(\"rejected: {:?}\", rej);\n                        rej.into_response()\n                    }\n                };\n                let (parts, body) = res.into_parts();\n                {\n                    body.collect()\n                        .map_ok(|chunk| Response::from_parts(parts, chunk.to_bytes()))\n                }\n            }),\n        );\n\n        let fut = future::poll_fn(move |cx| route::set(&route, || fut.as_mut().poll(cx)));\n\n        fut.await.expect(\"reply shouldn't fail\")\n    }\n\n    fn apply_filter<F>(self, f: &F) -> impl Future<Output = Result<F::Extract, F::Error>>\n    where\n        F: Filter,\n        F::Future: Send + 'static,\n        F::Extract: Send + 'static,\n        F::Error: Send + 'static,\n    {\n        assert!(!route::is_set(), \"nested test filter calls\");\n\n        let route = Route::new(self.req);\n        let mut fut = Box::pin(route::set(&route, move || {\n            f.filter(crate::filter::Internal)\n        }));\n        future::poll_fn(move |cx| route::set(&route, || fut.as_mut().poll(cx)))\n    }\n}\n\n#[cfg(feature = \"websocket\")]\nimpl WsBuilder {\n    /// Sets the request path of this builder.\n    ///\n    /// The default is not set is `/`.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// let req = warp::test::ws()\n    ///     .path(\"/chat\");\n    /// ```\n    ///\n    /// # Panic\n    ///\n    /// This panics if the passed string is not able to be parsed as a valid\n    /// `Uri`.\n    pub fn path(self, p: &str) -> Self {\n        WsBuilder {\n            req: self.req.path(p),\n        }\n    }\n\n    /// Set a header for this request.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// let req = warp::test::ws()\n    ///     .header(\"foo\", \"bar\");\n    /// ```\n    ///\n    /// # Panic\n    ///\n    /// This panics if the passed strings are not able to be parsed as a valid\n    /// `HeaderName` and `HeaderValue`.\n    pub fn header<K, V>(self, key: K, value: V) -> Self\n    where\n        HeaderName: TryFrom<K>,\n        HeaderValue: TryFrom<V>,\n    {\n        WsBuilder {\n            req: self.req.header(key, value),\n        }\n    }\n\n    /// Execute this Websocket request against the provided filter.\n    ///\n    /// If the handshake succeeds, returns a `WsClient`.\n    ///\n    /// # Example\n    ///\n    /// ```no_run\n    /// use futures_util::future;\n    /// use warp::Filter;\n    /// #[tokio::main]\n    /// # async fn main() {\n    ///\n    /// // Some route that accepts websockets (but drops them immediately).\n    /// let route = warp::ws()\n    ///     .map(|ws: warp::ws::Ws| {\n    ///         ws.on_upgrade(|_| future::ready(()))\n    ///     });\n    ///\n    /// let client = warp::test::ws()\n    ///     .handshake(route)\n    ///     .await\n    ///     .expect(\"handshake\");\n    /// # }\n    /// ```\n    pub async fn handshake<F>(self, f: F) -> Result<WsClient, WsError>\n    where\n        F: Filter + Clone + Send + Sync + 'static,\n        F::Extract: Reply + Send,\n        F::Error: IsReject + Send,\n    {\n        let (upgraded_tx, upgraded_rx) = oneshot::channel();\n        let (wr_tx, wr_rx) = mpsc::unbounded();\n        let (rd_tx, rd_rx) = mpsc::unbounded();\n\n        tokio::spawn(async move {\n            use tokio_tungstenite::tungstenite::protocol;\n\n            let listener = tokio::net::TcpListener::bind(SocketAddr::from(([127, 0, 0, 1], 0)))\n                .await\n                .expect(\"binding\");\n            let addr = listener.local_addr().unwrap();\n            tokio::spawn(async move {\n                crate::serve(f).incoming(listener).run().await;\n            });\n\n            let mut req = self\n                .req\n                .header(\"connection\", \"upgrade\")\n                .header(\"upgrade\", \"websocket\")\n                .header(\"sec-websocket-version\", \"13\")\n                .header(\"sec-websocket-key\", \"dGhlIHNhbXBsZSBub25jZQ==\")\n                .req;\n\n            let query_string = match req.uri().query() {\n                Some(q) => format!(\"?{}\", q),\n                None => String::from(\"\"),\n            };\n\n            let uri = format!(\"http://{}{}{}\", addr, req.uri().path(), query_string)\n                .parse()\n                .expect(\"addr + path is valid URI\");\n\n            *req.uri_mut() = uri;\n\n            let upgrade = async move {\n                let io = tokio::net::TcpStream::connect(addr).await?;\n                let io = hyper_util::rt::TokioIo::new(io);\n                let (mut tx, conn) = hyper::client::conn::http1::handshake(io).await?;\n                tokio::spawn(async move {\n                    let _ = conn.with_upgrades().await;\n                });\n                let res = tx.send_request(req).await?;\n                hyper::upgrade::on(res)\n                    .await\n                    .map_err(|e| Box::new(e) as Box<dyn StdError + Send + Sync>)\n            };\n\n            let upgraded = match upgrade.await {\n                Ok(up) => {\n                    let _ = upgraded_tx.send(Ok(()));\n                    up\n                }\n                Err(err) => {\n                    let _ = upgraded_tx.send(Err(err));\n                    return;\n                }\n            };\n            let ws = crate::ws::WebSocket::from_raw_socket(\n                upgraded,\n                protocol::Role::Client,\n                Default::default(),\n            )\n            .await;\n\n            let (tx, rx) = ws.split();\n            let write = wr_rx.map(Ok).forward(tx).map(|_| ());\n\n            let read = rx\n                .take_while(|result| match result {\n                    Err(_) => future::ready(false),\n                    Ok(m) => future::ready(!m.is_close()),\n                })\n                .for_each(move |item| {\n                    rd_tx.unbounded_send(item).expect(\"ws receive error\");\n                    future::ready(())\n                });\n\n            future::join(write, read).await;\n        });\n\n        match upgraded_rx.await {\n            Ok(Ok(())) => Ok(WsClient {\n                tx: wr_tx,\n                rx: rd_rx,\n            }),\n            Ok(Err(err)) => Err(WsError::new(err)),\n            Err(_canceled) => panic!(\"websocket handshake thread panicked\"),\n        }\n    }\n}\n\n#[cfg(feature = \"websocket\")]\nimpl WsClient {\n    /// Send a \"text\" websocket message to the server.\n    pub async fn send_text(&mut self, text: impl Into<String>) {\n        self.send(crate::ws::Message::text(text.into())).await;\n    }\n\n    /// Send a websocket message to the server.\n    pub async fn send(&mut self, msg: crate::ws::Message) {\n        self.tx.unbounded_send(msg).unwrap();\n    }\n\n    /// Receive a websocket message from the server.\n    pub async fn recv(&mut self) -> Result<crate::filters::ws::Message, WsError> {\n        self.rx\n            .next()\n            .await\n            .map(|result| result.map_err(WsError::new))\n            .unwrap_or_else(|| {\n                // websocket is closed\n                Err(WsError::new(\"closed\"))\n            })\n    }\n\n    /// Assert the server has closed the connection.\n    pub async fn recv_closed(&mut self) -> Result<(), WsError> {\n        self.rx\n            .next()\n            .await\n            .map(|result| match result {\n                Ok(msg) => Err(WsError::new(format!(\"received message: {:?}\", msg))),\n                Err(err) => Err(WsError::new(err)),\n            })\n            .unwrap_or_else(|| {\n                // closed successfully\n                Ok(())\n            })\n    }\n\n    fn pinned_tx(self: Pin<&mut Self>) -> Pin<&mut mpsc::UnboundedSender<crate::ws::Message>> {\n        let this = Pin::into_inner(self);\n        Pin::new(&mut this.tx)\n    }\n}\n\n#[cfg(feature = \"websocket\")]\nimpl fmt::Debug for WsClient {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"WsClient\").finish()\n    }\n}\n\n#[cfg(feature = \"websocket\")]\nimpl Sink<crate::ws::Message> for WsClient {\n    type Error = WsError;\n\n    fn poll_ready(\n        self: Pin<&mut Self>,\n        context: &mut Context<'_>,\n    ) -> Poll<Result<(), Self::Error>> {\n        self.pinned_tx().poll_ready(context).map_err(WsError::new)\n    }\n\n    fn start_send(self: Pin<&mut Self>, message: Message) -> Result<(), Self::Error> {\n        self.pinned_tx().start_send(message).map_err(WsError::new)\n    }\n\n    fn poll_flush(\n        self: Pin<&mut Self>,\n        context: &mut Context<'_>,\n    ) -> Poll<Result<(), Self::Error>> {\n        self.pinned_tx().poll_flush(context).map_err(WsError::new)\n    }\n\n    fn poll_close(\n        self: Pin<&mut Self>,\n        context: &mut Context<'_>,\n    ) -> Poll<Result<(), Self::Error>> {\n        self.pinned_tx().poll_close(context).map_err(WsError::new)\n    }\n}\n\n#[cfg(feature = \"websocket\")]\nimpl Stream for WsClient {\n    type Item = Result<crate::ws::Message, WsError>;\n\n    fn poll_next(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        let this = Pin::into_inner(self);\n        let rx = Pin::new(&mut this.rx);\n        match rx.poll_next(context) {\n            Poll::Ready(Some(result)) => Poll::Ready(Some(result.map_err(WsError::new))),\n            Poll::Ready(None) => Poll::Ready(None),\n            Poll::Pending => Poll::Pending,\n        }\n    }\n}\n\n// ===== impl WsError =====\n\n#[cfg(feature = \"websocket\")]\nimpl WsError {\n    fn new<E: Into<Box<dyn StdError + Send + Sync>>>(cause: E) -> Self {\n        WsError {\n            cause: cause.into(),\n        }\n    }\n}\n\nimpl fmt::Display for WsError {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"websocket error: {}\", self.cause)\n    }\n}\n\nimpl StdError for WsError {\n    fn description(&self) -> &str {\n        \"websocket error\"\n    }\n}\n\nmod inner {\n    pub trait OneOrTuple {\n        type Output;\n\n        fn one_or_tuple(self) -> Self::Output;\n    }\n\n    impl OneOrTuple for () {\n        type Output = ();\n        fn one_or_tuple(self) -> Self::Output {}\n    }\n\n    macro_rules! one_or_tuple {\n        ($type1:ident) => {\n            impl<$type1> OneOrTuple for ($type1,) {\n                type Output = $type1;\n                fn one_or_tuple(self) -> Self::Output {\n                    self.0\n                }\n            }\n        };\n        ($type1:ident, $( $type:ident ),*) => {\n            one_or_tuple!($( $type ),*);\n\n            impl<$type1, $($type),*> OneOrTuple for ($type1, $($type),*) {\n                type Output = Self;\n                fn one_or_tuple(self) -> Self::Output {\n                    self\n                }\n            }\n        }\n    }\n\n    one_or_tuple! {\n        T1,\n        T2,\n        T3,\n        T4,\n        T5,\n        T6,\n        T7,\n        T8,\n        T9,\n        T10,\n        T11,\n        T12,\n        T13,\n        T14,\n        T15,\n        T16\n    }\n}\n"
  },
  {
    "path": "src/tls.rs",
    "content": "use std::fmt;\nuse std::fs::File;\nuse std::future::Future;\nuse std::io::{self, BufReader, Cursor, Read};\nuse std::net::SocketAddr;\nuse std::path::{Path, PathBuf};\nuse std::pin::Pin;\nuse std::sync::Arc;\nuse std::task::{Context, Poll};\nuse tokio::io::{AsyncRead, AsyncWrite, ReadBuf};\n\nuse futures_util::ready;\nuse hyper::server::accept::Accept;\nuse hyper::server::conn::{AddrIncoming, AddrStream};\nuse tokio_rustls::rustls::server::WebPkiClientVerifier;\nuse tokio_rustls::rustls::{Error as TlsError, RootCertStore, ServerConfig};\n\nuse crate::transport::Transport;\n\n/// Represents errors that can occur building the TlsConfig\n#[derive(Debug)]\npub(crate) enum TlsConfigError {\n    Io(io::Error),\n    /// An Error parsing the Certificate\n    CertParseError,\n    /// Identity PEM is invalid\n    InvalidIdentityPem,\n    /// Identity PEM is missing a private key such as RSA, ECC or PKCS8\n    MissingPrivateKey,\n    /// Unknown private key format\n    UnknownPrivateKeyFormat,\n    /// An error from an empty key\n    EmptyKey,\n    /// An error from an invalid key\n    InvalidKey(TlsError),\n}\n\nimpl fmt::Display for TlsConfigError {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            TlsConfigError::Io(err) => err.fmt(f),\n            TlsConfigError::CertParseError => write!(f, \"certificate parse error\"),\n            TlsConfigError::UnknownPrivateKeyFormat => write!(f, \"unknown private key format\"),\n            TlsConfigError::MissingPrivateKey => write!(\n                f,\n                \"Identity PEM is missing a private key such as RSA, ECC or PKCS8\"\n            ),\n            TlsConfigError::InvalidIdentityPem => write!(f, \"identity PEM is invalid\"),\n            TlsConfigError::EmptyKey => write!(f, \"key contains no private key\"),\n            TlsConfigError::InvalidKey(err) => write!(f, \"key contains an invalid key, {}\", err),\n        }\n    }\n}\n\nimpl std::error::Error for TlsConfigError {}\n\n/// Tls client authentication configuration.\npub(crate) enum TlsClientAuth {\n    /// No client auth.\n    Off,\n    /// Allow any anonymous or authenticated client.\n    Optional(Box<dyn Read + Send + Sync>),\n    /// Allow any authenticated client.\n    Required(Box<dyn Read + Send + Sync>),\n}\n\n/// Builder to set the configuration for the Tls server.\npub(crate) struct TlsConfigBuilder {\n    cert: Box<dyn Read + Send + Sync>,\n    key: Box<dyn Read + Send + Sync>,\n    client_auth: TlsClientAuth,\n    ocsp_resp: Vec<u8>,\n}\n\nimpl fmt::Debug for TlsConfigBuilder {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"TlsConfigBuilder\").finish()\n    }\n}\n\nimpl TlsConfigBuilder {\n    /// Create a new TlsConfigBuilder\n    pub(crate) fn new() -> TlsConfigBuilder {\n        TlsConfigBuilder {\n            key: Box::new(io::empty()),\n            cert: Box::new(io::empty()),\n            client_auth: TlsClientAuth::Off,\n            ocsp_resp: Vec::new(),\n        }\n    }\n\n    /// sets the Tls key via File Path, returns `TlsConfigError::IoError` if the file cannot be open\n    pub(crate) fn key_path(mut self, path: impl AsRef<Path>) -> Self {\n        self.key = Box::new(LazyFile {\n            path: path.as_ref().into(),\n            file: None,\n        });\n        self\n    }\n\n    /// sets the Tls key via bytes slice\n    pub(crate) fn key(mut self, key: &[u8]) -> Self {\n        self.key = Box::new(Cursor::new(Vec::from(key)));\n        self\n    }\n\n    /// Specify the file path for the TLS certificate to use.\n    pub(crate) fn cert_path(mut self, path: impl AsRef<Path>) -> Self {\n        self.cert = Box::new(LazyFile {\n            path: path.as_ref().into(),\n            file: None,\n        });\n        self\n    }\n\n    /// sets the Tls certificate via bytes slice\n    pub(crate) fn cert(mut self, cert: &[u8]) -> Self {\n        self.cert = Box::new(Cursor::new(Vec::from(cert)));\n        self\n    }\n\n    /// Sets the trust anchor for optional Tls client authentication via file path.\n    ///\n    /// Anonymous and authenticated clients will be accepted. If no trust anchor is provided by any\n    /// of the `client_auth_` methods, then client authentication is disabled by default.\n    pub(crate) fn client_auth_optional_path(mut self, path: impl AsRef<Path>) -> Self {\n        let file = Box::new(LazyFile {\n            path: path.as_ref().into(),\n            file: None,\n        });\n        self.client_auth = TlsClientAuth::Optional(file);\n        self\n    }\n\n    /// Sets the trust anchor for optional Tls client authentication via bytes slice.\n    ///\n    /// Anonymous and authenticated clients will be accepted. If no trust anchor is provided by any\n    /// of the `client_auth_` methods, then client authentication is disabled by default.\n    pub(crate) fn client_auth_optional(mut self, trust_anchor: &[u8]) -> Self {\n        let cursor = Box::new(Cursor::new(Vec::from(trust_anchor)));\n        self.client_auth = TlsClientAuth::Optional(cursor);\n        self\n    }\n\n    /// Sets the trust anchor for required Tls client authentication via file path.\n    ///\n    /// Only authenticated clients will be accepted. If no trust anchor is provided by any of the\n    /// `client_auth_` methods, then client authentication is disabled by default.\n    pub(crate) fn client_auth_required_path(mut self, path: impl AsRef<Path>) -> Self {\n        let file = Box::new(LazyFile {\n            path: path.as_ref().into(),\n            file: None,\n        });\n        self.client_auth = TlsClientAuth::Required(file);\n        self\n    }\n\n    /// Sets the trust anchor for required Tls client authentication via bytes slice.\n    ///\n    /// Only authenticated clients will be accepted. If no trust anchor is provided by any of the\n    /// `client_auth_` methods, then client authentication is disabled by default.\n    pub(crate) fn client_auth_required(mut self, trust_anchor: &[u8]) -> Self {\n        let cursor = Box::new(Cursor::new(Vec::from(trust_anchor)));\n        self.client_auth = TlsClientAuth::Required(cursor);\n        self\n    }\n\n    /// sets the DER-encoded OCSP response\n    pub(crate) fn ocsp_resp(mut self, ocsp_resp: &[u8]) -> Self {\n        self.ocsp_resp = Vec::from(ocsp_resp);\n        self\n    }\n\n    pub(crate) fn build(mut self) -> Result<ServerConfig, TlsConfigError> {\n        let mut cert_rdr = BufReader::new(self.cert);\n        let cert = rustls_pemfile::certs(&mut cert_rdr)\n            .collect::<Result<Vec<_>, _>>()\n            .map_err(|_e| TlsConfigError::CertParseError)?;\n\n        let mut key_vec = Vec::new();\n        self.key\n            .read_to_end(&mut key_vec)\n            .map_err(TlsConfigError::Io)?;\n\n        if key_vec.is_empty() {\n            return Err(TlsConfigError::EmptyKey);\n        }\n\n        let mut key_opt = None;\n        let mut key_cur = std::io::Cursor::new(key_vec);\n        for item in rustls_pemfile::read_all(&mut key_cur)\n            .collect::<Result<Vec<_>, _>>()\n            .map_err(|_e| TlsConfigError::InvalidIdentityPem)?\n        {\n            match item {\n                rustls_pemfile::Item::Pkcs1Key(k) => key_opt = Some(k.into()),\n                rustls_pemfile::Item::Pkcs8Key(k) => key_opt = Some(k.into()),\n                rustls_pemfile::Item::Sec1Key(k) => key_opt = Some(k.into()),\n                _ => return Err(TlsConfigError::UnknownPrivateKeyFormat),\n            }\n        }\n        let key = match key_opt {\n            Some(v) => v,\n            _ => return Err(TlsConfigError::MissingPrivateKey),\n        };\n\n        fn read_trust_anchor(\n            trust_anchor: Box<dyn Read + Send + Sync>,\n        ) -> Result<RootCertStore, TlsConfigError> {\n            let trust_anchors = {\n                let mut reader = BufReader::new(trust_anchor);\n                rustls_pemfile::certs(&mut reader)\n                    .collect::<Result<Vec<_>, _>>()\n                    .map_err(TlsConfigError::Io)?\n            };\n\n            let mut store = RootCertStore::empty();\n            let (added, _skipped) = store.add_parsable_certificates(trust_anchors);\n            if added == 0 {\n                return Err(TlsConfigError::CertParseError);\n            }\n\n            Ok(store)\n        }\n\n        let config = {\n            let builder = ServerConfig::builder();\n            let mut config = match self.client_auth {\n                TlsClientAuth::Off => builder.with_no_client_auth(),\n                TlsClientAuth::Optional(trust_anchor) => {\n                    let verifier =\n                        WebPkiClientVerifier::builder(read_trust_anchor(trust_anchor)?.into())\n                            .allow_unauthenticated()\n                            .build()\n                            .map_err(|_| TlsConfigError::CertParseError)?;\n                    builder.with_client_cert_verifier(verifier)\n                }\n                TlsClientAuth::Required(trust_anchor) => {\n                    let verifier =\n                        WebPkiClientVerifier::builder(read_trust_anchor(trust_anchor)?.into())\n                            .build()\n                            .map_err(|_| TlsConfigError::CertParseError)?;\n                    builder.with_client_cert_verifier(verifier)\n                }\n            }\n            .with_single_cert_with_ocsp(cert, key, self.ocsp_resp)\n            .map_err(TlsConfigError::InvalidKey)?;\n            config.alpn_protocols = vec![\"h2\".into(), \"http/1.1\".into()];\n            config\n        };\n\n        Ok(config)\n    }\n}\n\nstruct LazyFile {\n    path: PathBuf,\n    file: Option<File>,\n}\n\nimpl LazyFile {\n    fn lazy_read(&mut self, buf: &mut [u8]) -> io::Result<usize> {\n        if self.file.is_none() {\n            self.file = Some(File::open(&self.path)?);\n        }\n\n        self.file.as_mut().unwrap().read(buf)\n    }\n}\n\nimpl Read for LazyFile {\n    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {\n        self.lazy_read(buf).map_err(|err| {\n            let kind = err.kind();\n            io::Error::new(\n                kind,\n                format!(\"error reading file ({:?}): {}\", self.path.display(), err),\n            )\n        })\n    }\n}\n\nimpl Transport for TlsStream {\n    fn remote_addr(&self) -> Option<SocketAddr> {\n        Some(self.remote_addr)\n    }\n}\n\nenum State {\n    Handshaking(tokio_rustls::Accept<AddrStream>),\n    Streaming(tokio_rustls::server::TlsStream<AddrStream>),\n}\n\n// tokio_rustls::server::TlsStream doesn't expose constructor methods,\n// so we have to TlsAcceptor::accept and handshake to have access to it\n// TlsStream implements AsyncRead/AsyncWrite handshaking tokio_rustls::Accept first\npub(crate) struct TlsStream {\n    state: State,\n    remote_addr: SocketAddr,\n}\n\nimpl TlsStream {\n    fn new(stream: AddrStream, config: Arc<ServerConfig>) -> TlsStream {\n        let remote_addr = stream.remote_addr();\n        let accept = tokio_rustls::TlsAcceptor::from(config).accept(stream);\n        TlsStream {\n            state: State::Handshaking(accept),\n            remote_addr,\n        }\n    }\n}\n\nimpl AsyncRead for TlsStream {\n    fn poll_read(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &mut ReadBuf<'_>,\n    ) -> Poll<io::Result<()>> {\n        let pin = self.get_mut();\n        match pin.state {\n            State::Handshaking(ref mut accept) => match ready!(Pin::new(accept).poll(cx)) {\n                Ok(mut stream) => {\n                    let result = Pin::new(&mut stream).poll_read(cx, buf);\n                    pin.state = State::Streaming(stream);\n                    result\n                }\n                Err(err) => Poll::Ready(Err(err)),\n            },\n            State::Streaming(ref mut stream) => Pin::new(stream).poll_read(cx, buf),\n        }\n    }\n}\n\nimpl AsyncWrite for TlsStream {\n    fn poll_write(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n    ) -> Poll<io::Result<usize>> {\n        let pin = self.get_mut();\n        match pin.state {\n            State::Handshaking(ref mut accept) => match ready!(Pin::new(accept).poll(cx)) {\n                Ok(mut stream) => {\n                    let result = Pin::new(&mut stream).poll_write(cx, buf);\n                    pin.state = State::Streaming(stream);\n                    result\n                }\n                Err(err) => Poll::Ready(Err(err)),\n            },\n            State::Streaming(ref mut stream) => Pin::new(stream).poll_write(cx, buf),\n        }\n    }\n\n    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        match self.state {\n            State::Handshaking(_) => Poll::Ready(Ok(())),\n            State::Streaming(ref mut stream) => Pin::new(stream).poll_flush(cx),\n        }\n    }\n\n    fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        match self.state {\n            State::Handshaking(_) => Poll::Ready(Ok(())),\n            State::Streaming(ref mut stream) => Pin::new(stream).poll_shutdown(cx),\n        }\n    }\n}\n\npub(crate) struct TlsAcceptor {\n    config: Arc<ServerConfig>,\n    incoming: AddrIncoming,\n}\n\nimpl TlsAcceptor {\n    pub(crate) fn new(config: ServerConfig, incoming: AddrIncoming) -> TlsAcceptor {\n        TlsAcceptor {\n            config: Arc::new(config),\n            incoming,\n        }\n    }\n}\n\nimpl Accept for TlsAcceptor {\n    type Conn = TlsStream;\n    type Error = io::Error;\n\n    fn poll_accept(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Option<Result<Self::Conn, Self::Error>>> {\n        let pin = self.get_mut();\n        match ready!(Pin::new(&mut pin.incoming).poll_accept(cx)) {\n            Some(Ok(sock)) => Poll::Ready(Some(Ok(TlsStream::new(sock, pin.config.clone())))),\n            Some(Err(e)) => Poll::Ready(Some(Err(e))),\n            None => Poll::Ready(None),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn file_cert_key() {\n        TlsConfigBuilder::new()\n            .key_path(\"examples/tls/key.rsa\")\n            .cert_path(\"examples/tls/cert.pem\")\n            .build()\n            .unwrap();\n    }\n\n    #[test]\n    fn bytes_cert_key() {\n        let key = include_str!(\"../examples/tls/key.rsa\");\n        let cert = include_str!(\"../examples/tls/cert.pem\");\n\n        TlsConfigBuilder::new()\n            .key(key.as_bytes())\n            .cert(cert.as_bytes())\n            .build()\n            .unwrap();\n    }\n\n    #[test]\n    fn file_ecc_cert_key() {\n        TlsConfigBuilder::new()\n            .key_path(\"examples/tls/key.ecc\")\n            .cert_path(\"examples/tls/cert.ecc.pem\")\n            .build()\n            .unwrap();\n    }\n\n    #[test]\n    fn bytes_ecc_cert_key() {\n        let key = include_str!(\"../examples/tls/key.ecc\");\n        let cert = include_str!(\"../examples/tls/cert.ecc.pem\");\n\n        TlsConfigBuilder::new()\n            .key(key.as_bytes())\n            .cert(cert.as_bytes())\n            .build()\n            .unwrap();\n    }\n}\n"
  },
  {
    "path": "tests/addr.rs",
    "content": "#![deny(warnings)]\n\nuse std::net::{IpAddr, Ipv4Addr, SocketAddr};\n\n#[tokio::test]\nasync fn remote_addr_missing() {\n    let extract_remote_addr = warp::addr::remote();\n\n    let req = warp::test::request();\n    let resp = req.filter(&extract_remote_addr).await.unwrap();\n    assert_eq!(resp, None)\n}\n\n#[tokio::test]\nasync fn remote_addr_present() {\n    let extract_remote_addr = warp::addr::remote();\n\n    let req = warp::test::request().remote_addr(\"1.2.3.4:5678\".parse().unwrap());\n    let resp = req.filter(&extract_remote_addr).await.unwrap();\n    assert_eq!(\n        resp,\n        Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4)), 5678))\n    )\n}\n"
  },
  {
    "path": "tests/body.rs",
    "content": "#![deny(warnings)]\n\nuse bytes::Buf;\nuse futures_util::TryStreamExt;\nuse warp::Filter;\n\n#[tokio::test]\nasync fn matches() {\n    let _ = pretty_env_logger::try_init();\n\n    let concat = warp::body::bytes();\n\n    let req = warp::test::request().path(\"/nothing-matches-me\");\n\n    assert!(req.matches(&concat).await);\n\n    let p = warp::path(\"body\");\n    let req = warp::test::request().path(\"/body\");\n\n    let and = p.and(concat);\n\n    assert!(req.matches(&and).await);\n}\n\n#[tokio::test]\nasync fn server_error_if_taking_body_multiple_times() {\n    let _ = pretty_env_logger::try_init();\n\n    let concat = warp::body::bytes();\n    let double = concat.and(concat).map(|_, _| warp::reply());\n\n    let res = warp::test::request().reply(&double).await;\n\n    assert_eq!(res.status(), 500);\n    assert_eq!(res.body(), \"Request body consumed multiple times\");\n}\n\n#[tokio::test]\nasync fn content_length_limit() {\n    let _ = pretty_env_logger::try_init();\n\n    let limit = warp::body::content_length_limit(30).map(warp::reply);\n\n    let res = warp::test::request().reply(&limit).await;\n    assert_eq!(res.status(), 411, \"missing content-length returns 411\");\n\n    let res = warp::test::request()\n        .header(\"content-length\", \"999\")\n        .reply(&limit)\n        .await;\n    assert_eq!(res.status(), 413, \"over limit returns 413\");\n\n    let res = warp::test::request()\n        .header(\"content-length\", \"2\")\n        .reply(&limit)\n        .await;\n    assert_eq!(res.status(), 200, \"under limit succeeds\");\n}\n\n#[tokio::test]\nasync fn json() {\n    let _ = pretty_env_logger::try_init();\n\n    let json = warp::body::json::<Vec<i32>>();\n\n    let req = warp::test::request().body(\"[1, 2, 3]\");\n\n    let vec = req.filter(&json).await.unwrap();\n    assert_eq!(vec, &[1, 2, 3]);\n\n    let req = warp::test::request()\n        .header(\"content-type\", \"application/json\")\n        .body(\"[3, 2, 1]\");\n\n    let vec = req.filter(&json).await.unwrap();\n    assert_eq!(vec, &[3, 2, 1], \"matches content-type\");\n}\n\n#[tokio::test]\nasync fn json_rejects_bad_content_type() {\n    let _ = pretty_env_logger::try_init();\n\n    let json = warp::body::json::<Vec<i32>>().map(|_| warp::reply());\n\n    let req = warp::test::request()\n        .header(\"content-type\", \"text/xml\")\n        .body(\"[3, 2, 1]\");\n\n    let res = req.reply(&json).await;\n    assert_eq!(\n        res.status(),\n        415,\n        \"bad content-type should be 415 Unsupported Media Type\"\n    );\n}\n\n#[tokio::test]\nasync fn json_invalid() {\n    let _ = pretty_env_logger::try_init();\n\n    let json = warp::body::json::<Vec<i32>>().map(|vec| warp::reply::json(&vec));\n\n    let res = warp::test::request().body(\"lol#wat\").reply(&json).await;\n    assert_eq!(res.status(), 400);\n    let prefix = b\"Request body deserialize error: \";\n    assert_eq!(&res.body()[..prefix.len()], prefix);\n}\n\n#[test]\nfn json_size_of() {\n    let json = warp::body::json::<Vec<i32>>();\n    assert_eq!(std::mem::size_of_val(&json), 0);\n}\n\n#[tokio::test]\nasync fn form() {\n    let _ = pretty_env_logger::try_init();\n\n    let form = warp::body::form::<Vec<(String, String)>>();\n\n    let req = warp::test::request().body(\"foo=bar&baz=quux\");\n\n    let vec = req.filter(&form).await.unwrap();\n    let expected = vec![\n        (\"foo\".to_owned(), \"bar\".to_owned()),\n        (\"baz\".to_owned(), \"quux\".to_owned()),\n    ];\n    assert_eq!(vec, expected);\n}\n\n#[tokio::test]\nasync fn form_rejects_bad_content_type() {\n    let _ = pretty_env_logger::try_init();\n\n    let form = warp::body::form::<Vec<(String, String)>>().map(|_| warp::reply());\n\n    let req = warp::test::request()\n        .header(\"content-type\", \"application/x-www-form-urlencoded\")\n        .body(\"foo=bar\");\n\n    let res = req.reply(&form).await;\n    assert_eq!(res.status(), 200);\n\n    let req = warp::test::request()\n        .header(\"content-type\", \"text/xml\")\n        .body(\"foo=bar\");\n    let res = req.reply(&form).await;\n    assert_eq!(\n        res.status(),\n        415,\n        \"bad content-type should be 415 Unsupported Media Type\"\n    );\n}\n\n#[tokio::test]\nasync fn form_allows_charset() {\n    let _ = pretty_env_logger::try_init();\n\n    let form = warp::body::form::<Vec<(String, String)>>();\n\n    let req = warp::test::request()\n        .header(\n            \"content-type\",\n            \"application/x-www-form-urlencoded; charset=utf-8\",\n        )\n        .body(\"foo=bar\");\n\n    let vec = req.filter(&form).await.unwrap();\n    let expected = vec![(\"foo\".to_owned(), \"bar\".to_owned())];\n    assert_eq!(vec, expected);\n}\n\n#[tokio::test]\nasync fn form_invalid() {\n    let _ = pretty_env_logger::try_init();\n\n    let form = warp::body::form::<Vec<i32>>().map(|vec| warp::reply::json(&vec));\n\n    let res = warp::test::request().body(\"nope\").reply(&form).await;\n    assert_eq!(res.status(), 400);\n    let prefix = b\"Request body deserialize error: \";\n    assert_eq!(&res.body()[..prefix.len()], prefix);\n}\n\n#[tokio::test]\nasync fn stream() {\n    let _ = pretty_env_logger::try_init();\n\n    let stream = warp::body::stream();\n\n    let body = warp::test::request()\n        .body(\"foo=bar\")\n        .filter(&stream)\n        .await\n        .expect(\"filter() stream\");\n\n    let bufs: Result<Vec<_>, warp::Error> = body.try_collect().await;\n    let bufs = bufs.unwrap();\n\n    assert_eq!(bufs.len(), 1);\n    assert_eq!(bufs[0].chunk(), b\"foo=bar\");\n}\n"
  },
  {
    "path": "tests/cookie.rs",
    "content": "#![deny(warnings)]\n\n#[tokio::test]\nasync fn cookie() {\n    let foo = warp::cookie::<String>(\"foo\");\n\n    let req = warp::test::request().header(\"cookie\", \"foo=bar\");\n    assert_eq!(req.filter(&foo).await.unwrap(), \"bar\");\n\n    let req = warp::test::request().header(\"cookie\", \"abc=def; foo=baz\");\n    assert_eq!(req.filter(&foo).await.unwrap(), \"baz\");\n\n    let req = warp::test::request().header(\"cookie\", \"abc=def\");\n    assert!(!req.matches(&foo).await);\n\n    let req = warp::test::request().header(\"cookie\", \"foobar=quux\");\n    assert!(!req.matches(&foo).await);\n}\n\n#[tokio::test]\nasync fn optional() {\n    let foo = warp::cookie::optional::<String>(\"foo\");\n\n    let req = warp::test::request().header(\"cookie\", \"foo=bar\");\n    assert_eq!(req.filter(&foo).await.unwrap().unwrap(), \"bar\");\n\n    let req = warp::test::request().header(\"cookie\", \"abc=def; foo=baz\");\n    assert_eq!(req.filter(&foo).await.unwrap().unwrap(), \"baz\");\n\n    let req = warp::test::request().header(\"cookie\", \"abc=def\");\n    assert!(req.matches(&foo).await);\n\n    let req = warp::test::request().header(\"cookie\", \"foobar=quux\");\n    assert!(req.matches(&foo).await);\n}\n\n#[tokio::test]\nasync fn missing() {\n    let _ = pretty_env_logger::try_init();\n\n    let cookie = warp::cookie::<String>(\"foo\");\n\n    let res = warp::test::request()\n        .header(\"cookie\", \"not=here\")\n        .reply(&cookie)\n        .await;\n\n    assert_eq!(res.status(), 400);\n    assert_eq!(res.body(), \"Missing request cookie \\\"foo\\\"\");\n}\n"
  },
  {
    "path": "tests/cors.rs",
    "content": "#![deny(warnings)]\nuse warp::{http::Method, Filter};\n\n#[tokio::test]\nasync fn allow_methods() {\n    let cors = warp::cors().allow_methods(&[Method::GET, Method::POST, Method::DELETE]);\n\n    let route = warp::any().map(warp::reply).with(cors);\n\n    let res = warp::test::request()\n        .method(\"OPTIONS\")\n        .header(\"origin\", \"warp\")\n        .header(\"access-control-request-method\", \"DELETE\")\n        .reply(&route)\n        .await;\n\n    assert_eq!(res.status(), 200);\n\n    let res = warp::test::request()\n        .method(\"OPTIONS\")\n        .header(\"origin\", \"warp\")\n        .header(\"access-control-request-method\", \"PUT\")\n        .reply(&route)\n        .await;\n\n    assert_eq!(res.status(), 403);\n}\n\n#[tokio::test]\nasync fn origin_not_allowed() {\n    let cors = warp::cors()\n        .allow_methods(&[Method::DELETE])\n        .allow_origin(\"https://hyper.rs\");\n\n    let route = warp::any().map(warp::reply).with(cors);\n\n    let res = warp::test::request()\n        .method(\"OPTIONS\")\n        .header(\"origin\", \"https://warp.rs\")\n        .header(\"access-control-request-method\", \"DELETE\")\n        .reply(&route)\n        .await;\n\n    assert_eq!(res.status(), 403);\n\n    let res = warp::test::request()\n        .header(\"origin\", \"https://warp.rs\")\n        .header(\"access-control-request-method\", \"DELETE\")\n        .reply(&route)\n        .await;\n\n    assert_eq!(res.status(), 403);\n}\n\n#[tokio::test]\nasync fn headers_not_exposed() {\n    let cors = warp::cors()\n        .allow_any_origin()\n        .allow_methods(&[Method::GET]);\n\n    let route = warp::any().map(warp::reply).with(cors);\n\n    let res = warp::test::request()\n        .method(\"OPTIONS\")\n        .header(\"origin\", \"https://warp.rs\")\n        .header(\"access-control-request-method\", \"GET\")\n        .reply(&route)\n        .await;\n\n    assert_eq!(\n        res.headers().contains_key(\"access-control-expose-headers\"),\n        false\n    );\n\n    let res = warp::test::request()\n        .method(\"GET\")\n        .header(\"origin\", \"https://warp.rs\")\n        .reply(&route)\n        .await;\n\n    assert_eq!(\n        res.headers().contains_key(\"access-control-expose-headers\"),\n        false\n    );\n}\n\n#[tokio::test]\nasync fn headers_not_allowed() {\n    let cors = warp::cors()\n        .allow_methods(&[Method::DELETE])\n        .allow_headers(vec![\"x-foo\"]);\n\n    let route = warp::any().map(warp::reply).with(cors);\n\n    let res = warp::test::request()\n        .method(\"OPTIONS\")\n        .header(\"origin\", \"https://warp.rs\")\n        .header(\"access-control-request-headers\", \"x-bar\")\n        .header(\"access-control-request-method\", \"DELETE\")\n        .reply(&route)\n        .await;\n\n    assert_eq!(res.status(), 403);\n}\n\n#[tokio::test]\nasync fn success() {\n    let cors = warp::cors()\n        .allow_credentials(true)\n        .allow_headers(vec![\"x-foo\", \"x-bar\"])\n        .allow_methods(&[Method::POST, Method::DELETE])\n        .expose_header(\"x-header1\")\n        .expose_headers(vec![\"x-header2\"])\n        .max_age(30);\n\n    let route = warp::any().map(warp::reply).with(cors);\n\n    // preflight\n    let res = warp::test::request()\n        .method(\"OPTIONS\")\n        .header(\"origin\", \"https://hyper.rs\")\n        .header(\"access-control-request-headers\", \"x-bar, x-foo\")\n        .header(\"access-control-request-method\", \"DELETE\")\n        .reply(&route)\n        .await;\n    assert_eq!(res.status(), 200);\n    assert_eq!(\n        res.headers()[\"access-control-allow-origin\"],\n        \"https://hyper.rs\"\n    );\n    assert_eq!(res.headers()[\"access-control-allow-credentials\"], \"true\");\n    let allowed_headers = &res.headers()[\"access-control-allow-headers\"];\n    assert!(allowed_headers == \"x-bar, x-foo\" || allowed_headers == \"x-foo, x-bar\");\n    let exposed_headers = &res.headers()[\"access-control-expose-headers\"];\n    assert!(exposed_headers == \"x-header1, x-header2\" || exposed_headers == \"x-header2, x-header1\");\n    assert_eq!(res.headers()[\"access-control-max-age\"], \"30\");\n    let methods = &res.headers()[\"access-control-allow-methods\"];\n    assert!(\n        // HashSet randomly orders these...\n        methods == \"DELETE, POST\" || methods == \"POST, DELETE\",\n        \"access-control-allow-methods: {:?}\",\n        methods,\n    );\n\n    // cors request\n    let res = warp::test::request()\n        .method(\"DELETE\")\n        .header(\"origin\", \"https://hyper.rs\")\n        .header(\"x-foo\", \"hello\")\n        .header(\"x-bar\", \"world\")\n        .reply(&route)\n        .await;\n    assert_eq!(res.status(), 200);\n    assert_eq!(\n        res.headers()[\"access-control-allow-origin\"],\n        \"https://hyper.rs\"\n    );\n    assert_eq!(res.headers()[\"access-control-allow-credentials\"], \"true\");\n    assert_eq!(res.headers().get(\"access-control-max-age\"), None);\n    assert_eq!(res.headers().get(\"access-control-allow-methods\"), None);\n    let exposed_headers = &res.headers()[\"access-control-expose-headers\"];\n    assert!(exposed_headers == \"x-header1, x-header2\" || exposed_headers == \"x-header2, x-header1\");\n}\n\n#[tokio::test]\nasync fn with_log() {\n    let cors = warp::cors()\n        .allow_any_origin()\n        .allow_methods(&[Method::GET]);\n\n    let route = warp::any()\n        .map(warp::reply)\n        .with(cors)\n        .with(warp::log(\"cors test\"));\n\n    let res = warp::test::request()\n        .method(\"OPTIONS\")\n        .header(\"origin\", \"warp\")\n        .header(\"access-control-request-method\", \"GET\")\n        .reply(&route)\n        .await;\n\n    assert_eq!(res.status(), 200);\n}\n"
  },
  {
    "path": "tests/ext.rs",
    "content": "#![deny(warnings)]\nuse warp::Filter;\n\n#[derive(Clone, Debug, PartialEq)]\nstruct Ext1(i32);\n\n#[tokio::test]\nasync fn set_and_get() {\n    let ext = warp::ext::get::<Ext1>();\n\n    let extracted = warp::test::request()\n        .extension(Ext1(55))\n        .filter(&ext)\n        .await\n        .unwrap();\n\n    assert_eq!(extracted, Ext1(55));\n}\n\n#[tokio::test]\nasync fn get_missing() {\n    let ext = warp::ext::get().map(|e: Ext1| e.0.to_string());\n\n    let res = warp::test::request().reply(&ext).await;\n\n    assert_eq!(res.status(), 500);\n    assert_eq!(res.body(), \"Missing request extension\");\n}\n"
  },
  {
    "path": "tests/filter.rs",
    "content": "#![deny(warnings)]\nuse std::convert::Infallible;\nuse warp::Filter;\n\n#[tokio::test]\nasync fn flattens_tuples() {\n    let _ = pretty_env_logger::try_init();\n\n    let str1 = warp::any().map(|| \"warp\");\n    let true1 = warp::any().map(|| true);\n    let unit1 = warp::any();\n\n    // just 1 value\n    let ext = warp::test::request().filter(&str1).await.unwrap();\n    assert_eq!(ext, \"warp\");\n\n    // just 1 unit\n    let ext = warp::test::request().filter(&unit1).await.unwrap();\n    assert_eq!(ext, ());\n\n    // combine 2 values\n    let and = str1.and(true1);\n    let ext = warp::test::request().filter(&and).await.unwrap();\n    assert_eq!(ext, (\"warp\", true));\n\n    // combine 2 reversed\n    let and = true1.and(str1);\n    let ext = warp::test::request().filter(&and).await.unwrap();\n    assert_eq!(ext, (true, \"warp\"));\n\n    // combine 1 with unit\n    let and = str1.and(unit1);\n    let ext = warp::test::request().filter(&and).await.unwrap();\n    assert_eq!(ext, \"warp\");\n\n    let and = unit1.and(str1);\n    let ext = warp::test::request().filter(&and).await.unwrap();\n    assert_eq!(ext, \"warp\");\n\n    // combine 3 values\n    let and = str1.and(str1).and(true1);\n    let ext = warp::test::request().filter(&and).await.unwrap();\n    assert_eq!(ext, (\"warp\", \"warp\", true));\n\n    // combine 2 with unit\n    let and = str1.and(unit1).and(true1);\n    let ext = warp::test::request().filter(&and).await.unwrap();\n    assert_eq!(ext, (\"warp\", true));\n\n    let and = unit1.and(str1).and(true1);\n    let ext = warp::test::request().filter(&and).await.unwrap();\n    assert_eq!(ext, (\"warp\", true));\n\n    let and = str1.and(true1).and(unit1);\n    let ext = warp::test::request().filter(&and).await.unwrap();\n    assert_eq!(ext, (\"warp\", true));\n\n    // nested tuples\n    let str_true_unit = str1.and(true1).and(unit1);\n    let unit_str_true = unit1.and(str1).and(true1);\n\n    let and = str_true_unit.and(unit_str_true);\n    let ext = warp::test::request().filter(&and).await.unwrap();\n    assert_eq!(ext, (\"warp\", true, \"warp\", true));\n\n    let and = unit_str_true.and(unit1).and(str1).and(str_true_unit);\n    let ext = warp::test::request().filter(&and).await.unwrap();\n    assert_eq!(ext, (\"warp\", true, \"warp\", \"warp\", true));\n}\n\n#[tokio::test]\nasync fn map() {\n    let _ = pretty_env_logger::try_init();\n\n    let ok = warp::any().map(warp::reply);\n\n    let req = warp::test::request();\n    let resp = req.reply(&ok).await;\n    assert_eq!(resp.status(), 200);\n}\n\n#[tokio::test]\nasync fn or() {\n    let _ = pretty_env_logger::try_init();\n\n    // Or can be combined with an infallible filter\n    let a = warp::path::param::<u32>();\n    let b = warp::any().map(|| 41i32);\n    let f = a.or(b);\n\n    let _: Result<_, Infallible> = warp::test::request().filter(&f).await;\n}\n\n#[tokio::test]\nasync fn or_else() {\n    let _ = pretty_env_logger::try_init();\n\n    let a = warp::path::param::<u32>();\n    let f = a.or_else(|_| async { Ok::<_, warp::Rejection>((44u32,)) });\n\n    assert_eq!(\n        warp::test::request().path(\"/33\").filter(&f).await.unwrap(),\n        33,\n    );\n    assert_eq!(warp::test::request().filter(&f).await.unwrap(), 44,);\n\n    // OrElse can be combined with an infallible filter\n    let a = warp::path::param::<u32>();\n    let f = a.or_else(|_| async { Ok::<_, Infallible>((44u32,)) });\n\n    let _: Result<_, Infallible> = warp::test::request().filter(&f).await;\n}\n\n#[tokio::test]\nasync fn recover() {\n    let _ = pretty_env_logger::try_init();\n\n    let a = warp::path::param::<String>();\n    let f = a.recover(|err| async move { Err::<String, _>(err) });\n\n    // not rejected\n    let resp = warp::test::request().path(\"/hi\").reply(&f).await;\n    assert_eq!(resp.status(), 200);\n    assert_eq!(resp.body(), \"hi\");\n\n    // rejected, recovered, re-rejected\n    let resp = warp::test::request().reply(&f).await;\n    assert_eq!(resp.status(), 404);\n\n    // Recover can be infallible\n    let f = a.recover(|_| async move { Ok::<_, Infallible>(\"shh\") });\n\n    let _: Result<_, Infallible> = warp::test::request().filter(&f).await;\n}\n\n#[tokio::test]\nasync fn unify() {\n    let _ = pretty_env_logger::try_init();\n\n    let a = warp::path::param::<u32>();\n    let b = warp::path::param::<u32>();\n    let f = a.or(b).unify();\n\n    let ex = warp::test::request().path(\"/1\").filter(&f).await.unwrap();\n\n    assert_eq!(ex, 1);\n}\n\n#[should_panic]\n#[tokio::test]\nasync fn nested() {\n    let f = warp::any().and_then(|| async {\n        let p = warp::path::param::<u32>();\n        warp::test::request().filter(&p).await\n    });\n\n    let _ = warp::test::request().filter(&f).await;\n}\n"
  },
  {
    "path": "tests/fs.rs",
    "content": "#![deny(warnings)]\nuse std::fs;\n\n#[tokio::test]\nasync fn file() {\n    let _ = pretty_env_logger::try_init();\n\n    let file = warp::fs::file(\"README.md\");\n\n    let req = warp::test::request();\n    let res = req.reply(&file).await;\n\n    assert_eq!(res.status(), 200);\n\n    let contents = fs::read(\"README.md\").expect(\"fs::read README.md\");\n    assert_eq!(res.headers()[\"content-length\"], contents.len().to_string());\n    assert_eq!(res.headers()[\"accept-ranges\"], \"bytes\");\n\n    let ct = &res.headers()[\"content-type\"];\n    assert!(\n        ct == \"text/x-markdown\" || ct == \"text/markdown\",\n        \"content-type is not markdown: {:?}\",\n        ct,\n    );\n\n    assert_eq!(res.body(), &*contents);\n}\n\n#[tokio::test]\nasync fn dir() {\n    let _ = pretty_env_logger::try_init();\n\n    let file = warp::fs::dir(\"examples\");\n\n    let req = warp::test::request().path(\"/todos.rs\");\n    let res = req.reply(&file).await;\n\n    assert_eq!(res.status(), 200);\n\n    let contents = fs::read(\"examples/todos.rs\").expect(\"fs::read\");\n    assert_eq!(res.headers()[\"content-length\"], contents.len().to_string());\n    assert_eq!(res.headers()[\"content-type\"], \"text/x-rust\");\n    assert_eq!(res.headers()[\"accept-ranges\"], \"bytes\");\n\n    assert_eq!(res.body(), &*contents);\n\n    let malformed_req = warp::test::request().path(\"todos.rs\");\n    assert_eq!(malformed_req.reply(&file).await.status(), 404);\n}\n\n#[tokio::test]\nasync fn dir_encoded() {\n    let _ = pretty_env_logger::try_init();\n\n    let file = warp::fs::dir(\"examples\");\n\n    let req = warp::test::request().path(\"/todos%2ers\");\n    let res = req.reply(&file).await;\n\n    assert_eq!(res.status(), 200);\n\n    let contents = fs::read(\"examples/todos.rs\").expect(\"fs::read\");\n    assert_eq!(res.headers()[\"content-length\"], contents.len().to_string());\n\n    assert_eq!(res.body(), &*contents);\n}\n\n#[tokio::test]\nasync fn dir_not_found() {\n    let _ = pretty_env_logger::try_init();\n\n    let file = warp::fs::dir(\"examples\");\n\n    let req = warp::test::request().path(\"/definitely-not-found\");\n    let res = req.reply(&file).await;\n\n    assert_eq!(res.status(), 404);\n}\n\n#[tokio::test]\nasync fn dir_bad_path() {\n    let _ = pretty_env_logger::try_init();\n\n    let file = warp::fs::dir(\"examples\");\n\n    let req = warp::test::request().path(\"/../README.md\");\n    let res = req.reply(&file).await;\n\n    assert_eq!(res.status(), 404);\n}\n\n#[tokio::test]\nasync fn dir_bad_encoded_path() {\n    let _ = pretty_env_logger::try_init();\n\n    let file = warp::fs::dir(\"examples\");\n\n    let req = warp::test::request().path(\"/%2E%2e/README.md\");\n    let res = req.reply(&file).await;\n\n    assert_eq!(res.status(), 404);\n}\n\n#[tokio::test]\nasync fn dir_fallback_index_on_dir() {\n    let _ = pretty_env_logger::try_init();\n\n    let file = warp::fs::dir(\"examples\");\n    let req = warp::test::request().path(\"/dir\");\n    let res = req.reply(&file).await;\n    let contents = fs::read(\"examples/dir/index.html\").expect(\"fs::read\");\n    assert_eq!(res.headers()[\"content-length\"], contents.len().to_string());\n    assert_eq!(res.status(), 200);\n    let req = warp::test::request().path(\"/dir/\");\n    let res = req.reply(&file).await;\n    assert_eq!(res.headers()[\"content-length\"], contents.len().to_string());\n    assert_eq!(res.status(), 200);\n}\n\n#[tokio::test]\nasync fn not_modified() {\n    let _ = pretty_env_logger::try_init();\n\n    let file = warp::fs::file(\"README.md\");\n\n    let req = warp::test::request();\n    let body = fs::read(\"README.md\").unwrap();\n    let res1 = req.reply(&file).await;\n    assert_eq!(res1.status(), 200);\n    assert_eq!(res1.headers()[\"content-length\"], body.len().to_string());\n\n    // if-modified-since\n    let res = warp::test::request()\n        .header(\"if-modified-since\", &res1.headers()[\"last-modified\"])\n        .reply(&file)\n        .await;\n    assert_eq!(res.headers().get(\"content-length\"), None);\n    assert_eq!(res.status(), 304);\n    assert_eq!(res.body(), \"\");\n\n    // clearly too old\n    let res = warp::test::request()\n        .header(\"if-modified-since\", \"Mon, 07 Nov 1994 01:00:00 GMT\")\n        .reply(&file)\n        .await;\n    assert_eq!(res.status(), 200);\n    assert_eq!(res.body(), &body);\n    assert_eq!(res1.headers()[\"content-length\"], body.len().to_string());\n}\n\n#[tokio::test]\nasync fn precondition() {\n    let _ = pretty_env_logger::try_init();\n\n    let file = warp::fs::file(\"README.md\");\n\n    let req = warp::test::request();\n    let res1 = req.reply(&file).await;\n    assert_eq!(res1.status(), 200);\n\n    // if-unmodified-since\n    let res = warp::test::request()\n        .header(\"if-unmodified-since\", &res1.headers()[\"last-modified\"])\n        .reply(&file)\n        .await;\n    assert_eq!(res.status(), 200);\n\n    // clearly too old\n    let res = warp::test::request()\n        .header(\"if-unmodified-since\", \"Mon, 07 Nov 1994 01:00:00 GMT\")\n        .reply(&file)\n        .await;\n    assert_eq!(res.status(), 412);\n    assert_eq!(res.body(), \"\");\n}\n\n#[tokio::test]\nasync fn byte_ranges() {\n    let _ = pretty_env_logger::try_init();\n\n    let contents = fs::read(\"README.md\").expect(\"fs::read README.md\");\n    let file = warp::fs::file(\"README.md\");\n\n    let res = warp::test::request()\n        .header(\"range\", \"bytes=100-200\")\n        .reply(&file)\n        .await;\n    assert_eq!(res.status(), 206);\n    assert_eq!(\n        res.headers()[\"content-range\"],\n        format!(\"bytes 100-200/{}\", contents.len())\n    );\n    assert_eq!(res.headers()[\"content-length\"], \"101\");\n    assert_eq!(res.body(), &contents[100..=200]);\n\n    // bad range\n    let res = warp::test::request()\n        .header(\"range\", \"bytes=100-10\")\n        .reply(&file)\n        .await;\n    assert_eq!(res.status(), 416);\n    assert_eq!(\n        res.headers()[\"content-range\"],\n        format!(\"bytes */{}\", contents.len())\n    );\n    assert_eq!(res.headers().get(\"content-length\"), None);\n    assert_eq!(res.body(), \"\");\n\n    // out of range\n    let res = warp::test::request()\n        .header(\"range\", \"bytes=100-100000\")\n        .reply(&file)\n        .await;\n    assert_eq!(res.status(), 416);\n    assert_eq!(\n        res.headers()[\"content-range\"],\n        format!(\"bytes */{}\", contents.len())\n    );\n    assert_eq!(res.headers().get(\"content-length\"), None);\n    assert_eq!(res.body(), \"\");\n\n    // if-range too old\n    let res = warp::test::request()\n        .header(\"range\", \"bytes=100-200\")\n        .header(\"if-range\", \"Mon, 07 Nov 1994 01:00:00 GMT\")\n        .reply(&file)\n        .await;\n    assert_eq!(res.status(), 200);\n    assert_eq!(res.headers()[\"content-length\"], contents.len().to_string());\n    assert_eq!(res.headers().get(\"content-range\"), None);\n}\n\n#[tokio::test]\nasync fn byte_ranges_with_excluded_file_size() {\n    let _ = pretty_env_logger::try_init();\n\n    let contents = fs::read(\"README.md\").expect(\"fs::read README.md\");\n    let file = warp::fs::file(\"README.md\");\n\n    // range including end of file (non-inclusive result)\n    let res = warp::test::request()\n        .header(\"range\", format!(\"bytes=100-{}\", contents.len()))\n        .reply(&file)\n        .await;\n    assert_eq!(res.status(), 206);\n    assert_eq!(\n        res.headers()[\"content-range\"],\n        format!(\"bytes 100-{}/{}\", contents.len() - 1, contents.len())\n    );\n    assert_eq!(\n        res.headers()[\"content-length\"],\n        format!(\"{}\", contents.len() - 100)\n    );\n    assert_eq!(res.body(), &contents[100..=contents.len() - 1]);\n\n    // range with 1 byte to end yields same result as above. (inclusive result)\n    let res = warp::test::request()\n        .header(\"range\", format!(\"bytes=100-{}\", contents.len() - 1))\n        .reply(&file)\n        .await;\n    assert_eq!(res.status(), 206);\n    assert_eq!(\n        res.headers()[\"content-range\"],\n        format!(\"bytes 100-{}/{}\", contents.len() - 1, contents.len())\n    );\n    assert_eq!(\n        res.headers()[\"content-length\"],\n        format!(\"{}\", contents.len() - 100)\n    );\n    assert_eq!(res.body(), &contents[100..=contents.len() - 1]);\n}\n"
  },
  {
    "path": "tests/header.rs",
    "content": "#![deny(warnings)]\nuse warp::Filter;\n\n#[tokio::test]\nasync fn exact() {\n    let _ = pretty_env_logger::try_init();\n\n    let host = warp::header::exact(\"host\", \"localhost\");\n\n    let req = warp::test::request().header(\"host\", \"localhost\");\n\n    assert!(req.matches(&host).await);\n\n    let req = warp::test::request();\n    assert!(!req.matches(&host).await, \"header missing\");\n\n    let req = warp::test::request().header(\"host\", \"hyper.rs\");\n    assert!(!req.matches(&host).await, \"header value different\");\n}\n\n#[tokio::test]\nasync fn exact_rejections() {\n    let _ = pretty_env_logger::try_init();\n\n    let host = warp::header::exact(\"host\", \"localhost\").map(warp::reply);\n\n    let res = warp::test::request()\n        .header(\"host\", \"nope\")\n        .reply(&host)\n        .await;\n\n    assert_eq!(res.status(), 400);\n    assert_eq!(res.body(), \"Invalid request header \\\"host\\\"\");\n\n    let res = warp::test::request()\n        .header(\"not-even-a-host\", \"localhost\")\n        .reply(&host)\n        .await;\n\n    assert_eq!(res.status(), 400);\n    assert_eq!(res.body(), \"Missing request header \\\"host\\\"\");\n}\n\n#[tokio::test]\nasync fn optional() {\n    let _ = pretty_env_logger::try_init();\n\n    let con_len = warp::header::optional::<u64>(\"content-length\");\n\n    let val = warp::test::request()\n        .filter(&con_len)\n        .await\n        .expect(\"missing header matches\");\n    assert_eq!(val, None);\n\n    let val = warp::test::request()\n        .header(\"content-length\", \"5\")\n        .filter(&con_len)\n        .await\n        .expect(\"existing header matches\");\n\n    assert_eq!(val, Some(5));\n\n    assert!(\n        !warp::test::request()\n            .header(\"content-length\", \"boom\")\n            .matches(&con_len)\n            .await,\n        \"invalid optional header still rejects\",\n    );\n}\n"
  },
  {
    "path": "tests/host.rs",
    "content": "#![deny(warnings)]\nuse warp::host::Authority;\n\n#[tokio::test]\nasync fn exact() {\n    let filter = warp::host::exact(\"known.com\");\n\n    // no authority\n    let req = warp::test::request();\n    assert!(req.filter(&filter).await.unwrap_err().is_not_found());\n\n    // specified in URI\n    let req = warp::test::request().path(\"http://known.com/about-us\");\n    assert!(req.filter(&filter).await.is_ok());\n\n    let req = warp::test::request().path(\"http://unknown.com/about-us\");\n    assert!(req.filter(&filter).await.unwrap_err().is_not_found());\n\n    // specified in Host header\n    let req = warp::test::request()\n        .header(\"host\", \"known.com\")\n        .path(\"/about-us\");\n    assert!(req.filter(&filter).await.is_ok());\n\n    let req = warp::test::request()\n        .header(\"host\", \"unknown.com\")\n        .path(\"/about-us\");\n    assert!(req.filter(&filter).await.unwrap_err().is_not_found());\n\n    // specified in both - matching\n    let req = warp::test::request()\n        .header(\"host\", \"known.com\")\n        .path(\"http://known.com/about-us\");\n    assert!(req.filter(&filter).await.is_ok());\n\n    let req = warp::test::request()\n        .header(\"host\", \"unknown.com\")\n        .path(\"http://unknown.com/about-us\");\n    assert!(req.filter(&filter).await.unwrap_err().is_not_found());\n\n    // specified in both - mismatch\n    let req = warp::test::request()\n        .header(\"host\", \"known.com\")\n        .path(\"http://known2.com/about-us\");\n    assert!(req\n        .filter(&filter)\n        .await\n        .unwrap_err()\n        .find::<warp::reject::InvalidHeader>()\n        .is_some());\n\n    // bad host header - invalid chars\n    let req = warp::test::request()\n        .header(\"host\", \"😭\")\n        .path(\"http://known.com/about-us\");\n    assert!(req\n        .filter(&filter)\n        .await\n        .unwrap_err()\n        .find::<warp::reject::InvalidHeader>()\n        .is_some());\n\n    // bad host header - invalid format\n    let req = warp::test::request()\n        .header(\"host\", \"hello space.com\")\n        .path(\"http://known.com//about-us\");\n    assert!(req\n        .filter(&filter)\n        .await\n        .unwrap_err()\n        .find::<warp::reject::InvalidHeader>()\n        .is_some());\n}\n\n#[tokio::test]\nasync fn optional() {\n    let filter = warp::host::optional();\n\n    let req = warp::test::request().header(\"host\", \"example.com\");\n    assert_eq!(\n        req.filter(&filter).await.unwrap(),\n        Some(Authority::from_static(\"example.com\"))\n    );\n\n    let req = warp::test::request();\n    assert_eq!(req.filter(&filter).await.unwrap(), None);\n}\n"
  },
  {
    "path": "tests/method.rs",
    "content": "#![deny(warnings)]\nuse warp::Filter;\n\n#[tokio::test]\nasync fn method() {\n    let _ = pretty_env_logger::try_init();\n    let get = warp::get().map(warp::reply);\n\n    let req = warp::test::request();\n    assert!(req.matches(&get).await);\n\n    let req = warp::test::request().method(\"POST\");\n    assert!(!req.matches(&get).await);\n\n    let req = warp::test::request().method(\"POST\");\n    let resp = req.reply(&get).await;\n    assert_eq!(resp.status(), 405);\n}\n\n#[tokio::test]\nasync fn method_not_allowed_trumps_not_found() {\n    let _ = pretty_env_logger::try_init();\n    let get = warp::get().and(warp::path(\"hello\").map(warp::reply));\n    let post = warp::post().and(warp::path(\"bye\").map(warp::reply));\n\n    let routes = get.or(post);\n\n    let req = warp::test::request().method(\"GET\").path(\"/bye\");\n\n    let resp = req.reply(&routes).await;\n    // GET was allowed, but only for /hello, so POST returning 405 is fine.\n    assert_eq!(resp.status(), 405);\n}\n\n#[tokio::test]\nasync fn bad_request_trumps_method_not_allowed() {\n    let _ = pretty_env_logger::try_init();\n    let get = warp::get()\n        .and(warp::path(\"hello\"))\n        .and(warp::header::exact(\"foo\", \"bar\"))\n        .map(warp::reply);\n    let post = warp::post().and(warp::path(\"bye\")).map(warp::reply);\n\n    let routes = get.or(post);\n\n    let req = warp::test::request().method(\"GET\").path(\"/hello\");\n\n    let resp = req.reply(&routes).await;\n    // GET was allowed, but header rejects with 400, should not\n    // assume POST was the appropriate method.\n    assert_eq!(resp.status(), 400);\n}\n"
  },
  {
    "path": "tests/multipart.rs",
    "content": "#![deny(warnings)]\nuse bytes::BufMut;\nuse futures_util::{TryFutureExt, TryStreamExt};\nuse warp::{multipart, Filter};\n\n#[tokio::test]\nasync fn form_fields() {\n    let _ = pretty_env_logger::try_init();\n\n    let route = multipart::form().and_then(|form: multipart::FormData| {\n        async {\n            // Collect the fields into (name, value): (String, Vec<u8>)\n            let part: Result<Vec<(String, Vec<u8>)>, warp::Rejection> = form\n                .and_then(|part| {\n                    let name = part.name().to_string();\n                    let value = part.stream().try_fold(Vec::new(), |mut vec, data| {\n                        vec.put(data);\n                        async move { Ok(vec) }\n                    });\n                    value.map_ok(move |vec| (name, vec))\n                })\n                .try_collect()\n                .await\n                .map_err(|e| {\n                    panic!(\"multipart error: {:?}\", e);\n                });\n            part\n        }\n    });\n\n    let boundary = \"--abcdef1234--\";\n    let body = format!(\n        \"\\\n         --{0}\\r\\n\\\n         content-disposition: form-data; name=\\\"foo\\\"\\r\\n\\r\\n\\\n         bar\\r\\n\\\n         --{0}--\\r\\n\\\n         \",\n        boundary\n    );\n\n    let req = warp::test::request()\n        .method(\"POST\")\n        .header(\"content-length\", body.len())\n        .header(\n            \"content-type\",\n            format!(\"multipart/form-data; boundary={}\", boundary),\n        )\n        .body(body);\n\n    let vec = req.filter(&route).await.unwrap();\n    assert_eq!(&vec[0].0, \"foo\");\n    assert_eq!(&vec[0].1, b\"bar\");\n}\n\n#[tokio::test]\nasync fn max_length_is_enforced() {\n    let _ = pretty_env_logger::try_init();\n\n    let route = multipart::form()\n        .and_then(|_: multipart::FormData| async { Ok::<(), warp::Rejection>(()) });\n\n    let boundary = \"--abcdef1234--\";\n\n    let req = warp::test::request()\n        .method(\"POST\")\n        // Note no content-length header\n        .header(\"transfer-encoding\", \"chunked\")\n        .header(\n            \"content-type\",\n            format!(\"multipart/form-data; boundary={}\", boundary),\n        );\n\n    // Intentionally don't add body, as it automatically also adds\n    // content-length header\n    let resp = req.filter(&route).await;\n    assert!(resp.is_err());\n}\n\n#[tokio::test]\nasync fn max_length_can_be_disabled() {\n    let _ = pretty_env_logger::try_init();\n\n    let route = multipart::form()\n        .max_length(None)\n        .and_then(|_: multipart::FormData| async { Ok::<(), warp::Rejection>(()) });\n\n    let boundary = \"--abcdef1234--\";\n\n    let req = warp::test::request()\n        .method(\"POST\")\n        .header(\"transfer-encoding\", \"chunked\")\n        .header(\n            \"content-type\",\n            format!(\"multipart/form-data; boundary={}\", boundary),\n        );\n\n    // Intentionally don't add body, as it automatically also adds\n    // content-length header\n    let resp = req.filter(&route).await;\n    assert!(resp.is_ok());\n}\n"
  },
  {
    "path": "tests/path.rs",
    "content": "#![deny(warnings)]\n#[macro_use]\nextern crate warp;\n\nuse futures_util::future;\nuse warp::Filter;\n\n#[tokio::test]\nasync fn path() {\n    let _ = pretty_env_logger::try_init();\n\n    let foo = warp::path(\"foo\");\n    let bar = warp::path(String::from(\"bar\"));\n    let foo_bar = foo.and(bar.clone());\n\n    // /foo\n    let foo_req = || warp::test::request().path(\"/foo\");\n\n    assert!(foo_req().matches(&foo).await);\n    assert!(!foo_req().matches(&bar).await);\n    assert!(!foo_req().matches(&foo_bar).await);\n\n    // /foo/bar\n    let foo_bar_req = || warp::test::request().path(\"/foo/bar\");\n\n    assert!(foo_bar_req().matches(&foo).await);\n    assert!(!foo_bar_req().matches(&bar).await);\n    assert!(foo_bar_req().matches(&foo_bar).await);\n}\n\n#[tokio::test]\nasync fn param() {\n    let _ = pretty_env_logger::try_init();\n\n    let num = warp::path::param::<u32>();\n\n    let req = warp::test::request().path(\"/321\");\n    assert_eq!(req.filter(&num).await.unwrap(), 321);\n\n    let s = warp::path::param::<String>();\n\n    let req = warp::test::request().path(\"/warp\");\n    assert_eq!(req.filter(&s).await.unwrap(), \"warp\");\n\n    // u32 doesn't extract a non-int\n    let req = warp::test::request().path(\"/warp\");\n    assert!(!req.matches(&num).await);\n\n    let combo = num.map(|n| n + 5).and(s);\n\n    let req = warp::test::request().path(\"/42/vroom\");\n    assert_eq!(req.filter(&combo).await.unwrap(), (47, \"vroom\".to_string()));\n\n    // empty segments never match\n    let req = warp::test::request();\n    assert!(\n        !req.matches(&s).await,\n        \"param should never match an empty segment\"\n    );\n}\n\n#[tokio::test]\nasync fn end() {\n    let _ = pretty_env_logger::try_init();\n\n    let foo = warp::path(\"foo\");\n    let end = warp::path::end();\n    let foo_end = foo.and(end);\n\n    assert!(\n        warp::test::request().path(\"/\").matches(&end).await,\n        \"end() matches /\"\n    );\n\n    assert!(\n        warp::test::request()\n            .path(\"http://localhost:1234\")\n            .matches(&end)\n            .await,\n        \"end() matches /\"\n    );\n\n    assert!(\n        warp::test::request()\n            .path(\"http://localhost:1234?q=2\")\n            .matches(&end)\n            .await,\n        \"end() matches empty path\"\n    );\n\n    assert!(\n        warp::test::request()\n            .path(\"localhost:1234\")\n            .matches(&end)\n            .await,\n        \"end() matches authority-form\"\n    );\n\n    assert!(\n        !warp::test::request().path(\"/foo\").matches(&end).await,\n        \"end() doesn't match /foo\"\n    );\n\n    assert!(\n        warp::test::request().path(\"/foo\").matches(&foo_end).await,\n        \"path().and(end()) matches /foo\"\n    );\n\n    assert!(\n        warp::test::request().path(\"/foo/\").matches(&foo_end).await,\n        \"path().and(end()) matches /foo/\"\n    );\n}\n\n#[tokio::test]\nasync fn tail() {\n    let tail = warp::path::tail();\n\n    // matches full path\n    let ex = warp::test::request()\n        .path(\"/42/vroom\")\n        .filter(&tail)\n        .await\n        .unwrap();\n    assert_eq!(ex.as_str(), \"42/vroom\");\n\n    // matches index\n    let ex = warp::test::request().path(\"/\").filter(&tail).await.unwrap();\n    assert_eq!(ex.as_str(), \"\");\n\n    // doesn't include query\n    let ex = warp::test::request()\n        .path(\"/foo/bar?baz=quux\")\n        .filter(&tail)\n        .await\n        .unwrap();\n    assert_eq!(ex.as_str(), \"foo/bar\");\n\n    // doesn't include previously matched prefix\n    let and = warp::path(\"foo\").and(tail);\n    let ex = warp::test::request()\n        .path(\"/foo/bar\")\n        .filter(&and)\n        .await\n        .unwrap();\n    assert_eq!(ex.as_str(), \"bar\");\n\n    // sets unmatched path index to end\n    let m = tail.and(warp::path(\"foo\"));\n    assert!(!warp::test::request().path(\"/foo/bar\").matches(&m).await);\n\n    let m = tail.and(warp::path::end());\n    assert!(warp::test::request().path(\"/foo/bar\").matches(&m).await);\n\n    let ex = warp::test::request()\n        .path(\"localhost\")\n        .filter(&tail)\n        .await\n        .unwrap();\n    assert_eq!(ex.as_str(), \"/\");\n}\n\n#[tokio::test]\nasync fn or() {\n    let _ = pretty_env_logger::try_init();\n\n    // /foo/bar OR /foo/baz\n    let foo = warp::path(\"foo\");\n    let bar = warp::path(\"bar\");\n    let baz = warp::path(\"baz\");\n    let p = foo.and(bar.or(baz));\n\n    // /foo/bar\n    let req = warp::test::request().path(\"/foo/bar\");\n\n    assert!(req.matches(&p).await);\n\n    // /foo/baz\n    let req = warp::test::request().path(\"/foo/baz\");\n\n    assert!(req.matches(&p).await);\n\n    // deeper nested ORs\n    // /foo/bar/baz OR /foo/baz/bar OR /foo/bar/bar\n    let p = foo\n        .and(bar.and(baz).map(|| panic!(\"shouldn't match\")))\n        .or(foo.and(baz.and(bar)).map(|| panic!(\"shouldn't match\")))\n        .or(foo.and(bar.and(bar)));\n\n    // /foo/baz\n    let req = warp::test::request().path(\"/foo/baz/baz\");\n    assert!(!req.matches(&p).await);\n\n    // /foo/bar/bar\n    let req = warp::test::request().path(\"/foo/bar/bar\");\n    assert!(req.matches(&p).await);\n}\n\n#[tokio::test]\nasync fn or_else() {\n    let _ = pretty_env_logger::try_init();\n\n    let foo = warp::path(\"foo\");\n    let bar = warp::path(\"bar\");\n\n    let p = foo.and(bar.or_else(|_| future::ok::<_, std::convert::Infallible>(())));\n\n    // /foo/bar\n    let req = warp::test::request().path(\"/foo/nope\");\n\n    assert!(req.matches(&p).await);\n}\n\n#[tokio::test]\nasync fn path_macro() {\n    let _ = pretty_env_logger::try_init();\n\n    let req = warp::test::request().path(\"/foo/bar\");\n    let p = path!(\"foo\" / \"bar\");\n    assert!(req.matches(&p).await);\n\n    let req = warp::test::request().path(\"/foo/bar\");\n    let p = path!(String / \"bar\");\n    assert_eq!(req.filter(&p).await.unwrap(), \"foo\");\n\n    let req = warp::test::request().path(\"/foo/bar\");\n    let p = path!(\"foo\" / String);\n    assert_eq!(req.filter(&p).await.unwrap(), \"bar\");\n\n    // Requires path end\n\n    let req = warp::test::request().path(\"/foo/bar/baz\");\n    let p = path!(\"foo\" / \"bar\");\n    assert!(!req.matches(&p).await);\n\n    let req = warp::test::request().path(\"/foo/bar/baz\");\n    let p = path!(\"foo\" / \"bar\").and(warp::path(\"baz\"));\n    assert!(!req.matches(&p).await);\n\n    // Prefix syntax\n\n    let req = warp::test::request().path(\"/foo/bar/baz\");\n    let p = path!(\"foo\" / \"bar\" / ..);\n    assert!(req.matches(&p).await);\n\n    let req = warp::test::request().path(\"/foo/bar/baz\");\n    let p = path!(\"foo\" / \"bar\" / ..).and(warp::path!(\"baz\"));\n    assert!(req.matches(&p).await);\n\n    // Empty\n\n    let req = warp::test::request().path(\"/\");\n    let p = path!();\n    assert!(req.matches(&p).await);\n\n    let req = warp::test::request().path(\"/foo\");\n    let p = path!();\n    assert!(!req.matches(&p).await);\n}\n\n#[tokio::test]\nasync fn full_path() {\n    let full_path = warp::path::full();\n\n    let foo = warp::path(\"foo\");\n    let bar = warp::path(\"bar\");\n    let param = warp::path::param::<u32>();\n\n    // matches full request path\n    let ex = warp::test::request()\n        .path(\"/42/vroom\")\n        .filter(&full_path)\n        .await\n        .unwrap();\n    assert_eq!(ex.as_str(), \"/42/vroom\");\n\n    // matches index\n    let ex = warp::test::request()\n        .path(\"/\")\n        .filter(&full_path)\n        .await\n        .unwrap();\n    assert_eq!(ex.as_str(), \"/\");\n\n    // does not include query\n    let ex = warp::test::request()\n        .path(\"/foo/bar?baz=quux\")\n        .filter(&full_path)\n        .await\n        .unwrap();\n    assert_eq!(ex.as_str(), \"/foo/bar\");\n\n    // includes previously matched prefix\n    let and = foo.and(full_path);\n    let ex = warp::test::request()\n        .path(\"/foo/bar\")\n        .filter(&and)\n        .await\n        .unwrap();\n    assert_eq!(ex.as_str(), \"/foo/bar\");\n\n    // includes following matches\n    let and = full_path.and(foo);\n    let ex = warp::test::request()\n        .path(\"/foo/bar\")\n        .filter(&and)\n        .await\n        .unwrap();\n    assert_eq!(ex.as_str(), \"/foo/bar\");\n\n    // includes previously matched param\n    let and = foo.and(param).and(full_path);\n    let (_, ex) = warp::test::request()\n        .path(\"/foo/123\")\n        .filter(&and)\n        .await\n        .unwrap();\n    assert_eq!(ex.as_str(), \"/foo/123\");\n\n    // does not modify matching\n    let m = full_path.and(foo).and(bar);\n    assert!(warp::test::request().path(\"/foo/bar\").matches(&m).await);\n\n    // doesn't panic on authority-form\n    let ex = warp::test::request()\n        .path(\"localhost:1234\")\n        .filter(&full_path)\n        .await\n        .unwrap();\n    assert_eq!(ex.as_str(), \"/\");\n}\n\n#[tokio::test]\nasync fn peek() {\n    let peek = warp::path::peek();\n\n    let foo = warp::path(\"foo\");\n    let bar = warp::path(\"bar\");\n    let param = warp::path::param::<u32>();\n\n    // matches full request path\n    let ex = warp::test::request()\n        .path(\"/42/vroom\")\n        .filter(&peek)\n        .await\n        .unwrap();\n    assert_eq!(ex.as_str(), \"42/vroom\");\n\n    // matches index\n    let ex = warp::test::request().path(\"/\").filter(&peek).await.unwrap();\n    assert_eq!(ex.as_str(), \"\");\n\n    // does not include query\n    let ex = warp::test::request()\n        .path(\"/foo/bar?baz=quux\")\n        .filter(&peek)\n        .await\n        .unwrap();\n    assert_eq!(ex.as_str(), \"foo/bar\");\n\n    // does not include previously matched prefix\n    let and = foo.and(peek);\n    let ex = warp::test::request()\n        .path(\"/foo/bar\")\n        .filter(&and)\n        .await\n        .unwrap();\n    assert_eq!(ex.as_str(), \"bar\");\n\n    // includes following matches\n    let and = peek.and(foo);\n    let ex = warp::test::request()\n        .path(\"/foo/bar\")\n        .filter(&and)\n        .await\n        .unwrap();\n    assert_eq!(ex.as_str(), \"foo/bar\");\n\n    // does not include previously matched param\n    let and = foo.and(param).and(peek);\n    let (_, ex) = warp::test::request()\n        .path(\"/foo/123\")\n        .filter(&and)\n        .await\n        .unwrap();\n    assert_eq!(ex.as_str(), \"\");\n\n    // does not modify matching\n    let and = peek.and(foo).and(bar);\n    assert!(warp::test::request().path(\"/foo/bar\").matches(&and).await);\n}\n\n#[tokio::test]\nasync fn peek_segments() {\n    let peek = warp::path::peek();\n\n    // matches full request path\n    let ex = warp::test::request()\n        .path(\"/42/vroom\")\n        .filter(&peek)\n        .await\n        .unwrap();\n\n    assert_eq!(ex.segments().collect::<Vec<_>>(), &[\"42\", \"vroom\"]);\n\n    // matches index\n    let ex = warp::test::request().path(\"/\").filter(&peek).await.unwrap();\n\n    let segs = ex.segments().collect::<Vec<_>>();\n    assert_eq!(segs, Vec::<&str>::new());\n}\n"
  },
  {
    "path": "tests/query.rs",
    "content": "#![deny(warnings)]\n\nuse serde_derive::Deserialize;\nuse std::collections::HashMap;\nuse warp::Filter;\n\n#[tokio::test]\nasync fn query() {\n    let as_map = warp::query::<HashMap<String, String>>();\n\n    let req = warp::test::request().path(\"/?foo=bar&baz=quux\");\n\n    let extracted = req.filter(&as_map).await.unwrap();\n    assert_eq!(extracted[\"foo\"], \"bar\");\n    assert_eq!(extracted[\"baz\"], \"quux\");\n}\n\n#[tokio::test]\nasync fn query_struct() {\n    let as_struct = warp::query::<MyArgs>();\n\n    let req = warp::test::request().path(\"/?foo=bar&baz=quux\");\n\n    let extracted = req.filter(&as_struct).await.unwrap();\n    assert_eq!(\n        extracted,\n        MyArgs {\n            foo: Some(\"bar\".into()),\n            baz: Some(\"quux\".into())\n        }\n    );\n}\n\n#[tokio::test]\nasync fn empty_query_struct() {\n    let as_struct = warp::query::<MyArgs>();\n\n    let req = warp::test::request().path(\"/?\");\n\n    let extracted = req.filter(&as_struct).await.unwrap();\n    assert_eq!(\n        extracted,\n        MyArgs {\n            foo: None,\n            baz: None\n        }\n    );\n}\n\n#[tokio::test]\nasync fn query_struct_no_values() {\n    let as_struct = warp::query::<MyArgs>();\n\n    let req = warp::test::request().path(\"/?foo&baz\");\n\n    let extracted = req.filter(&as_struct).await.unwrap();\n    assert_eq!(\n        extracted,\n        MyArgs {\n            foo: Some(\"\".into()),\n            baz: Some(\"\".into())\n        }\n    );\n}\n\n#[tokio::test]\nasync fn missing_query_struct() {\n    let as_struct = warp::query::<MyArgs>();\n\n    let req = warp::test::request().path(\"/\");\n\n    let extracted = req.filter(&as_struct).await.unwrap();\n    assert_eq!(\n        extracted,\n        MyArgs {\n            foo: None,\n            baz: None\n        }\n    );\n}\n\n#[derive(Deserialize, Debug, Eq, PartialEq)]\nstruct MyArgs {\n    foo: Option<String>,\n    baz: Option<String>,\n}\n\n#[tokio::test]\nasync fn required_query_struct() {\n    let as_struct = warp::query::<MyRequiredArgs>();\n\n    let req = warp::test::request().path(\"/?foo=bar&baz=quux\");\n\n    let extracted = req.filter(&as_struct).await.unwrap();\n    assert_eq!(\n        extracted,\n        MyRequiredArgs {\n            foo: \"bar\".into(),\n            baz: \"quux\".into()\n        }\n    );\n}\n\n#[tokio::test]\nasync fn missing_required_query_struct_partial() {\n    let as_struct = warp::query::<MyRequiredArgs>();\n\n    let req = warp::test::request().path(\"/?foo=something\");\n\n    let extracted = req.filter(&as_struct).await;\n    assert!(extracted.is_err())\n}\n\n#[tokio::test]\nasync fn missing_required_query_struct_no_query() {\n    let as_struct = warp::query::<MyRequiredArgs>().map(|_| warp::reply());\n\n    let req = warp::test::request().path(\"/\");\n\n    let res = req.reply(&as_struct).await;\n    assert_eq!(res.status(), 400);\n    assert_eq!(res.body(), \"Invalid query string\");\n}\n\n#[derive(Deserialize, Debug, Eq, PartialEq)]\nstruct MyRequiredArgs {\n    foo: String,\n    baz: String,\n}\n\n#[tokio::test]\nasync fn raw_query() {\n    let as_raw = warp::query::raw();\n\n    let req = warp::test::request().path(\"/?foo=bar&baz=quux\");\n\n    let extracted = req.filter(&as_raw).await.unwrap();\n    assert_eq!(extracted, \"foo=bar&baz=quux\".to_owned());\n}\n"
  },
  {
    "path": "tests/redirect.rs",
    "content": "#![deny(warnings)]\nuse warp::{http::Uri, Filter};\n\n#[tokio::test]\nasync fn redirect_uri() {\n    let over_there = warp::any().map(|| warp::redirect(Uri::from_static(\"/over-there\")));\n\n    let req = warp::test::request();\n    let resp = req.reply(&over_there).await;\n\n    assert_eq!(resp.status(), 301);\n    assert_eq!(resp.headers()[\"location\"], \"/over-there\");\n}\n\n#[tokio::test]\nasync fn redirect_found_uri() {\n    let over_there = warp::any().map(|| warp::redirect::found(Uri::from_static(\"/over-there\")));\n\n    let req = warp::test::request();\n    let resp = req.reply(&over_there).await;\n\n    assert_eq!(resp.status(), 302);\n    assert_eq!(resp.headers()[\"location\"], \"/over-there\");\n}\n\n#[tokio::test]\nasync fn redirect_see_other_uri() {\n    let over_there = warp::any().map(|| warp::redirect::see_other(Uri::from_static(\"/over-there\")));\n\n    let req = warp::test::request();\n    let resp = req.reply(&over_there).await;\n\n    assert_eq!(resp.status(), 303);\n    assert_eq!(resp.headers()[\"location\"], \"/over-there\");\n}\n\n#[tokio::test]\nasync fn redirect_temporary_uri() {\n    let over_there = warp::any().map(|| warp::redirect::temporary(Uri::from_static(\"/over-there\")));\n\n    let req = warp::test::request();\n    let resp = req.reply(&over_there).await;\n\n    assert_eq!(resp.status(), 307);\n    assert_eq!(resp.headers()[\"location\"], \"/over-there\");\n}\n\n#[tokio::test]\nasync fn redirect_permanent_uri() {\n    let over_there = warp::any().map(|| warp::redirect::permanent(Uri::from_static(\"/over-there\")));\n\n    let req = warp::test::request();\n    let resp = req.reply(&over_there).await;\n\n    assert_eq!(resp.status(), 308);\n    assert_eq!(resp.headers()[\"location\"], \"/over-there\");\n}\n"
  },
  {
    "path": "tests/reply_with.rs",
    "content": "#![deny(warnings)]\nuse warp::http::header::{HeaderMap, HeaderValue};\nuse warp::Filter;\n\n#[tokio::test]\nasync fn header() {\n    let header = warp::reply::with::header(\"foo\", \"bar\");\n\n    let no_header = warp::any().map(warp::reply).with(&header);\n\n    let req = warp::test::request();\n    let resp = req.reply(&no_header).await;\n    assert_eq!(resp.headers()[\"foo\"], \"bar\");\n\n    let prev_header = warp::reply::with::header(\"foo\", \"sean\");\n    let yes_header = warp::any().map(warp::reply).with(prev_header).with(header);\n\n    let req = warp::test::request();\n    let resp = req.reply(&yes_header).await;\n    assert_eq!(resp.headers()[\"foo\"], \"bar\", \"replaces header\");\n}\n\n#[tokio::test]\nasync fn headers() {\n    let mut headers = HeaderMap::new();\n    headers.insert(\"server\", HeaderValue::from_static(\"warp\"));\n    headers.insert(\"foo\", HeaderValue::from_static(\"bar\"));\n\n    let headers = warp::reply::with::headers(headers);\n\n    let no_header = warp::any().map(warp::reply).with(&headers);\n\n    let req = warp::test::request();\n    let resp = req.reply(&no_header).await;\n    assert_eq!(resp.headers()[\"foo\"], \"bar\");\n    assert_eq!(resp.headers()[\"server\"], \"warp\");\n\n    let prev_header = warp::reply::with::header(\"foo\", \"sean\");\n    let yes_header = warp::any().map(warp::reply).with(prev_header).with(headers);\n\n    let req = warp::test::request();\n    let resp = req.reply(&yes_header).await;\n    assert_eq!(resp.headers()[\"foo\"], \"bar\", \"replaces header\");\n}\n\n#[tokio::test]\nasync fn default_header() {\n    let def_header = warp::reply::with::default_header(\"foo\", \"bar\");\n\n    let no_header = warp::any().map(warp::reply).with(&def_header);\n\n    let req = warp::test::request();\n    let resp = req.reply(&no_header).await;\n\n    assert_eq!(resp.headers()[\"foo\"], \"bar\");\n\n    let header = warp::reply::with::header(\"foo\", \"sean\");\n    let yes_header = warp::any().map(warp::reply).with(header).with(def_header);\n\n    let req = warp::test::request();\n    let resp = req.reply(&yes_header).await;\n\n    assert_eq!(resp.headers()[\"foo\"], \"sean\", \"doesn't replace header\");\n}\n"
  },
  {
    "path": "tests/tracing.rs",
    "content": "use warp::Filter;\n\n#[tokio::test]\nasync fn uses_tracing() {\n    // Setup a log subscriber (responsible to print to output)\n    let subscriber = tracing_subscriber::fmt()\n        .with_env_filter(\"trace\")\n        .without_time()\n        .finish();\n\n    // Set the previously created subscriber as the global subscriber\n    tracing::subscriber::set_global_default(subscriber).unwrap();\n    // Redirect normal log messages to the tracing subscriber\n    tracing_log::LogTracer::init().unwrap();\n\n    // Start a span with some metadata (fields)\n    let span = tracing::info_span!(\"app\", domain = \"www.example.org\");\n    let _guard = span.enter();\n\n    log::info!(\"logged using log macro\");\n\n    let ok = warp::any()\n        .map(|| {\n            tracing::info!(\"printed for every request\");\n        })\n        .untuple_one()\n        .and(warp::path(\"aa\"))\n        .map(|| {\n            tracing::info!(\"only printed when path '/aa' matches\");\n        })\n        .untuple_one()\n        .map(warp::reply)\n        // Here we add the tracing logger which will ensure that all requests has a span with\n        // useful information about the request (method, url, version, remote_addr, etc.)\n        .with(warp::trace::request());\n\n    tracing::info!(\"logged using tracing macro\");\n\n    // Send a request for /\n    let req = warp::test::request();\n    let resp = req.reply(&ok);\n    assert_eq!(resp.await.status(), 404);\n\n    // Send a request for /aa\n    let req = warp::test::request().path(\"/aa\");\n    let resp = req.reply(&ok);\n    assert_eq!(resp.await.status(), 200);\n}\n"
  },
  {
    "path": "tests/ws.rs",
    "content": "#![deny(warnings)]\n\nuse futures_util::{FutureExt, SinkExt, StreamExt};\nuse serde_derive::Deserialize;\nuse warp::ws::Message;\nuse warp::Filter;\n\n#[tokio::test]\nasync fn upgrade() {\n    let _ = pretty_env_logger::try_init();\n\n    let route = warp::ws().map(|ws: warp::ws::Ws| ws.on_upgrade(|_| async {}));\n\n    // From https://tools.ietf.org/html/rfc6455#section-1.2\n    let key = \"dGhlIHNhbXBsZSBub25jZQ==\";\n    let accept = \"s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\";\n\n    let resp = warp::test::request()\n        .header(\"connection\", \"upgrade\")\n        .header(\"upgrade\", \"websocket\")\n        .header(\"sec-websocket-version\", \"13\")\n        .header(\"sec-websocket-key\", key)\n        .reply(&route)\n        .await;\n\n    assert_eq!(resp.status(), 101);\n    assert_eq!(resp.headers()[\"connection\"], \"upgrade\");\n    assert_eq!(resp.headers()[\"upgrade\"], \"websocket\");\n    assert_eq!(resp.headers()[\"sec-websocket-accept\"], accept);\n\n    let resp = warp::test::request()\n        .header(\"connection\", \"keep-alive, Upgrade\")\n        .header(\"upgrade\", \"Websocket\")\n        .header(\"sec-websocket-version\", \"13\")\n        .header(\"sec-websocket-key\", key)\n        .reply(&route)\n        .await;\n\n    assert_eq!(resp.status(), 101);\n}\n\n#[tokio::test]\nasync fn fail() {\n    let _ = pretty_env_logger::try_init();\n\n    let route = warp::any().map(warp::reply);\n\n    warp::test::ws()\n        .handshake(route)\n        .await\n        .expect_err(\"handshake non-websocket route should fail\");\n}\n\n#[tokio::test]\nasync fn text() {\n    let _ = pretty_env_logger::try_init();\n\n    let mut client = warp::test::ws()\n        .handshake(ws_echo())\n        .await\n        .expect(\"handshake\");\n\n    client.send_text(\"hello warp\").await;\n\n    let msg = client.recv().await.expect(\"recv\");\n    assert_eq!(msg.to_str(), Ok(\"hello warp\"));\n}\n\n#[tokio::test]\nasync fn binary() {\n    let _ = pretty_env_logger::try_init();\n\n    let mut client = warp::test::ws()\n        .handshake(ws_echo())\n        .await\n        .expect(\"handshake\");\n\n    client.send(warp::ws::Message::binary(&b\"bonk\"[..])).await;\n    let msg = client.recv().await.expect(\"recv\");\n    assert!(msg.is_binary());\n    assert_eq!(msg.as_bytes(), &b\"bonk\"[..]);\n}\n\n#[tokio::test]\nasync fn wsclient_sink_and_stream() {\n    let _ = pretty_env_logger::try_init();\n\n    let mut client = warp::test::ws()\n        .handshake(ws_echo())\n        .await\n        .expect(\"handshake\");\n\n    let message = warp::ws::Message::text(\"hello\");\n    SinkExt::send(&mut client, message.clone()).await.unwrap();\n    let received_message = client.next().await.unwrap().unwrap();\n    assert_eq!(message, received_message);\n}\n\n#[tokio::test]\nasync fn close_frame() {\n    let _ = pretty_env_logger::try_init();\n\n    let route = warp::ws().map(|ws: warp::ws::Ws| {\n        ws.on_upgrade(|mut websocket| async move {\n            let msg = websocket.next().await.expect(\"item\").expect(\"ok\");\n            let _ = msg.close_frame().expect(\"close frame\");\n        })\n    });\n\n    let client = warp::test::ws().handshake(route).await.expect(\"handshake\");\n    drop(client);\n}\n\n#[tokio::test]\nasync fn send_ping() {\n    let _ = pretty_env_logger::try_init();\n\n    let filter = warp::ws().map(|ws: warp::ws::Ws| {\n        ws.on_upgrade(|mut websocket| {\n            async move {\n                websocket.send(Message::ping(\"srv\")).await.unwrap();\n                // assume the client will pong back\n                let msg = websocket.next().await.expect(\"item\").expect(\"ok\");\n                assert!(msg.is_pong());\n                assert_eq!(msg.as_bytes(), &b\"srv\"[..]);\n            }\n        })\n    });\n\n    let mut client = warp::test::ws().handshake(filter).await.expect(\"handshake\");\n\n    let msg = client.recv().await.expect(\"recv\");\n    assert!(msg.is_ping());\n    assert_eq!(msg.as_bytes(), &b\"srv\"[..]);\n\n    client.recv_closed().await.expect(\"closed\");\n}\n\n#[tokio::test]\nasync fn echo_pings() {\n    let _ = pretty_env_logger::try_init();\n\n    let mut client = warp::test::ws()\n        .handshake(ws_echo())\n        .await\n        .expect(\"handshake\");\n\n    client.send(Message::ping(\"clt\")).await;\n\n    // tungstenite sends the PONG first\n    let msg = client.recv().await.expect(\"recv\");\n    assert!(msg.is_pong());\n    assert_eq!(msg.as_bytes(), &b\"clt\"[..]);\n\n    // and then `ws_echo` sends us back the same PING\n    let msg = client.recv().await.expect(\"recv\");\n    assert!(msg.is_ping());\n    assert_eq!(msg.as_bytes(), &b\"clt\"[..]);\n\n    // and then our client would have sent *its* PONG\n    // and `ws_echo` would send *that* back too\n    let msg = client.recv().await.expect(\"recv\");\n    assert!(msg.is_pong());\n    assert_eq!(msg.as_bytes(), &b\"clt\"[..]);\n}\n\n#[tokio::test]\nasync fn pongs_only() {\n    let _ = pretty_env_logger::try_init();\n\n    let mut client = warp::test::ws()\n        .handshake(ws_echo())\n        .await\n        .expect(\"handshake\");\n\n    // construct a pong message and make sure it is correct\n    let msg = Message::pong(\"clt\");\n    assert!(msg.is_pong());\n    assert_eq!(msg.as_bytes(), &b\"clt\"[..]);\n\n    // send it to echo and wait for `ws_echo` to send it back\n    client.send(msg).await;\n\n    let msg = client.recv().await.expect(\"recv\");\n    assert!(msg.is_pong());\n    assert_eq!(msg.as_bytes(), &b\"clt\"[..]);\n}\n\n#[tokio::test]\nasync fn closed() {\n    let _ = pretty_env_logger::try_init();\n\n    let route =\n        warp::ws().map(|ws: warp::ws::Ws| ws.on_upgrade(|websocket| websocket.close().map(|_| ())));\n\n    let mut client = warp::test::ws().handshake(route).await.expect(\"handshake\");\n\n    client.recv_closed().await.expect(\"closed\");\n}\n\n#[tokio::test]\nasync fn limit_message_size() {\n    let _ = pretty_env_logger::try_init();\n\n    let echo = warp::ws().map(|ws: warp::ws::Ws| {\n        ws.max_message_size(1024).on_upgrade(|websocket| {\n            // Just echo all messages back...\n            let (tx, rx) = websocket.split();\n            rx.forward(tx).map(|result| {\n                assert!(result.is_err());\n                assert_eq!(\n                    format!(\"{}\", result.unwrap_err()).as_str(),\n                    \"Space limit exceeded: Message too big: 0 + 1025 > 1024\"\n                );\n            })\n        })\n    });\n    let mut client = warp::test::ws().handshake(echo).await.expect(\"handshake\");\n\n    client.send(warp::ws::Message::binary(vec![0; 1025])).await;\n    client.send_text(\"hello warp\").await;\n    assert!(client.recv().await.is_err());\n}\n\n#[tokio::test]\nasync fn limit_frame_size() {\n    let _ = pretty_env_logger::try_init();\n\n    let echo = warp::ws().map(|ws: warp::ws::Ws| {\n        ws.max_frame_size(1024).on_upgrade(|websocket| {\n            // Just echo all messages back...\n            let (tx, rx) = websocket.split();\n            rx.forward(tx).map(|result| {\n                assert!(result.is_err());\n                assert_eq!(\n                    format!(\"{}\", result.unwrap_err()).as_str(),\n                    \"Space limit exceeded: Message length too big: 1025 > 1024\"\n                );\n            })\n        })\n    });\n    let mut client = warp::test::ws().handshake(echo).await.expect(\"handshake\");\n\n    client.send(warp::ws::Message::binary(vec![0; 1025])).await;\n    client.send_text(\"hello warp\").await;\n    assert!(client.recv().await.is_err());\n}\n\n#[derive(Deserialize)]\nstruct MyQuery {\n    hello: String,\n}\n\n#[tokio::test]\nasync fn ws_with_query() {\n    let ws_filter = warp::path(\"my-ws\")\n        .and(warp::query::<MyQuery>())\n        .and(warp::ws())\n        .map(|query: MyQuery, ws: warp::ws::Ws| {\n            assert_eq!(query.hello, \"world\");\n\n            ws.on_upgrade(|websocket| {\n                let (tx, rx) = websocket.split();\n                rx.inspect(|i| log::debug!(\"ws recv: {:?}\", i))\n                    .forward(tx)\n                    .map(|_| ())\n            })\n        });\n\n    warp::test::ws()\n        .path(\"/my-ws?hello=world\")\n        .handshake(ws_filter)\n        .await\n        .expect(\"handshake\");\n}\n\n// Websocket filter that echoes all messages back.\nfn ws_echo() -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Copy {\n    warp::ws().map(|ws: warp::ws::Ws| {\n        ws.on_upgrade(|websocket| {\n            // Just echo all messages back...\n            let (tx, rx) = websocket.split();\n            rx.inspect(|i| log::debug!(\"ws recv: {:?}\", i))\n                .forward(tx)\n                .map(|_| ())\n        })\n    })\n}\n"
  }
]