]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/urllib.qc
Merge remote-tracking branch 'origin/samual/fix_crosshair_hitindication'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / urllib.qc
index 83e00f119bfd8a0edb8955e1fde0992267a87962..54bcefecca9b01a2f10e1b6a5d49267c9954dca9 100644 (file)
@@ -11,9 +11,8 @@
 .url_ready_func url_ready;
 .entity url_ready_pass;
 
-#define MIN_URL_ID 128
-#define NUM_URL_ID 64
 entity url_fromid[NUM_URL_ID];
+float autocvar__urllib_nextslot;
 
 float url_URI_Get_Callback(float id, float status, string data)
 {
@@ -41,13 +40,22 @@ float url_URI_Get_Callback(float id, float status, string data)
                float n, i;
                n = tokenizebyseparator(data, "\n");
                e.url_rbuf = buf_create();
+               if(e.url_rbuf < 0)
+               {
+                       print("url_URI_Get_Callback: out of memory in buf_create\n");
+                       e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
+                       strunzone(e.url_url);
+                       remove(e);
+                       return 1;
+               }
                e.url_rbufpos = 0;
                if(e.url_rbuf < 0)
                {
-                       print("buf_create: out of memory\n");
+                       print("url_URI_Get_Callback: out of memory in buf_create\n");
                        e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
                        strunzone(e.url_url);
                        remove(e);
+                       return 1;
                }
                for(i = 0; i < n; ++i)
                        bufstr_set(e.url_rbuf, i, argv(i));
@@ -64,11 +72,11 @@ float url_URI_Get_Callback(float id, float status, string data)
        }
 }
 
-void url_fopen(string url, float mode, entity pass, url_ready_func rdy)
+void url_fopen(string url, float mode, url_ready_func rdy, entity pass)
 {
        entity e;
        float i;
-       if(strstrofs(url, "://", -1))
+       if(strstrofs(url, "://", 0) >= 0)
        {
                switch(mode)
                {
@@ -76,6 +84,8 @@ void url_fopen(string url, float mode, entity pass, url_ready_func rdy)
                        case FILE_APPEND:
                                // collect data to a stringbuffer for a POST request
                                // attempts to close will result in a reading handle
+
+                               // create a writing end that does nothing yet
                                e = spawn();
                                e.classname = "url_fopen_file";
                                e.url_url = strzone(url);
@@ -83,10 +93,10 @@ void url_fopen(string url, float mode, entity pass, url_ready_func rdy)
                                e.url_wbuf = buf_create();
                                if(e.url_wbuf < 0)
                                {
-                                       print("buf_create: out of memory\n");
+                                       print("url_fopen: out of memory in buf_create\n");
+                                       rdy(e, pass, URL_READY_ERROR);
                                        strunzone(e.url_url);
                                        remove(e);
-                                       rdy(world, pass, URL_READY_ERROR);
                                        return;
                                }
                                e.url_wbufpos = 0;
@@ -96,33 +106,48 @@ void url_fopen(string url, float mode, entity pass, url_ready_func rdy)
 
                        case FILE_READ:
                                // read data only
-                               for(i = 0; i < NUM_URL_ID; ++i)
+
+                               // get slot for HTTP request
+                               for(i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
                                        if(url_fromid[i] == world)
                                                break;
                                if(i >= NUM_URL_ID)
                                {
+                                       for(i = 0; i < autocvar__urllib_nextslot; ++i)
+                                               if(url_fromid[i] == world)
+                                                       break;
+                                       if(i >= autocvar__urllib_nextslot)
+                                       {
+                                               print("url_fopen: too many concurrent requests\n");
+                                               rdy(world, pass, URL_READY_ERROR);
+                                               return;
+                                       }
+                               }
+
+                               // GET the data
+                               if(!crypto_uri_postbuf(url, i + MIN_URL_ID, string_null, string_null, -1, 0))
+                               {
+                                       print("url_fopen: failure in crypto_uri_postbuf\n");
                                        rdy(world, pass, URL_READY_ERROR);
                                        return;
                                }
 
+                               // Make a dummy handle object (no buffers at
+                               // all). Wait for data to come from the
+                               // server, then call the callback
                                e = spawn();
                                e.classname = "url_fopen_file";
                                e.url_url = strzone(url);
                                e.url_fh = -1;
                                e.url_rbuf = -1;
                                e.url_wbuf = -1;
-                               if(!uri_get(url, i + MIN_URL_ID))
-                               {
-                                       print("uri_get: failed\n");
-                                       strunzone(e.url_url);
-                                       remove(e);
-                                       rdy(world, pass, URL_READY_ERROR);
-                                       return;
-                               }
                                e.url_ready = rdy;
                                e.url_ready_pass = pass;
                                e.url_id = i;
                                url_fromid[i] = e;
+
+                               // make sure this slot won't be reused quickly even on map change
+                               cvar_set("_urllib_nextslot", ftos(mod(i + 1, NUM_URL_ID)));
                                break;
                }
        }
@@ -148,28 +173,42 @@ void url_fopen(string url, float mode, entity pass, url_ready_func rdy)
        }
 }
 
-void url_fclose(entity e, entity pass, url_ready_func rdy)
+// close a file
+void url_fclose(entity e, url_ready_func rdy, entity pass)
 {
        float i;
 
        if(e.url_fh < 0)
        {
+               // closing an URL!
                if(e.url_wbuf >= 0)
                {
-                       for(i = 0; i < NUM_URL_ID; ++i)
+                       // we are closing the write end (HTTP POST request)
+
+                       // get slot for HTTP request
+                       for(i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
                                if(url_fromid[i] == world)
                                        break;
                        if(i >= NUM_URL_ID)
                        {
-                               rdy(e, pass, URL_READY_ERROR);
-                               buf_del(e.url_wbuf);
-                               strunzone(e.url_url);
-                               remove(e);
-                               return;
+                               for(i = 0; i < autocvar__urllib_nextslot; ++i)
+                                       if(url_fromid[i] == world)
+                                               break;
+                               if(i >= autocvar__urllib_nextslot)
+                               {
+                                       print("url_fclose: too many concurrent requests\n");
+                                       rdy(e, pass, URL_READY_ERROR);
+                                       buf_del(e.url_wbuf);
+                                       strunzone(e.url_url);
+                                       remove(e);
+                                       return;
+                               }
                        }
 
-                       if(!uri_postbuf(e.url_url, e.url_id + MIN_URL_ID, "text/plain", "\n", e.url_wbuf))
+                       // POST the data
+                       if(!crypto_uri_postbuf(e.url_url, i + MIN_URL_ID, "text/plain", "", e.url_wbuf, 0))
                        {
+                               print("url_fclose: failure in crypto_uri_postbuf\n");
                                rdy(e, pass, URL_READY_ERROR);
                                buf_del(e.url_wbuf);
                                strunzone(e.url_url);
@@ -177,16 +216,22 @@ void url_fclose(entity e, entity pass, url_ready_func rdy)
                                return;
                        }
 
+                       // delete write end. File handle is now in unusable
+                       // state. Wait for data to come from the server, then
+                       // call the callback
                        buf_del(e.url_wbuf);
                        e.url_wbuf = -1;
                        e.url_ready = rdy;
                        e.url_ready_pass = pass;
                        e.url_id = i;
                        url_fromid[i] = e;
+
+                       // make sure this slot won't be reused quickly even on map change
+                       cvar_set("_urllib_nextslot", ftos(mod(i + 1, NUM_URL_ID)));
                }
                else
                {
-                       // we have READ all data
+                       // we have READ all data, just close
                        rdy(e, pass, URL_READY_CLOSED);
                        buf_del(e.url_rbuf);
                        strunzone(e.url_url);
@@ -202,7 +247,7 @@ void url_fclose(entity e, entity pass, url_ready_func rdy)
        }
 }
 
-// with \n
+// with \n (blame FRIK_FILE)
 string url_fgets(entity e)
 {
        if(e.url_fh < 0)
@@ -220,7 +265,7 @@ string url_fgets(entity e)
        }
 }
 
-// without \n
+// without \n (blame FRIK_FILE)
 void url_fputs(entity e, string s)
 {
        if(e.url_fh < 0)