X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=libcurl.c;h=b90bbd14d496151f4f50ce59bfacbfd470a9922e;hb=9829ccb76b1b5f2cb18d14cae0092ab94f183ece;hp=30a48aff07d97f399a014dfe1fa5dd5c931856f2;hpb=0f80ff51ff9f369233d17b3377d3a0d34b4c8e5a;p=xonotic%2Fdarkplaces.git diff --git a/libcurl.c b/libcurl.c index 30a48aff..b90bbd14 100644 --- a/libcurl.c +++ b/libcurl.c @@ -22,6 +22,7 @@ static cvar_t cl_curl_enabled = {CVAR_SAVE, "cl_curl_enabled","1", "whether clie typedef struct CURL_s CURL; typedef struct CURLM_s CURLM; +typedef struct curl_slist curl_slist; typedef enum { CURLE_OK = 0 @@ -47,13 +48,17 @@ typedef enum CINIT(URL, OBJECTPOINT, 2), CINIT(ERRORBUFFER, OBJECTPOINT, 10), CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), + CINIT(POSTFIELDS, OBJECTPOINT, 15), CINIT(REFERER, OBJECTPOINT, 16), CINIT(USERAGENT, OBJECTPOINT, 18), + CINIT(LOW_SPEED_LIMIT, LONG , 19), + CINIT(LOW_SPEED_TIME, LONG, 20), CINIT(RESUME_FROM, LONG, 21), + CINIT(HTTPHEADER, OBJECTPOINT, 23), + CINIT(POST, LONG, 47), /* HTTP POST method */ CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ + CINIT(POSTFIELDSIZE, LONG, 60), CINIT(PRIVATE, OBJECTPOINT, 103), - CINIT(LOW_SPEED_LIMIT, LONG , 19), - CINIT(LOW_SPEED_TIME, LONG, 20), CINIT(PROTOCOLS, LONG, 181), CINIT(REDIR_PROTOCOLS, LONG, 182) } @@ -149,6 +154,8 @@ static CURLMcode (*qcurl_multi_remove_handle) (CURLM *multi_handle, CURL *easy_h static CURLMsg * (*qcurl_multi_info_read) (CURLM *multi_handle, int *msgs_in_queue); static void (*qcurl_multi_cleanup) (CURLM *); static const char * (*qcurl_multi_strerror) (CURLcode); +static curl_slist * (*qcurl_slist_append) (curl_slist *list, const char *string); +static void (*qcurl_slist_free_all) (curl_slist *list); static dllfunction_t curlfuncs[] = { @@ -166,6 +173,8 @@ static dllfunction_t curlfuncs[] = {"curl_multi_info_read", (void **) &qcurl_multi_info_read}, {"curl_multi_cleanup", (void **) &qcurl_multi_cleanup}, {"curl_multi_strerror", (void **) &qcurl_multi_strerror}, + {"curl_slist_append", (void **) &qcurl_slist_append}, + {"curl_slist_free_all", (void **) &qcurl_slist_free_all}, {NULL, NULL} }; @@ -183,15 +192,23 @@ typedef struct downloadinfo_s CURL *curle; qboolean started; qboolean ispak; - unsigned long bytes_received; + unsigned long bytes_received; // for buffer + double bytes_received_curl; // for throttling + double bytes_sent_curl; // for throttling struct downloadinfo_s *next, *prev; qboolean forthismap; double maxspeed; + curl_slist *slist; // http headers unsigned char *buffer; size_t buffersize; curl_callback_t callback; void *callback_data; + + const unsigned char *postbuf; + size_t postbufsize; + const char *post_content_type; + const char *extraheaders; } downloadinfo; static downloadinfo *downloads = NULL; @@ -358,7 +375,8 @@ static void CURL_CloseLibrary (void) static CURLM *curlm = NULL; -static unsigned long bytes_received = 0; // used for bandwidth throttling +static double bytes_received = 0; // used for bandwidth throttling +static double bytes_sent = 0; // used for bandwidth throttling static double curltime = 0; /* @@ -390,7 +408,6 @@ static size_t CURL_fwrite(void *data, size_t size, size_t nmemb, void *vdi) ret = FS_Write(di->stream, data, bytes); } - bytes_received += bytes; di->bytes_received += bytes; return ret; // why not ret / nmemb? @@ -445,7 +462,7 @@ CURL_DOWNLOAD_FAILED or CURL_DOWNLOAD_ABORTED) and in the second case the error code from libcurl, or 0, if another error has occurred. ==================== */ -static qboolean Curl_Begin(const char *URL, double maxspeed, const char *name, qboolean ispak, qboolean forthismap, unsigned char *buf, size_t bufsize, curl_callback_t callback, void *cbdata); +static qboolean Curl_Begin(const char *URL, const char *extraheaders, double maxspeed, const char *name, qboolean ispak, qboolean forthismap, const char *post_content_type, const unsigned char *postbuf, size_t postbufsize, unsigned char *buf, size_t bufsize, curl_callback_t callback, void *cbdata); static void Curl_EndDownload(downloadinfo *di, CurlStatus status, CURLcode error) { qboolean ok = false; @@ -484,6 +501,8 @@ static void Curl_EndDownload(downloadinfo *di, CurlStatus status, CURLcode error { qcurl_multi_remove_handle(curlm, di->curle); qcurl_easy_cleanup(di->curle); + if(di->slist) + qcurl_slist_free_all(di->slist); } if(!di->callback && ok && !di->bytes_received) @@ -510,7 +529,7 @@ static void Curl_EndDownload(downloadinfo *di, CurlStatus status, CURLcode error { // this was a resume? // then try to redownload it without reporting the error - Curl_Begin(di->url, di->maxspeed, di->filename, di->ispak, di->forthismap, NULL, 0, NULL, NULL); + Curl_Begin(di->url, di->extraheaders, di->maxspeed, di->filename, di->ispak, di->forthismap, di->post_content_type, di->postbuf, di->postbufsize, NULL, 0, NULL, NULL); di->forthismap = false; // don't count the error } } @@ -534,6 +553,37 @@ static void Curl_EndDownload(downloadinfo *di, CurlStatus status, CURLcode error Z_Free(di); } +/* +==================== +CleanURL + +Returns a "cleaned up" URL for display (to strip login data) +==================== +*/ +static const char *CleanURL(const char *url) +{ + static char urlbuf[1024]; + const char *p, *q, *r; + + // if URL is of form anything://foo-without-slash@rest, replace by anything://rest + p = strstr(url, "://"); + if(p) + { + q = strchr(p + 3, '@'); + if(q) + { + r = strchr(p + 3, '/'); + if(!r || q < r) + { + dpsnprintf(urlbuf, sizeof(urlbuf), "%.*s%s", (int)(p - url + 3), url, q + 1); + return urlbuf; + } + } + } + + return url; +} + /* ==================== CheckPendingDownloads @@ -545,6 +595,7 @@ up to a maximum number of cl_curl_maxdownloads are running. */ static void CheckPendingDownloads(void) { + const char *h; if(!curl_dll) return; if(numdownloads < cl_curl_maxdownloads.integer) @@ -556,7 +607,7 @@ static void CheckPendingDownloads(void) { if(!di->buffer) { - Con_Printf("Downloading %s -> %s", di->url, di->filename); + Con_Printf("Downloading %s -> %s", CleanURL(di->url), di->filename); di->stream = FS_OpenRealFile(di->filename, "ab", false); if(!di->stream) @@ -574,11 +625,12 @@ static void CheckPendingDownloads(void) } else { - Con_DPrintf("Downloading %s -> memory\n", di->url); + Con_DPrintf("Downloading %s -> memory\n", CleanURL(di->url)); di->startpos = 0; } di->curle = qcurl_easy_init(); + di->slist = NULL; qcurl_easy_setopt(di->curle, CURLOPT_URL, di->url); qcurl_easy_setopt(di->curle, CURLOPT_USERAGENT, engineversion); qcurl_easy_setopt(di->curle, CURLOPT_REFERER, di->referer); @@ -595,6 +647,37 @@ static void CheckPendingDownloads(void) Con_Printf("^1WARNING:^7 for security reasons, please upgrade to libcurl 7.19.4 or above. In a later version of DarkPlaces, HTTP redirect support will be disabled for this libcurl version.\n"); //qcurl_easy_setopt(di->curle, CURLOPT_FOLLOWLOCATION, 0); } + if(di->post_content_type) + { + qcurl_easy_setopt(di->curle, CURLOPT_POST, 1); + qcurl_easy_setopt(di->curle, CURLOPT_POSTFIELDS, di->postbuf); + qcurl_easy_setopt(di->curle, CURLOPT_POSTFIELDSIZE, di->postbufsize); + di->slist = qcurl_slist_append(di->slist, va("Content-Type: %s", di->post_content_type)); + } + + // parse extra headers into slist + // \n separated list! + h = di->extraheaders; + while(h) + { + const char *hh = strchr(h, '\n'); + if(hh) + { + char *buf = (char *) Mem_Alloc(tempmempool, hh - h + 1); + memcpy(buf, h, hh - h); + buf[hh - h] = 0; + di->slist = qcurl_slist_append(di->slist, buf); + h = hh + 1; + } + else + { + di->slist = qcurl_slist_append(di->slist, h); + h = NULL; + } + } + + qcurl_easy_setopt(di->curle, CURLOPT_HTTPHEADER, di->slist); + qcurl_multi_add_handle(curlm, di->curle); di->started = true; @@ -685,7 +768,7 @@ Starts a download of a given URL to the file name portion of this URL (or name if given) in the "dlcache/" folder. ==================== */ -static qboolean Curl_Begin(const char *URL, double maxspeed, const char *name, qboolean ispak, qboolean forthismap, unsigned char *buf, size_t bufsize, curl_callback_t callback, void *cbdata) +static qboolean Curl_Begin(const char *URL, const char *extraheaders, double maxspeed, const char *name, qboolean ispak, qboolean forthismap, const char *post_content_type, const unsigned char *postbuf, size_t postbufsize, unsigned char *buf, size_t bufsize, curl_callback_t callback, void *cbdata) { if(!curl_dll) { @@ -746,7 +829,7 @@ static qboolean Curl_Begin(const char *URL, double maxspeed, const char *name, q // 141.2.16.3 - - [17/Mar/2006:22:32:43 +0100] "GET /maps/tznex07.pk3 HTTP/1.1" 200 1077455 "dp://141.2.16.7:26000/" "Nexuiz Linux 22:07:43 Mar 17 2006" if(!name) - name = URL; + name = CleanURL(URL); if(!buf) { @@ -763,7 +846,7 @@ static qboolean Curl_Begin(const char *URL, double maxspeed, const char *name, q downloadinfo *di = Curl_Find(fn); if(di) { - Con_Printf("Can't download %s, already getting it from %s!\n", fn, di->url); + Con_Printf("Can't download %s, already getting it from %s!\n", fn, CleanURL(di->url)); // however, if it was not for this map yet... if(forthismap && !di->forthismap) @@ -845,6 +928,9 @@ static qboolean Curl_Begin(const char *URL, double maxspeed, const char *name, q di->ispak = (ispak && !buf); di->maxspeed = maxspeed; di->bytes_received = 0; + di->bytes_received_curl = 0; + di->bytes_sent_curl = 0; + di->extraheaders = extraheaders; di->next = downloads; di->prev = NULL; if(di->next) @@ -863,6 +949,19 @@ static qboolean Curl_Begin(const char *URL, double maxspeed, const char *name, q di->callback_data = cbdata; } + if(post_content_type) + { + di->post_content_type = post_content_type; + di->postbuf = postbuf; + di->postbufsize = postbufsize; + } + else + { + di->post_content_type = NULL; + di->postbuf = NULL; + di->postbufsize = 0; + } + downloads = di; return true; } @@ -870,11 +969,15 @@ static qboolean Curl_Begin(const char *URL, double maxspeed, const char *name, q qboolean Curl_Begin_ToFile(const char *URL, double maxspeed, const char *name, qboolean ispak, qboolean forthismap) { - return Curl_Begin(URL, maxspeed, name, ispak, forthismap, NULL, 0, NULL, NULL); + return Curl_Begin(URL, NULL, maxspeed, name, ispak, forthismap, NULL, NULL, 0, NULL, 0, NULL, NULL); } qboolean Curl_Begin_ToMemory(const char *URL, double maxspeed, unsigned char *buf, size_t bufsize, curl_callback_t callback, void *cbdata) { - return Curl_Begin(URL, maxspeed, NULL, false, false, buf, bufsize, callback, cbdata); + return Curl_Begin(URL, NULL, maxspeed, NULL, false, false, NULL, NULL, 0, buf, bufsize, callback, cbdata); +} +qboolean Curl_Begin_ToMemory_POST(const char *URL, const char *extraheaders, double maxspeed, const char *post_content_type, const unsigned char *postbuf, size_t postbufsize, unsigned char *buf, size_t bufsize, curl_callback_t callback, void *cbdata) +{ + return Curl_Begin(URL, extraheaders, maxspeed, NULL, false, false, post_content_type, postbuf, postbufsize, buf, bufsize, callback, cbdata); } /* @@ -916,6 +1019,17 @@ void Curl_Run(void) } while(mc == CURLM_CALL_MULTI_PERFORM); + for(di = downloads; di; di = di->next) + { + double b = 0; + qcurl_easy_getinfo(di->curle, CURLINFO_SIZE_UPLOAD, &b); + bytes_sent += (b - di->bytes_sent_curl); + di->bytes_sent_curl = b; + qcurl_easy_getinfo(di->curle, CURLINFO_SIZE_DOWNLOAD, &b); + bytes_sent += (b - di->bytes_received_curl); + di->bytes_received_curl = b; + } + for(;;) { CURLMsg *msg = qcurl_multi_info_read(curlm, &remaining); @@ -966,9 +1080,10 @@ void Curl_Run(void) if(maxspeed > 0) { - unsigned long bytes = bytes_received; // maybe smoothen a bit? + double bytes = bytes_sent + bytes_received; // maybe smoothen a bit? curltime = realtime + bytes / (cl_curl_maxspeed.value * 1024.0); - bytes_received -= bytes; + bytes_sent = 0; + bytes_received = 0; } else curltime = realtime; @@ -1073,7 +1188,7 @@ static void Curl_Info_f(void) for(di = downloads; di; di = di->next) { double speed, percent; - Con_Printf(" %s -> %s ", di->url, di->filename); + Con_Printf(" %s -> %s ", CleanURL(di->url), di->filename); percent = 100.0 * Curl_GetDownloadAmount(di); speed = Curl_GetDownloadSpeed(di); if(percent >= 0) @@ -1136,10 +1251,6 @@ void Curl_Curl_f(void) return; } - for(i = 0; i != Cmd_Argc(); ++i) - Con_DPrintf("%s ", Cmd_Argv(i)); - Con_DPrint("\n"); - if(Cmd_Argc() < 2) { Con_Print("usage:\ncurl --info, curl --cancel [filename], curl url\n");