]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/urllib.qc
urllib: more error fixes
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / urllib.qc
1 // files (-1 for URL)
2 .float url_fh;
3
4 // URLs
5 .string url_url;
6 .float url_wbuf;
7 .float url_wbufpos;
8 .float url_rbuf;
9 .float url_rbufpos;
10 .float url_id;
11 .url_ready_func url_ready;
12 .entity url_ready_pass;
13
14 #define MIN_URL_ID 128
15 #define NUM_URL_ID 64
16 entity url_fromid[NUM_URL_ID];
17
18 float url_URI_Get_Callback(float id, float status, string data)
19 {
20         if(id < MIN_URL_ID)
21                 return 0;
22         id -= MIN_URL_ID;
23         if(id >= NUM_URL_ID)
24                 return 0;
25         entity e;
26         e = url_fromid[id];
27         if(!e)
28                 return 0;
29         if(e.url_rbuf >= 0 || e.url_wbuf >= 0)
30         {
31                 print(sprintf("WARNING: handle %d (%s) has already received data?!?\n", id + NUM_URL_ID, e.url_url));
32                 return 0;
33         }
34
35         // whatever happens, we will remove the URL from the list of IDs
36         url_fromid[id] = world;
37
38         if(status == 0)
39         {
40                 // WE GOT DATA!
41                 float n, i;
42                 n = tokenizebyseparator(data, "\n");
43                 e.url_rbuf = buf_create();
44                 e.url_rbufpos = 0;
45                 if(e.url_rbuf < 0)
46                 {
47                         print("buf_create: out of memory\n");
48                         e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
49                         strunzone(e.url_url);
50                         remove(e);
51                 }
52                 for(i = 0; i < n; ++i)
53                         bufstr_set(e.url_rbuf, i, argv(i));
54                 e.url_ready(e, e.url_ready_pass, URL_READY_CANREAD);
55                 return 1;
56         }
57         else
58         {
59                 // an ERROR
60                 e.url_ready(e, e.url_ready_pass, -status);
61                 strunzone(e.url_url);
62                 remove(e);
63                 return 1;
64         }
65 }
66
67 void url_fopen(string url, float mode, url_ready_func rdy, entity pass)
68 {
69         entity e;
70         float i;
71         if(strstrofs(url, "://", -1))
72         {
73                 switch(mode)
74                 {
75                         case FILE_WRITE:
76                         case FILE_APPEND:
77                                 // collect data to a stringbuffer for a POST request
78                                 // attempts to close will result in a reading handle
79                                 e = spawn();
80                                 e.classname = "url_fopen_file";
81                                 e.url_url = strzone(url);
82                                 e.url_fh = -1;
83                                 e.url_wbuf = buf_create();
84                                 if(e.url_wbuf < 0)
85                                 {
86                                         print("buf_create: out of memory\n");
87                                         rdy(e, pass, URL_READY_ERROR);
88                                         strunzone(e.url_url);
89                                         remove(e);
90                                         return;
91                                 }
92                                 e.url_wbufpos = 0;
93                                 e.url_rbuf = -1;
94                                 rdy(e, pass, URL_READY_CANWRITE);
95                                 break;
96
97                         case FILE_READ:
98                                 // read data only
99                                 for(i = 0; i < NUM_URL_ID; ++i)
100                                         if(url_fromid[i] == world)
101                                                 break;
102                                 if(i >= NUM_URL_ID)
103                                 {
104                                         rdy(world, pass, URL_READY_ERROR);
105                                         return;
106                                 }
107
108                                 e = spawn();
109                                 e.classname = "url_fopen_file";
110                                 e.url_url = strzone(url);
111                                 e.url_fh = -1;
112                                 e.url_rbuf = -1;
113                                 e.url_wbuf = -1;
114                                 if(!uri_get(url, i + MIN_URL_ID))
115                                 {
116                                         rdy(e, pass, URL_READY_ERROR);
117                                         strunzone(e.url_url);
118                                         remove(e);
119                                         return;
120                                 }
121                                 e.url_ready = rdy;
122                                 e.url_ready_pass = pass;
123                                 e.url_id = i;
124                                 url_fromid[i] = e;
125                                 break;
126                 }
127         }
128         else
129         {
130                 float fh;
131                 fh = fopen(url, mode);
132                 if(fh < 0)
133                 {
134                         rdy(world, pass, URL_READY_ERROR);
135                         return;
136                 }
137                 else
138                 {
139                         e = spawn();
140                         e.classname = "url_fopen_file";
141                         e.url_fh = fh;
142                         if(mode == FILE_READ)
143                                 rdy(e, pass, URL_READY_CANREAD);
144                         else
145                                 rdy(e, pass, URL_READY_CANWRITE);
146                 }
147         }
148 }
149
150 void url_fclose(entity e, url_ready_func rdy, entity pass)
151 {
152         float i;
153
154         if(e.url_fh < 0)
155         {
156                 if(e.url_wbuf >= 0)
157                 {
158                         for(i = 0; i < NUM_URL_ID; ++i)
159                                 if(url_fromid[i] == world)
160                                         break;
161                         if(i >= NUM_URL_ID)
162                         {
163                                 buf_del(e.url_wbuf);
164                                 rdy(e, pass, URL_READY_ERROR);
165                                 strunzone(e.url_url);
166                                 remove(e);
167                                 return;
168                         }
169
170                         if(!uri_postbuf(e.url_url, e.url_id + MIN_URL_ID, "text/plain", "\n", e.url_wbuf))
171                         {
172                                 buf_del(e.url_wbuf);
173                                 rdy(e, pass, URL_READY_ERROR);
174                                 strunzone(e.url_url);
175                                 remove(e);
176                                 return;
177                         }
178
179                         buf_del(e.url_wbuf);
180                         e.url_wbuf = -1;
181                         e.url_ready = rdy;
182                         e.url_ready_pass = pass;
183                         e.url_id = i;
184                         url_fromid[i] = e;
185                 }
186                 else
187                 {
188                         // we have READ all data
189                         rdy(e, pass, URL_READY_CLOSED);
190                         buf_del(e.url_rbuf);
191                         strunzone(e.url_url);
192                         remove(e);
193                 }
194         }
195         else
196         {
197                 // file
198                 fclose(e.url_fh);
199                 rdy(e, pass, URL_READY_CLOSED); // closing creates no reading handle
200                 remove(e);
201         }
202 }
203
204 // with \n
205 string url_fgets(entity e)
206 {
207         if(e.url_fh < 0)
208         {
209                 // curl
210                 string s;
211                 s = bufstr_get(e.url_rbuf, e.url_rbufpos);
212                 e.url_rbufpos += 1;
213                 return s;
214         }
215         else
216         {
217                 // file
218                 return fgets(e.url_fh);
219         }
220 }
221
222 // without \n
223 void url_fputs(entity e, string s)
224 {
225         if(e.url_fh < 0)
226         {
227                 // curl
228                 bufstr_set(e.url_wbuf, e.url_wbufpos, s);
229                 e.url_wbufpos += 1;
230         }
231         else
232         {
233                 // file
234                 fputs(e.url_fh, s);
235         }
236 }