首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >actix-web:限制上传文件大小

actix-web:限制上传文件大小
EN

Stack Overflow用户
提问于 2022-04-02 03:25:57
回答 2查看 708关注 0票数 0

我成功地上传了引用这个示例的文件,但是我不知道如何限制文件的大小,例如,我不能比5M更多地保存文件

代码语言:javascript
复制
[dependencies]
actix-web = "4"
actix-multipart = "0.4" 

我试过了,但没成功。

代码语言:javascript
复制
        web::resource("/upload_file")
            .app_data(web::PayloadConfig::new(1024 * 5))
            .route(web::post().to(views::save_file)),
EN

回答 2

Stack Overflow用户

发布于 2022-04-17 08:53:46

中间件

默认情况下,它在所有请求中都使用,并且可以使用req.path()在指定的路由中使用。

代码语言:javascript
复制
use actix_web::Error;
use std::future::{ready, Ready};

use actix_web::dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform};
use futures_util::future::LocalBoxFuture;


pub struct ContentLengthLimit {
    pub limit: u64, // byte
}
impl<S, B> Transform<S, ServiceRequest> for ContentLengthLimit
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
    B: 'static,
{
    type Response = ServiceResponse<B>;
    type Error = Error;
    type InitError = ();
    type Transform = ContentLengthLimitMiddleware<S>;
    type Future = Ready<Result<Self::Transform, Self::InitError>>;

    fn new_transform(&self, service: S) -> Self::Future {
        ready(Ok(ContentLengthLimitMiddleware {
            service,
            limit: self.limit,
        }))
    }
}

impl Default for ContentLengthLimit {
    fn default() -> Self {
        Self {
            limit: 1024 * 1024 * 5, /* 5M */
        }
    }
}

pub struct ContentLengthLimitMiddleware<S> {
    service: S,
    limit: u64,
}

impl<S, B> ContentLengthLimitMiddleware<S>
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
    B: 'static,
{
    fn is_big(&self, req: &ServiceRequest) -> Result<bool, ()> {
        Ok(req
            .headers()
            .get("content-length")
            .ok_or(())?
            .to_str()
            .map_err(|_| ())?
            .parse::<u64>()
            .map_err(|_| ())?
            > self.limit)
    }
}

impl<S, B> Service<ServiceRequest> for ContentLengthLimitMiddleware<S>
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
    B: 'static,
{
    type Response = ServiceResponse<B>;
    type Error = Error;
    type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;

    forward_ready!(service);

    fn call(&self, req: ServiceRequest) -> Self::Future {
        if let Ok(r) = self.is_big(&req) {
            if r {
                return Box::pin(async { Err(hje("error").actix()) });
            }
        }

        let fut = self.service.call(req);

        Box::pin(async move {
            let res = fut.await?;
            Ok(res)
        })
    }
}

使用

代码语言:javascript
复制
App::new().wrap(ContentLengthLimit::default())
票数 1
EN

Stack Overflow用户

发布于 2022-07-31 20:05:58

这个发布的答案引用了Actix中的多部分上传示例。目前,由于:

https://github.com/actix/actix-web/issues/2695

在返回错误之前,必须清除有效负载,否则连接可能挂起,或者线程可能会出现恐慌。这里有一个示例,它将首先耗尽有效负载,然后才返回PayloadTooLarge错误。一旦上述问题得到解决,就可能没有必要:

代码语言:javascript
复制
lazy_static! {
    pub static ref MAX_ALLOWED_CONTENT_LENGTH: u64 =
        settings::get_setting("service_max_content_length")
            .unwrap_or("20971520".to_owned())
            .parse::<u64>()
            .unwrap_or(20971520);
}

#[derive(Debug)]
pub struct ContentLengthChecker;

impl<S, B> Transform<S, ServiceRequest> for ContentLengthChecker
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
    S::Future: 'static,
    B: 'static,
{
    type Response = ServiceResponse<EitherBody<B>>;
    type Error = Error;
    type Transform = ContentLengthCheckerMiddleware<S>;
    type InitError = ();
    type Future = Ready<Result<Self::Transform, Self::InitError>>;

    fn new_transform(&self, service: S) -> Self::Future {
        ok(ContentLengthCheckerMiddleware {
            service: Rc::new(service),
        })
    }
}

#[derive(Debug)]
pub struct ContentLengthCheckerMiddleware<S> {
    service: Rc<S>,
}

impl<S, B> Service<ServiceRequest> for ContentLengthCheckerMiddleware<S>
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
    S::Future: 'static,
    B: 'static,
{
    type Response = ServiceResponse<EitherBody<B>>;
    type Error = Error;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;

    forward_ready!(service);

    fn call(&self, mut req: ServiceRequest) -> Self::Future {
        let service = Rc::clone(&self.service);

        let content_length = match req.headers().get("content-length") {
            None => 0,
            Some(content_length) => MiddlewareUtility::get_content_length(Some(content_length)),
        };

        if content_length <= *MAX_ALLOWED_CONTENT_LENGTH {
            return Box::pin(async move {
                service
                    .call(req)
                    .await
                    .map(ServiceResponse::map_into_left_body)
            });
        }

        Box::pin(async move {
            /* need to drain the body due to
             https://github.com/actix/actix-web/issues/2695
             */
            let mut payload = req.take_payload();
            while let Ok(Some(_)) = payload.try_next().await {}

            Ok(req.into_response(
                HttpResponse::new(StatusCode::PAYLOAD_TOO_LARGE).map_into_right_body(),
            ))
        })
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71714621

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档