Будущий трейт не реализован при использовании Warp's and_then

Я пытаюсь добавить принудительное использование HTTPS в свое веб-приложение на основе Warp на GKE.

Платформа GKE в основном неактуальна; Важная деталь заключается в том, что балансировщик нагрузки завершает соединения SSL / TLS, поэтому «настоящая» схема предоставляется в заголовке X-Forwarded-Proto. Буквальная схема, анализируемая Warp, всегда будет HTTP.

Логика следующая:

  1. Если схема HTTPS, запросы обрабатываются нормально.
  2. Если используется схема HTTP, отправьте 301 редирект на эквивалентный HTTPS URL.
  3. Если это другая схема, отправьте ошибку 421 (неверно направленный запрос).
  4. Если заголовок X-Forwarded-Proto отсутствует (или возникает любой другой реально невозможный сценарий), отправьте ошибку 400 (неверный запрос).

В этом примере ответы об ошибках не имеют основного содержимого, и все запросы HTTPS должны отвечать текстом Hello, world!.

Эта проблема:

error[E0277]: the trait bound `std::result::Result<(), warp::reject::Rejection>: core::future::future::Future` is not satisfied
  --> src/main.rs:23:10
   |
23 |         .and_then(|scheme_header: Option<String>, host: String, path: FullPath| {
   |          ^^^^^^^^ the trait `core::future::future::Future` is not implemented for `std::result::Result<(), warp::reject::Rejection>`
   |
   = note: required because of the requirements on the impl of `futures_core::future::TryFuture` for `std::result::Result<(), warp::reject::Rejection>`

error[E0599]: no method named `and` found for type `warp::filter::and_then::AndThen<warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, impl warp::filter::Filter+std::marker::Copy>, impl warp::filter::Filter+std::marker::Copy>, [closure@src/main.rs:23:19: 43:10]>` in the current scope
  --> src/main.rs:44:10
   |
44 |         .and(filter)
   |          ^^^ method not found in `warp::filter::and_then::AndThen<warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, impl warp::filter::Filter+std::marker::Copy>, impl warp::filter::Filter+std::marker::Copy>, [closure@src/main.rs:23:19: 43:10]>`
   |
   = note: the method `and` exists but the following trait bounds were not satisfied:
           `&mut warp::filter::and_then::AndThen<warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, impl warp::filter::Filter+std::marker::Copy>, impl warp::filter::Filter+std::marker::Copy>, [closure@src/main.rs:23:19: 43:10]> : warp::filter::Filter`
           `&warp::filter::and_then::AndThen<warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, impl warp::filter::Filter+std::marker::Copy>, impl warp::filter::Filter+std::marker::Copy>, [closure@src/main.rs:23:19: 43:10]> : warp::filter::Filter`
           `warp::filter::and_then::AndThen<warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, impl warp::filter::Filter+std::marker::Copy>, impl warp::filter::Filter+std::marker::Copy>, [closure@src/main.rs:23:19: 43:10]> : warp::filter::Filter`

Очевидно, мне здесь не хватает чего-то очевидного, поэтому я надеюсь, что кто-то сможет подтолкнуть меня в правильном направлении!

use futures::{FutureExt, StreamExt};
use warp::{Filter, Rejection};
use warp::filters::path::{FullPath};
use warp::http::{StatusCode, Uri};
use warp::http::uri::{Parts, Scheme};
use warp::reply::Reply;

enum SchemeError {
    InsecureScheme(Uri),
    UnknownScheme,
    MissingScheme,
}

impl warp::reject::Reject for SchemeError {}

async fn requires_https(filter: impl Filter<Extract = (Scheme,), Error = Rejection> + Copy) -> impl Filter<Extract = (), Error = Rejection> + Copy {
    warp::header::optional("X-Forwarded-Proto")
        .and(warp::header("Host"))
        .and(warp::path::full())
        .and_then(|scheme_header: Option<String>, host: String, path: FullPath| {
            if let Some(scheme) = scheme_header {
                match scheme.to_ascii_lowercase().as_str() {
                    "https" => Ok(()),
                    "http" => {
                        let mut uri_parts = Parts::default();
                        uri_parts.scheme = Some(Scheme::HTTPS);
                        uri_parts.authority = Some(host.parse().unwrap());
                        uri_parts.path_and_query = Some(path.as_str().parse().unwrap());
                        let uri_parts = uri_parts;

                        let new_uri = Uri::from_parts(uri_parts).unwrap();
                        println!("Redirecting to secure URL: {}", new_uri);
                        Err(warp::reject::custom(SchemeError::InsecureScheme(new_uri)))
                    },
                    _ => Err(warp::reject::custom(SchemeError::UnknownScheme)),
                }
            } else {
                Err(warp::reject::custom(SchemeError::MissingScheme))
            }
        })
        .and(filter)
        .recover(|err: Rejection| {
            if let Some(scheme_error) = err.find::<SchemeError>() {
                match scheme_error {
                    SchemeError::InsecureScheme(new_uri) => Ok(warp::redirect(new_uri)),
                    SchemeError::UnknownScheme => Ok(StatusCode::MISDIRECTED_REQUEST),
                    SchemeError::MissingScheme => Ok(StatusCode::BAD_REQUEST),
                }
            } else {
                Err(err)
            }
        })
}

#[tokio::main]
async fn main() {
    let routes = requires_https(warp::any().map(|| "Hello, world!"));

    warp::serve(routes)
        .run(([0, 0, 0, 0], 8080))
        .await;
}

person MTCoster    schedule 23.02.2020    source источник


Ответы (1)


Я новичок в ржавчине, но столкнулся с аналогичной ошибкой компилятора

Моя проблема заключалась в просмотре документов warp 0.1 при использовании warp 0.2 https://docs.rs/warp/0.2.0/warp/trait.Filter.html#example-3

Мне нужно было поставить async move после закрывающих трубок в and_then

Если это не так, это может быть похоже на ошибку понимания: черта `futures: : future :: Future не реализован для `()`

где std::result::Result<(), warp::reject::Rejection> указывает, что вы возвращаете тип блока как левый результат, который, возможно, не будет реализован в будущем для него.

person ThePianoDentist    schedule 30.03.2020