TerminalWitchcraft / actix-ratelimit

Rate limiter framework for Actix web
MIT License
127 stars 25 forks source link

Wrap doesn't work within scope #24

Open Mondei1 opened 2 years ago

Mondei1 commented 2 years ago

Hey @TerminalWitchcraft,

my use-case currently is that I only want to apply a rate limiter to my /auth path. In issue #10 you wrote the following:

Hey, yes you can using scopes. Each scope can register independent middlewares and it's also a nice utility to group related resources/endpoints! More information here: https://docs.rs/actix-web/3.3.2/actix_web/struct.Scope.html

I haven't personally tried it, but it should work if I understand the documentation correctly. Let me know if you run into any trouble using this.

Scopes would actually work perfectly for me. I just never worked with them before.

Well, I tried them and my code looks like this:

let cors = Cors::default();
let store = MemoryStore::new();

App::new()
    .wrap(Compress::default())
    .service(
      web::scope("/auth")
        .wrap(cors)    // This .wrap actually works with actix-cors
        .wrap(
          RateLimiter::new(
              MemoryStoreActor::from(store.clone()).start()
          )
          .with_interval(Duration::from_secs(60 * 10))
          .with_max_requests(20)
        )
        .service(web::resource("/").to(auth::get_auth))
    )
    /* Some more routes down here */
)

As it seems actix-ratelimit doesn't work properly as scoped middleware because the Rust compiler complains:

error[E0277]: the trait bound `RateLimiter<MemoryStoreActor>: Transform<actix_web::scope::ScopeService, ServiceRequest>` is not satisfied
   --> src/main.rs:69:25
    |
68  |                       .wrap(
    |                        ---- required by a bound introduced by this call
69  | /                         RateLimiter::new(
70  | |                             MemoryStoreActor::from(store.clone()).start()
71  | |                         )
72  | |                         .with_interval(Duration::from_secs(60 * 10))
73  | |                         .with_max_requests(20)
    | |______________________________________________^ the trait `Transform<actix_web::scope::ScopeService, ServiceRequest>` is not implemented for `RateLimiter<MemoryStoreActor>`
    |

The problem may lay in this implementation of RateLimiter<T>: https://github.com/TerminalWitchcraft/actix-ratelimit/blob/master/src/middleware.rs#L100

Their implementation (from actix-cors) looks like this:

impl<S, B> Transform<S, ServiceRequest> for Cors
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,

    B: MessageBody + 'static,
{
    type Response = ServiceResponse<EitherBody<B>>;
    type Error = Error;
    type InitError = ();
    type Transform = CorsMiddleware<S>;
    type Future = Ready<Result<Self::Transform, Self::InitError>>;

    fn new_transform(&self, service: S) -> Self::Future {
        // ...
    }
}

Source: https://github.com/actix/actix-extras/blob/master/actix-cors/src/builder.rs#L486

I'm not a Rust expert, I've just started using it seriously for ~3 months, but I'd bet that the S generic is incorrectly defined. Do you know how to fix this?

Thanks in advance, Nicolas

TommyLike commented 1 year ago

Having this issue now @Mondei1

tkr-sh commented 1 year ago

Same