HttpClient/Downloader cancel/abort a request

I was wondering how to cancel/abort a long running http request.

My investigation are, that the HttpClient is using curl (only checked the macOS sources yet). The main usage is, that one scene is for downloading some big data and I want to give the user the option to cancel the request. Also the Downloader doesn’t have any function to cancel a request (or I’m just unable to find that).

Any suggestions from the community on that?

// cc @tranthor

1 Like

I am using cocos2d\cocos\network\CCDownloader.h
Unfortunately there is no abort…

This is what I am doing:

  1. Init Downloader with some shorter timeout e.g.: 20s instead of default 45s
    cocos2d::network::DownloaderHints{6, 20 /45/, “.tmp”}
  2. Instead of one big file download many small files.
  3. Wait for completed or failed event (onTaskError, onFileTaskSuccess)
    In 99% you have good internet connection so you will download small file in 1-2 seconds or it will fail in few seconds (no internet or connection broken). Yes there is chance that user will have to wait 20 seconds …

Warning:
It is important to wait for onTaskError, onFileTaskSuccess
Stop is called in Downloader destructor. So in theory you can just stop/destroy object

    void stop()
    {
        lock_guard<mutex> lock(_threadMutex);
        if (_thread.joinable())
        {
            _thread.detach();
        }
    }

But it does not stop downloading… thread will be running in background.
Next time when you run the same task two thread may write to the same file.

It seems like there is workaround for Downloader.stop and detached thread: instead of “.tmp” for tempFileNameSuffix you can use e.g. uuid. But I did not check it …
cocos2d::network::DownloaderHints{6, 20 /45/, “.tmp”}

With that idea, I would better to implement a download queue and only download the next file, if the user didn’t cancelled it. But this won’t help, if the file is large and it will download it completely before stopping the queue.

I can’t believe, that no one has such a feature request. :confused:

// cc @slackmoehrle

Here is my class using curl to download files:
https://pastebin.com/vyiV0wPP .h file
https://pastebin.com/UNWHBGJa .cpp file

you can set public variable downloading to false for canceling download.

1 Like

The question for the millon dollars is:

HttpClient provides a solution for it? :sunglasses:

Okay, your checking in every progress update callback, if the download was canceled. The same behavior could maybe manually be implemented into the Downloader (onTaskProgress ??) from cocos, but I don’t unterstand, why this isn’t by default?

@tranthor I believe currently will no one win the million dollar.

Hi @mars3142
If you want to abort the request then We are handling this via below code into destructor, you just need to save pointer to HttpRequest and set nullptr to responseCallback and call release.
We have multiple request so we store into vec.

 LoginMode::~LoginMode() {
	for (int i = 0;i < (int)httpVec.size();i++)
	{
		httpVec.at(i)->setResponseCallback(nullptr);
		httpVec.at(i)->release();
	}
}

@smitpatel88 i’m trying to test your alternative.
How do you fill httpVec ? I’m trying like this but i’ve problems:

Declaration in my singleton class:
vector<cocos2d::network::HttpRequest*> httpVec;

In class method:

network::HttpRequest* request = new network::HttpRequest();
request->setUrl(urlRequest);
request->setRequestType(network::HttpRequest::Type::GET);
request->setResponseCallback([](network::HttpClient* client, network::HttpResponse* response) {

 //Content

});
network::HttpClient::getInstance()->send(request);
request->release();

httpVec.push_back(request);

The error occurs in push_back line. Probably because of bad handle pointers.

As far, as I understand the code from @smitpatel88 you didn’t call release directly after creation, but within the loop of the destructor. But the code didn’t cancel long running downloads, it just remove the callback, so the response will never be processed. Right.

Yes, I understand like you, I never “cancel” the request but if I set nullptr is equal to cancel it. So, it could solve the “cancel” problem. But I wonder how can I fill httpVec… hmm…

@CAPONE sorry, I don’t understand your example.
How can I fill httpVec, following the example?

// cc @smitpatel88

As i told that we have multiple request so we have to use vec, but if you have single request then use this,

 LoginMode::~LoginMode() {
	httpReq->setResponseCallback(nullptr);
	httpReq->release();
}

@smitpatel88 i’ve multiple request, how do you fill the vec? look my last post, i’ve an error when I try to insert in the vec using push_back

Are you taking this pointer as local variable? It must be global.
Declare in header file.

Thanks @smitpatel88 , that was the problem.
However, this alternative didn’t solve my problem.

My program crashes inside the for, at this line:
httpVec.at(i)->setResponseCallback(nullptr);

Sometimes in the first element, sometimes in the second, etc. but it crashes.
Maybe because if the http response is in “action” i can’t set null there.

i’m requesting http info when I touch a button.
but when i touch the “Close” button i would like to cancel all requests. Because of this, i put this code in “close” button action:

for (int i = 0;i < (int)httpVec.size();i++)
{
	httpVec.at(i)->setResponseCallback(nullptr);
	httpVec.at(i)->release();
}

but it crashes when i touch it, as i said before.

Try giving callback method.
request->setResponseCallback(CC_CALLBACK_2(LoginMode::onHttpRequestCompleted, this));

Nope. I continue with the problem…

can you pls share me simple helloworld files to reproduce this?

Yep.
I uploaded here an example.
As you can see, you’ve a green and red button.

If you touch green button, i’m trying to request 1000 cocos2d page (GET’s).
If you touch red button, i’m setting to NULL all elements in the vector.

If you touch green button and quicky you touch red button. The program crashes.