forked from mirrors/gecko-dev
Bug 1868472 - Upgrade warp to 0.3.6. r=webdriver-reviewers,supply-chain-reviewers,bholley
https://github.com/seanmonstar/warp/pull/1069 is the same patch as https://github.com/seanmonstar/warp/pull/1007, but was applied to current master and will be in next release. Differential Revision: https://phabricator.services.mozilla.com/D195605
This commit is contained in:
parent
fbad034953
commit
d3a07c9082
34 changed files with 440 additions and 169 deletions
|
|
@ -30,11 +30,6 @@ git = "https://github.com/gfx-rs/wgpu"
|
|||
rev = "767ac03245ee937d3dc552edc13fe7ab0a860eec"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/glandium/warp?rev=4af45fae95bc98b0eba1ef0db17e1dac471bb23d"]
|
||||
git = "https://github.com/glandium/warp"
|
||||
rev = "4af45fae95bc98b0eba1ef0db17e1dac471bb23d"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/hsivonen/chardetng?rev=3484d3e3ebdc8931493aa5df4d7ee9360a90e76b"]
|
||||
git = "https://github.com/hsivonen/chardetng"
|
||||
rev = "3484d3e3ebdc8931493aa5df4d7ee9360a90e76b"
|
||||
|
|
@ -100,6 +95,11 @@ git = "https://github.com/rust-lang/rust-bindgen"
|
|||
rev = "86f3dbe846020e2ba573d6eb38d1434d0cbcbb40"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/seanmonstar/warp?rev=9d081461ae1167eb321585ce424f4fef6cf0092b"]
|
||||
git = "https://github.com/seanmonstar/warp"
|
||||
rev = "9d081461ae1167eb321585ce424f4fef6cf0092b"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/servo/rust-cssparser?rev=aaa966d9d6ae70c4b8a62bb5e3a14c068bb7dff0"]
|
||||
git = "https://github.com/servo/rust-cssparser"
|
||||
rev = "aaa966d9d6ae70c4b8a62bb5e3a14c068bb7dff0"
|
||||
|
|
|
|||
4
Cargo.lock
generated
4
Cargo.lock
generated
|
|
@ -6132,8 +6132,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "warp"
|
||||
version = "0.3.3"
|
||||
source = "git+https://github.com/glandium/warp?rev=4af45fae95bc98b0eba1ef0db17e1dac471bb23d#4af45fae95bc98b0eba1ef0db17e1dac471bb23d"
|
||||
version = "0.3.6"
|
||||
source = "git+https://github.com/seanmonstar/warp?rev=9d081461ae1167eb321585ce424f4fef6cf0092b#9d081461ae1167eb321585ce424f4fef6cf0092b"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
|
|
|
|||
|
|
@ -196,8 +196,8 @@ icu_capi = { path = "intl/icu_capi" }
|
|||
icu_segmenter_data = { path = "intl/icu_segmenter_data" }
|
||||
libudev-sys = { path = "dom/webauthn/libudev-sys" }
|
||||
midir = { git = "https://github.com/mozilla/midir.git", rev = "519e651241e867af3391db08f9ae6400bc023e18" }
|
||||
# warp 0.3.3 + https://github.com/seanmonstar/warp/pull/1007
|
||||
warp = { git = "https://github.com/glandium/warp", rev = "4af45fae95bc98b0eba1ef0db17e1dac471bb23d" }
|
||||
# warp 0.3.6 + https://github.com/seanmonstar/warp/pull/1069
|
||||
warp = { git = "https://github.com/seanmonstar/warp", rev = "9d081461ae1167eb321585ce424f4fef6cf0092b" }
|
||||
# Allow webrender to have a versioned dependency on the older crate on crates.io
|
||||
# in order to build standalone.
|
||||
malloc_size_of_derive = { path = "xpcom/rust/malloc_size_of_derive" }
|
||||
|
|
|
|||
|
|
@ -4080,6 +4080,11 @@ who = "Bobby Holley <bobbyholley@gmail.com>"
|
|||
criteria = "safe-to-run"
|
||||
delta = "0.3.3 -> 0.3.3@git:4af45fae95bc98b0eba1ef0db17e1dac471bb23d"
|
||||
|
||||
[[audits.warp]]
|
||||
who = "Mike Hommey <mh+mozilla@glandium.org>"
|
||||
criteria = "safe-to-run"
|
||||
delta = "0.3.6 -> 0.3.6@git:9d081461ae1167eb321585ce424f4fef6cf0092b"
|
||||
|
||||
[[audits.wasm-encoder]]
|
||||
who = "Ryan Hunt <rhunt@eqrion.net>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
|
|
|||
|
|
@ -727,6 +727,13 @@ user-id = 359
|
|||
user-login = "seanmonstar"
|
||||
user-name = "Sean McArthur"
|
||||
|
||||
[[publisher.warp]]
|
||||
version = "0.3.6"
|
||||
when = "2023-09-27"
|
||||
user-id = 359
|
||||
user-login = "seanmonstar"
|
||||
user-name = "Sean McArthur"
|
||||
|
||||
[[publisher.wasi]]
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
when = "2022-01-19"
|
||||
|
|
|
|||
2
third_party/rust/warp/.cargo-checksum.json
vendored
2
third_party/rust/warp/.cargo-checksum.json
vendored
File diff suppressed because one or more lines are too long
43
third_party/rust/warp/.github/workflows/ci.yml
vendored
43
third_party/rust/warp/.github/workflows/ci.yml
vendored
|
|
@ -12,21 +12,14 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: stable
|
||||
components: rustfmt
|
||||
profile: minimal
|
||||
override: true
|
||||
|
||||
- name: cargo fmt -- --check
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
- run: cargo fmt --all --check
|
||||
|
||||
test:
|
||||
name: Test
|
||||
|
|
@ -50,30 +43,21 @@ jobs:
|
|||
- build: compression
|
||||
features: "--features compression"
|
||||
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: ${{ matrix.rust || 'stable' }}
|
||||
profile: minimal
|
||||
override: true
|
||||
|
||||
- name: Test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: ${{ matrix.features }}
|
||||
run: cargo test ${{ matrix.features }}
|
||||
|
||||
- name: Test all benches
|
||||
if: matrix.benches
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --benches ${{ matrix.features }}
|
||||
run: cargo test --benches ${{ matrix.features }}
|
||||
|
||||
doc:
|
||||
name: Build docs
|
||||
|
|
@ -81,17 +65,10 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly
|
||||
override: true
|
||||
uses: dtolnay/rust-toolchain@nightly
|
||||
|
||||
- name: cargo doc
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: rustdoc
|
||||
args: -- -D broken_intra_doc_links
|
||||
run: cargo rustdoc -- -D broken_intra_doc_links
|
||||
|
|
|
|||
22
third_party/rust/warp/CHANGELOG.md
vendored
22
third_party/rust/warp/CHANGELOG.md
vendored
|
|
@ -1,3 +1,25 @@
|
|||
### v0.3.6 (September 27, 2023)
|
||||
|
||||
- **Features**:
|
||||
- Add ability to pass `None` to `multipart::form().max_length()`.
|
||||
- Implement `Reply` for `Result<impl Reply, impl Reply>`.
|
||||
- Make `multipart::Part::content_type()` return the full mime string.
|
||||
- Add `TlsServer::try_bind_with_graceful_shutdown()`.
|
||||
- **Fixes**:
|
||||
- Updated tungstenite and rustls dependencies for security fixes.
|
||||
|
||||
### v0.3.5 (April 28, 2023)
|
||||
|
||||
- **Fixes**:
|
||||
- `multipart` filters now use `multer` dependency, fixing some streaming bugs.
|
||||
- `Rejection::into_response()` is significantly faster.
|
||||
|
||||
### v0.3.4 (March 31, 2023)
|
||||
|
||||
- **Fixes**:
|
||||
- `multipart::Part` data is now streamed instead of buffered.
|
||||
- Update dependency used for `multipart` filters.
|
||||
|
||||
### v0.3.3 (September 27, 2022)
|
||||
|
||||
- **Fixes**:
|
||||
|
|
|
|||
28
third_party/rust/warp/Cargo.toml
vendored
28
third_party/rust/warp/Cargo.toml
vendored
|
|
@ -12,7 +12,7 @@
|
|||
[package]
|
||||
edition = "2018"
|
||||
name = "warp"
|
||||
version = "0.3.3"
|
||||
version = "0.3.6"
|
||||
authors = ["Sean McArthur <sean@seanmonstar.com>"]
|
||||
autoexamples = true
|
||||
autotests = true
|
||||
|
|
@ -58,6 +58,10 @@ required-features = ["websocket"]
|
|||
[[example]]
|
||||
name = "query_string"
|
||||
|
||||
[[example]]
|
||||
name = "multipart"
|
||||
required-features = ["multipart"]
|
||||
|
||||
[[test]]
|
||||
name = "multipart"
|
||||
required-features = ["multipart"]
|
||||
|
|
@ -107,14 +111,12 @@ features = [
|
|||
"client",
|
||||
]
|
||||
|
||||
[dependencies.multipart]
|
||||
version = "0.18"
|
||||
features = ["server"]
|
||||
[dependencies.multer]
|
||||
version = "2.1.0"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.rustls-pemfile]
|
||||
version = "0.2"
|
||||
version = "1.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.tokio]
|
||||
|
|
@ -126,11 +128,11 @@ features = [
|
|||
]
|
||||
|
||||
[dependencies.tokio-rustls]
|
||||
version = "0.23"
|
||||
version = "0.24"
|
||||
optional = true
|
||||
|
||||
[dependencies.tokio-tungstenite]
|
||||
version = "0.17"
|
||||
version = "0.20"
|
||||
optional = true
|
||||
|
||||
[dependencies.tokio-util]
|
||||
|
|
@ -147,11 +149,10 @@ default-features = false
|
|||
|
||||
[dev-dependencies]
|
||||
handlebars = "4.0"
|
||||
listenfd = "0.3"
|
||||
pretty_env_logger = "0.4"
|
||||
listenfd = "1.0"
|
||||
pretty_env_logger = "0.5"
|
||||
serde_derive = "1.0"
|
||||
tracing-log = "0.1"
|
||||
tracing-subscriber = "0.2.7"
|
||||
|
||||
[dev-dependencies.tokio]
|
||||
version = "1.0"
|
||||
|
|
@ -164,6 +165,10 @@ features = [
|
|||
version = "0.1.1"
|
||||
features = ["net"]
|
||||
|
||||
[dev-dependencies.tracing-subscriber]
|
||||
version = "0.3"
|
||||
features = ["env-filter"]
|
||||
|
||||
[features]
|
||||
compression = [
|
||||
"compression-brotli",
|
||||
|
|
@ -178,6 +183,7 @@ default = [
|
|||
"multipart",
|
||||
"websocket",
|
||||
]
|
||||
multipart = ["multer"]
|
||||
tls = [
|
||||
"tokio-rustls",
|
||||
"rustls-pemfile",
|
||||
|
|
|
|||
32
third_party/rust/warp/examples/multipart.rs
vendored
Normal file
32
third_party/rust/warp/examples/multipart.rs
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
use bytes::BufMut;
|
||||
use futures_util::TryStreamExt;
|
||||
use warp::multipart::FormData;
|
||||
use warp::Filter;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// Running curl -F file=@.gitignore 'localhost:3030/' should print [("file", ".gitignore", "\n/target\n**/*.rs.bk\nCargo.lock\n.idea/\nwarp.iml\n")]
|
||||
let route = warp::multipart::form().and_then(|form: FormData| async move {
|
||||
let field_names: Vec<_> = form
|
||||
.and_then(|mut field| async move {
|
||||
let mut bytes: Vec<u8> = Vec::new();
|
||||
|
||||
// field.data() only returns a piece of the content, you should call over it until it replies None
|
||||
while let Some(content) = field.data().await {
|
||||
let content = content.unwrap();
|
||||
bytes.put(content);
|
||||
}
|
||||
Ok((
|
||||
field.name().to_string(),
|
||||
field.filename().unwrap().to_string(),
|
||||
String::from_utf8_lossy(&*bytes).to_string(),
|
||||
))
|
||||
})
|
||||
.try_collect()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
Ok::<_, warp::Rejection>(format!("{:?}", field_names))
|
||||
});
|
||||
warp::serve(route).run(([127, 0, 0, 1], 3030)).await;
|
||||
}
|
||||
30
third_party/rust/warp/examples/stream.rs
vendored
Normal file
30
third_party/rust/warp/examples/stream.rs
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
use bytes::Buf;
|
||||
use futures_util::{Stream, StreamExt};
|
||||
use warp::{reply::Response, Filter, Reply};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// Running curl -T /path/to/a/file 'localhost:3030/' should echo back the content of the file,
|
||||
// or an HTTP 413 error if the configured size limit is exceeded.
|
||||
let route = warp::body::content_length_limit(65536)
|
||||
.and(warp::body::stream())
|
||||
.then(handler);
|
||||
warp::serve(route).run(([127, 0, 0, 1], 3030)).await;
|
||||
}
|
||||
|
||||
async fn handler(
|
||||
mut body: impl Stream<Item = Result<impl Buf, warp::Error>> + Unpin + Send + Sync,
|
||||
) -> Response {
|
||||
let mut collected: Vec<u8> = vec![];
|
||||
while let Some(buf) = body.next().await {
|
||||
let mut buf = buf.unwrap();
|
||||
while buf.remaining() > 0 {
|
||||
let chunk = buf.chunk();
|
||||
let chunk_len = chunk.len();
|
||||
collected.extend_from_slice(chunk);
|
||||
buf.advance(chunk_len);
|
||||
}
|
||||
}
|
||||
println!("Sending {} bytes", collected.len());
|
||||
collected.into_response()
|
||||
}
|
||||
10
third_party/rust/warp/examples/todos.rs
vendored
10
third_party/rust/warp/examples/todos.rs
vendored
|
|
@ -38,7 +38,7 @@ mod filters {
|
|||
/// The 4 TODOs filters combined.
|
||||
pub fn todos(
|
||||
db: Db,
|
||||
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
|
||||
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
|
||||
todos_list(db.clone())
|
||||
.or(todos_create(db.clone()))
|
||||
.or(todos_update(db.clone()))
|
||||
|
|
@ -48,7 +48,7 @@ mod filters {
|
|||
/// GET /todos?offset=3&limit=5
|
||||
pub fn todos_list(
|
||||
db: Db,
|
||||
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
|
||||
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
|
||||
warp::path!("todos")
|
||||
.and(warp::get())
|
||||
.and(warp::query::<ListOptions>())
|
||||
|
|
@ -59,7 +59,7 @@ mod filters {
|
|||
/// POST /todos with JSON body
|
||||
pub fn todos_create(
|
||||
db: Db,
|
||||
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
|
||||
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
|
||||
warp::path!("todos")
|
||||
.and(warp::post())
|
||||
.and(json_body())
|
||||
|
|
@ -70,7 +70,7 @@ mod filters {
|
|||
/// PUT /todos/:id with JSON body
|
||||
pub fn todos_update(
|
||||
db: Db,
|
||||
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
|
||||
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
|
||||
warp::path!("todos" / u64)
|
||||
.and(warp::put())
|
||||
.and(json_body())
|
||||
|
|
@ -81,7 +81,7 @@ mod filters {
|
|||
/// DELETE /todos/:id
|
||||
pub fn todos_delete(
|
||||
db: Db,
|
||||
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
|
||||
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
|
||||
// We'll make one of our endpoints admin-only to show how authentication filters are used
|
||||
let admin_only = warp::header::exact("authorization", "Bearer admin");
|
||||
|
||||
|
|
|
|||
2
third_party/rust/warp/src/filter/boxed.rs
vendored
2
third_party/rust/warp/src/filter/boxed.rs
vendored
|
|
@ -8,7 +8,7 @@ use futures_util::TryFutureExt;
|
|||
use super::{Filter, FilterBase, Internal, Tuple};
|
||||
use crate::reject::Rejection;
|
||||
|
||||
/// A type representing a boxed `Filter` trait object.
|
||||
/// A type representing a boxed [`Filter`](crate::Filter) trait object.
|
||||
///
|
||||
/// The filter inside is a dynamic trait object. The purpose of this type is
|
||||
/// to ease returning `Filter`s from other functions.
|
||||
|
|
|
|||
4
third_party/rust/warp/src/filters/any.rs
vendored
4
third_party/rust/warp/src/filters/any.rs
vendored
|
|
@ -6,10 +6,10 @@ use std::task::{Context, Poll};
|
|||
|
||||
use crate::filter::{Filter, FilterBase, Internal};
|
||||
|
||||
/// A filter that matches any route.
|
||||
/// A [`Filter`](crate::Filter) that matches any route.
|
||||
///
|
||||
/// This can be a useful building block to build new filters from,
|
||||
/// since [`Filter`](crate::Filter) is otherwise a sealed trait.
|
||||
/// since [`Filter`] is otherwise a sealed trait.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
|
|
|||
2
third_party/rust/warp/src/filters/body.rs
vendored
2
third_party/rust/warp/src/filters/body.rs
vendored
|
|
@ -70,6 +70,8 @@ pub fn content_length_limit(limit: u64) -> impl Filter<Extract = (), Error = Rej
|
|||
/// If other filters have already extracted the body, this filter will reject
|
||||
/// with a `500 Internal Server Error`.
|
||||
///
|
||||
/// For example usage, please take a look at [examples/stream.rs](https://github.com/seanmonstar/warp/blob/master/examples/stream.rs).
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// This does not have a default size limit, it would be wise to use one to
|
||||
|
|
|
|||
4
third_party/rust/warp/src/filters/cors.rs
vendored
4
third_party/rust/warp/src/filters/cors.rs
vendored
|
|
@ -20,7 +20,7 @@ use crate::reply::Reply;
|
|||
|
||||
use self::internal::{CorsFilter, IntoOrigin, Seconds};
|
||||
|
||||
/// Create a wrapping filter that exposes [CORS][] behavior for a wrapped
|
||||
/// Create a wrapping [`Filter`](crate::Filter) that exposes [CORS][] behavior for a wrapped
|
||||
/// filter.
|
||||
///
|
||||
/// [CORS]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
||||
|
|
@ -56,7 +56,7 @@ pub fn cors() -> Builder {
|
|||
}
|
||||
}
|
||||
|
||||
/// A wrapping filter constructed via `warp::cors()`.
|
||||
/// A wrapping [`Filter`](crate::Filter) constructed via `warp::cors()`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Cors {
|
||||
config: Arc<Configured>,
|
||||
|
|
|
|||
2
third_party/rust/warp/src/filters/fs.rs
vendored
2
third_party/rust/warp/src/filters/fs.rs
vendored
|
|
@ -37,7 +37,7 @@ use crate::reply::{Reply, Response};
|
|||
/// filters, such as after validating in `POST` request, wanting to return a
|
||||
/// specific file as the body.
|
||||
///
|
||||
/// For serving a directory, see [dir](dir).
|
||||
/// For serving a directory, see [dir].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
|
|
|||
6
third_party/rust/warp/src/filters/log.rs
vendored
6
third_party/rust/warp/src/filters/log.rs
vendored
|
|
@ -13,7 +13,7 @@ use crate::route::Route;
|
|||
|
||||
use self::internal::WithLog;
|
||||
|
||||
/// Create a wrapping filter with the specified `name` as the `target`.
|
||||
/// Create a wrapping [`Filter`](crate::Filter) with the specified `name` as the `target`.
|
||||
///
|
||||
/// This uses the default access logging format, and log records produced
|
||||
/// will have their `target` set to `name`.
|
||||
|
|
@ -50,7 +50,7 @@ pub fn log(name: &'static str) -> Log<impl Fn(Info<'_>) + Copy> {
|
|||
Log { func }
|
||||
}
|
||||
|
||||
/// Create a wrapping filter that receives `warp::log::Info`.
|
||||
/// Create a wrapping [`Filter`](crate::Filter) that receives `warp::log::Info`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
|
@ -77,7 +77,7 @@ where
|
|||
Log { func }
|
||||
}
|
||||
|
||||
/// Decorates a [`Filter`](crate::Filter) to log requests and responses.
|
||||
/// Decorates a [`Filter`] to log requests and responses.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Log<F> {
|
||||
func: F,
|
||||
|
|
|
|||
138
third_party/rust/warp/src/filters/multipart.rs
vendored
138
third_party/rust/warp/src/filters/multipart.rs
vendored
|
|
@ -1,18 +1,20 @@
|
|||
//! Multipart body filters
|
||||
//!
|
||||
//! Filters that extract a multipart body for a route.
|
||||
//! [`Filter`](crate::Filter)s that extract a multipart body for a route.
|
||||
|
||||
use std::fmt;
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::future::Future;
|
||||
use std::io::{Cursor, Read};
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use std::{fmt, io};
|
||||
|
||||
use bytes::{Buf, Bytes};
|
||||
use futures_util::{future, Stream};
|
||||
use headers::ContentType;
|
||||
use hyper::Body;
|
||||
use mime::Mime;
|
||||
use multipart::server::Multipart;
|
||||
use multer::{Field as PartInner, Multipart as FormDataInner};
|
||||
|
||||
use crate::filter::{Filter, FilterBase, Internal};
|
||||
use crate::reject::{self, Rejection};
|
||||
|
|
@ -20,38 +22,35 @@ use crate::reject::{self, Rejection};
|
|||
// If not otherwise configured, default to 2MB.
|
||||
const DEFAULT_FORM_DATA_MAX_LENGTH: u64 = 1024 * 1024 * 2;
|
||||
|
||||
/// A `Filter` to extract a `multipart/form-data` body from a request.
|
||||
/// A [`Filter`](crate::Filter) to extract a `multipart/form-data` body from a request.
|
||||
///
|
||||
/// Create with the `warp::multipart::form()` function.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FormOptions {
|
||||
max_length: u64,
|
||||
max_length: Option<u64>,
|
||||
}
|
||||
|
||||
/// A `Stream` of multipart/form-data `Part`s.
|
||||
///
|
||||
/// Extracted with a `warp::multipart::form` filter.
|
||||
pub struct FormData {
|
||||
inner: Multipart<Cursor<::bytes::Bytes>>,
|
||||
inner: FormDataInner<'static>,
|
||||
}
|
||||
|
||||
/// A single "part" of a multipart/form-data body.
|
||||
///
|
||||
/// Yielded from the `FormData` stream.
|
||||
pub struct Part {
|
||||
name: String,
|
||||
filename: Option<String>,
|
||||
content_type: Option<String>,
|
||||
data: Option<Vec<u8>>,
|
||||
part: PartInner<'static>,
|
||||
}
|
||||
|
||||
/// Create a `Filter` to extract a `multipart/form-data` body from a request.
|
||||
/// Create a [`Filter`](crate::Filter) to extract a `multipart/form-data` body from a request.
|
||||
///
|
||||
/// The extracted `FormData` type is a `Stream` of `Part`s, and each `Part`
|
||||
/// in turn is a `Stream` of bytes.
|
||||
pub fn form() -> FormOptions {
|
||||
FormOptions {
|
||||
max_length: DEFAULT_FORM_DATA_MAX_LENGTH,
|
||||
max_length: Some(DEFAULT_FORM_DATA_MAX_LENGTH),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -60,9 +59,10 @@ pub fn form() -> FormOptions {
|
|||
impl FormOptions {
|
||||
/// Set the maximum byte length allowed for this body.
|
||||
///
|
||||
/// `max_length(None)` means that maximum byte length is not checked.
|
||||
/// Defaults to 2MB.
|
||||
pub fn max_length(mut self, max: u64) -> Self {
|
||||
self.max_length = max;
|
||||
pub fn max_length(mut self, max: impl Into<Option<u64>>) -> Self {
|
||||
self.max_length = max.into();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
@ -84,16 +84,24 @@ impl FilterBase for FormOptions {
|
|||
future::ready(mime)
|
||||
});
|
||||
|
||||
let filt = super::body::content_length_limit(self.max_length)
|
||||
.and(boundary)
|
||||
.and(super::body::bytes())
|
||||
.map(|boundary, body| FormData {
|
||||
inner: Multipart::with_body(Cursor::new(body), boundary),
|
||||
let filt = boundary
|
||||
.and(super::body::body())
|
||||
.map(|boundary: String, body| {
|
||||
let body = BodyIoError(body);
|
||||
FormData {
|
||||
inner: FormDataInner::new(body, &boundary),
|
||||
}
|
||||
});
|
||||
|
||||
let fut = filt.filter(Internal);
|
||||
|
||||
Box::pin(fut)
|
||||
if let Some(max_length) = self.max_length {
|
||||
Box::pin(
|
||||
super::body::content_length_limit(max_length)
|
||||
.and(filt)
|
||||
.filter(Internal),
|
||||
)
|
||||
} else {
|
||||
Box::pin(filt.filter(Internal))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -108,23 +116,18 @@ impl fmt::Debug for FormData {
|
|||
impl Stream for FormData {
|
||||
type Item = Result<Part, crate::Error>;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
match (*self).inner.read_entry() {
|
||||
Ok(Some(mut field)) => {
|
||||
let mut data = Vec::new();
|
||||
field
|
||||
.data
|
||||
.read_to_end(&mut data)
|
||||
.map_err(crate::Error::new)?;
|
||||
Poll::Ready(Some(Ok(Part {
|
||||
name: field.headers.name.to_string(),
|
||||
filename: field.headers.filename,
|
||||
content_type: field.headers.content_type.map(|m| m.to_string()),
|
||||
data: Some(data),
|
||||
})))
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
match self.inner.poll_next_field(cx) {
|
||||
Poll::Pending => Poll::Pending,
|
||||
Poll::Ready(Ok(Some(part))) => {
|
||||
if part.name().is_some() {
|
||||
Poll::Ready(Some(Ok(Part { part })))
|
||||
} else {
|
||||
Poll::Ready(Some(Err(crate::Error::new(MultipartFieldMissingName))))
|
||||
}
|
||||
}
|
||||
Ok(None) => Poll::Ready(None),
|
||||
Err(e) => Poll::Ready(Some(Err(crate::Error::new(e)))),
|
||||
Poll::Ready(Ok(None)) => Poll::Ready(None),
|
||||
Poll::Ready(Err(err)) => Poll::Ready(Some(Err(crate::Error::new(err)))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -134,22 +137,23 @@ impl Stream for FormData {
|
|||
impl Part {
|
||||
/// Get the name of this part.
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
self.part.name().expect("checked for name previously")
|
||||
}
|
||||
|
||||
/// Get the filename of this part, if present.
|
||||
pub fn filename(&self) -> Option<&str> {
|
||||
self.filename.as_deref()
|
||||
self.part.file_name()
|
||||
}
|
||||
|
||||
/// Get the content-type of this part, if present.
|
||||
pub fn content_type(&self) -> Option<&str> {
|
||||
self.content_type.as_deref()
|
||||
let content_type = self.part.content_type();
|
||||
content_type.map(|t| t.as_ref())
|
||||
}
|
||||
|
||||
/// Asynchronously get some of the data for this `Part`.
|
||||
pub async fn data(&mut self) -> Option<Result<impl Buf, crate::Error>> {
|
||||
self.take_data()
|
||||
future::poll_fn(|cx| self.poll_next(cx)).await
|
||||
}
|
||||
|
||||
/// Convert this `Part` into a `Stream` of `Buf`s.
|
||||
|
|
@ -157,21 +161,26 @@ impl Part {
|
|||
PartStream(self)
|
||||
}
|
||||
|
||||
fn take_data(&mut self) -> Option<Result<Bytes, crate::Error>> {
|
||||
self.data.take().map(|vec| Ok(vec.into()))
|
||||
fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Bytes, crate::Error>>> {
|
||||
match Pin::new(&mut self.part).poll_next(cx) {
|
||||
Poll::Pending => Poll::Pending,
|
||||
Poll::Ready(Some(Ok(bytes))) => Poll::Ready(Some(Ok(bytes))),
|
||||
Poll::Ready(None) => Poll::Ready(None),
|
||||
Poll::Ready(Some(Err(err))) => Poll::Ready(Some(Err(crate::Error::new(err)))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Part {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut builder = f.debug_struct("Part");
|
||||
builder.field("name", &self.name);
|
||||
builder.field("name", &self.part.name());
|
||||
|
||||
if let Some(ref filename) = self.filename {
|
||||
if let Some(ref filename) = self.part.file_name() {
|
||||
builder.field("filename", filename);
|
||||
}
|
||||
|
||||
if let Some(ref mime) = self.content_type {
|
||||
if let Some(ref mime) = self.part.content_type() {
|
||||
builder.field("content_type", mime);
|
||||
}
|
||||
|
||||
|
|
@ -184,7 +193,36 @@ struct PartStream(Part);
|
|||
impl Stream for PartStream {
|
||||
type Item = Result<Bytes, crate::Error>;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
Poll::Ready(self.0.take_data())
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
self.0.poll_next(cx)
|
||||
}
|
||||
}
|
||||
|
||||
struct BodyIoError(Body);
|
||||
|
||||
impl Stream for BodyIoError {
|
||||
type Item = io::Result<Bytes>;
|
||||
|
||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
match Pin::new(&mut self.0).poll_next(cx) {
|
||||
Poll::Pending => Poll::Pending,
|
||||
Poll::Ready(Some(Ok(bytes))) => Poll::Ready(Some(Ok(bytes))),
|
||||
Poll::Ready(None) => Poll::Ready(None),
|
||||
Poll::Ready(Some(Err(err))) => {
|
||||
Poll::Ready(Some(Err(io::Error::new(io::ErrorKind::Other, err))))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An error used when a multipart field is missing a name.
|
||||
#[derive(Debug)]
|
||||
struct MultipartFieldMissingName;
|
||||
|
||||
impl Display for MultipartFieldMissingName {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Multipart field is missing a name")
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for MultipartFieldMissingName {}
|
||||
|
|
|
|||
6
third_party/rust/warp/src/filters/path.rs
vendored
6
third_party/rust/warp/src/filters/path.rs
vendored
|
|
@ -1,6 +1,6 @@
|
|||
//! Path Filters
|
||||
//!
|
||||
//! The filters here work on the "path" of requests.
|
||||
//! The [`Filter`](crate::Filter)s here work on the "path" of requests.
|
||||
//!
|
||||
//! - [`path`](./fn.path.html) matches a specific segment, like `/foo`.
|
||||
//! - [`param`](./fn.param.html) tries to parse a segment into a type, like `/:u16`.
|
||||
|
|
@ -137,7 +137,7 @@ use crate::filter::{filter_fn, one, Filter, FilterBase, Internal, One, Tuple};
|
|||
use crate::reject::{self, Rejection};
|
||||
use crate::route::{self, Route};
|
||||
|
||||
/// Create an exact match path segment `Filter`.
|
||||
/// Create an exact match path segment [`Filter`](crate::Filter).
|
||||
///
|
||||
/// This will try to match exactly to the current request path segment.
|
||||
///
|
||||
|
|
@ -189,7 +189,7 @@ where
|
|||
*/
|
||||
}
|
||||
|
||||
/// A `Filter` matching an exact path segment.
|
||||
/// A [`Filter`](crate::Filter) matching an exact path segment.
|
||||
///
|
||||
/// Constructed from `path()` or `path!()`.
|
||||
#[allow(missing_debug_implementations)]
|
||||
|
|
|
|||
12
third_party/rust/warp/src/filters/reply.rs
vendored
12
third_party/rust/warp/src/filters/reply.rs
vendored
|
|
@ -28,12 +28,12 @@ use self::sealed::{WithDefaultHeader_, WithHeader_, WithHeaders_};
|
|||
use crate::filter::{Filter, Map, WrapSealed};
|
||||
use crate::reply::Reply;
|
||||
|
||||
/// Wrap a [`Filter`](crate::Filter) that adds a header to the reply.
|
||||
/// Wrap a [`Filter`] that adds a header to the reply.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This **only** adds a header if the underlying filter is successful, and
|
||||
/// returns a [`Reply`](Reply). If the underlying filter was rejected, the
|
||||
/// returns a [`Reply`] If the underlying filter was rejected, the
|
||||
/// header is not added.
|
||||
///
|
||||
/// # Example
|
||||
|
|
@ -57,12 +57,12 @@ where
|
|||
WithHeader { name, value }
|
||||
}
|
||||
|
||||
/// Wrap a [`Filter`](crate::Filter) that adds multiple headers to the reply.
|
||||
/// Wrap a [`Filter`] that adds multiple headers to the reply.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This **only** adds a header if the underlying filter is successful, and
|
||||
/// returns a [`Reply`](Reply). If the underlying filter was rejected, the
|
||||
/// returns a [`Reply`] If the underlying filter was rejected, the
|
||||
/// header is not added.
|
||||
///
|
||||
/// # Example
|
||||
|
|
@ -88,13 +88,13 @@ pub fn headers(headers: HeaderMap) -> WithHeaders {
|
|||
|
||||
// pub fn headers?
|
||||
|
||||
/// Wrap a [`Filter`](crate::Filter) that adds a header to the reply, if they
|
||||
/// Wrap a [`Filter`] that adds a header to the reply, if they
|
||||
/// aren't already set.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This **only** adds a header if the underlying filter is successful, and
|
||||
/// returns a [`Reply`](Reply). If the underlying filter was rejected, the
|
||||
/// returns a [`Reply`] If the underlying filter was rejected, the
|
||||
/// header is not added.
|
||||
///
|
||||
/// # Example
|
||||
|
|
|
|||
4
third_party/rust/warp/src/filters/sse.rs
vendored
4
third_party/rust/warp/src/filters/sse.rs
vendored
|
|
@ -39,6 +39,8 @@
|
|||
//! which specifies the expected behavior of Server Sent Events.
|
||||
//!
|
||||
|
||||
#![allow(rustdoc::invalid_html_tags)]
|
||||
|
||||
use serde::Serialize;
|
||||
use std::borrow::Cow;
|
||||
use std::error::Error as StdError;
|
||||
|
|
@ -376,7 +378,7 @@ impl KeepAlive {
|
|||
|
||||
/// Wrap an event stream with keep-alive functionality.
|
||||
///
|
||||
/// See [`keep_alive`](keep_alive) for more.
|
||||
/// See [`keep_alive`] for more.
|
||||
pub fn stream<S>(
|
||||
self,
|
||||
event_stream: S,
|
||||
|
|
|
|||
2
third_party/rust/warp/src/filters/trace.rs
vendored
2
third_party/rust/warp/src/filters/trace.rs
vendored
|
|
@ -123,7 +123,7 @@ pub fn named(name: &'static str) -> Trace<impl Fn(Info<'_>) -> Span + Copy> {
|
|||
trace(move |_| tracing::debug_span!("context", "{}", name,))
|
||||
}
|
||||
|
||||
/// Decorates a [`Filter`](crate::Filter) to create a [`tracing`] [span] for
|
||||
/// Decorates a [`Filter`] to create a [`tracing`] [span] for
|
||||
/// requests and responses.
|
||||
///
|
||||
/// [`tracing`]: https://crates.io/crates/tracing
|
||||
|
|
|
|||
18
third_party/rust/warp/src/filters/ws.rs
vendored
18
third_party/rust/warp/src/filters/ws.rs
vendored
|
|
@ -68,7 +68,7 @@ pub fn ws() -> impl Filter<Extract = One<Ws>, Error = Rejection> + Copy {
|
|||
)
|
||||
}
|
||||
|
||||
/// Extracted by the [`ws`](ws) filter, and used to finish an upgrade.
|
||||
/// Extracted by the [`ws`] filter, and used to finish an upgrade.
|
||||
pub struct Ws {
|
||||
config: Option<WebSocketConfig>,
|
||||
key: SecWebsocketKey,
|
||||
|
|
@ -92,11 +92,21 @@ impl Ws {
|
|||
|
||||
// config
|
||||
|
||||
/// Set the size of the internal message send queue.
|
||||
pub fn max_send_queue(mut self, max: usize) -> Self {
|
||||
/// Does nothing.
|
||||
///
|
||||
/// # Deprecated
|
||||
///
|
||||
/// Use `max_write_buffer_size()` instead.
|
||||
#[deprecated = "use max_write_buffer_size instead"]
|
||||
pub fn max_send_queue(self, _max: usize) -> Self {
|
||||
self
|
||||
}
|
||||
|
||||
/// The max size of the write buffer, in bytes.
|
||||
pub fn max_write_buffer_size(mut self, max: usize) -> Self {
|
||||
self.config
|
||||
.get_or_insert_with(WebSocketConfig::default)
|
||||
.max_send_queue = Some(max);
|
||||
.max_write_buffer_size = max;
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
4
third_party/rust/warp/src/lib.rs
vendored
4
third_party/rust/warp/src/lib.rs
vendored
|
|
@ -1,4 +1,4 @@
|
|||
#![doc(html_root_url = "https://docs.rs/warp/0.3.3")]
|
||||
#![doc(html_root_url = "https://docs.rs/warp/0.3.6")]
|
||||
#![deny(missing_docs)]
|
||||
#![deny(missing_debug_implementations)]
|
||||
#![deny(rust_2018_idioms)]
|
||||
|
|
@ -81,7 +81,7 @@
|
|||
//! ## Testing
|
||||
//!
|
||||
//! Testing your web services easily is extremely important, and warp provides
|
||||
//! a [`test`](self::test) module to help send mocked requests through your service.
|
||||
//! a [`test`](mod@self::test) module to help send mocked requests through your service.
|
||||
//!
|
||||
//! [Filter]: trait.Filter.html
|
||||
//! [reject]: reject/index.html
|
||||
|
|
|
|||
27
third_party/rust/warp/src/redirect.rs
vendored
27
third_party/rust/warp/src/redirect.rs
vendored
|
|
@ -1,6 +1,6 @@
|
|||
//! Redirect requests to a new location.
|
||||
//!
|
||||
//! The types in this module are helpers that implement [`Reply`](Reply), and easy
|
||||
//! The types in this module are helpers that implement [`Reply`], and easy
|
||||
//! to use in order to setup redirects.
|
||||
|
||||
use http::{header, StatusCode};
|
||||
|
|
@ -8,7 +8,10 @@ use http::{header, StatusCode};
|
|||
pub use self::sealed::AsLocation;
|
||||
use crate::reply::{self, Reply};
|
||||
|
||||
/// A simple `301` permanent redirect to a different location.
|
||||
/// HTTP 301 Moved Permanently
|
||||
/// Description: The requested resource has been permanently moved to a new URL.
|
||||
/// 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.
|
||||
/// Common Use Case: Changing domain names, restructuring website URLs.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
|
@ -28,7 +31,10 @@ pub fn redirect(uri: impl AsLocation) -> impl Reply {
|
|||
)
|
||||
}
|
||||
|
||||
/// A simple `302` found redirect to a different location
|
||||
/// HTTP 302 Found (or Temporary Redirect)
|
||||
/// Description: The requested resource can be found at a different URL temporarily.
|
||||
/// 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.
|
||||
/// Common Use Case: Rarely used directly due to ambiguity; replaced by 307 or 303.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
|
@ -44,7 +50,10 @@ pub fn found(uri: impl AsLocation) -> impl Reply {
|
|||
reply::with_header(StatusCode::FOUND, header::LOCATION, uri.header_value())
|
||||
}
|
||||
|
||||
/// A simple `303` redirect to a different location.
|
||||
/// HTTP 303 See Other
|
||||
/// Description: The response to the request can be found at a different URL, and the client should retrieve it using the GET method.
|
||||
/// 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.
|
||||
/// Common Use Case: After form submissions or any non-idempotent request.
|
||||
///
|
||||
/// The HTTP method of the request to the new location will always be `GET`.
|
||||
///
|
||||
|
|
@ -62,7 +71,10 @@ pub fn see_other(uri: impl AsLocation) -> impl Reply {
|
|||
reply::with_header(StatusCode::SEE_OTHER, header::LOCATION, uri.header_value())
|
||||
}
|
||||
|
||||
/// A simple `307` temporary redirect to a different location.
|
||||
/// HTTP 307 Temporary Redirect:
|
||||
/// Description: The requested resource can be found at a different URL temporarily.
|
||||
/// 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.
|
||||
/// Common Use Case: Temporary redirects that should preserve the original request method.
|
||||
///
|
||||
/// This is similar to [`see_other`](fn@see_other) but the HTTP method and the body of the request
|
||||
/// to the new location will be the same as the method and body of the current request.
|
||||
|
|
@ -85,7 +97,10 @@ pub fn temporary(uri: impl AsLocation) -> impl Reply {
|
|||
)
|
||||
}
|
||||
|
||||
/// A simple `308` permanent redirect to a different location.
|
||||
/// HTTP 308 Permanent Redirect
|
||||
/// Description: The requested resource has been permanently moved to a new URL, and future requests should use the new URL.
|
||||
/// 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.
|
||||
// Common Use Case: Permanently moving resources to a new URL while maintaining the original request method.
|
||||
///
|
||||
/// This is similar to [`redirect`](fn@redirect) but the HTTP method of the request to the new
|
||||
/// location will be the same as the method of the current request.
|
||||
|
|
|
|||
60
third_party/rust/warp/src/reject.rs
vendored
60
third_party/rust/warp/src/reject.rs
vendored
|
|
@ -436,7 +436,7 @@ impl Rejections {
|
|||
| Known::BodyConsumedMultipleTimes(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
},
|
||||
Rejections::Custom(..) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Rejections::Combined(ref a, ref b) => preferred(a, b).status(),
|
||||
Rejections::Combined(..) => self.preferred().status(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -465,7 +465,7 @@ impl Rejections {
|
|||
);
|
||||
res
|
||||
}
|
||||
Rejections::Combined(ref a, ref b) => preferred(a, b).into_response(),
|
||||
Rejections::Combined(..) => self.preferred().into_response(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -491,21 +491,30 @@ impl Rejections {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn preferred<'a>(a: &'a Rejections, b: &'a Rejections) -> &'a Rejections {
|
||||
// Compare status codes, with this priority:
|
||||
// - NOT_FOUND is lowest
|
||||
// - METHOD_NOT_ALLOWED is second
|
||||
// - if one status code is greater than the other
|
||||
// - otherwise, prefer A...
|
||||
match (a.status(), b.status()) {
|
||||
(_, StatusCode::NOT_FOUND) => a,
|
||||
(StatusCode::NOT_FOUND, _) => b,
|
||||
(_, StatusCode::METHOD_NOT_ALLOWED) => a,
|
||||
(StatusCode::METHOD_NOT_ALLOWED, _) => b,
|
||||
(sa, sb) if sa < sb => b,
|
||||
_ => a,
|
||||
fn preferred(&self) -> &Rejections {
|
||||
match self {
|
||||
Rejections::Known(_) | Rejections::Custom(_) => self,
|
||||
Rejections::Combined(a, b) => {
|
||||
let a = a.preferred();
|
||||
let b = b.preferred();
|
||||
// Now both a and b are known or custom, so it is safe
|
||||
// to get status
|
||||
// Compare status codes, with this priority:
|
||||
// - NOT_FOUND is lowest
|
||||
// - METHOD_NOT_ALLOWED is second
|
||||
// - if one status code is greater than the other
|
||||
// - otherwise, prefer A...
|
||||
match (a.status(), b.status()) {
|
||||
(_, StatusCode::NOT_FOUND) => a,
|
||||
(StatusCode::NOT_FOUND, _) => b,
|
||||
(_, StatusCode::METHOD_NOT_ALLOWED) => a,
|
||||
(StatusCode::METHOD_NOT_ALLOWED, _) => b,
|
||||
(sa, sb) if sa < sb => b,
|
||||
_ => a,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -841,4 +850,23 @@ mod tests {
|
|||
let s = format!("{:?}", rej);
|
||||
assert_eq!(s, "Rejection([X(0), X(1), X(2)])");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_big_rejections_into_response() {
|
||||
let mut rejections = Rejections::Custom(Box::new(std::io::Error::from_raw_os_error(100)));
|
||||
for _ in 0..50 {
|
||||
rejections = Rejections::Combined(
|
||||
Box::new(Rejections::Known(Known::MethodNotAllowed(
|
||||
MethodNotAllowed { _p: () },
|
||||
))),
|
||||
Box::new(rejections),
|
||||
);
|
||||
}
|
||||
let reason = Reason::Other(Box::new(rejections));
|
||||
let rejection = Rejection { reason };
|
||||
assert_eq!(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
rejection.into_response().status()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
18
third_party/rust/warp/src/reply.rs
vendored
18
third_party/rust/warp/src/reply.rs
vendored
|
|
@ -411,18 +411,24 @@ impl Reply for ::http::StatusCode {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Reply for Result<T, ::http::Error>
|
||||
impl Reply for ::http::Error {
|
||||
#[inline]
|
||||
fn into_response(self) -> Response {
|
||||
tracing::error!("reply error: {:?}", self);
|
||||
StatusCode::INTERNAL_SERVER_ERROR.into_response()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> Reply for Result<T, E>
|
||||
where
|
||||
T: Reply + Send,
|
||||
T: Reply,
|
||||
E: Reply,
|
||||
{
|
||||
#[inline]
|
||||
fn into_response(self) -> Response {
|
||||
match self {
|
||||
Ok(t) => t.into_response(),
|
||||
Err(e) => {
|
||||
tracing::error!("reply error: {:?}", e);
|
||||
StatusCode::INTERNAL_SERVER_ERROR.into_response()
|
||||
}
|
||||
Err(e) => e.into_response(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
42
third_party/rust/warp/src/server.rs
vendored
42
third_party/rust/warp/src/server.rs
vendored
|
|
@ -128,6 +128,10 @@ where
|
|||
<F::Future as TryFuture>::Error: IsReject,
|
||||
{
|
||||
/// Run this `Server` forever on the current thread.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if we are unable to bind to the provided address.
|
||||
pub async fn run(self, addr: impl Into<SocketAddr>) {
|
||||
let (addr, fut) = self.bind_ephemeral(addr);
|
||||
let span = tracing::info_span!("Server::run", ?addr);
|
||||
|
|
@ -275,6 +279,10 @@ where
|
|||
/// let _ = tx.send(());
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if we are unable to bind to the provided address.
|
||||
pub fn bind_with_graceful_shutdown(
|
||||
self,
|
||||
addr: impl Into<SocketAddr> + 'static,
|
||||
|
|
@ -516,6 +524,10 @@ where
|
|||
/// executed on a runtime.
|
||||
///
|
||||
/// *This function requires the `"tls"` feature.*
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if we are unable to bind to the provided address.
|
||||
pub async fn bind(self, addr: impl Into<SocketAddr>) {
|
||||
let (_, fut) = self.bind_ephemeral(addr);
|
||||
fut.await;
|
||||
|
|
@ -527,6 +539,10 @@ where
|
|||
/// the current runtime.
|
||||
///
|
||||
/// *This function requires the `"tls"` feature.*
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if we are unable to bind to the provided address.
|
||||
pub fn bind_ephemeral(
|
||||
self,
|
||||
addr: impl Into<SocketAddr>,
|
||||
|
|
@ -547,6 +563,10 @@ where
|
|||
/// process.
|
||||
///
|
||||
/// *This function requires the `"tls"` feature.*
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if we are unable to bind to the provided address.
|
||||
pub fn bind_with_graceful_shutdown(
|
||||
self,
|
||||
addr: impl Into<SocketAddr> + 'static,
|
||||
|
|
@ -561,6 +581,28 @@ where
|
|||
});
|
||||
(addr, fut)
|
||||
}
|
||||
|
||||
/// Create a server with graceful shutdown signal.
|
||||
///
|
||||
/// When the signal completes, the server will start the graceful shutdown
|
||||
/// process.
|
||||
///
|
||||
/// *This function requires the `"tls"` feature.*
|
||||
pub fn try_bind_with_graceful_shutdown(
|
||||
self,
|
||||
addr: impl Into<SocketAddr> + 'static,
|
||||
signal: impl Future<Output = ()> + Send + 'static,
|
||||
) -> Result<(SocketAddr, impl Future<Output = ()> + 'static), crate::Error> {
|
||||
let addr = addr.into();
|
||||
let (addr, srv) = try_bind!(tls: self, &addr).map_err(crate::Error::new)?;
|
||||
let srv = srv.with_graceful_shutdown(signal).map(|result| {
|
||||
if let Err(err) = result {
|
||||
tracing::error!("server error: {}", err)
|
||||
}
|
||||
});
|
||||
|
||||
Ok((addr, srv))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "tls")]
|
||||
|
|
|
|||
2
third_party/rust/warp/src/test.rs
vendored
2
third_party/rust/warp/src/test.rs
vendored
|
|
@ -366,7 +366,7 @@ impl RequestBuilder {
|
|||
|
||||
/// Returns `Response` provided by applying the `Filter`.
|
||||
///
|
||||
/// This requires that the supplied `Filter` return a [`Reply`](Reply).
|
||||
/// This requires that the supplied `Filter` return a [`Reply`].
|
||||
pub async fn reply<F>(self, f: &F) -> Response<Bytes>
|
||||
where
|
||||
F: Filter + 'static,
|
||||
|
|
|
|||
7
third_party/rust/warp/src/tls.rs
vendored
7
third_party/rust/warp/src/tls.rs
vendored
|
|
@ -221,18 +221,19 @@ impl TlsConfigBuilder {
|
|||
}
|
||||
|
||||
let client_auth = match self.client_auth {
|
||||
TlsClientAuth::Off => NoClientAuth::new(),
|
||||
TlsClientAuth::Off => NoClientAuth::boxed(),
|
||||
TlsClientAuth::Optional(trust_anchor) => {
|
||||
AllowAnyAnonymousOrAuthenticatedClient::new(read_trust_anchor(trust_anchor)?)
|
||||
.boxed()
|
||||
}
|
||||
TlsClientAuth::Required(trust_anchor) => {
|
||||
AllowAnyAuthenticatedClient::new(read_trust_anchor(trust_anchor)?)
|
||||
AllowAnyAuthenticatedClient::new(read_trust_anchor(trust_anchor)?).boxed()
|
||||
}
|
||||
};
|
||||
|
||||
let mut config = ServerConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_client_cert_verifier(client_auth.into())
|
||||
.with_client_cert_verifier(client_auth)
|
||||
.with_single_cert_with_ocsp_and_sct(cert, key, self.ocsp_resp, Vec::new())
|
||||
.map_err(TlsConfigError::InvalidKey)?;
|
||||
config.alpn_protocols = vec!["h2".into(), "http/1.1".into()];
|
||||
|
|
|
|||
48
third_party/rust/warp/tests/multipart.rs
vendored
48
third_party/rust/warp/tests/multipart.rs
vendored
|
|
@ -52,3 +52,51 @@ async fn form_fields() {
|
|||
assert_eq!(&vec[0].0, "foo");
|
||||
assert_eq!(&vec[0].1, b"bar");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn max_length_is_enforced() {
|
||||
let _ = pretty_env_logger::try_init();
|
||||
|
||||
let route = multipart::form()
|
||||
.and_then(|_: multipart::FormData| async { Ok::<(), warp::Rejection>(()) });
|
||||
|
||||
let boundary = "--abcdef1234--";
|
||||
|
||||
let req = warp::test::request()
|
||||
.method("POST")
|
||||
// Note no content-length header
|
||||
.header("transfer-encoding", "chunked")
|
||||
.header(
|
||||
"content-type",
|
||||
format!("multipart/form-data; boundary={}", boundary),
|
||||
);
|
||||
|
||||
// Intentionally don't add body, as it automatically also adds
|
||||
// content-length header
|
||||
let resp = req.filter(&route).await;
|
||||
assert!(resp.is_err());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn max_length_can_be_disabled() {
|
||||
let _ = pretty_env_logger::try_init();
|
||||
|
||||
let route = multipart::form()
|
||||
.max_length(None)
|
||||
.and_then(|_: multipart::FormData| async { Ok::<(), warp::Rejection>(()) });
|
||||
|
||||
let boundary = "--abcdef1234--";
|
||||
|
||||
let req = warp::test::request()
|
||||
.method("POST")
|
||||
.header("transfer-encoding", "chunked")
|
||||
.header(
|
||||
"content-type",
|
||||
format!("multipart/form-data; boundary={}", boundary),
|
||||
);
|
||||
|
||||
// Intentionally don't add body, as it automatically also adds
|
||||
// content-length header
|
||||
let resp = req.filter(&route).await;
|
||||
assert!(resp.is_ok());
|
||||
}
|
||||
|
|
|
|||
2
third_party/rust/warp/tests/tracing.rs
vendored
2
third_party/rust/warp/tests/tracing.rs
vendored
|
|
@ -3,7 +3,7 @@ use warp::Filter;
|
|||
#[tokio::test]
|
||||
async fn uses_tracing() {
|
||||
// Setup a log subscriber (responsible to print to output)
|
||||
let subscriber = tracing_subscriber::fmt::Subscriber::builder()
|
||||
let subscriber = tracing_subscriber::fmt()
|
||||
.with_env_filter("trace")
|
||||
.without_time()
|
||||
.finish();
|
||||
|
|
|
|||
2
third_party/rust/warp/tests/ws.rs
vendored
2
third_party/rust/warp/tests/ws.rs
vendored
|
|
@ -275,7 +275,7 @@ async fn ws_with_query() {
|
|||
}
|
||||
|
||||
// Websocket filter that echoes all messages back.
|
||||
fn ws_echo() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Copy {
|
||||
fn ws_echo() -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Copy {
|
||||
warp::ws().map(|ws: warp::ws::Ws| {
|
||||
ws.on_upgrade(|websocket| {
|
||||
// Just echo all messages back...
|
||||
|
|
|
|||
Loading…
Reference in a new issue