add support for port and path settings for autodownload servers

actually, addpckserver now supports a full url as "host" field - but only
domain, port and path are used
This commit is contained in:
ac-stef
2015-09-07 14:53:57 +02:00
parent 9965f53d28
commit fd2109adc5
3 changed files with 101 additions and 16 deletions
+21 -15
View File
@@ -67,38 +67,41 @@ const char *updatestxt = "/updates.txt";
int pingpckserver(void *data) // fetch updates.txt from a media server, measure required time
{
httpget h;
urlparse u;
pckserver *s = (pckserver *)data;
s->resolved = h.set_host(s->host) ? 1 : 0;
u.set(s->host);
s->resolved = h.set_host(u.domain) ? 1 : 0;
SDL_mutexP(pckpinglog_lock);
cvecprintf(pckping_log, "lresolving hostname %s %s\n", s->host, s->resolved ? "succeeded" : "failed");
cvecprintf(pckping_log, "lresolving hostname %s %s (%s)\n", u.domain, s->resolved ? "succeeded" : "failed", iptoa(ntohl(h.ip.host)));
SDL_mutexV(pckpinglog_lock);
if(s->resolved)
{
int res = h.get(updatestxt, 5000, 10000, 0, true); // http HEAD request only - to get a nice ping value
if(*u.port) h.set_port(atoi(u.port));
defformatstring(url)("%s%s", u.path, updatestxt);
int res = h.get(url, 5000, 10000, 0, true); // http HEAD request only - to get a nice ping value
if(h.response > 0)
{
s->ping = h.elapsedtime;
SDL_mutexP(pckpinglog_lock);
cvecprintf(pckping_log, "lhttp head %s%s response time: %d, status: %d, contentlength: %d\n", s->host, updatestxt, s->ping, h.response, h.contentlength);
cvecprintf(pckping_log, "lhttp head %s:%d%s response time: %d, status: %d, contentlength: %d\n", u.domain, h.ip.port, url, s->ping, h.response, h.contentlength);
SDL_mutexV(pckpinglog_lock);
if(h.response == 200)
{
h.outvec = new vector<uchar>;
res = h.get(updatestxt, 5000, 20000); // http GET
res = h.get(url, 5000, 20000); // http GET
if(res >= 0 && h.response == 200)
{ // parse updates.txt
h.outvec->add('\0');
s->updates.clear();
parseupdatelist(s->updates, (char *)h.outvec->getbuf()); // don't filter entries
SDL_mutexP(pckpinglog_lock);
cvecprintf(pckping_log, "lgot %s%s: %d bytes, %d valid update lines\n", s->host, updatestxt, res, s->updates.numelems);
cvecprintf(pckping_log, "lgot %s:%d%s: %d bytes, %d valid update lines\n", u.domain, h.ip.port, url, res, s->updates.numelems);
SDL_mutexV(pckpinglog_lock);
}
else
{
SDL_mutexP(pckpinglog_lock);
cvecprintf(pckping_log, "lretrieving %s%s failed: response %d%s%s\n", s->host, updatestxt, h.response, h.err ? ", err: " : "", h.err ? h.err : "");
cvecprintf(pckping_log, "lretrieving %s:%d%s failed: response %d%s%s\n", u.domain, h.ip.port, url, h.response, h.err ? ", err: " : "", h.err ? h.err : "");
SDL_mutexV(pckpinglog_lock);
}
DELETEP(h.outvec);
@@ -355,37 +358,40 @@ int progress_callback_dlpackage(void *data, float progress)
bool dlpackage(httpget &h, package *pck, pckserver *s) // download one package from one server
{
const char *host = s ? s->host : pck->host;
urlparse u;
u.set(s ? s->host : pck->host);
h.callbackfunc = progress_callback_dlpackage;
h.callbackdata = pck->name;
progress_n = progress_of - pendingpackages.length();
if(*host && h.set_host(host))
if(*u.domain && h.set_host(u.domain))
{
if(*u.port) h.set_port(atoi(u.port));
h.outstream = openvecfile(NULL);
int got = h.get(pck->requestname, 6000, 90000);
defformatstring(url)("%s%s", u.path, pck->requestname);
int got = h.get(url, 6000, 90000);
if(!h.response)
{
if(!canceldownloads && s) s->ping = 0; // received a hard error from the server connection, better not try this one again
clientlogf("download %s%s failed%s%s", host, pck->requestname, h.err ? ", err: " : "", h.err ? h.err : "");
clientlogf("download %s:%d%s failed%s%s", u.domain, h.ip.port, url, h.err ? ", err: " : "", h.err ? h.err : "");
h.disconnect();
}
else
{
if(h.response == 200)
{
clientlogf("downloaded %s%s, %d bytes (%d raw), %d msec", host, pck->requestname, got, h.contentlength, h.elapsedtime);
clientlogf("downloaded %s:%d%s, %d bytes (%d raw), %d msec", u.domain, h.ip.port, url, got, h.contentlength, h.elapsedtime);
processdownload(pck, h.outstream);
h.outstream = NULL; // deleted by processdownload()
return true;
}
else clientlogf("download %s%s failed, server response %d%s%s", host, pck->requestname, h.response, h.err ? ", err: " : "", h.err ? h.err : "");
else clientlogf("download %s:%d%s failed, server response %d%s%s", u.domain, h.ip.port, url, h.response, h.err ? ", err: " : "", h.err ? h.err : "");
}
DELETEP(h.outstream);
}
else
{
if(s) s->resolved = 0;
clientlogf("resolving host \"%s\" failed", host);
clientlogf("resolving host \"%s\" failed", u.domain);
h.disconnect();
}
return false;
+67
View File
@@ -49,6 +49,14 @@ bool httpget::set_host(const char *newhostname) // set and resolve host
return ip.host != ENET_HOST_ANY;
}
void httpget::set_port(int port) // set port (disconnect, if different to previous)
{
port &= 65535;
if(port < 80) port = 80;
if(port != ip.port) disconnect();
ip.port = port;
}
bool httpget::execcallback(float progress)
{
if(callbackfunc && (*callbackfunc)(callbackdata, progress))
@@ -334,3 +342,62 @@ char *urlencode(const char *s, bool strict)
return newstring(d.getbuf());
}
// parse URLs: scheme:[//[user:password@]domain[:port]][/]path[?query][#fragment]
void urlparse::set(const char *newurl)
{
DELSTRING(buf);
char *p, *s = buf = newstring(newurl, strlen(newurl) + 3);
scheme = userpassword = port = path = query = fragment = "";
filtertext(s, s, FTXT_NOWHITE);
if((p = strstr(s, "://"))) // domain part is mandatory, which makes the double slash a given - if a scheme is specified
{ // scheme found
scheme = s;
*p = '\0';
s = p + 3;
}
if((p = strchr(s, '@')))
{ // user:password found
userpassword = s;
*p = '\0';
s = p + 1;
}
domain = s;
if(*s == '[' && (p = strchr(s, ']'))) s = p + 1; // [....]
else while(isalnum(*s) || *s == '.' || *s == '-') s++; // skip domain
if(*s == ':')
{ // port found
*s = '\0';
port = ++s;
while(isdigit(*s)) s++;
}
if(*s)
{
memmove(s + 2, s, strlen(s) + 1);
*s++ = '\0'; // end domain or port string
*s++ = '/'; // add mandatory slash for path
if(*s != '/') s--;
path = s;
if((p = strchr(s, '?')))
{ // query found
*p++ = '\0';
query = s = p;
}
if((p = strchr(s, '#')))
{ // fragment found
*p++ = '\0';
fragment = s = p;
}
// fix path, if necessary
size_t pl = strlen(path);
if(pl < 2) path = ""; // ignore single slash
else
{
p = (char *)path;
unixpath(p);
p += pl - 1;
if(*p == '/') *p = '\0'; // remove trailing slash
}
}
}
+13 -1
View File
@@ -245,7 +245,7 @@ struct httpget
const char *hostname, *url; // set by set_host() and get()
const char *useragent, *referrer; // can be set manually with "newstrings", deleted automatically
const char *err; // read-only
ENetAddress ip; // set by set_host(), port may be changed manually
ENetAddress ip; // set by set_host()
int maxredirects, maxtransfer, maxsize; // set manually
int (__cdecl *callbackfunc)(void *data, float progress);
void *callbackdata;
@@ -266,12 +266,24 @@ struct httpget
~httpget() { reset(); DELSTRING(useragent); DELSTRING(referrer); DELETEP(outvec); DELETEP(outstream); }
void reset(int keep = 0); // cleanup
bool set_host(const char *newhostname); // set and resolve host
void set_port(int port); // set port (disconnect, if different to previous)
bool execcallback(float progress);
void disconnect();
bool connect(bool force = false);
int get(const char *url1, uint timeout, uint totaltimeout, int range = 0, bool head = false); // get web ressource
};
struct urlparse
{
char *buf;
// result (scheme:[//[user:password@]domain[:port]][/]path[?query][#fragment])
const char *scheme, *userpassword, *domain, *port, *path, *query, *fragment;
urlparse() { memset(&buf, 0, sizeof(struct urlparse)); }
~urlparse() { DELSTRING(buf); }
void set(const char *newurl); // set and parse url
};
extern char *urlencode(const char *s, bool strict = false);
struct packetqueue