#include "curlmanager.h" #ifdef PLATFORM_LINUX #include #endif cURLManager g_cURLManager; struct data_t { data_t(cURLHandle *_handle, size_t _bytes, size_t _nmemb): handle(_handle), buffer(NULL), bytes(_bytes), nmemb(_nmemb) { } cURLHandle *handle; char *buffer; size_t bytes; size_t nmemb; size_t return_value; }; #include /* Write Function */ static size_t curl_write_function_default(void *ptr, size_t bytes, size_t nmemb, void *stream) { FILE *file = (FILE *)stream; #ifdef WIN32 //if(file->_file >= 3) if ( _filelength(_fileno(file)) >= 3 ) #else if(file->_fileno >= 3) #endif { return fwrite(ptr, bytes, nmemb, file); } return (bytes * nmemb); } static size_t Call_Write_Function(cURLHandle *handle, const char *buffer, size_t bytes, size_t nmemb) { IPluginFunction *pFunc = handle->callback_Function[cURL_CallBack_WRITE_FUNCTION]; assert((pFunc != NULL)); cell_t result = bytes * nmemb; if(pFunc != NULL) { pFunc->PushCell(handle->hndl); pFunc->PushStringEx((char *)buffer, nmemb+1, SM_PARAM_STRING_COPY|SM_PARAM_STRING_BINARY, 0); pFunc->PushCell(bytes); pFunc->PushCell(nmemb); pFunc->PushCell(handle->UserData[UserData_Type_Write_Func]); pFunc->Execute(&result); } return result; } static void sm_write_function_FrameAction(void *data) { if(data == NULL) return; data_t *wdata = (data_t*)data; wdata->return_value = Call_Write_Function(wdata->handle, wdata->buffer, wdata->bytes, wdata->nmemb); wdata->handle->thread->EventSignal(); } static size_t curl_write_function_SM(void *ptr, size_t bytes, size_t nmemb, void *stream) { cURLHandle *handle = (cURLHandle *)stream; size_t ret; if(handle->thread == NULL) { char *buffer = new char[nmemb+1]; memcpy(buffer,ptr, nmemb); buffer[nmemb] = '\0'; ret = Call_Write_Function(handle, buffer, bytes, nmemb); delete [] buffer; } else { if(g_cURL_SM.IsShutdown()) return (bytes * nmemb); data_t *data = new data_t(handle, bytes, nmemb); data->buffer = new char[nmemb+1]; memcpy(data->buffer,ptr, nmemb); data->buffer[nmemb] = '\0'; smutils->AddFrameAction(sm_write_function_FrameAction, data); handle->thread->EventWait(); ret = data->return_value; delete [] data->buffer; delete data; if(g_cURL_SM.IsShutdown()) return (bytes * nmemb); } return ret; } /* Read Function */ static size_t Call_Read_Function(cURLHandle *handle, size_t bytes, size_t nmemb) { IPluginFunction *pFunc = handle->callback_Function[cURL_CallBack_READ_FUNCTION]; assert((pFunc != NULL)); cell_t result = bytes * nmemb; if(pFunc != NULL) { pFunc->PushCell(handle->hndl); pFunc->PushCell(bytes); pFunc->PushCell(nmemb); pFunc->PushCell(handle->UserData[UserData_Type_Read_Func]); pFunc->Execute(&result); } return result; } static void sm_read_function_FrameAction(void *data) { if(data == NULL) return; data_t *rdata = (data_t*)data; rdata->return_value = Call_Read_Function(rdata->handle, rdata->bytes, rdata->nmemb); rdata->handle->thread->EventSignal(); } static size_t curl_read_function_SM(char *ptr, size_t bytes, size_t nmemb, void *stream) { cURLHandle *handle = (cURLHandle *)stream; size_t ret = 0; if(handle->thread == NULL) { ret = Call_Read_Function(handle, bytes, nmemb); } else { if(g_cURL_SM.IsShutdown()) return 0; data_t *data = new data_t(handle, bytes, nmemb); smutils->AddFrameAction(sm_read_function_FrameAction, data); handle->thread->EventWait(); ret = data->return_value; delete data; if(g_cURL_SM.IsShutdown()) return 0; } if(ret > 0) { memcpy(ptr,handle->send_buffer.data(), handle->send_buffer.size()); } return ret; } static curl_socket_t curl_opensocket_function(void *clientp, curlsocktype purpose, struct curl_sockaddr *address) { cURLHandle *handle = (cURLHandle *)clientp; if(handle->is_udp) { address->socktype = SOCK_DGRAM; address->protocol = IPPROTO_UDP; address->family = AF_INET; } return socket(address->family, address->socktype, address->protocol); } void cURLManager::SDK_OnLoad() { curlhandle_list_mutex = threader->MakeMutex(); shutdown_event = threader->MakeEventSignal(); closehelper_list_mutex = threader->MakeMutex(); waiting = false; } void cURLManager::SDK_OnUnload() { curlhandle_list_mutex->Lock(); if(g_cURLThread_List.size() > 0) { printf("[%s] Waiting %d cURL Threads Terminate...\n",SMEXT_CONF_LOGTAG,g_cURLThread_List.size()); SourceHook::List::iterator iter = g_cURLThread_List.begin(); cURLThread *pInfo; while (iter != g_cURLThread_List.end()) { pInfo = (*iter); if(pInfo->waiting) { pInfo->event->Signal(); } iter++; } curlhandle_list_mutex->Unlock(); waiting = true; shutdown_event->Wait(); printf("[%s] All cURL Thread Terminated !!!\n",SMEXT_CONF_LOGTAG); } else { curlhandle_list_mutex->Unlock(); } shutdown_event->DestroyThis(); curlhandle_list_mutex->DestroyThis(); shutdown_event = NULL; curlhandle_list_mutex = NULL; g_cURLThread_List.clear(); g_CloseHelper_List.clear(); } void cURLManager::CreatecURLThread(cURLThread *thread) { if(g_cURL_SM.IsShutdown()) { delete thread; return; } curlhandle_list_mutex->Lock(); g_cURLThread_List.push_back(thread); curlhandle_list_mutex->Unlock(); threader->MakeThread(thread); } void cURLManager::RemovecURLThread(cURLThread *thread) { if(g_cURL_SM.IsShutdown()) { RemovecURLHandle(thread->handle); } curlhandle_list_mutex->Lock(); g_cURLThread_List.remove(thread); if(waiting) { if(g_cURLThread_List.size() == 0) { curlhandle_list_mutex->Unlock(); shutdown_event->Signal(); return; } } curlhandle_list_mutex->Unlock(); } void cURLManager::AddCloseHelperHandle(ICloseHelper *helper) { closehelper_list_mutex->Lock(); if(g_CloseHelper_List.find(helper) == g_CloseHelper_List.end()) { g_CloseHelper_List.push_back(helper); } closehelper_list_mutex->Unlock(); } void cURLManager::RemoveCloseHelperHandle(ICloseHelper *helper) { closehelper_list_mutex->Lock(); g_CloseHelper_List.remove(helper); closehelper_list_mutex->Unlock(); } void cURLManager::RemoveLinkedICloseHelper(cURLHandle *handle) { closehelper_list_mutex->Lock(); SourceHook::List::iterator iter; ICloseHelper *pInfo; for (iter=g_CloseHelper_List.begin(); iter!=g_CloseHelper_List.end(); iter++) { pInfo = (*iter); if(pInfo->_handle == handle) { pInfo->_handle = NULL; if(pInfo->_marked_delete) { pInfo->Delete(); iter = g_CloseHelper_List.erase(iter); } } } closehelper_list_mutex->Unlock(); } void cURLManager::RemovecURLHandle(cURLHandle *handle) { if(!handle || handle->running) return; if(handle->thread != NULL) { handle->thread->handle = NULL; } curl_easy_cleanup(handle->curl); handle->curl = NULL; SourceHook::List::iterator iter; cURLOpt_string *pInfo; for (iter=handle->opt_string_list.begin(); iter!=handle->opt_string_list.end(); iter++) { pInfo = (*iter); delete [] pInfo->value; delete pInfo; } handle->opt_string_list.clear(); SourceHook::List::iterator iter2; cURLOpt_int*pInfo2; for (iter2=handle->opt_int_list.begin(); iter2!=handle->opt_int_list.end(); iter2++) { pInfo2 = (*iter2); delete pInfo2; } handle->opt_int_list.clear(); SourceHook::List::iterator iter3; cURLOpt_pointer *pInfo3; for(iter3=handle->opt_pointer_list.begin(); iter3!=handle->opt_pointer_list.end(); iter3++) { pInfo3 = (*iter3); delete pInfo3; } handle->opt_pointer_list.clear(); SourceHook::List::iterator iter4; cURLOpt_int64 *pInfo4; for(iter4=handle->opt_int64_list.begin(); iter4!=handle->opt_int64_list.end(); iter4++) { pInfo4 = (*iter4); delete pInfo4; } handle->opt_int64_list.clear(); handle->send_buffer.clear(); RemoveLinkedICloseHelper(handle); delete handle; } bool cURLManager::AddcURLOptionString(cURLHandle *handle, CURLoption opt, char *value) { if(!handle || handle->running || !value) return false; std::string value_str; bool supported = false; switch(opt) { case CURLOPT_URL: { char *lowercase_value = UTIL_ToLowerCase(value); std::string value_str_lower(lowercase_value); delete [] lowercase_value; if(!value_str_lower.compare(0,6, "udp://")) { handle->is_udp = true; value_str.assign(&value[6]); } else { value_str = value; handle->is_udp = false; } supported = true; break; } case CURLOPT_PROXY: case CURLOPT_PROXYUSERPWD: case CURLOPT_RANGE: case CURLOPT_USERPWD: case CURLOPT_KEYPASSWD: case CURLOPT_POSTFIELDS: case CURLOPT_REFERER: case CURLOPT_FTPPORT: case CURLOPT_USERAGENT: case CURLOPT_COOKIE: case CURLOPT_ENCODING: case CURLOPT_CUSTOMREQUEST: case CURLOPT_WRITEINFO: case CURLOPT_INTERFACE: case CURLOPT_KRBLEVEL: case CURLOPT_SSL_CIPHER_LIST: case CURLOPT_SSLCERTTYPE: case CURLOPT_SSLKEYTYPE: case CURLOPT_SSLENGINE: case CURLOPT_FTP_ACCOUNT: case CURLOPT_COOKIELIST: case CURLOPT_FTP_ALTERNATIVE_TO_USER: case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5: case CURLOPT_USERNAME: case CURLOPT_PASSWORD: case CURLOPT_PROXYUSERNAME: case CURLOPT_PROXYPASSWORD: case CURLOPT_NOPROXY: case CURLOPT_SOCKS5_GSSAPI_SERVICE: case CURLOPT_MAIL_FROM: case CURLOPT_RTSP_SESSION_ID: case CURLOPT_RTSP_STREAM_URI: case CURLOPT_RTSP_TRANSPORT: value_str.assign(value); supported = true; break; case CURLOPT_COOKIEFILE: case CURLOPT_COOKIEJAR: case CURLOPT_RANDOM_FILE: case CURLOPT_EGDSOCKET: case CURLOPT_SSLCERT: case CURLOPT_SSLKEY: case CURLOPT_CAINFO: case CURLOPT_CAPATH: case CURLOPT_NETRC_FILE: case CURLOPT_SSH_PUBLIC_KEYFILE: case CURLOPT_SSH_PRIVATE_KEYFILE: case CURLOPT_CRLFILE: case CURLOPT_ISSUERCERT: case CURLOPT_SSH_KNOWNHOSTS: { char realpath[PLATFORM_MAX_PATH]; g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", value); value_str.assign(realpath); supported = true; break; } } assert((supported != false)); if(!supported) return false; cURLOpt_string *stringopt = new cURLOpt_string(); stringopt->opt = opt; stringopt->value = new char[value_str.size()+1]; memset(stringopt->value, 0, value_str.size()+1); memcpy(stringopt->value,value_str.c_str(), value_str.size()); handle->opt_string_list.push_back(stringopt); return true; } bool cURLManager::AddcURLOptionInt(cURLHandle *handle, CURLoption opt, int value) { if(!handle || handle->running) return false; bool supported = false; switch(opt) { case CURLOPT_PORT: case CURLOPT_NOPROGRESS: case CURLOPT_VERBOSE: case CURLOPT_PROXYTYPE: case CURLOPT_HTTPPROXYTUNNEL: case CURLOPT_TIMEOUT: case CURLOPT_SSL_VERIFYPEER: case CURLOPT_SSL_VERIFYHOST: case CURLOPT_UPLOAD: case CURLOPT_INFILESIZE: case CURLOPT_LOW_SPEED_LIMIT: case CURLOPT_LOW_SPEED_TIME: case CURLOPT_RESUME_FROM: case CURLOPT_CRLF: case CURLOPT_SSLVERSION: case CURLOPT_TIMECONDITION: case CURLOPT_TIMEVALUE: case CURLOPT_HEADER: case CURLOPT_NOBODY: case CURLOPT_FAILONERROR: case CURLOPT_POST: case CURLOPT_DIRLISTONLY: case CURLOPT_APPEND: case CURLOPT_NETRC: case CURLOPT_FOLLOWLOCATION: case CURLOPT_TRANSFERTEXT: case CURLOPT_PUT: case CURLOPT_AUTOREFERER: case CURLOPT_PROXYPORT: case CURLOPT_POSTFIELDSIZE: case CURLOPT_MAXREDIRS: case CURLOPT_FILETIME: case CURLOPT_MAXCONNECTS: case CURLOPT_CLOSEPOLICY: case CURLOPT_FRESH_CONNECT: case CURLOPT_FORBID_REUSE: case CURLOPT_CONNECTTIMEOUT: case CURLOPT_HTTPGET: case CURLOPT_HTTP_VERSION: case CURLOPT_FTP_USE_EPSV: case CURLOPT_SSLENGINE_DEFAULT: case CURLOPT_DNS_USE_GLOBAL_CACHE: case CURLOPT_DNS_CACHE_TIMEOUT: case CURLOPT_COOKIESESSION: case CURLOPT_BUFFERSIZE: case CURLOPT_NOSIGNAL: case CURLOPT_UNRESTRICTED_AUTH: case CURLOPT_FTP_USE_EPRT: case CURLOPT_HTTPAUTH: case CURLOPT_FTP_CREATE_MISSING_DIRS: case CURLOPT_PROXYAUTH: case CURLOPT_FTP_RESPONSE_TIMEOUT: case CURLOPT_IPRESOLVE: case CURLOPT_MAXFILESIZE: case CURLOPT_USE_SSL: case CURLOPT_TCP_NODELAY: case CURLOPT_FTPSSLAUTH: case CURLOPT_IGNORE_CONTENT_LENGTH: case CURLOPT_FTP_SKIP_PASV_IP: case CURLOPT_FTP_FILEMETHOD: case CURLOPT_LOCALPORT: case CURLOPT_LOCALPORTRANGE: case CURLOPT_CONNECT_ONLY: case CURLOPT_SSL_SESSIONID_CACHE: case CURLOPT_SSH_AUTH_TYPES: case CURLOPT_FTP_SSL_CCC: case CURLOPT_TIMEOUT_MS: case CURLOPT_CONNECTTIMEOUT_MS: case CURLOPT_HTTP_TRANSFER_DECODING: case CURLOPT_HTTP_CONTENT_DECODING: case CURLOPT_NEW_FILE_PERMS: case CURLOPT_NEW_DIRECTORY_PERMS: case CURLOPT_POSTREDIR: case CURLOPT_PROXY_TRANSFER_MODE: case CURLOPT_ADDRESS_SCOPE: case CURLOPT_CERTINFO: case CURLOPT_TFTP_BLKSIZE: case CURLOPT_PROTOCOLS: case CURLOPT_REDIR_PROTOCOLS: case CURLOPT_FTP_USE_PRET: case CURLOPT_RTSP_REQUEST: case CURLOPT_RTSP_CLIENT_CSEQ: case CURLOPT_RTSP_SERVER_CSEQ: case CURLOPT_WILDCARDMATCH: case CURLOPT_TRANSFER_ENCODING: case CURLOPT_GSSAPI_DELEGATION: supported = true; break; } assert((supported != false)); if(!supported) return false; cURLOpt_int *intopt = new cURLOpt_int(); intopt->opt = opt; intopt->value = value; handle->opt_int_list.push_back(intopt); return true; } bool cURLManager::AddcURLOptionInt64(cURLHandle *handle, CURLoption opt, long long value) { if(!handle || handle->running) return false; bool supported = false; switch(opt) { case CURLOPT_INFILESIZE_LARGE: case CURLOPT_RESUME_FROM_LARGE: case CURLOPT_MAXFILESIZE_LARGE: case CURLOPT_POSTFIELDSIZE_LARGE: case CURLOPT_MAX_SEND_SPEED_LARGE: case CURLOPT_MAX_RECV_SPEED_LARGE: supported = true; break; } assert((supported != false)); if(!supported) return false; cURLOpt_int64 *int64opt = new cURLOpt_int64(); int64opt->opt = opt; int64opt->value = (curl_off_t)value; handle->opt_int64_list.push_back(int64opt); return true; } bool cURLManager::AddcURLOptionFunction(IPluginContext *pContext, cURLHandle *handle, CURLoption opt, IPluginFunction *pFunction, int value) { if(!handle || handle->running) return false; cURL_CallBack index = cURL_CallBack_NOTHING; switch(opt) { case CURLOPT_WRITEFUNCTION: index = cURL_CallBack_WRITE_FUNCTION; handle->UserData[UserData_Type_Write_Func] = value; break; case CURLOPT_READFUNCTION: index = cURL_CallBack_READ_FUNCTION; handle->UserData[UserData_Type_Read_Func] = value; break; } if(index == cURL_CallBack_NOTHING) return false; handle->callback_Function[index] = pFunction; return true; } bool cURLManager::AddcURLOptionHandle(IPluginContext *pContext, cURLHandle *handle, HandleSecurity *sec, CURLoption opt, Handle_t hndl) { if(!handle || handle->running) return false; void *pointer = NULL; int err = SP_ERROR_NONE; ICloseHelper *helper = NULL; switch(opt) { case CURLOPT_WRITEDATA: case CURLOPT_HEADERDATA: case CURLOPT_READDATA: case CURLOPT_STDERR: case CURLOPT_INTERLEAVEDATA: { cURL_OpenFile *openfile = NULL; err = handlesys->ReadHandle(hndl, g_cURLFile, sec, (void **)&openfile); if(openfile != NULL) { pointer = openfile->pFile; openfile->_handle = handle; helper = openfile; } break; } case CURLOPT_HTTPPOST: { WebForm *webform = NULL; err = handlesys->ReadHandle(hndl, g_WebForm, sec, (void **)&webform); if(webform != NULL) { pointer = webform->first; webform->_handle = handle; helper = webform; SourceHook::List::iterator iter; cURL_slist_pack *pInfo; for(iter=webform->slist_record.begin(); iter!=webform->slist_record.end(); iter++) { pInfo = (*iter); pInfo->_handle = handle; AddCloseHelperHandle(pInfo); } } break; } case CURLOPT_HTTPHEADER: case CURLOPT_QUOTE: case CURLOPT_POSTQUOTE: case CURLOPT_TELNETOPTIONS: case CURLOPT_PREQUOTE: case CURLOPT_HTTP200ALIASES: case CURLOPT_MAIL_RCPT: case CURLOPT_RESOLVE: { cURL_slist_pack *slist = NULL; err = handlesys->ReadHandle(hndl, g_cURLSlist, sec, (void **)&slist); if(slist != NULL) { pointer = slist->chunk; slist->_handle = handle; helper = slist; } break; } } if(err != SP_ERROR_NONE) { pContext->ThrowNativeErrorEx(err, NULL); return false; } assert((pointer != NULL)); if(pointer == NULL) return false; cURLOpt_pointer *pointeropt = new cURLOpt_pointer(); pointeropt->opt = opt; pointeropt->value = pointer; handle->opt_pointer_list.push_back(pointeropt); AddCloseHelperHandle(helper); return true; } void cURLManager::LoadcURLOption(cURLHandle *handle) { if(!handle || handle->opt_loaded) return; handle->opt_loaded = true; curl_easy_setopt(handle->curl, CURLOPT_ERRORBUFFER, handle->errorBuffer); curl_easy_setopt(handle->curl, CURLOPT_OPENSOCKETFUNCTION, curl_opensocket_function); curl_easy_setopt(handle->curl, CURLOPT_OPENSOCKETDATA, handle); if(handle->callback_Function[cURL_CallBack_WRITE_FUNCTION] == NULL) { curl_easy_setopt(handle->curl, CURLOPT_WRITEFUNCTION, curl_write_function_default); } else { curl_easy_setopt(handle->curl, CURLOPT_WRITEFUNCTION, curl_write_function_SM); curl_easy_setopt(handle->curl, CURLOPT_WRITEDATA, handle); } if(handle->callback_Function[cURL_CallBack_READ_FUNCTION] != NULL) { curl_easy_setopt(handle->curl, CURLOPT_READFUNCTION, curl_read_function_SM); curl_easy_setopt(handle->curl, CURLOPT_READDATA, handle); } SourceHook::List::iterator iter; cURLOpt_string *pInfo; for(iter=handle->opt_string_list.begin(); iter!=handle->opt_string_list.end(); iter++) { pInfo = (*iter); if((handle->lasterror = curl_easy_setopt(handle->curl, pInfo->opt, pInfo->value)) != CURLE_OK) return; } SourceHook::List::iterator iter2; cURLOpt_int *pInfo2; for(iter2=handle->opt_int_list.begin(); iter2!=handle->opt_int_list.end(); iter2++) { pInfo2 = (*iter2); if((handle->lasterror = curl_easy_setopt(handle->curl, pInfo2->opt, pInfo2->value)) != CURLE_OK) return; } SourceHook::List::iterator iter3; cURLOpt_pointer *pInfo3; for(iter3=handle->opt_pointer_list.begin(); iter3!=handle->opt_pointer_list.end(); iter3++) { pInfo3 = (*iter3); //Not allow use CURLOPT_WRITEDATA, CURLOPT_READDATA, if write/read function set if((handle->callback_Function[cURL_CallBack_WRITE_FUNCTION] != NULL && pInfo3->opt == CURLOPT_WRITEDATA) || (handle->callback_Function[cURL_CallBack_READ_FUNCTION] != NULL && pInfo3->opt == CURLOPT_READDATA)) { continue; } if((handle->lasterror = curl_easy_setopt(handle->curl, pInfo3->opt, pInfo3->value)) != CURLE_OK) return; } SourceHook::List::iterator iter4; cURLOpt_int64 *pInfo4; for(iter4=handle->opt_int64_list.begin(); iter4!=handle->opt_int64_list.end(); iter4++) { pInfo4 = (*iter4); if((handle->lasterror = curl_easy_setopt(handle->curl, pInfo4->opt, (curl_off_t)pInfo4->value)) != CURLE_OK) return; } } CURLFORMcode cURLManager::cURLFormAdd(IPluginContext *pContext, const cell_t *params, WebForm *handle) { assert((handle != NULL)); if(handle == NULL) return CURL_FORMADD_INCOMPLETE; unsigned int numparams = (unsigned)params[0]; unsigned int startparam = 2; if(numparams <= 1 || numparams > 22) return CURL_FORMADD_INCOMPLETE; // there are only 10 available/supported CURLFORM_* CURLformoption form_opts[11] = {CURLFORM_NOTHING}; char *form_data[10]; memset(form_data, 0, sizeof(form_data)); cell_t *addr; int count = 0; int err; int value; for(unsigned int i=startparam;i<=numparams;i++) { if((err=pContext->LocalToPhysAddr(params[i], &addr)) != SP_ERROR_NONE) { pContext->ThrowNativeErrorEx(err, NULL); return CURL_FORMADD_INCOMPLETE; } CURLformoption form_code = (CURLformoption)*addr; switch(form_code) { case CURLFORM_COPYNAME: case CURLFORM_COPYCONTENTS: case CURLFORM_FILECONTENT: case CURLFORM_FILE: case CURLFORM_CONTENTTYPE: case CURLFORM_FILENAME: if((err=pContext->LocalToString(params[i+1], &form_data[count])) != SP_ERROR_NONE) { pContext->ThrowNativeErrorEx(err, NULL); return CURL_FORMADD_INCOMPLETE; } if(form_code == CURLFORM_FILE || form_code == CURLFORM_FILECONTENT) // absolute path { char realpath[PLATFORM_MAX_PATH]; g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", form_data[count]); form_data[count] = realpath; } form_opts[count] = form_code; count++; i++; break; case CURLFORM_NAMELENGTH: case CURLFORM_CONTENTSLENGTH: if((err=pContext->LocalToPhysAddr(params[i+1], &addr)) != SP_ERROR_NONE) { pContext->ThrowNativeErrorEx(err, NULL); return CURL_FORMADD_INCOMPLETE; } form_opts[count] = form_code; value = *addr; form_data[count] = (char *)value; count++; i++; break; case CURLFORM_CONTENTHEADER: { if((err=pContext->LocalToPhysAddr(params[i+1], &addr)) != SP_ERROR_NONE) { pContext->ThrowNativeErrorEx(err, NULL); return CURL_FORMADD_INCOMPLETE; } cURL_slist_pack *slist; HandleError hndl_err; HandleSecurity sec(pContext->GetIdentity(), myself_Identity); if((hndl_err = handlesys->ReadHandle(*addr, g_cURLSlist, &sec, (void **)&slist)) != HandleError_None) { pContext->ThrowNativeError("Invalid curl_slist Handle %x (error %d)", params[1], hndl_err); return CURL_FORMADD_INCOMPLETE; } form_opts[count] = form_code; form_data[count] = (char *)slist->chunk; handle->slist_record.push_back(slist); // when webform add into curlhandle, will add slist handle to close helper count++; i++; break; } case CURLFORM_END: form_opts[count] = CURLFORM_END; goto end; } } end: CURLFORMcode ret = curl_formadd(&handle->first, &handle->last, form_opts[0], form_data[0], form_opts[1], form_data[1], form_opts[2], form_data[2], form_opts[3], form_data[3], form_opts[4], form_data[4], form_opts[5], form_data[5], form_opts[6], form_data[6], form_opts[7], form_data[7], form_opts[8], form_data[8], form_opts[9], form_data[9], form_opts[10] ); return ret; }