UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
cl_http.cpp
Go to the documentation of this file.
1 
14 /*
15 Copyright (C) 1997-2001 Id Software, Inc.
16 
17 This program is free software; you can redistribute it and/or
18 modify it under the terms of the GNU General Public License
19 as published by the Free Software Foundation; either version 2
20 of the License, or (at your option) any later version.
21 
22 This program is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25 
26 See the GNU General Public License for more details.
27 
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 
32 */
33 
34 #include "client.h"
35 #include "cl_http.h"
36 #include "battlescape/cl_parse.h"
37 
38 #ifndef NO_HTTP
39 
43 
44 enum {
48 };
49 
50 static CURLM *multi = nullptr;
51 static int handleCount = 0;
52 static int pendingCount = 0;
54 static bool downloadingPK3 = false;
55 
56 static 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 
70 static inline bool isvalidchar (int c)
71 {
72  if (!isalnum(c) && c != '_' && c != '-')
73  return false;
74  return true;
75 }
76 
81 static 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
95  cls.downloadPercent = 0;
96  }
97 
98  return abortDownloads;
99 }
100 
106 static 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 
140 static void CL_StartHTTPDownload (dlqueue_t* entry, dlhandle_t* dl)
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 
160  FS_CreatePath(dl->filePath);
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 
225 void CL_SetHTTPServer (const char* URL)
226 {
227  CL_HTTP_Cleanup();
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 
250 void 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 
286 bool CL_QueueHTTPDownload (const char* ufoPath)
287 {
288  /* no http server (or we got booted) */
289  if (!cls.downloadServer[0] || abortDownloads || !cl_http_downloads->integer)
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 
299  dlqueue_t* const q = Mem_AllocType(dlqueue_t);
300  q->next = nullptr;
302  Q_strncpyz(q->ufoPath, ufoPath, sizeof(q->ufoPath));
303  *anchor = q;
304 
305  /* special case for map file lists */
306  if (cl_http_filelists->integer) {
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 
379  if (CL_QueueHTTPDownload(filename))
380  return false;
381 
382  return true;
383 }
384 
391 static 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. */
474  d->next = cls.downloadQueue;
475  cls.downloadQueue = d;
476  }
477  }
478  }
479  } else
481 }
482 
486 static void CL_ParseFileList (dlhandle_t* dl)
487 {
488  if (!cl_http_filelists->integer)
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 
515 static 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 
532 void CL_HTTP_Cleanup (void)
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 
566 static 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;
617  cls.downloadPosition = 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)
635  FS_RemoveFile(dl->filePath);
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)
649  CL_ParseFileList(dl);
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)
660  FS_RemoveFile(dl->filePath);
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)
672  FS_RemoveFile(dl->filePath);
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) {
712  else if (abortDownloads == HTTPDL_ABORT_HARD)
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 
725 static 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 
733  CL_StartHTTPDownload(q, dl);
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 
787 void HTTP_InitStartup (void)
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
794 void CL_CancelHTTPDownloads(bool permKill) {}
795 bool CL_QueueHTTPDownload(const char* ufoPath) {return false;}
796 void CL_RunHTTPDownloads(void) {}
797 bool CL_PendingHTTPDownloads(void) {return false;}
798 void CL_SetHTTPServer(const char* URL) {}
799 void CL_HTTP_Cleanup(void) {}
800 void CL_RequestNextDownload(void) {}
801 bool CL_CheckOrDownloadFile(const char* filename) {return false;}
802 
803 void HTTP_InitStartup(void){}
804 #endif
bool Q_strnull(const char *string)
Definition: shared.h:138
#define BASEDIRNAME
Definition: filesys.h:34
void CL_CancelHTTPDownloads(bool permKill)
Cancel all downloads and nuke the queue.
Definition: cl_http.cpp:250
static dlhandle_t * CL_GetFreeDLHandle(void)
Find a free download handle to start another queue entry on.
Definition: cl_http.cpp:271
char URL[576]
Definition: http.h:54
int FS_CheckFile(const char *fmt,...)
Just returns the filelength and -1 if the file wasn't found.
Definition: files.cpp:298
static cvar_t * cl_http_filelists
Definition: cl_http.cpp:41
static int handleCount
Definition: cl_http.cpp:51
static CURLM * multi
Definition: cl_http.cpp:50
const char * Com_GetExtension(const char *path)
Definition: shared.cpp:282
size_t HTTP_Header(void *ptr, size_t size, size_t nmemb, void *stream)
libcurl callback to update header info.
Definition: http.cpp:126
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition: cvar.h:71
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
static int abortDownloads
Definition: cl_http.cpp:53
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
const char * filename
Definition: ioapi.h:41
#define FILE
Definition: test_webapi.cpp:30
void FS_RestartFilesystem(const char *gamedir)
Restart the filesystem (reload all pk3 files)
Definition: files.cpp:1641
void FS_RemoveFile(const char *osPath)
Definition: files.cpp:1690
char downloadServer[512]
Definition: client.h:92
int FS_LoadFile(const char *path, byte **buffer)
Filenames are relative to the quake search path.
Definition: files.cpp:384
dlqueue_t * downloadQueue
Definition: client.h:88
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
#define MAX_OSPATH
Definition: filesys.h:44
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
size_t HTTP_Recv(void *ptr, size_t size, size_t nmemb, void *stream)
libcurl callback for HTTP_GetURL
Definition: http.cpp:154
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
int integer
Definition: cvar.h:81
static int pendingCount
Definition: cl_http.cpp:52
char * tempBuffer
Definition: http.h:55
char filePath[MAX_OSPATH]
Definition: http.h:48
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
static bool downloadingPK3
Definition: cl_http.cpp:54
cvar_t * http_proxy
Definition: common.cpp:47
const char * FS_Gamedir(void)
Called to find where to write a file (savegames, etc)
Definition: files.cpp:68
client_static_t cls
Definition: cl_main.cpp:83
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
#define UFO_VERSION
Definition: common.h:36
#define ERR_DROP
Definition: common.h:211
Definition: http.h:40
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 CL_HTTP_Cleanup(void)
UFO is exiting or we're changing servers. Clean up.
Definition: cl_http.cpp:532
static void StripHighBits(char *string)
Definition: cl_http.cpp:56
QGL_EXTERN GLuint GLsizei GLsizei * length
Definition: r_gl.h:110
dlhandle_t HTTPHandles[4]
Definition: client.h:89
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
size_t downloadPosition
Definition: client.h:83
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
double speed
Definition: http.h:53
int Sys_Remove(const char *filename)
Definition: unix_files.cpp:245
cvar_t * http_timeout
Definition: common.cpp:48
bool CL_CheckOrDownloadFile(const char *filename)
Definition: cl_http.cpp:341
char downloadReferer[32]
Definition: client.h:93
#define GAME_TITLE
Definition: common.h:37
char ufoPath[MAX_QPATH]
Definition: http.h:42
#define Q_strcasecmp(a, b)
Definition: shared.h:131
static bool isvalidchar(int c)
Definition: cl_http.cpp:70
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
static cvar_t * cl_http_max_connections
Definition: cl_http.cpp:42
cURL header
CURL * curl
Definition: http.h:47
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
static void CL_StartNextHTTPDownload(void)
Start another HTTP download if possible.
Definition: cl_http.cpp:725
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
void CL_SetHTTPServer(const char *URL)
A new server is specified, so we nuke all our state.
Definition: cl_http.cpp:225
bool FS_RenameFile(const char *from, const char *to, bool relative)
Renames a file.
Definition: files.cpp:1707
FILE * file
Definition: http.h:49
#define MAX_QPATH
Definition: filesys.h:40
QGL_EXTERN GLint i
Definition: r_gl.h:113
QGL_EXTERN GLuint GLchar GLuint * len
Definition: r_gl.h:99
dlq_state state
Definition: http.h:43
char * string
Definition: cvar.h:73
size_t fileSize
Definition: http.h:51
#define Mem_Free(ptr)
Definition: mem.h:35
static void CL_FinishHTTPDownload(void)
A download finished, find out what it was, whether there were any errors and if so, how severe. If none, rename file and other such stuff.
Definition: cl_http.cpp:566
int downloadPercent
Definition: client.h:84
FILE * Sys_Fopen(const char *filename, const char *mode)
Definition: unix_files.cpp:240
#define Mem_AllocType(type)
Definition: mem.h:39
connstate_t state
Definition: client.h:55
Primary header for client.
#define Q_streq(a, b)
Definition: shared.h:136
bool CL_QueueHTTPDownload(const char *ufoPath)
Called from the precache check to queue a download.
Definition: cl_http.cpp:286
static void CL_CheckAndQueueDownload(char *path)
Validate a path supplied by a filelist.
Definition: cl_http.cpp:391
char downloadName[MAX_OSPATH]
Definition: client.h:82
dlqueue_t * queueEntry
Definition: http.h:50
void FS_CreatePath(const char *path)
Creates any directories needed to store the given filename.
Definition: files.cpp:117
struct dlqueue_s * next
Definition: http.h:41
static cvar_t * cl_http_downloads
Definition: cl_http.cpp:40
void CL_RequestNextDownload(void)
Definition: cl_main.cpp:603
void HTTP_InitStartup(void)
Definition: cl_http.cpp:787
size_t position
Definition: http.h:52