Curl request not working with app_data in actix_web

I have my actix-web server as follows

    let server = HttpServer::new(move || {
        App::new()
        .app_data(data.clone())
        .service(get_response)
    })
    .listen(listener)?
    .run();

My data in app_data is like this

    let engine = Engine::new().unwrap();

    let data = Data::new(engine);

My Engine struct is as follows

pub struct Engine {
    engine: Arc<Mutex<EngineWrapper>>
}

pub struct EngineWrapper {
    task_ptr: *const EngineTask,
}

I have implemented send for my EngineWrapper
My get_response endpoint code


#[post("/get_response")]
async fn get_response(data: web::Data<Engine>, body: web::Bytes) -> impl Responder {
    HttpResponse::Ok().body(body)
}

when i do a curl request on get_response endpoint curl waits and does not finishes. But I see logs on server side that it has processed the request.

Strangely if I remove app_data from my server the curl request returns a response
This works

  let server = HttpServer::new(move || {
        App::new()
        .service(get_response)
    })
    .listen(listener)?
    .run();

Can you show how you implemented it?

I simply did this

unsafe impl Send for EngineWrapper {} 

Have you tried putting something else in place of EngineWrapper?

There might be something funky going on with your raw pointer.

Are there any alternative options to using app_data like will I have to create a global static variable?
Will creating global static variable be safe?

A global static variable is the worst possible option.

Any other alternatives?
Or any idea on how to debug the issue?

Have you tried using type Arc<Mutex<Engine>> instead of Arc<Mutex<EngineWrapper>>? I don't understand why you need EngineWrapper, since you can access Engine via an Arc<Mutex<..>> mutably from all threads.

If holding an exclusive lock on the engine causes too much contention, perhaps you can use Arc<RwLock<Engine>> instead. When you don't need mutable/exclusive access, get a read lock instead of a write lock.

I would try removing the use of unsafe to see if that's the problem. If you don't use EngineWrapper, can you avoid unsafe entirely?

I am depending on a c++ library for the engine. So I can't really remove unsafe.
I will try wrapping Engine in Arc<Mutex<..>> and tell if it works or not

That won't have any impact, it will just be double-wrapped, if I understand.

I suggest showing your code that uses the raw pointer.

will share it in a bit

I have shared the details of my ffi library in this previous question

In the linked topic you said that your type is not thread-safe. Which of the following do you mean by "thread-safe"?:

  1. The type cannot be transferred to another thread. It must be used in the same thread in which it was originally created.
  2. Or, the type can be transferred to another thread, but cannot be accessed from multiple threads concurrently.

I am getting the following error

Failed to extract `Data<Engine>` for `get_response` handler. For the Data extractor to work correctly, wrap the data with `Data::new()` and pass it to `App::app_data()`. Ensure that types align in both the set and retrieve calls.

My current server side code

let engine = Engine::new().unwrap();

let data = Data::new(Arc::new(Mutex::new(engine)));

let server = HttpServer::new(move || {
        App::new()
        .app_data(data.clone())
        .service(get_response)
    })
    .listen(listener)?
    .run();

My get_response handler is unchanged

I meant this one

This sounds like the extractor is not set up properly, which is an actix-web usage issue rather than a raw pointer issue. I have not used actix-web so I won't be able to help with that. Sorry for the confusion.

Yes I forgot to replace

with

async fn get_response(data: web::Data<Arc<Mutex<Engine>>>, body: web::Bytes) -> impl Responder

but now again the curl is hanging but i can see logs on server side

My curl is stuck like this

} [2 bytes data]
100     2    0     0    0     2      0      0 --:--:--  0:05:08 --:--:--     0

In order for someone to guide you in the debugging process, you'll need to share a lot more, for example:

  • The server log entries that you say prove that the request was processed, and your reasoning for why you believe the request was fully processed and the response was sent.
  • All the code you've written that is involved in creating the response message. The best thing is to share all your code by linking to the repo.
  • Be sure to share the current logging output and code, and the symptoms you're seeing for that particular code and logging output.
2 Likes