From 077640b8850b6c35942559bbc786099a76af1820 Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Wed, 17 Aug 2011 20:14:05 +0200 Subject: [PATCH] add urllib (not used yet) --- qcsrc/common/urllib.qc | 225 +++++++++++++++++++++++++++++++++++++++++ qcsrc/common/urllib.qh | 13 +++ 2 files changed, 238 insertions(+) create mode 100644 qcsrc/common/urllib.qc create mode 100644 qcsrc/common/urllib.qh diff --git a/qcsrc/common/urllib.qc b/qcsrc/common/urllib.qc new file mode 100644 index 000000000..31fd07eae --- /dev/null +++ b/qcsrc/common/urllib.qc @@ -0,0 +1,225 @@ +// files (-1 for URL) +.float url_fh; + +// URLs +.string url_url; +.float url_wbuf; +.float url_wbufpos; +.float url_rbuf; +.float url_rbufpos; +.float url_id; +.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]; + +void url_URI_Get_Callback(float id, float status, string data) +{ + if(id < MIN_URL_ID) + return 0; + id -= MIN_URL_ID; + if(id >= NUM_URL_ID) + return 0; + entity e; + e = url_fromid(id); + if(!e) + return 0; + if(e.url_rbuf >= 0) + { + print(sprintf("WARNING: handle %d (%s) has already received data?!?\n", id + NUM_URL_ID, e.url_url)); + return 0; + } + + if(status == 0) + { + // WE GOT DATA! + float n, i; + n = tokenizebyseparator(data, "\n"); + e.url_rbuf = buf_create(); + e.url_rbufpos = 0; + if(e.url_rbuf < 0) + { + backtrace("buf_create: out of memory"); + e.url_ready(e, e.url_ready_pass, URL_READY_ERROR); + strunzone(e.url_url); + remove(e); + } + for(i = 0; i < n; ++i) + bufstr_set(e.url_rbuf, i, argv(i)); + e.url_ready(e, e.url_ready_pass, URL_READY_CANREAD); + return 1; + } + else + { + // an ERROR + e.url_ready(e, e.url_ready_pass, -status); + strunzone(e.url_url); + remove(e); + return 1; + } +} + +void url_fopen(string url, float mode, entity pass, url_ready_func ready) +{ + entity e; + float i; + if(strstrofs(url, "://", -1)) + { + switch(mode) + { + case FILE_WRITE: + case FILE_APPEND: + // collect data to a stringbuffer for a POST request + // attempts to close will result in a reading handle + e = spawn(); + e.classname = "url_fopen_file"; + e.url_url = strzone(url); + e.url_fh = -1; + e.url_wbuf = buf_create(); + if(e.url_wbuf < 0) + { + backtrace("buf_create: out of memory"); + strunzone(e.url_url); + remove(e); + ready(world, pass, URL_READY_ERROR); + return; + } + e.url_wbufpos = 0; + e.url_rbuf = -1; + ready(e, pass, URL_READY_CANWRITE); + break; + + case FILE_READ: + // read data only + for(i = 0; i < NUM_URL_ID; ++i) + if(url_fromid[i] == world) + break; + if(i >= NUM_URL_ID) + return -1; + + e = spawn(); + e.classname = "url_fopen_file"; + e.url_url = strzone(url); + e.url_fh = -1; + e.url_rbuf = -1; + e.url_wbuf = -1; + e.url_id = i; + if(!uri_get(uri, e.url_id + MIN_URL_ID)) + { + backtrace("uri_get: failed"); + strunzone(e.url_url); + remove(e); + ready(world, pass, URL_READY_ERROR); + return; + } + e.url_ready = ready; + e.url_ready_pass = pass; + break; + } + } + else + { + float fh; + fh = fopen(url, mode); + if(fh < 0) + return -1; + else + { + e = spawn(); + e.classname = "url_fopen_file"; + e.url_fh = fh; + if(mode == FILE_READ) + ready(e, pass, URL_READY_CANREAD); + else + ready(e, pass, URL_READY_CANWRITE); + } + } +} + +void url_fclose(entity e, entity pass, url_ready_func ready) +{ + float i; + + if(e.url_fh < 0) + { + if(e.url_wbuf >= 0) + { + for(i = 0; i < NUM_URL_ID; ++i) + if(url_fromid[i] == world) + break; + if(i >= NUM_URL_ID) + { + ready(e, pass, URL_READY_ERROR); + buf_del(e.url_wbuf); + strunzone(e.url_url); + remove(e); + return; + } + + if(!uri_postbuf(uri, e.url_id + MIN_URL_ID, "text/plain", "\n", e.url_wbuf)) + { + ready(e, pass, URL_READY_ERROR); + buf_del(e.url_wbuf); + strunzone(e.url_url); + remove(e); + return; + } + + buf_del(e.url_wbuf); + e.url_wbuf = -1; + e.url_ready = ready; + e.url_ready_pass = pass; + } + else + { + // we have READ all data + ready(e, pass, URL_READY_CLOSED); + buf_del(e.url_rbuf); + strunzone(e.url_url); + remove(e); + } + } + else + { + // file + fclose(e.url_fh); + ready(e, pass, URL_READY_CLOSED); // closing creates no reading handle + remove(e); + } +} + +// with \n +string url_fgets(entity e) +{ + if(e.url_fh < 0) + { + // curl + string s; + s = bufstr_get(e.url_rbuf, e.url_rbufpos); + ++e.url_rbufpos; + return s; + } + else + { + // file + return fgets(e.url_fh); + } +} + +// without \n +void url_fputs(entity e, string s) +{ + if(e.url_fh < 0) + { + // curl + bufstr_set(e.url_wbuf, e.url_wbufpos, s); + ++e.url_wbufpos; + } + else + { + // file + fputs(e, s); + } +} diff --git a/qcsrc/common/urllib.qh b/qcsrc/common/urllib.qh new file mode 100644 index 000000000..f3aadcb84 --- /dev/null +++ b/qcsrc/common/urllib.qh @@ -0,0 +1,13 @@ +float URL_READY_CLOSED 0 +float URL_READY_CANWRITE 1 +float URL_READY_CANREAD 2 +// errors: -1, or negative HTTP status code +typedef void(entity handle, entity pass, float status) url_ready_func; + +void url_fopen(string url, float mode, entity pass, url_fopen_ready_func ready); +void url_fclose(entity e, entity pass, url_fclose_ready_func ready) +string url_fgets(entity e); +void url_fputs(entity e, string s); + +// returns true if handled +float url_URI_Get_Callback(float id, float status, string data); -- 2.39.2