UFO: Alien Invasion
cl_http.cpp
Go to the documentation of this file.
1
14/*
15Copyright (C) 1997-2001 Id Software, Inc.
16
17This program is free software; you can redistribute it and/or
18modify it under the terms of the GNU General Public License
19as published by the Free Software Foundation; either version 2
20of the License, or (at your option) any later version.
21
22This program is distributed in the hope that it will be useful,
23but WITHOUT ANY WARRANTY; without even the implied warranty of
24MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25
26See the GNU General Public License for more details.
27
28You should have received a copy of the GNU General Public License
29along with this program; if not, write to the Free Software
30Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31
32*/
33
34#include "client.h"
35#include "cl_http.h"
37
38#ifndef NO_HTTP
39
43
44enum {
48};
49
50static CURLM *multi = nullptr;
51static int handleCount = 0;
52static int pendingCount = 0;
54static bool downloadingPK3 = false;
55
56static void StripHighBits (char* string)
57{
58 char* p = string;
59
60 while (string[0]) {
61 const unsigned char c = *(string++);
62
63 if (c >= 32 && c <= 127)
64 *p++ = c;
65 }
66
67 p[0] = '\0';
68}
69
70static inline bool isvalidchar (int c)
71{
72 if (!isalnum(c) && c != '_' && c != '-')
73 return false;
74 return true;
75}
76
81static int CL_HTTP_Progress (void* clientp, double dltotal, double dlnow, double ultotal, double ulnow)
82{
83 dlhandle_t* dl = (dlhandle_t*)clientp;
84
85 dl->position = (unsigned)dlnow;
86
87 /* don't care which download shows as long as something does :) */
88 if (!abortDownloads) {
91
92 if (dltotal > 0.0)
93 cls.downloadPercent = (int)((dlnow / dltotal) * 100.0f);
94 else
96 }
97
98 return abortDownloads;
99}
100
106static void CL_EscapeHTTPPath (const char* filePath, char* escaped)
107{
108 char *p = escaped;
109
110 size_t len = strlen(filePath);
111 for (int i = 0; i < len; i++) {
112 if (!isalnum(filePath[i]) && filePath[i] != ';' && filePath[i] != '/' &&
113 filePath[i] != '?' && filePath[i] != ':' && filePath[i] != '@' && filePath[i] != '&' &&
114 filePath[i] != '=' && filePath[i] != '+' && filePath[i] != '$' && filePath[i] != ',' &&
115 filePath[i] != '[' && filePath[i] != ']' && filePath[i] != '-' && filePath[i] != '_' &&
116 filePath[i] != '.' && filePath[i] != '!' && filePath[i] != '~' && filePath[i] != '*' &&
117 filePath[i] != '\'' && filePath[i] != '(' && filePath[i] != ')') {
118 sprintf(p, "%%%02x", filePath[i]);
119 p += 3;
120 } else {
121 *p = filePath[i];
122 p++;
123 }
124 }
125 p[0] = 0;
126
127 /* using ./ in a url is legal, but all browsers condense the path and some IDS / request */
128 /* filtering systems act a bit funky if http requests come in with uncondensed paths. */
129 len = strlen(escaped);
130 p = escaped;
131 while ((p = strstr (p, "./"))) {
132 memmove(p, p + 2, len - (p - escaped) - 1);
133 len -= 2;
134 }
135}
136
141{
142 char escapedFilePath[MAX_QPATH * 4];
143 const char* extension = Com_GetExtension(entry->ufoPath);
144
145 /* yet another hack to accomodate filelists, how i wish i could push :(
146 * nullptr file handle indicates filelist. */
147 if (extension != nullptr && Q_streq(extension, "filelist")) {
148 dl->file = nullptr;
149 CL_EscapeHTTPPath(entry->ufoPath, escapedFilePath);
150 } else {
151 char tempFile[MAX_OSPATH];
153 Com_sprintf(dl->filePath, sizeof(dl->filePath), "%s/%s", FS_Gamedir(), entry->ufoPath);
154
155 Com_sprintf(tempFile, sizeof(tempFile), BASEDIRNAME "/%s", entry->ufoPath);
156 CL_EscapeHTTPPath(tempFile, escapedFilePath);
157
158 strcat(dl->filePath, ".tmp");
159
161
162 /* don't bother with http resume... too annoying if server doesn't support it. */
163 dl->file = Sys_Fopen(dl->filePath, "wb");
164 if (!dl->file) {
165 Com_Printf("CL_StartHTTPDownload: Couldn't open %s for writing.\n", dl->filePath);
166 entry->state = DLQ_STATE_DONE;
167 /* CL_RemoveHTTPDownload(entry->ufoPath); */
168 return;
169 }
170 }
171
172 dl->tempBuffer = nullptr;
173 dl->speed = 0;
174 dl->fileSize = 0;
175 dl->position = 0;
176 dl->queueEntry = entry;
177
178 if (!dl->curl)
179 dl->curl = curl_easy_init();
180
181 Com_sprintf(dl->URL, sizeof(dl->URL), "%s%s", cls.downloadServer, escapedFilePath);
182
183 curl_easy_setopt(dl->curl, CURLOPT_ENCODING, "");
184#ifdef PARANOID
185 curl_easy_setopt(dl->curl, CURLOPT_VERBOSE, 1);
186#endif
187 curl_easy_setopt(dl->curl, CURLOPT_NOPROGRESS, 0);
188 if (dl->file) {
189 curl_easy_setopt(dl->curl, CURLOPT_WRITEDATA, dl->file);
190 curl_easy_setopt(dl->curl, CURLOPT_WRITEFUNCTION, nullptr);
191 } else {
192 curl_easy_setopt(dl->curl, CURLOPT_WRITEDATA, dl);
193 curl_easy_setopt(dl->curl, CURLOPT_WRITEFUNCTION, HTTP_Recv);
194 }
195 curl_easy_setopt(dl->curl, CURLOPT_CONNECTTIMEOUT, http_timeout->integer);
196 curl_easy_setopt(dl->curl, CURLOPT_TIMEOUT, http_timeout->integer);
197 curl_easy_setopt(dl->curl, CURLOPT_FAILONERROR, 1);
198 curl_easy_setopt(dl->curl, CURLOPT_PROXY, http_proxy->string);
199 curl_easy_setopt(dl->curl, CURLOPT_FOLLOWLOCATION, 1);
200 curl_easy_setopt(dl->curl, CURLOPT_MAXREDIRS, 5);
201 curl_easy_setopt(dl->curl, CURLOPT_WRITEHEADER, dl);
202 curl_easy_setopt(dl->curl, CURLOPT_HEADERFUNCTION, HTTP_Header);
203 curl_easy_setopt(dl->curl, CURLOPT_PROGRESSFUNCTION, CL_HTTP_Progress);
204 curl_easy_setopt(dl->curl, CURLOPT_PROGRESSDATA, dl);
205 curl_easy_setopt(dl->curl, CURLOPT_USERAGENT, GAME_TITLE " " UFO_VERSION);
206 curl_easy_setopt(dl->curl, CURLOPT_REFERER, cls.downloadReferer);
207 curl_easy_setopt(dl->curl, CURLOPT_URL, dl->URL);
208 curl_easy_setopt(dl->curl, CURLOPT_NOSIGNAL, 1);
209
210 if (curl_multi_add_handle(multi, dl->curl) != CURLM_OK) {
211 Com_Printf("curl_multi_add_handle: error\n");
213 return;
214 }
215
216 handleCount++;
217 /*Com_Printf("started dl: hc = %d\n", handleCount); */
218 Com_Printf("CL_StartHTTPDownload: Fetching %s...\n", dl->URL);
220}
221
225void CL_SetHTTPServer (const char* URL)
226{
228
229 for (dlqueue_t* q = cls.downloadQueue; q;) {
230 dlqueue_t* const del = q;
231 q = q->next;
232 Mem_Free(del);
233 }
234 cls.downloadQueue = 0;
235
236 if (multi)
237 Com_Error(ERR_DROP, "CL_SetHTTPServer: Still have old handle");
238
239 multi = curl_multi_init();
240
243
245}
246
250void CL_CancelHTTPDownloads (bool permKill)
251{
252 if (permKill)
254 else
256
257 for (dlqueue_t* q = cls.downloadQueue; q; q = q->next) {
258 if (q->state == DLQ_STATE_NOT_STARTED)
259 q->state = DLQ_STATE_DONE;
260 }
261
263 cls.downloadServer[0] = 0;
264
265 pendingCount = 0;
266}
267
272{
273 for (int i = 0; i < 4; i++) {
274 dlhandle_t* dl = &cls.HTTPHandles[i];
275 if (!dl->queueEntry || dl->queueEntry->state == DLQ_STATE_DONE)
276 return dl;
277 }
278
279 return nullptr;
280}
281
286bool CL_QueueHTTPDownload (const char* ufoPath)
287{
288 /* no http server (or we got booted) */
290 return false;
291
292 dlqueue_t** anchor = &cls.downloadQueue;
293 for (; *anchor; anchor = &(*anchor)->next) {
294 /* avoid sending duplicate requests */
295 if (Q_streq(ufoPath, (*anchor)->ufoPath))
296 return true;
297 }
298
300 q->next = nullptr;
302 Q_strncpyz(q->ufoPath, ufoPath, sizeof(q->ufoPath));
303 *anchor = q;
304
305 /* special case for map file lists */
307 const char* extension = Com_GetExtension(ufoPath);
308 if (extension != nullptr && !Q_strcasecmp(extension, "bsp")) {
309 char listPath[MAX_OSPATH];
310 const size_t len = strlen(ufoPath);
311 Com_sprintf(listPath, sizeof(listPath), BASEDIRNAME"/%.*s.filelist", (int)(len - 4), ufoPath);
312 CL_QueueHTTPDownload(listPath);
313 }
314 }
315
316 /* if a download entry has made it this far, CL_FinishHTTPDownload is guaranteed to be called. */
317 pendingCount++;
318
319 return true;
320}
321
329{
330 if (cls.downloadServer[0] == '\0')
331 return false;
332
333 return pendingCount + handleCount;
334}
335
342{
343 static char lastfilename[MAX_OSPATH] = "";
344
345 if (Q_strnull(filename))
346 return true;
347
348 /* r1: don't attempt same file many times */
349 if (Q_streq(filename, lastfilename))
350 return true;
351
352 Q_strncpyz(lastfilename, filename, sizeof(lastfilename));
353
354 if (strstr(filename, "..")) {
355 Com_Printf("Refusing to check a path with .. (%s)\n", filename);
356 return true;
357 }
358
359 if (strchr(filename, ' ')) {
360 Com_Printf("Refusing to check a path containing spaces (%s)\n", filename);
361 return true;
362 }
363
364 if (strchr(filename, ':')) {
365 Com_Printf("Refusing to check a path containing a colon (%s)\n", filename);
366 return true;
367 }
368
369 if (filename[0] == '/') {
370 Com_Printf("Refusing to check a path starting with / (%s)\n", filename);
371 return true;
372 }
373
374 if (FS_LoadFile(filename, nullptr) != -1) {
375 /* it exists, no need to download */
376 return true;
377 }
378
380 return false;
381
382 return true;
383}
384
391static void CL_CheckAndQueueDownload (char* path)
392{
393 StripHighBits(path);
394
395 size_t length = strlen(path);
396
397 if (length >= MAX_QPATH)
398 return;
399
400 const char* ext = Com_GetExtension(path);
401 if (ext == nullptr)
402 return;
403
404 bool pak;
405 if (Q_streq(ext, "pk3")) {
406 Com_Printf("NOTICE: Filelist is requesting a .pk3 file (%s)\n", path);
407 pak = true;
408 } else
409 pak = false;
410
411 if (!pak &&
412 !Q_streq(ext, "bsp") &&
413 !Q_streq(ext, "wav") &&
414 !Q_streq(ext, "md2") &&
415 !Q_streq(ext, "ogg") &&
416 !Q_streq(ext, "md3") &&
417 !Q_streq(ext, "png") &&
418 !Q_streq(ext, "jpg") &&
419 !Q_streq(ext, "obj") &&
420 !Q_streq(ext, "mat") &&
421 !Q_streq(ext, "ump")) {
422 Com_Printf("WARNING: Illegal file type '%s' in filelist.\n", path);
423 return;
424 }
425
426 bool gameLocal;
427 if (path[0] == '@') {
428 if (pak) {
429 Com_Printf("WARNING: @ prefix used on a pk3 file (%s) in filelist.\n", path);
430 return;
431 }
432 gameLocal = true;
433 path++;
434 length--;
435 } else
436 gameLocal = false;
437
438 if (strstr(path, "..") || !isvalidchar(path[0]) || !isvalidchar(path[length - 1]) || strstr(path, "//") ||
439 strchr(path, '\\') || (!pak && !strchr(path, '/')) || (pak && strchr(path, '/'))) {
440 Com_Printf("WARNING: Illegal path '%s' in filelist.\n", path);
441 return;
442 }
443
444 /* by definition pk3s are game-local */
445 if (gameLocal || pak) {
446 bool exists;
447
448 /* search the user homedir to find the pk3 file */
449 if (pak) {
450 char gamePath[MAX_OSPATH];
451 Com_sprintf(gamePath, sizeof(gamePath), "%s/%s", FS_Gamedir(), path);
452 FILE* f = Sys_Fopen(gamePath, "rb");
453 if (!f)
454 exists = false;
455 else {
456 exists = true;
457 fclose(f);
458 }
459 } else
460 exists = FS_CheckFile("%s", path);
461
462 if (!exists) {
463 if (CL_QueueHTTPDownload(path)) {
464 /* pk3s get bumped to the top and HTTP switches to single downloading.
465 * this prevents someone on 28k dialup trying to do both the main .pk3
466 * and referenced configstrings data at once. */
467 if (pak) {
468 dlqueue_t** anchor = &cls.downloadQueue;
469 while ((*anchor)->next) anchor = &(*anchor)->next;
470 /* Remove the last element from the end of the list ... */
471 dlqueue_t* const d = *anchor;
472 *anchor = 0;
473 /* ... and prepend it to the list. */
475 cls.downloadQueue = d;
476 }
477 }
478 }
479 } else
481}
482
487{
489 return;
490
491 char* list = dl->tempBuffer;
492
493 for (;;) {
494 char* p = strchr(list, '\n');
495 if (p) {
496 p[0] = 0;
497 if (list[0])
499 list = p + 1;
500 } else {
501 if (list[0])
503 break;
504 }
505 }
506
507 Mem_Free(dl->tempBuffer);
508 dl->tempBuffer = nullptr;
509}
510
515static void CL_ReVerifyHTTPQueue (void)
516{
517 pendingCount = 0;
518
519 for (dlqueue_t* q = cls.downloadQueue; q; q = q->next) {
520 if (q->state == DLQ_STATE_NOT_STARTED) {
521 if (FS_LoadFile(q->ufoPath, nullptr) != -1)
522 q->state = DLQ_STATE_DONE;
523 else
524 pendingCount++;
525 }
526 }
527}
528
533{
534 for (int i = 0; i < 4; i++) {
535 dlhandle_t* dl = &cls.HTTPHandles[i];
536
537 if (dl->file) {
538 fclose(dl->file);
539 Sys_Remove(dl->filePath);
540 dl->file = nullptr;
541 }
542
543 Mem_Free(dl->tempBuffer);
544 dl->tempBuffer = nullptr;
545
546 if (dl->curl) {
547 if (multi)
548 curl_multi_remove_handle(multi, dl->curl);
549 curl_easy_cleanup(dl->curl);
550 dl->curl = nullptr;
551 }
552
553 dl->queueEntry = nullptr;
554 }
555
556 if (multi) {
557 curl_multi_cleanup(multi);
558 multi = nullptr;
559 }
560}
561
566static void CL_FinishHTTPDownload (void)
567{
568 int messagesInQueue;
569 do {
570 CURLMsg* msg = curl_multi_info_read(multi, &messagesInQueue);
571 dlhandle_t* dl = nullptr;
572
573 if (!msg) {
574 Com_Printf("CL_FinishHTTPDownload: Odd, no message for us...\n");
575 return;
576 }
577
578 if (msg->msg != CURLMSG_DONE) {
579 Com_Printf("CL_FinishHTTPDownload: Got some weird message...\n");
580 continue;
581 }
582
583 CURL* curl = msg->easy_handle;
584
585 /* curl doesn't provide reverse-lookup of the void* ptr, so search for it */
586 for (int i = 0; i < 4; i++) {
587 if (cls.HTTPHandles[i].curl == curl) {
588 dl = &cls.HTTPHandles[i];
589 break;
590 }
591 }
592
593 if (!dl)
594 Com_Error(ERR_DROP, "CL_FinishHTTPDownload: Handle not found");
595
596 /* we mark everything as done even if it errored to prevent multiple attempts. */
598
599 /* filelist processing is done on read */
600 bool isFile;
601 if (dl->file)
602 isFile = true;
603 else
604 isFile = false;
605
606 if (isFile) {
607 fclose(dl->file);
608 dl->file = nullptr;
609 }
610
611 /* might be aborted */
612 if (pendingCount)
613 pendingCount--;
614 handleCount--;
615 /* Com_Printf("finished dl: hc = %d\n", handleCount); */
616 cls.downloadName[0] = 0;
618
619 CURLcode result = msg->data.result;
620
621 long responseCode;
622 double timeTaken, fileSize;
623 char tempName[MAX_OSPATH];
624 switch (result) {
625 /* for some reason curl returns CURLE_OK for a 404... */
626 case CURLE_HTTP_RETURNED_ERROR:
627 case CURLE_OK:
628 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
629 if (responseCode == 404) {
630 const char* extension = Com_GetExtension(dl->queueEntry->ufoPath);
631 if (extension != nullptr && Q_streq(extension, "pk3"))
632 downloadingPK3 = false;
633
634 if (isFile)
636 Com_Printf("HTTP(%s): 404 File Not Found [%d remaining files]\n", dl->queueEntry->ufoPath, pendingCount);
637 curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &fileSize);
638 if (fileSize > 512) {
639 /* ick */
640 isFile = false;
641 result = CURLE_FILESIZE_EXCEEDED;
642 Com_Printf("Oversized 404 body received (%d bytes), aborting HTTP downloading.\n", (int)fileSize);
643 } else {
644 curl_multi_remove_handle(multi, dl->curl);
645 continue;
646 }
647 } else if (responseCode == 200) {
648 if (!isFile && !abortDownloads)
650 break;
651 }
652
653 /* every other code is treated as fatal, fallthrough here */
654
655 /* fatal error, disable http */
656 case CURLE_COULDNT_RESOLVE_HOST:
657 case CURLE_COULDNT_CONNECT:
658 case CURLE_COULDNT_RESOLVE_PROXY:
659 if (isFile)
661 Com_Printf("Fatal HTTP error: %s\n", curl_easy_strerror(result));
662 curl_multi_remove_handle(multi, dl->curl);
663 if (abortDownloads)
664 continue;
666 continue;
667 default:
668 //i = strlen(dl->queueEntry->ufoPath);
669 if (Q_streq(dl->queueEntry->ufoPath + strlen(dl->queueEntry->ufoPath) - 4, ".pk3"))
670 downloadingPK3 = false;
671 if (isFile)
673 Com_Printf("HTTP download failed: %s\n", curl_easy_strerror(result));
674 curl_multi_remove_handle(multi, dl->curl);
675 continue;
676 }
677
678 if (isFile) {
679 /* rename the temp file */
680 Com_sprintf(tempName, sizeof(tempName), "%s/%s", FS_Gamedir(), dl->queueEntry->ufoPath);
681
682 if (!FS_RenameFile(dl->filePath, tempName, false))
683 Com_Printf("Failed to rename %s for some odd reason...", dl->filePath);
684
685 /* a pk3 file is very special... */
686 int i = strlen(tempName);
687 if (Q_streq(tempName + i - 4, ".pk3")) {
688 FS_RestartFilesystem(nullptr);
690 downloadingPK3 = false;
691 }
692 }
693
694 /* show some stats */
695 curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &timeTaken);
696 curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &fileSize);
697
703 curl_multi_remove_handle(multi, dl->curl);
704
705 Com_Printf("HTTP(%s): %.f bytes, %.2fkB/sec [%d remaining files]\n",
706 dl->queueEntry->ufoPath, fileSize, (fileSize / 1024.0) / timeTaken, pendingCount);
707 } while (messagesInQueue > 0);
708
709 if (handleCount == 0) {
713 cls.downloadServer[0] = 0;
714 }
715
716 /* done current batch, see if we have more to dl - maybe a .bsp needs downloaded */
719}
720
725static void CL_StartNextHTTPDownload (void)
726{
727 for (dlqueue_t* q = cls.downloadQueue; q; q = q->next) {
728 if (q->state == DLQ_STATE_NOT_STARTED) {
730 if (!dl)
731 return;
732
734
735 /* ugly hack for pk3 file single downloading */
736 const size_t len = strlen(q->ufoPath);
737 if (len > 4 && !Q_strcasecmp(q->ufoPath + len - 4, ".pk3"))
738 downloadingPK3 = true;
739
740 break;
741 }
742 }
743}
744
752{
753 CURLMcode ret;
754
755 if (!cls.downloadServer[0])
756 return;
757
758 /* Com_Printf("handle %d, pending %d\n", handleCount, pendingCount); */
759
760 /* not enough downloads running, queue some more! */
762 !downloadingPK3 && handleCount < cl_http_max_connections->integer)
764
765 do {
766 int newHandleCount;
767 ret = curl_multi_perform(multi, &newHandleCount);
768 if (newHandleCount < handleCount) {
769 /* Com_Printf("runnd dl: hc = %d, nc = %d\n", handleCount, newHandleCount); */
770 /* hmm, something either finished or errored out. */
772 handleCount = newHandleCount;
773 }
774 } while (ret == CURLM_CALL_MULTI_PERFORM);
775
776 if (ret != CURLM_OK) {
777 Com_Printf("curl_multi_perform error. Aborting HTTP downloads.\n");
779 }
780
781 /* not enough downloads running, queue some more! */
783 !downloadingPK3 && handleCount < cl_http_max_connections->integer)
785}
786
788{
789 cl_http_filelists = Cvar_Get("cl_http_filelists", "1");
790 cl_http_downloads = Cvar_Get("cl_http_downloads", "1", 0, "Try to download files via http");
791 cl_http_max_connections = Cvar_Get("cl_http_max_connections", "1");
792}
793#else
794void CL_CancelHTTPDownloads(bool permKill) {}
795bool CL_QueueHTTPDownload(const char* ufoPath) {return false;}
796void CL_RunHTTPDownloads(void) {}
797bool CL_PendingHTTPDownloads(void) {return false;}
798void CL_SetHTTPServer(const char* URL) {}
799void CL_HTTP_Cleanup(void) {}
800void CL_RequestNextDownload(void) {}
801bool CL_CheckOrDownloadFile(const char* filename) {return false;}
802
803void HTTP_InitStartup(void){}
804#endif
static int CL_HTTP_Progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
libcurl callback to update progress info. Mainly just used as a way to cancel the transfer if require...
Definition: cl_http.cpp:81
bool CL_CheckOrDownloadFile(const char *filename)
Definition: cl_http.cpp:341
static void StripHighBits(char *string)
Definition: cl_http.cpp:56
static void CL_CheckAndQueueDownload(char *path)
Validate a path supplied by a filelist.
Definition: cl_http.cpp:391
bool CL_PendingHTTPDownloads(void)
See if we're still busy with some downloads. Called by precacher just before it loads the map since w...
Definition: cl_http.cpp:328
static int pendingCount
Definition: cl_http.cpp:52
static bool isvalidchar(int c)
Definition: cl_http.cpp:70
void CL_RunHTTPDownloads(void)
This calls curl_multi_perform do actually do stuff. Called every frame while connecting to minimise l...
Definition: cl_http.cpp:751
static cvar_t * cl_http_filelists
Definition: cl_http.cpp:41
static int handleCount
Definition: cl_http.cpp:51
static dlhandle_t * CL_GetFreeDLHandle(void)
Find a free download handle to start another queue entry on.
Definition: cl_http.cpp:271
void CL_HTTP_Cleanup(void)
UFO is exiting or we're changing servers. Clean up.
Definition: cl_http.cpp:532
@ HTTPDL_ABORT_SOFT
Definition: cl_http.cpp:46
@ HTTPDL_ABORT_NONE
Definition: cl_http.cpp:45
@ HTTPDL_ABORT_HARD
Definition: cl_http.cpp:47
static int abortDownloads
Definition: cl_http.cpp:53
static void CL_StartHTTPDownload(dlqueue_t *entry, dlhandle_t *dl)
Actually starts a download by adding it to the curl multi handle.
Definition: cl_http.cpp:140
void CL_CancelHTTPDownloads(bool permKill)
Cancel all downloads and nuke the queue.
Definition: cl_http.cpp:250
static bool downloadingPK3
Definition: cl_http.cpp:54
static CURLM * multi
Definition: cl_http.cpp:50
static void CL_ParseFileList(dlhandle_t *dl)
A filelist is in memory, scan and validate it and queue up the files.
Definition: cl_http.cpp:486
void CL_SetHTTPServer(const char *URL)
A new server is specified, so we nuke all our state.
Definition: cl_http.cpp:225
static void CL_FinishHTTPDownload(void)
A download finished, find out what it was, whether there were any errors and if so,...
Definition: cl_http.cpp:566
bool CL_QueueHTTPDownload(const char *ufoPath)
Called from the precache check to queue a download.
Definition: cl_http.cpp:286
static cvar_t * cl_http_max_connections
Definition: cl_http.cpp:42
static cvar_t * cl_http_downloads
Definition: cl_http.cpp:40
static void CL_EscapeHTTPPath(const char *filePath, char *escaped)
Properly escapes a path with HTTP encoding. libcurl's function seems to treat '/' and such as illegal...
Definition: cl_http.cpp:106
static void CL_ReVerifyHTTPQueue(void)
A pk3 file just downloaded, let's see if we can remove some stuff from the queue which is in the ....
Definition: cl_http.cpp:515
void HTTP_InitStartup(void)
Definition: cl_http.cpp:787
static void CL_StartNextHTTPDownload(void)
Start another HTTP download if possible.
Definition: cl_http.cpp:725
cURL header
void CL_RequestNextDownload(void)
Definition: cl_main.cpp:602
client_static_t cls
Definition: cl_main.cpp:83
@ ca_connected
Definition: cl_shared.h:79
Primary header for client.
cvar_t * http_proxy
Definition: common.cpp:47
cvar_t * http_timeout
Definition: common.cpp:48
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
#define GAME_TITLE
Definition: common.h:37
#define ERR_DROP
Definition: common.h:211
#define UFO_VERSION
Definition: common.h:36
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags, const char *desc)
Init or return a cvar.
Definition: cvar.cpp:342
void FS_CreatePath(const char *path)
Creates any directories needed to store the given filename.
Definition: files.cpp:117
void FS_RemoveFile(const char *osPath)
Definition: files.cpp:1692
int FS_CheckFile(const char *fmt,...)
Just returns the filelength and -1 if the file wasn't found.
Definition: files.cpp:298
int FS_LoadFile(const char *path, byte **buffer)
Filenames are relative to the quake search path.
Definition: files.cpp:384
void FS_RestartFilesystem(const char *gamedir)
Restart the filesystem (reload all pk3 files)
Definition: files.cpp:1643
bool FS_RenameFile(const char *from, const char *to, bool relative)
Renames a file.
Definition: files.cpp:1709
const char * FS_Gamedir(void)
Called to find where to write a file (savegames, etc)
Definition: files.cpp:68
#define MAX_OSPATH
Definition: filesys.h:44
#define BASEDIRNAME
Definition: filesys.h:34
#define MAX_QPATH
Definition: filesys.h:40
size_t HTTP_Recv(void *ptr, size_t size, size_t nmemb, void *stream)
libcurl callback for HTTP_GetURL
Definition: http.cpp:154
size_t HTTP_Header(void *ptr, size_t size, size_t nmemb, void *stream)
libcurl callback to update header info.
Definition: http.cpp:126
@ DLQ_STATE_RUNNING
Definition: http.h:36
@ DLQ_STATE_NOT_STARTED
Definition: http.h:35
@ DLQ_STATE_DONE
Definition: http.h:37
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
const char * filename
Definition: ioapi.h:41
#define Mem_Free(ptr)
Definition: mem.h:35
#define Mem_AllocType(type)
Definition: mem.h:39
QGL_EXTERN GLuint GLchar GLuint * len
Definition: r_gl.h:99
QGL_EXTERN GLuint GLsizei GLsizei * length
Definition: r_gl.h:110
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
QGL_EXTERN GLint i
Definition: r_gl.h:113
#define Q_strcasecmp(a, b)
Definition: shared.h:131
#define Q_streq(a, b)
Definition: shared.h:136
bool Q_strnull(const char *string)
Definition: shared.h:138
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
const char * Com_GetExtension(const char *path)
Definition: shared.cpp:282
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
size_t downloadPosition
Definition: client.h:83
char downloadServer[512]
Definition: client.h:92
connstate_t state
Definition: client.h:55
int downloadPercent
Definition: client.h:84
dlqueue_t * downloadQueue
Definition: client.h:88
char downloadName[MAX_OSPATH]
Definition: client.h:82
char downloadReferer[32]
Definition: client.h:93
dlhandle_t HTTPHandles[4]
Definition: client.h:89
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition: cvar.h:71
int integer
Definition: cvar.h:81
char * string
Definition: cvar.h:73
dlqueue_t * queueEntry
Definition: http.h:50
size_t fileSize
Definition: http.h:51
char URL[576]
Definition: http.h:54
char filePath[MAX_OSPATH]
Definition: http.h:48
double speed
Definition: http.h:53
FILE * file
Definition: http.h:49
char * tempBuffer
Definition: http.h:55
size_t position
Definition: http.h:52
CURL * curl
Definition: http.h:47
Definition: http.h:40
char ufoPath[MAX_QPATH]
Definition: http.h:42
dlq_state state
Definition: http.h:43
struct dlqueue_s * next
Definition: http.h:41
FILE * Sys_Fopen(const char *filename, const char *mode)
Definition: unix_files.cpp:240
int Sys_Remove(const char *filename)
Definition: unix_files.cpp:245
#define FILE
Definition: test_webapi.cpp:30