X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=libcurl.c;h=0d3f6c7c061ae5c62baf58b20632a4a10b2371f5;hb=66e2a20b4a20d03de1098a3c76186cb0ce316f21;hp=7c9b7dbdf0060802087ef8769881a7d686a8ddbc;hpb=aed8b84afc34596c6ec9e4dd35ada467539fbd8c;p=xonotic%2Fdarkplaces.git diff --git a/libcurl.c b/libcurl.c index 7c9b7dbd..0d3f6c7c 100644 --- a/libcurl.c +++ b/libcurl.c @@ -170,7 +170,7 @@ static dllhandle_t curl_dll = NULL; typedef struct downloadinfo_s { char filename[MAX_QPATH]; - char url[256]; + char url[1024]; char referer[256]; qfile_t *stream; fs_offset_t startpos; @@ -400,6 +400,38 @@ typedef enum } CurlStatus; +static void curl_default_callback(int status, size_t length_received, unsigned char *buffer, void *cbdata) +{ + downloadinfo *di = (downloadinfo *) cbdata; + switch(status) + { + case CURLCBSTATUS_OK: + Con_Printf("Download of %s: OK\n", di->filename); + break; + case CURLCBSTATUS_FAILED: + Con_Printf("Download of %s: FAILED\n", di->filename); + break; + case CURLCBSTATUS_ABORTED: + Con_Printf("Download of %s: ABORTED\n", di->filename); + break; + case CURLCBSTATUS_SERVERERROR: + Con_Printf("Download of %s: (unknown server error)\n", di->filename); + break; + case CURLCBSTATUS_UNKNOWN: + Con_Printf("Download of %s: (unknown client error)\n", di->filename); + break; + default: + Con_Printf("Download of %s: %d\n", di->filename, status); + break; + } +} + +static void curl_quiet_callback(int status, size_t length_received, unsigned char *buffer, void *cbdata) +{ + if(developer.integer) + curl_default_callback(status, length_received, buffer, cbdata); +} + /* ==================== Curl_EndDownload @@ -409,6 +441,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, const char *name, qboolean ispak, qboolean forthismap, 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; @@ -417,29 +450,16 @@ static void Curl_EndDownload(downloadinfo *di, CurlStatus status, CURLcode error switch(status) { case CURL_DOWNLOAD_SUCCESS: - Con_Printf("Download of %s: OK\n", di->filename); ok = true; - - if(di->callback) - di->callback(CURLCBSTATUS_OK, di->bytes_received, di->buffer, di->callback_data); + di->callback(CURLCBSTATUS_OK, di->bytes_received, di->buffer, di->callback_data); break; case CURL_DOWNLOAD_FAILED: - Con_Printf("Download of %s: FAILED\n", di->filename); - if(error) - Con_Printf("Reason given by libcurl: %s\n", qcurl_easy_strerror(error)); - - if(di->callback) - di->callback(CURLCBSTATUS_FAILED, di->bytes_received, di->buffer, di->callback_data); + di->callback(CURLCBSTATUS_FAILED, di->bytes_received, di->buffer, di->callback_data); break; case CURL_DOWNLOAD_ABORTED: - Con_Printf("Download of %s: ABORTED\n", di->filename); - - if(di->callback) - di->callback(CURLCBSTATUS_ABORTED, di->bytes_received, di->buffer, di->callback_data); + di->callback(CURLCBSTATUS_ABORTED, di->bytes_received, di->buffer, di->callback_data); break; case CURL_DOWNLOAD_SERVERERROR: - Con_Printf("Download of %s: %d\n", di->filename, (int) error); - // reopen to enforce it to have zero bytes again if(di->stream) { @@ -451,8 +471,6 @@ static void Curl_EndDownload(downloadinfo *di, CurlStatus status, CURLcode error di->callback(error ? (int) error : CURLCBSTATUS_SERVERERROR, di->bytes_received, di->buffer, di->callback_data); break; default: - Con_Printf("Download of %s: ???\n", di->filename); - if(di->callback) di->callback(CURLCBSTATUS_UNKNOWN, di->bytes_received, di->buffer, di->callback_data); break; @@ -464,7 +482,7 @@ static void Curl_EndDownload(downloadinfo *di, CurlStatus status, CURLcode error qcurl_easy_cleanup(di->curle); } - if(ok && !di->bytes_received) + if(!di->callback && ok && !di->bytes_received) { Con_Printf("ERROR: empty file\n"); ok = false; @@ -474,7 +492,25 @@ static void Curl_EndDownload(downloadinfo *di, CurlStatus status, CURLcode error FS_Close(di->stream); if(ok && di->ispak) + { ok = FS_AddPack(di->filename, NULL, true); + if(!ok) + { + // pack loading failed? + // this is critical + // better clear the file again... + di->stream = FS_OpenRealFile(di->filename, "wb", false); + FS_Close(di->stream); + + if(di->startpos && !di->callback) + { + // this was a resume? + // then try to redownload it without reporting the error + Curl_Begin(di->url, di->filename, di->ispak, di->forthismap, NULL, 0, NULL, NULL); + di->forthismap = false; // don't count the error + } + } + } if(di->prev) di->prev->next = di->next; @@ -514,10 +550,10 @@ static void CheckPendingDownloads() { if(!di->started) { - Con_Printf("Downloading %s -> %s", di->url, di->filename); - if(!di->buffer) { + Con_Printf("Downloading %s -> %s", di->url, di->filename); + di->stream = FS_OpenRealFile(di->filename, "ab", false); if(!di->stream) { @@ -527,16 +563,17 @@ static void CheckPendingDownloads() } FS_Seek(di->stream, 0, SEEK_END); di->startpos = FS_Tell(di->stream); + + if(di->startpos > 0) + Con_Printf(", resuming from position %ld", (long) di->startpos); + Con_Print("...\n"); } else { + Con_DPrintf("Downloading %s -> memory\n", di->url); di->startpos = 0; } - if(di->startpos > 0) - Con_Printf(", resuming from position %ld", (long) di->startpos); - Con_Print("...\n"); - di->curle = qcurl_easy_init(); qcurl_easy_setopt(di->curle, CURLOPT_URL, di->url); qcurl_easy_setopt(di->curle, CURLOPT_USERAGENT, engineversion); @@ -611,6 +648,24 @@ static downloadinfo *Curl_Find(const char *filename) return NULL; } +void Curl_Cancel_ToMemory(curl_callback_t callback, void *cbdata) +{ + downloadinfo *di; + if(!curl_dll) + return; + for(di = downloads; di; ) + { + if(di->callback == callback && di->callback_data == cbdata) + { + di->callback = curl_quiet_callback; // do NOT call the callback + Curl_EndDownload(di, CURL_DOWNLOAD_ABORTED, CURLE_OK); + di = downloads; + } + else + di = di->next; + } +} + /* ==================== Curl_Begin @@ -712,7 +767,7 @@ static qboolean Curl_Begin(const char *URL, const char *name, qboolean ispak, qb } else { - qfile_t *f = FS_OpenVirtualFile(fn, false); + qfile_t *f = FS_OpenRealFile(fn, "rb", false); if(f) { char buf[4] = {0}; @@ -736,6 +791,14 @@ static qboolean Curl_Begin(const char *URL, const char *name, qboolean ispak, qb } } + // if we get here, we actually want to download... so first verify the + // URL scheme (so one can't read local files using file://) + if(strncmp(URL, "http://", 7) && strncmp(URL, "ftp://", 6) && strncmp(URL, "https://", 8)) + { + Con_Printf("Curl_Begin(\"%s\"): nasty URL scheme rejected\n", URL); + return false; + } + if(forthismap) ++numdownloads_added; di = (downloadinfo *) Z_Malloc(sizeof(*di)); @@ -747,7 +810,7 @@ static qboolean Curl_Begin(const char *URL, const char *name, qboolean ispak, qb di->startpos = 0; di->curle = NULL; di->started = false; - di->ispak = ispak; + di->ispak = (ispak && !buf); di->bytes_received = 0; di->next = downloads; di->prev = NULL; @@ -756,8 +819,16 @@ static qboolean Curl_Begin(const char *URL, const char *name, qboolean ispak, qb di->buffer = buf; di->buffersize = bufsize; - di->callback = callback; - di->callback_data = cbdata; + if(callback == NULL) + { + di->callback = curl_default_callback; + di->callback_data = di; + } + else + { + di->callback = callback; + di->callback_data = cbdata; + } downloads = di; return true; @@ -834,7 +905,7 @@ void Curl_Run() case 4: // e.g. 404? case 5: // e.g. 500? failed = CURL_DOWNLOAD_SERVERERROR; - result = code; + result = (CURLcode) code; break; } } @@ -910,7 +981,7 @@ static double Curl_GetDownloadAmount(downloadinfo *di) double length; qcurl_easy_getinfo(di->curle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &length); if(length > 0) - return di->bytes_received / length; + return (di->startpos + di->bytes_received) / (di->startpos + length); else return 0; } @@ -1168,7 +1239,7 @@ array must be freed later using Z_Free. */ Curl_downloadinfo_t *Curl_GetDownloadInfo(int *nDownloads, const char **additional_info) { - int n, i; + int i; downloadinfo *di; Curl_downloadinfo_t *downinfo; static char addinfo[128]; @@ -1181,14 +1252,18 @@ Curl_downloadinfo_t *Curl_GetDownloadInfo(int *nDownloads, const char **addition return NULL; } - n = 0; + i = 0; for(di = downloads; di; di = di->next) - ++n; + ++i; - downinfo = (Curl_downloadinfo_t *) Z_Malloc(sizeof(*downinfo) * n); + downinfo = (Curl_downloadinfo_t *) Z_Malloc(sizeof(*downinfo) * i); i = 0; for(di = downloads; di; di = di->next) { + // do not show infobars for background downloads + if(!developer.integer) + if(di->buffer) + continue; strlcpy(downinfo[i].filename, di->filename, sizeof(downinfo[i].filename)); if(di->curle) { @@ -1220,7 +1295,7 @@ Curl_downloadinfo_t *Curl_GetDownloadInfo(int *nDownloads, const char **addition *additional_info = NULL; } - *nDownloads = n; + *nDownloads = i; return downinfo; } @@ -1251,7 +1326,7 @@ this file for obvious reasons. */ static const char *Curl_FindPackURL(const char *filename) { - static char foundurl[256]; + static char foundurl[1024]; fs_offset_t filesize; char *buf = (char *) FS_LoadFile("curl_urls.txt", tempmempool, true, &filesize); if(buf && filesize)