2

我正在尝试将 HTTPS 强制添加到 GKE 上基于 Warp 的 Web 应用程序中。

GKE 平台大多是无关紧要的;最重要的细节是负载均衡器终止 SSL/TLS 连接,因此X-Forwarded-Proto标题中提供了“真实”方案。Warp 解析的文字方案将始终为HTTP.

逻辑如下:

  1. 如果方案是HTTPS,则正常处理请求。
  2. 如果方案是,则向等效URLHTTP发送 301 重定向。HTTPS
  3. 如果该方案是其他任何内容,请发送 421(错误定向请求)错误。
  4. 如果X-Forwarded-Proto标头丢失(或发生任何其他实际不可能的情况),则发送 400(错误请求)错误。

此示例中的错误响应没有正文内容,所有 HTTPS 请求都应以 text 响应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;
}
4

1 回答 1

1

我是 rust 新手,但遇到了类似的编译器错误

我的问题是查看 warp 0.1 文档,同时使用 warp 0.2 https://docs.rs/warp/0.2.0/warp/trait.Filter.html#example-3

我需要async move在关闭管道后放入and_then

如果不是这样,可能类似于 理解错误: trait `futures::future::Future` is not implemented for `()`

wherestd::result::Result<(), warp::reject::Rejection>表示您将返回一个单元类型作为左结果,这可能不会在未来实现。

于 2020-03-30T09:10:15.323 回答