4 #define URL_FH_STDOUT -2
13 .url_ready_func url_ready;
14 .entity url_ready_pass;
16 entity url_fromid[NUM_URL_ID];
17 float autocvar__urllib_nextslot;
19 float url_URI_Get_Callback(float id, float status, string data)
30 if(e.url_rbuf >= 0 || e.url_wbuf >= 0)
32 print(sprintf("WARNING: handle %d (%s) has already received data?!?\n", id + NUM_URL_ID, e.url_url));
36 // whatever happens, we will remove the URL from the list of IDs
37 url_fromid[id] = world;
39 // if we get here, we MUST have both buffers cleared
40 if(e.url_rbuf != -1 || e.url_wbuf != -1 || e.url_fh != URL_FH_CURL)
41 error("url_URI_Get_Callback: not a request waiting for data");
47 n = tokenizebyseparator(data, "\n");
48 e.url_rbuf = buf_create();
51 print("url_URI_Get_Callback: out of memory in buf_create\n");
52 e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
60 print("url_URI_Get_Callback: out of memory in buf_create\n");
61 e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
66 for(i = 0; i < n; ++i)
67 bufstr_set(e.url_rbuf, i, argv(i));
68 e.url_ready(e, e.url_ready_pass, URL_READY_CANREAD);
74 e.url_ready(e, e.url_ready_pass, -fabs(status));
81 void url_fopen(string url, float mode, url_ready_func rdy, entity pass)
85 if(strstrofs(url, "://", 0) >= 0)
91 // collect data to a stringbuffer for a POST request
92 // attempts to close will result in a reading handle
94 // create a writing end that does nothing yet
96 e.classname = "url_fopen_file";
97 e.url_url = strzone(url);
98 e.url_fh = URL_FH_CURL;
99 e.url_wbuf = buf_create();
102 print("url_fopen: out of memory in buf_create\n");
103 rdy(e, pass, URL_READY_ERROR);
104 strunzone(e.url_url);
110 rdy(e, pass, URL_READY_CANWRITE);
116 // get slot for HTTP request
117 for(i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
118 if(url_fromid[i] == world)
122 for(i = 0; i < autocvar__urllib_nextslot; ++i)
123 if(url_fromid[i] == world)
125 if(i >= autocvar__urllib_nextslot)
127 print("url_fopen: too many concurrent requests\n");
128 rdy(world, pass, URL_READY_ERROR);
134 if(!crypto_uri_postbuf(url, i + MIN_URL_ID, string_null, string_null, -1, 0))
136 print("url_fopen: failure in crypto_uri_postbuf\n");
137 rdy(world, pass, URL_READY_ERROR);
141 // Make a dummy handle object (no buffers at
142 // all). Wait for data to come from the
143 // server, then call the callback
145 e.classname = "url_fopen_file";
146 e.url_url = strzone(url);
147 e.url_fh = URL_FH_CURL;
151 e.url_ready_pass = pass;
155 // make sure this slot won't be reused quickly even on map change
156 cvar_set("_urllib_nextslot", ftos(mod(i + 1, NUM_URL_ID)));
167 e.classname = "url_fopen_stdout";
168 e.url_fh = URL_FH_STDOUT;
169 rdy(e, pass, URL_READY_CANWRITE);
172 print("url_fopen: cannot open '-' for reading\n");
173 rdy(world, pass, URL_READY_ERROR);
180 fh = fopen(url, mode);
183 rdy(world, pass, URL_READY_ERROR);
189 e.classname = "url_fopen_file";
191 if(mode == FILE_READ)
192 rdy(e, pass, URL_READY_CANREAD);
194 rdy(e, pass, URL_READY_CANWRITE);
200 void url_fclose(entity e, url_ready_func rdy, entity pass)
204 if(e.url_fh == URL_FH_CURL)
206 if(e.url_rbuf == -1 || e.url_wbuf != -1) // not(post GET/POST request)
207 if(e.url_rbuf != -1 || e.url_wbuf == -1) // not(pre POST request)
208 error("url_fclose: not closable in current state");
213 // we are closing the write end (HTTP POST request)
215 // get slot for HTTP request
216 for(i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
217 if(url_fromid[i] == world)
221 for(i = 0; i < autocvar__urllib_nextslot; ++i)
222 if(url_fromid[i] == world)
224 if(i >= autocvar__urllib_nextslot)
226 print("url_fclose: too many concurrent requests\n");
227 rdy(e, pass, URL_READY_ERROR);
229 strunzone(e.url_url);
236 if(!crypto_uri_postbuf(e.url_url, i + MIN_URL_ID, "text/plain", "", e.url_wbuf, 0))
238 print("url_fclose: failure in crypto_uri_postbuf\n");
239 rdy(e, pass, URL_READY_ERROR);
241 strunzone(e.url_url);
246 // delete write end. File handle is now in unusable
247 // state. Wait for data to come from the server, then
252 e.url_ready_pass = pass;
256 // make sure this slot won't be reused quickly even on map change
257 cvar_set("_urllib_nextslot", ftos(mod(i + 1, NUM_URL_ID)));
261 // we have READ all data, just close
262 rdy(e, pass, URL_READY_CLOSED);
264 strunzone(e.url_url);
268 else if(e.url_fh == URL_FH_STDOUT)
276 rdy(e, pass, URL_READY_CLOSED); // closing creates no reading handle
281 // with \n (blame FRIK_FILE)
282 string url_fgets(entity e)
284 if(e.url_fh == URL_FH_CURL)
287 error("url_fgets: not readable in current state");
290 s = bufstr_get(e.url_rbuf, e.url_rbufpos);
294 else if(e.url_fh == URL_FH_STDOUT)
302 return fgets(e.url_fh);
306 // without \n (blame FRIK_FILE)
307 void url_fputs(entity e, string s)
309 if(e.url_fh == URL_FH_CURL)
312 error("url_fputs: not writable in current state");
314 bufstr_set(e.url_wbuf, e.url_wbufpos, s);
317 else if(e.url_fh == URL_FH_STDOUT)