Exemplo n.º 1
0
void HTTPRequest::startHTTPRequest(std::unique_ptr<Response> &&res) {
    assert(uv_thread_self() == thread_id);
    assert(!http_baton);

    http_baton = std::make_shared<HTTPRequestBaton>(path);
    http_baton->request = this;
    http_baton->async = new uv_async_t;
    http_baton->response = std::move(res);
    http_baton->async->data = new util::ptr<HTTPRequestBaton>(http_baton);

#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
    uv_async_init(loop, http_baton->async, [](uv_async_t *async, int) {
#else
    uv_async_init(loop, http_baton->async, [](uv_async_t *async) {
#endif
        util::ptr<HTTPRequestBaton> &baton = *(util::ptr<HTTPRequestBaton> *)async->data;

        if (baton->request) {
            HTTPRequest *request = baton->request;
            request->http_baton.reset();
            baton->request = nullptr;
            request->handleHTTPResponse(baton->type, std::move(baton->response));
        }

        delete (util::ptr<HTTPRequestBaton> *)async->data;
        uv_close((uv_handle_t *)async, [](uv_handle_t *handle) {
            uv_async_t *async_handle = (uv_async_t *)handle;
            delete async_handle;
        });
    });
    attempts++;
    HTTPRequestBaton::start(http_baton);
}



void HTTPRequest::handleHTTPResponse(HTTPResponseType responseType, std::unique_ptr<Response> &&res) {
    assert(uv_thread_self() == thread_id);
    assert(!http_baton);
    assert(!response);

    switch (responseType) {
        // This error was caused by a temporary error and it is likely that it will be resolved
        // immediately. We are going to try again right away. This is like the TemporaryError,
        // except that we will not perform exponential back-off.
        case HTTPResponseType::SingularError:
            if (attempts >= 4) {
                // Report as error after 4 attempts.
                response = std::move(res);
                notify();
            } else if (attempts >= 2) {
                // Switch to the back-off algorithm after the second failure.
                retryHTTPRequest(std::move(res), (1 << attempts) * 1000);
                return;
            } else {
                startHTTPRequest(std::move(res));
            }
            break;

        // This error might be resolved by waiting some time (e.g. server issues).
        // We are going to do an exponential back-off and will try again in a few seconds.
        case HTTPResponseType::TemporaryError:
            if (attempts >= 4) {
                // Report error back after it failed completely.
                response = std::move(res);
                notify();
            } else {
                retryHTTPRequest(std::move(res), (1 << attempts) * 1000);
            }
            break;

        // This error might be resolved once the network reachability status changes.
        // We are going to watch the network status for changes and will retry as soon as the
        // operating system notifies us of a network status change.
        case HTTPResponseType::ConnectionError:

            if (attempts >= 4) {
                // Report error back after it failed completely.
                response = std::move(res);
                notify();
            } else {
                // By default, we will retry every 60 seconds.
                retryHTTPRequest(std::move(res), 60000);
            }
            break;

        // The request was canceled programatically.
        case HTTPResponseType::Canceled:
            response.reset();
            notify();
            break;

        // This error probably won't be resolved by retrying anytime soon. We are giving up.
        case HTTPResponseType::PermanentError:
            response = std::move(res);
            notify();
            break;

        // The request returned data successfully. We retrieved and decoded the data successfully.
        case HTTPResponseType::Successful:
            if (store) {
                store->put(path, type, *res);
            }
            response = std::move(res);
            notify();
            break;

        // The request confirmed that the data wasn't changed. We already have the data.
        case HTTPResponseType::NotModified:
            if (store) {
                store->updateExpiration(path, res->expires);
            }
            response = std::move(res);
            notify();
            break;

        default:
            assert(!"Response wasn't set");
            break;
    }
}