http_exception confusion

May 31, 2015 at 12:44 AM
Edited May 31, 2015 at 12:47 AM
I am trying to figure out the correct way of handling exceptions for http_requests. I've read this and it makes sense on paper, but in practice not so much. I am getting exceptions thrown for http errors, like the documentation says, but my catch statements are never getting called. Here is what I have so far
    // Get our pplx::task for the given request, and return it
    __fireFuntionForRequest(request.get()) // <-- This is a shared_ptr::get(), not pplx
    .then([&](pplx::task<http_response> task){
        
        try
        {
            // Parse the result from the server, this may throw, if an error was encountered during the
            // trasnport of the request
            http_response response = task.get();  // <-- This line is causing an unhandled expceiton call
        
            response.extract_json()
            .then([&](pplx::task<json::value> value){
                
                // Attempt to get the json value from the async task
                // This will throw if the content type of the response is not application/json
                json::value bodyJSON = value.get();
                
                // Transition to the next state, either success or failure
                __transitionRequestToState(std::move(request), bodyJSON, success, error);
            });
        }
        catch (const std::exception& e) { // <-- This block is never called
            // Transition the request to the Error state, checking to see if a retry is necessary
            __transitionRequestToErrorStateGivenException(e, error);
        }
        
    });
__fireFunctionForRequest() returns a pplx::task from the appropriate http_client::request method. What I am seeing is that, before my first continuation is called, an exception is being throw on thread A. When my continuation is called on thread B, and task.get() is invoked, I get an unhandled exception crash, with out my catch block being called. If I understood the docs correctly, the exception thrown from the http_client::request on thread A is captured, and re-thrown on thread B when task.get() is called. Is my understanding correct, or is there a bug here that I am not seeing?
Coordinator
Jun 2, 2015 at 1:35 AM
Hi cbreed28,

What platform are you running on? Is it the ARM architecture on Android by chance?

Nothing is jumping out at me from your code. You are calling task.get() inside a try catch so it should catch any exceptions from that operation. The only way your catch block won't run is if the exception isn't of type std::exception. What is the exception, perhaps try catch(...) to look at it. I'd be surprised if there is a bug in the ppl task code with something this simple.

Steve
Coordinator
Jun 2, 2015 at 6:49 PM
While not directly your issue, you can probably simplify the code above and make it easier to find errors by doing something like:
__fireFuntionForRequest(request.get()).then([](http_response hr)
{
    return hr.extract_json();
}).then([=](json::value v)
{
    __transitionRequestToState(std::move(request), v, success, error);
}).then([=](pplx::task<void> t)
{
    // handle errors here
    try
    {
        t.get();
    } catch (const std::exception& e) {
        __transitionToErrorState(std::move(request), e);
    }
});
The idea is that the last .then() simply handles any errors from the above chain of tasks, so you can write them as simply as possible. In the case of no errors, it will do nothing.
Jun 2, 2015 at 8:35 PM
stevetgates, thanks for the reply! I'm currently working on iOS, and it turns out I am only seeing the issue with the i386 arch simulators. All of the other architectures for iOS seem to be working just fine, meaning I am able to catch the appropriate web::http::http_exception. I am able to reproduce the issue easily on the i386 simulators if I turn off my WiFi and attempt to run the above code. I added a C++ exception breakpoint and I can clearly see that cpprest is throwing a web::http::http_exception. Also, on the i386 devices, the unhandled exception gets printed to the console as -- "libc++abi.dylib: terminating with uncaught exception of type web::http::http_exception: Error resolving address" . Not sure what, specifically, would cause the i386 arch to not catch the exception? If it helps I am using XCode 6.3.1 and iOS 8.3 simulators.

roschuma, thanks for the reply also! Makes a lot of sense. The semantics here are very similar to other promise libraries that I have used in the past, with .then() and .fail() handlers. The value vs. task based continuations are an interesting syntax here. I need to do a lot of clean-up around the code that I posted as I am just starting to get my feet wet with the pplx tasks :) Do you, or stevetgates, have any best practices around using cpprest or pplx tasks in general ? Any tough lessons learned? I am beginning to port my networking library away from AFNetworking and into a reusable c++ codebase and would love to learn as much as I can.