gzip and returning nested continuation?

Jul 3, 2015 at 10:46 PM
Hi

I have some http request that might return gzip compressed text or plaintext. I'm trying to chain together continuations without calling blocking gets. This is what I have come up with. Does it look alight or do you have a better solution? Im mostly wondering if its okay for the return value of a task, to be a nested continuation task? As in:
        web::http::client::http_client client(url, client_config);

        auto resp = client.request(request)
            .then([](web::http::http_response response)
        {
            auto status_code = response.status_code();
            if (status_code != web::http::status_codes::OK)
            {
                throw std::exception("http status code not OK");//!!!
            }

            bool is_gzip = false; 
            const auto& header_res = response.headers();
            auto iter = header_res.find(L"Content-Encoding");
            if (iter != header_res.end()) {
                const auto& pair = *iter;
                const auto& val = pair.second;
                is_gzip = (val == L"gzip");
            }

            auto local_task = response.extract_utf8string();

            //Ideally I would like to return both local_task and is_gzip. But I dont know how to  return multiple values (cleanly), so I have to create a nested continuation, and return that. I hope its okay to do so.

            return local_task.then([is_gzip](pplx::task<utf8string> task_str){ //Is this okay?

                auto ret = task_str.get(); //not blocking
                
                if (is_gzip) { //compressed
                    ret = gzip_helper_uncompress(ret);
                }
                else { //uncompressed
                }
                return ret;
            });
        });

        //std::string ret = resp.get(); //blocking
Coordinator
Jul 6, 2015 at 9:35 AM
This looks pretty good! It's perfectly fine to return continuations (which will cause any continuations of the current task to be instead continued after the returned task -- which what you want in this case).

I think you could make your inner continuation simpler by just accepting a utf8string parameter instead of a pplx::task<>. Usually, you only use a task-based continuation when you want to do a try/catch around the .get() call for error handling. Since in this case it looks like you're just bubbling the error forward, there's no need to use a task<> there.

Another option: you can return different continuations depending on the value of is_gzip. Instead of piping it through (which you've done correctly), you could just have separate .then() lambdas returned for each case.

Other than those suggestions, your code looks pretty good; Good work!
Coordinator
Jul 6, 2015 at 6:03 PM
Hi petke,

I agree with roschuma's comments. Here are a few additional ones as well.

To check the Content-Encoding header there is functionality to help out on the http_headers class, specifically the has(...) and match(...) APIs would be useful.

If I were you I would just conditionally return a task continuation of the local_task variable from the extract_utf8string() function call depending on the value of is_gzip. In cases that gzip isn't necessary this will save the scheduling and execution of essentially an empty task.

Steve
Jul 6, 2015 at 11:33 PM
Thanks for your suggestions. They make a lot of sense. (I see now that I can just return the "local_task" for the non compressed conditional. That looks much cleaner.)