From bdbe1647dd039150a3bb86c1e48d6dc8d93cc596 Mon Sep 17 00:00:00 2001 From: Nathan Fulton Date: Thu, 25 Aug 2016 15:40:25 -0400 Subject: [PATCH] Improvements for SdlHttpRequest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - When “Downloaded X of Y bytes…” Y is no longer -1. - HTTP posting now works (e.g. uploading sync errors). --- game/sdl/sdlhttprequest.cpp | 233 +++++++++++++++++------------------- game/sdl/sdlhttprequest.h | 15 +-- 2 files changed, 120 insertions(+), 128 deletions(-) diff --git a/game/sdl/sdlhttprequest.cpp b/game/sdl/sdlhttprequest.cpp index 8404d7c..cbc1acc 100644 --- a/game/sdl/sdlhttprequest.cpp +++ b/game/sdl/sdlhttprequest.cpp @@ -3,31 +3,60 @@ #include "base/thread.h" #include -#include +#include // Curl implementation of HttpRequest for SDL namespace wi { +SdlHttpRequest::SdlHttpRequest(HttpResponseHandler *handler) : handler_(handler) { +} + +SdlHttpRequest::~SdlHttpRequest() { +} + size_t SdlHttpRequest::WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) { - LOG() << "WriteMemoryCallback"; - size_t realsize = size * nmemb; struct MemoryStruct *mem = (struct MemoryStruct *)userp; if (mem->what == CURLOPT_WRITEDATA) { - LOG() << "Data size: " << realsize; ReceivedDataParams *pparams = new ReceivedDataParams; - pparams->bb.WriteBytes((const byte*)contents,realsize); + pparams->bb.WriteBytes((const byte*)contents, (int)realsize); thread_.Post(kidmReceivedData, this, pparams); } - else if (mem->what == CURLOPT_HEADERDATA) + + if (mem->what == CURLOPT_HEADERDATA) { - LOG() << "Header"; ReceivedResponseParams *pparams = new ReceivedResponseParams; pparams->code = 200; - thread_.Post(kidmReceivedResponse, this, pparams); + + // Stuff for delimiting + size_t pos = 0; + std::string delimiter = ":"; + std::string str((char *)contents); + std::string key; + std::string value; + + // Split the HTTP header into a key and value + if ((pos = str.find(delimiter)) != std::string::npos) { + key = str.substr(0, pos); + str.erase(0, pos + delimiter.length()); + } + value = str; + + // Remove newlines and spaces that sneak in sometimes + value.erase(std::remove(value.begin(), value.end(), '\n'), value.end()); + value.erase(std::remove(value.begin(), value.end(), '\r'), value.end()); + value.erase(std::remove(value.begin(), value.end(), ' '), value.end()); + + // handler_ doesn't read the Content-Length header properly when + // other header(s) are posted. To be discovered why this happens. + // The game only uses Content-Length so only post it for now. + if (key == "Content-Length") { + pparams->headers.SetValue(key.c_str(), value.c_str()); + thread_.Post(kidmReceivedResponse, this, pparams); + } } mem->memory = (char*)realloc(mem->memory, mem->size + realsize + 1); @@ -44,157 +73,119 @@ size_t SdlHttpRequest::WriteMemoryCallback(void *contents, size_t size, size_t n return realsize; } -SdlHttpRequest::SdlHttpRequest(HttpResponseHandler *handler) : handler_(handler) { - LOG() << "SdlHttpRequest::SdlHttpRequest"; -} +void SdlHttpRequest::CreateCurlRequest() { + /* init the curl session */ + curl_handle_ = curl_easy_init(); -SdlHttpRequest::~SdlHttpRequest() { -} + chunk_.cls = this; + chunk_.memory = (char*)malloc(1); /* will be grown as needed by the realloc above */ + chunk_.size = 0; /* no data at this point */ + chunk_.what = CURLOPT_WRITEDATA; -void *SdlHttpRequest::doAccess(void *arg) -{ + chunkHeader_.cls = this; + chunkHeader_.memory = (char*)malloc(1); /* will be grown as needed by the realloc above */ + chunkHeader_.what = CURLOPT_HEADERDATA; + chunkHeader_.size = 0; /* no data at this point */ - CURL *curl_handle; - CURLcode res; - /* init the curl session */ - curl_handle = curl_easy_init(); - - struct MemoryStruct chunk; - struct MemoryStruct chunkHeader; - - chunk.cls = this; - chunk.memory = (char*)malloc(1); /* will be grown as needed by the realloc above */ - chunk.size = 0; /* no data at this point */ - chunk.what = CURLOPT_WRITEDATA; - - chunkHeader.cls = this; - chunkHeader.memory = (char*)malloc(1); /* will be grown as needed by the realloc above */ - chunkHeader.what = CURLOPT_HEADERDATA; - chunkHeader.size = 0; /* no data at this point */ - - curl_global_init(CURL_GLOBAL_ALL); + curl_global_init(CURL_GLOBAL_ALL); /* specify URL to get */ - curl_easy_setopt(curl_handle, CURLOPT_URL, url_.c_str()); + curl_easy_setopt(curl_handle_, CURLOPT_URL, url_.c_str()); + + /* specify body to post */ + if (pbb_ != NULL) { + int cb; + void *pv = pbb_->Strip(&cb); + curl_easy_setopt(curl_handle_, CURLOPT_POSTFIELDS, pv); + } /* send all data to this function */ - curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, SdlHttpRequest::WriteMemoryCallback_helper); + curl_easy_setopt(curl_handle_, CURLOPT_WRITEFUNCTION, SdlHttpRequest::WriteMemoryCallback_helper); /* we pass our 'chunk' struct to the callback function */ - curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); + curl_easy_setopt(curl_handle_, CURLOPT_WRITEDATA, (void *)&chunk_); /* we pass our 'chunk' struct to the callback function */ - curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, (void *)&chunkHeader); + curl_easy_setopt(curl_handle_, CURLOPT_HEADERDATA, (void *)&chunkHeader_); - curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT,10); + curl_easy_setopt(curl_handle_, CURLOPT_CONNECTTIMEOUT,10); /* some servers don't like requests that are made without a user-agent field, so we provide one */ - curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + curl_easy_setopt(curl_handle_, CURLOPT_USERAGENT, "libcurl-agent/1.0"); - curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(curl_handle_, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl_handle_, CURLOPT_SSL_VERIFYHOST, 0L); +} - res = curl_easy_perform(curl_handle); +void SdlHttpRequest::SubmitCurlRequest(void *pv) { + SdlHttpRequest *req = (SdlHttpRequest *)pv; - long http_code = 0; + CURLcode res = curl_easy_perform(req->curl_handle_); - /* check for errors */ + // check for errors if(res != CURLE_OK) { - LOG() << "curl_easy_perform() failed: " << curl_easy_strerror(res); ErrorParams *pparams = new ErrorParams; - strncpyz(pparams->szError, curl_easy_strerror(res), sizeof(pparams->szError)); - - // Called on main thread. Post this to game thread. - thread_.Post(kidmError, this, pparams); - } - else { - curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &http_code); - - LOG() << "Resp code = " << http_code; - - //base::ByteBuffer bb; - //bb.WriteBytes((const byte*)chunkHeader.memory,chunkHeader.size); - - //ReceivedResponseParams *pparams = new ReceivedResponseParams; - //pparams->code = http_code; - //thread_.Post(kidmReceivedResponse, this, pparams); - - if (http_code == 200) - { - LOG() << "Data length: " << chunk.size; - //ReceivedDataParams *pparams = new ReceivedDataParams; - //pparams->bb.WriteBytes((const byte*)chunk.memory,chunk.size); - //thread_.Post(kidmReceivedData, this, pparams); - } - - LOG() << "%lu bytes retrieved" << (long)chunk.size; - LOG() << "got: " << chunk.memory; - } - - /* cleanup curl stuff */ - curl_easy_cleanup(curl_handle); - - if(chunk.memory) - free(chunk.memory); - - if(chunkHeader.memory) - free(chunkHeader.memory); - - thread_.Post(kidmFinishedLoading, this); - - return 0; + strncpyz(pparams->szError, curl_easy_strerror(res), CURL_ERROR_SIZE); + req->thread().Post(kidmError, req, pparams); + } else { + req->thread().Post(kidmFinishedLoading, req); + } } void SdlHttpRequest::Submit() { - LOG() << "SdlHttpRequest::SdlHttpRequest, URL = " << url_.c_str(); - - pthread_t pth; // this is our thread identifier - pthread_create(&pth,NULL, SdlHttpRequest::doAccess_helper,this); + this->CreateCurlRequest(); + // SdlHttpRequest::Submit() is called on the game thread + // so spin off a new thread to run the request on. + base::Thread *thread = new base::Thread(); + thread->Start(SubmitCurlRequest, this); } void SdlHttpRequest::Release() { - LOG() << "SdlHttpRequest::Release"; - // TODO: need to abort thread.. + curl_easy_cleanup(curl_handle_); + + if (chunk_.memory) + free(chunk_.memory); + + if (chunkHeader_.memory) + free(chunkHeader_.memory); + thread_.Clear(this); } void SdlHttpRequest::OnMessage(base::Message *pmsg) { - LOG() << "SdlHttpRequest::OnMessage"; - switch (pmsg->id) { - case kidmReceivedResponse: - { - ReceivedResponseParams *pparams = - (ReceivedResponseParams *)pmsg->data; - handler_->OnReceivedResponse(this, pparams->code, - &pparams->headers); - delete pparams; + case kidmReceivedResponse: + { + ReceivedResponseParams *pparams = + (ReceivedResponseParams *)pmsg->data; + handler_->OnReceivedResponse(this, pparams->code, + &pparams->headers); + delete pparams; + } break; - } - case kidmReceivedData: - { - ReceivedDataParams *pparams = - (ReceivedDataParams *)pmsg->data; - handler_->OnReceivedData(this, &pparams->bb); - delete pparams; + case kidmReceivedData: + { + ReceivedDataParams *pparams = + (ReceivedDataParams *)pmsg->data; + handler_->OnReceivedData(this, &pparams->bb); + delete pparams; + } break; - } - case kidmFinishedLoading: - handler_->OnFinishedLoading(this); - break; - - case kidmError: - { - ErrorParams *pparams = (ErrorParams *)pmsg->data; - handler_->OnError(this, pparams->szError); - delete pparams; + case kidmFinishedLoading: + handler_->OnFinishedLoading(this); break; - } - } // switch + case kidmError: + { + ErrorParams *pparams = (ErrorParams *)pmsg->data; + handler_->OnError(this, pparams->szError); + delete pparams; + } + break; + } } } // namespace wi diff --git a/game/sdl/sdlhttprequest.h b/game/sdl/sdlhttprequest.h index fda26ec..2e0f93d 100644 --- a/game/sdl/sdlhttprequest.h +++ b/game/sdl/sdlhttprequest.h @@ -6,6 +6,8 @@ #include "base/thread.h" #include "base/bytebuffer.h" +#include + namespace wi { class SdlHttpRequest; @@ -17,7 +19,6 @@ struct MemoryStruct { size_t size; }; - class SdlHttpRequest : public HttpRequest, base::MessageHandler { public: SdlHttpRequest(HttpResponseHandler *phandler); @@ -29,15 +30,15 @@ public: private: HttpResponseHandler *handler_; + CURL *curl_handle_; + struct MemoryStruct chunk_; + struct MemoryStruct chunkHeader_; - void *doAccess(void *arg); virtual void OnMessage(base::Message *pmsg); + static void SubmitCurlRequest(void *pv); + void CreateCurlRequest(); + size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp); - - static void *doAccess_helper(void *context) { - return ((SdlHttpRequest *)context)->doAccess(0); - } - static size_t WriteMemoryCallback_helper(void *contents, size_t size, size_t nmemb, void *userp) { return (((MemoryStruct *)userp)->cls)->WriteMemoryCallback(contents,size,nmemb,userp);