Adding Multithreaded HTTP post to wxCurl

Talk here about issues with one of the components hosted at wxCode, or suggest features for it.
Post Reply
tonto
In need of some credit
In need of some credit
Posts: 6
Joined: Fri Oct 29, 2010 12:47 am

Adding Multithreaded HTTP post to wxCurl

Post by tonto » Sun Feb 09, 2014 2:52 am

Hi all,
I have some proposed additions to wxCurl that allow HTTP form posts.

The multithreaded classes for HTTP in wxCurl are really great for GUI applications, but currently they only have GET (wxCurlDownloadThread) and PUT requests (wxCurlUploadThread). I made a wxCurlFormPostThread class that is made for multithreaded HTTP POST requests on top of the wxCurlHTTP class.




wxcode/components/wxcurl/include/wx/curl/thread.h

Code: Select all

> // ----------------------------------------------------------------------------
> // wxCurlFormPostThread
> // ----------------------------------------------------------------------------
> 
> //! A simple joinable thread which allows uploading
> //! resources to the net without blocking the GUI of your app.
> class WXDLLIMPEXP_CURL wxCurlFormPostThread : public wxCurlBaseThread
> {
> 
> 
> public:
>     wxCurlFormPostThread(wxEvtHandler *handler = NULL,
>                          int id = wxID_ANY,
>                          const wxString &url = wxEmptyString)
>         : wxCurlBaseThread(handler, id)
>     {
>         if (!url.IsEmpty())
>             Post(url);
>     }
> 
> public:     // public API
> 
> 
>     //! Creates and runs this thread for upload to the given URL of the given
>     //! input stream (internally calls #SetURL and #SetOutputStream).
>     wxCurlThreadError Post(const wxString &url);
> 
>     //! Uploads the URL previously set with #SetURL using the input stream
>     //! previously set with #SetInputStream.
>     wxCurlThreadError Post();
> 	
> 	//void AddFileToForm(const wxString& name,const wxString& filepath);
> 	bool AddForm(const bool& bClear, const wxString& szName,
> 							struct curl_forms* pForms, CURLFORMcode* outErr);
> 
> 
> 	bool AddBufferToForm(const bool& bClear, const wxString& szName,
> 									char* buffer, size_t len, CURLFORMcode* outErr);
> 
> 
> 
> 
> 	bool AddFileToForm(const bool& bClear, const wxString& szName,
> 								   const wxString& filename, CURLFORMcode* outErr);
> 
> protected:
> 
>     // change access policy to force the user of the better-readable Upload() method:
>     virtual wxCurlThreadError StartTransfer()
>         { return Post(); }
> 
>     virtual void *Entry();
> 	
> 	wxString m_szName;
> 	wxString m_szFilepath;
> };



wxcode/components/wxcurl/src/thread.cpp

Code: Select all

> // ---------------------
> // wxCurlFormPostThread
> // ---------------------
> 
> 
> wxCurlThreadError wxCurlFormPostThread::Post()
> {
>     wxCHECK_MSG(!IsAlive(), wxCTE_NO_RESOURCE, wxS("Cannot use this function after the tranfer has begun"));
> 
>     // create & run this thread
>     wxCurlThreadError ret;
>     if ((ret=Create(wxCURL_THREAD_STACK_SIZE)) != wxCTE_NO_ERROR)
>         return ret;
>     if ((ret=Run()) != wxCTE_NO_ERROR)
>         return ret;
> 
>     return wxCTE_NO_ERROR;
> }
> 
> wxCurlThreadError wxCurlFormPostThread::Post(const wxString &url)
> {
>     wxCurlThreadError ret;
> 
>     if ((ret=SetURL(url)) != wxCTE_NO_ERROR)
>         return ret;
> 
>     return Post();
> }
> 
> void *wxCurlFormPostThread::Entry()
> {
>     if (!m_pCurl || !m_pCurl->IsOk())
>         return NULL;
> 
>     // NOTE: the TestDestroy() function will still be called in this thread
>     //       context by the m_output's OnSysWrite function which in turn is
>     //       called from libcurl whenever some new data arrives
>     if (m_pCurl->IsVerbose())
> 		wxLogDebug(wxS("wxCurlFormPostThread - uploading to %s"), m_url.c_str());
>     switch (m_protocol)
>     {
>         case wxCP_HTTP:
> 		{
> 		
> 			wxCurlHTTP *http=wx_static_cast(wxCurlHTTP*, m_pCurl);
>             return (void*)http->Post(m_url.c_str());
> 		}
> 		default:
> 			wxLogDebug("wxCurlFormPostThread - unknown protocol");
>     }
> 
>     return NULL;
> }
> 
> 
> bool wxCurlFormPostThread::AddForm(const bool& bClear, const wxString& szName,
>                         struct curl_forms* pForms, CURLFORMcode* outErr)
> {
> 	wxCurlHTTP *http=wx_static_cast(wxCurlHTTP*, m_pCurl);
> 	return http->AddForm(bClear, szName, pForms, outErr);
> }
> 
> bool wxCurlFormPostThread::AddBufferToForm(const bool& bClear, const wxString& szName,
>                                 char* buffer, size_t len, CURLFORMcode* outErr)
> {
> 
> 	wxCurlHTTP *http=wx_static_cast(wxCurlHTTP*, m_pCurl);
> 	return http->AddBufferToForm(bClear, szName, buffer, len, outErr);
> 
> }
> 
> 
> 
> bool wxCurlFormPostThread::AddFileToForm(const bool& bClear, const wxString& szName,
>                                const wxString& filename, CURLFORMcode* outErr)
> {
> 	wxCurlHTTP *http=wx_static_cast(wxCurlHTTP*, m_pCurl);
> 	return http->AddFileToForm(bClear, szName, filename,outErr);
> 
> }


I also made an wxCurlHTTP::AddFileToForm function for the wxCurlHTTP class. It isn't essential since you can use the wxCurlHTTP::AddForm function to create the parameters yourself, but I thought that it complemented the wxCurlHTTTP::AddBufferToForm function nicely


wxcode/components/wxcurl/src/http.cpp

Code: Select all

> bool wxCurlHTTP::AddFileToForm(const bool& bClear, const wxString& szName,
>                                const wxString& filename, CURLFORMcode* outErr)
> {
>     if(bClear)
>         ResetPostData();
> 
>     CURLFORMcode res = CURL_FORMADD_OK;
> 
>     res = curl_formadd(&m_pPostHead, &m_pPostTail, 
> 					CURLFORM_COPYNAME,(const char*)szName.ToAscii(),
> 					CURLFORM_FILE, (const char*)filename.ToAscii(), 
> 					CURLFORM_END);
> 
>     if (outErr != NULL)
>         *outErr = res;  // sometimes you want to/need to see what's going on
> 
>     return (res == CURL_FORMADD_OK);
> }
wxcode/components/wxcurl/include/wx/curl/http.h

Code: Select all

44c44,45
< 
---
>       bool            AddFileToForm(const bool& bClear, const wxString& szName,
>                                const wxString& filename, CURLFORMcode* outErr=NULL);

For anyone working on this
Here's a reference for using cURL forms in libcurl http://curl.haxx.se/libcurl/c/curl_formadd.html.


Here's an example of usage of the wxCurlFormPostThread class

Code: Select all

        int threadid=generate_thread_id();
        wxCurlFormPostThread *pthread=new wxCurlFormPostThread(parent, threadid);

        // set download params
        wxCurlThreadError ret=pthread->SetURL(url);
        wxASSERT(ret==wxCTE_NO_ERROR);
        pthread->GetCurlSession()->SetVerbose(true);
        pthread->GetCurlSession()->SetUsername(..);
        pthread->GetCurlSession()->SetPassword(..);
        pthread->GetCurlSession()->UseProxy(..);
        pthread->GetCurlSession()->SetProxyHost(..);
        pthread->GetCurlSession()->SetProxyUsername(..);
        pthread->GetCurlSession()->SetProxyPassword(..);
        pthread->GetCurlSession()->SetProxyPort(..);


        CURLFORMcode err;
        char cstring[1024];
        // assuming you want UTF-8, change the wxConv* parameter as needed
        strncpy(cstring, (const char*)"Buffer contents", 1023);
        pthread->AddBufferToForm(false,"HTTPFormName",cstring,strlen(cstring),&err);
        pthread->AddFileToForm(false,"HTTPFormFileName","filename.txt",&err);

        pthread->Post();//hopefully wxCTE_NO_ERROR
        Connect(threadid, wxCURL_END_PERFORM_EVENT,
                wxCurlEndPerformEventHandler(yourEventHandler));
So that's it. I would love to contribute these to the wxCurl base code but I'm not sure what the preferred route for that is (access to SVN?). anyways, feedback appreciated. I have made some other minor modifications to wxCurl to help it compile with 3.0 so it should be all up to date

-Colin

User avatar
evstevemd
Part Of The Furniture
Part Of The Furniture
Posts: 2293
Joined: Wed Jan 28, 2009 11:57 am
Location: United Republic of Tanzania
Contact:

Re: Adding Multithreaded HTTP post to wxCurl

Post by evstevemd » Sun Feb 09, 2014 4:17 pm

wxCurl is abandoned. I had to use pure libcurl in my projects since I could not maintain myself.
So you can make your github version which is maintained and I will be happy to use it and with
time contribute to it!
Chief Justice: We have trouble dear citizens!
Citizens: What it is his honor?
Chief Justice:Our president is an atheist, who will he swear to?
[Ubuntu 19.04/Windows 10 Pro/MacOS 10.13 - GCC/MinGW/Clang, CodeLite IDE]

Post Reply