uri_get session cookie support
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4974 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
6f49a392f8
commit
5e11342ee2
1 changed files with 200 additions and 17 deletions
|
@ -278,6 +278,139 @@ It doesn't use persistant connections.
|
|||
|
||||
*/
|
||||
|
||||
#define COOKIECOOKIECOOKIE
|
||||
typedef struct cookie_s
|
||||
{
|
||||
struct cookie_s *next;
|
||||
char *domain;
|
||||
int secure;
|
||||
char *name;
|
||||
char *value;
|
||||
} cookie_t;
|
||||
cookie_t *cookies;
|
||||
|
||||
//set a specific cookie.
|
||||
void Cookie_Feed(char *domain, int secure, char *name, char *value)
|
||||
{
|
||||
cookie_t **link, *c;
|
||||
for(link = &cookies; c = *link; link = &(*link)->next)
|
||||
{
|
||||
if (!strcmp(c->domain, domain) && c->secure == secure && !strcmp(c->name, name))
|
||||
break;
|
||||
}
|
||||
//delete it, if it exists, so we can create it anew.
|
||||
if (c)
|
||||
{
|
||||
*link = c->next;
|
||||
Z_Free(c);
|
||||
}
|
||||
if (!value || !*value)
|
||||
{
|
||||
// Con_Printf("Deleting cookie http%s://%s/ %s\n", secure?"s":"", domain, name);
|
||||
//no new value, hurrah.
|
||||
return;
|
||||
}
|
||||
// Con_Printf("Setting cookie http%s://%s/ %s=%s\n", secure?"s":"", domain, name, value);
|
||||
c = Z_Malloc(sizeof(*c) + strlen(domain) + strlen(name) + strlen(value) + 3);
|
||||
c->domain = (char*)(c+1);
|
||||
strcpy(c->domain, domain);
|
||||
c->secure = secure;
|
||||
c->name = c->domain+strlen(c->domain)+1;
|
||||
strcpy(c->name, name);
|
||||
c->value = c->name+strlen(c->name)+1;
|
||||
strcpy(c->value, value);
|
||||
c->next = cookies;
|
||||
cookies = c;
|
||||
}
|
||||
|
||||
//just removes all the cookies it can.
|
||||
void Cookie_Monster(void)
|
||||
{
|
||||
cookie_t *c;
|
||||
while (cookies)
|
||||
{
|
||||
c = cookies;
|
||||
cookies = c->next;
|
||||
Z_Free(c);
|
||||
}
|
||||
}
|
||||
|
||||
//parses Set-Cookie: THISPARTONLY\r\n
|
||||
//we don't support:
|
||||
//domain) we don't have a list of composite roots, like .co.uk, and thus this wouldn't work very safely anyway. thus we require the exact same host each time
|
||||
//path) I'm going to call this an optimisation feature and not bother with it... hopefully there won't be too many sites that have sub-paths or third-party stuff... gah.
|
||||
//httponly) irrelevant until we support javascript... which we don't.
|
||||
//secure) assumed to be true. https:// vs http:// are thus completely independant. sorry.
|
||||
//expires) gah, parsing time values sucks! plus we don't have persistent storage.
|
||||
void Cookie_Parse(char *domain, int secure, char *line, char *end)
|
||||
{
|
||||
char *e;
|
||||
while (*line == ' ' && line < end)
|
||||
line++;
|
||||
for (e = line; e < end; e++)
|
||||
if (*e == ';')
|
||||
end = e;
|
||||
|
||||
for (e = line; e < end; e++)
|
||||
if (*e == '=')
|
||||
break;
|
||||
|
||||
*e = 0;
|
||||
*end = 0;
|
||||
Cookie_Feed(domain, secure, line, e+1);
|
||||
}
|
||||
//outputs a complete http line: Cookie a=v1; b=v2\r\n
|
||||
void Cookie_Regurgitate(char *domain, int secure, char *buffer, size_t buffersize)
|
||||
{
|
||||
qboolean hascookies = false;
|
||||
cookie_t *c;
|
||||
char *l = buffer;
|
||||
buffersize -= 3; //\r\n\0
|
||||
*buffer = 0;
|
||||
for (c = cookies; c; c = c->next)
|
||||
{
|
||||
if (!strcmp(c->domain, domain) && c->secure == secure)
|
||||
{
|
||||
int nlen,vlen;
|
||||
if (!hascookies)
|
||||
{
|
||||
if (buffersize < 8)
|
||||
break;
|
||||
strcpy(buffer, "Cookie: ");
|
||||
buffersize -= 8;
|
||||
hascookies=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buffersize < 2)
|
||||
break;
|
||||
strcpy(buffer, "; ");
|
||||
buffersize -= 2;
|
||||
}
|
||||
buffer += strlen(buffer);
|
||||
|
||||
nlen = strlen(c->name);
|
||||
vlen = strlen(c->value);
|
||||
|
||||
if (buffersize < nlen+1+vlen)
|
||||
break;
|
||||
memcpy(buffer, c->name, nlen);
|
||||
buffer += nlen;
|
||||
*buffer++ = '=';
|
||||
memcpy(buffer, c->value, vlen);
|
||||
buffer += vlen;
|
||||
}
|
||||
}
|
||||
|
||||
if (hascookies)
|
||||
strcpy(buffer, "\r\n");
|
||||
else
|
||||
*buffer = 0;
|
||||
|
||||
// if (*l)
|
||||
// Con_Printf("Sending cookie(s) to http%s://%s/ %s\n", secure?"s":"", domain, l);
|
||||
}
|
||||
|
||||
struct http_dl_ctx_s {
|
||||
// struct dl_download *dlctx;
|
||||
|
||||
|
@ -289,6 +422,9 @@ struct http_dl_ctx_s {
|
|||
|
||||
char *buffer;
|
||||
|
||||
char server[128];
|
||||
qboolean secure;
|
||||
|
||||
size_t bufferused;
|
||||
size_t bufferlen;
|
||||
|
||||
|
@ -407,7 +543,7 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
|
|||
*mimetype = 0;
|
||||
*Location = 0;
|
||||
if (strnicmp(msg, "HTTP/", 5))
|
||||
{ //pre version 1. (lame servers.
|
||||
{ //pre version 1 (lame servers). no response headers at all.
|
||||
con->state = HC_GETTING;
|
||||
dl->status = DL_ACTIVE;
|
||||
con->contentlength = -1; //meaning end of stream.
|
||||
|
@ -415,6 +551,7 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
|
|||
}
|
||||
else
|
||||
{
|
||||
//check if the headers are complete or not
|
||||
qboolean hcomplete = false;
|
||||
while(*msg)
|
||||
{
|
||||
|
@ -440,6 +577,37 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
|
|||
nl = strchr(msg, '\n');
|
||||
if (!nl)
|
||||
break;//not complete, don't bother trying to parse it.
|
||||
msg = nl;
|
||||
}
|
||||
|
||||
if (!hcomplete)
|
||||
break;//headers not complete. break out of switch
|
||||
|
||||
//okay, they're complete, woot. we need to actually go through the headers now
|
||||
msg = con->buffer;
|
||||
while(*msg)
|
||||
{
|
||||
if (*msg == '\n')
|
||||
{
|
||||
if (msg[1] == '\n')
|
||||
{ //tut tut, not '\r'? that's not really allowed...
|
||||
msg+=2;
|
||||
break;
|
||||
}
|
||||
if (msg[1] == '\r' && msg[2] == '\n')
|
||||
{
|
||||
msg+=3;
|
||||
break;
|
||||
}
|
||||
msg++;
|
||||
}
|
||||
while (*msg == ' ' || *msg == '\t')
|
||||
msg++;
|
||||
|
||||
nl = strchr(msg, '\n');
|
||||
if (!nl)
|
||||
break;//not complete, don't bother trying to parse it.
|
||||
|
||||
if (!strnicmp(msg, "Content-Length: ", 16))
|
||||
con->contentlength = atoi(msg+16);
|
||||
else if (!strnicmp(msg, "Content-Type:", 13))
|
||||
|
@ -466,6 +634,10 @@ static qboolean HTTP_DL_Work(struct dl_download *dl)
|
|||
if (chunk < nl)
|
||||
con->chunking = true;
|
||||
}
|
||||
else if (!strnicmp(msg, "Set-Cookie: ", 12))
|
||||
{
|
||||
Cookie_Parse(con->server, con->secure, msg+12, nl);
|
||||
}
|
||||
msg = nl;
|
||||
}
|
||||
if (!hcomplete)
|
||||
|
@ -735,7 +907,7 @@ void HTTPDL_Establish(struct dl_download *dl)
|
|||
struct http_dl_ctx_s *con;
|
||||
qboolean https = false;
|
||||
|
||||
char server[128];
|
||||
char cookies[8192];
|
||||
char uri[MAX_OSPATH];
|
||||
char *slash;
|
||||
const char *url = dl->redir;
|
||||
|
@ -750,21 +922,22 @@ void HTTPDL_Establish(struct dl_download *dl)
|
|||
else if (!strnicmp(url, "http://", 7))
|
||||
url+=7;
|
||||
|
||||
con = malloc(sizeof(*con));
|
||||
memset(con, 0, sizeof(*con));
|
||||
|
||||
slash = strchr(url, '/');
|
||||
if (!slash)
|
||||
{
|
||||
Q_strncpyz(server, url, sizeof(server));
|
||||
Q_strncpyz(con->server, url, sizeof(con->server));
|
||||
Q_strncpyz(uri, "/", sizeof(uri));
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_strncpyz(uri, slash, sizeof(uri));
|
||||
Q_strncpyz(server, url, sizeof(server));
|
||||
server[slash-url] = '\0';
|
||||
Q_strncpyz(con->server, url, sizeof(con->server));
|
||||
con->server[slash-url] = '\0';
|
||||
}
|
||||
|
||||
con = malloc(sizeof(*con));
|
||||
memset(con, 0, sizeof(*con));
|
||||
dl->ctx = con;
|
||||
dl->abort = HTTP_Cleanup;
|
||||
|
||||
|
@ -775,16 +948,18 @@ void HTTPDL_Establish(struct dl_download *dl)
|
|||
{
|
||||
#ifdef HAVE_SSL
|
||||
//https uses port 443 instead of 80 by default
|
||||
con->sock = FS_OpenTCP(server, 443);
|
||||
con->sock = FS_OpenTCP(con->server, 443);
|
||||
//and with an extra ssl/tls layer between tcp and http.
|
||||
con->sock = FS_OpenSSL(server, con->sock, false);
|
||||
con->sock = FS_OpenSSL(con->server, con->sock, false);
|
||||
#else
|
||||
con->sock = NULL;
|
||||
#endif
|
||||
con->secure = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
con->sock = FS_OpenTCP(server, 80);
|
||||
con->sock = FS_OpenTCP(con->server, 80);
|
||||
con->secure = false;
|
||||
}
|
||||
if (!con->sock)
|
||||
{
|
||||
|
@ -792,7 +967,8 @@ void HTTPDL_Establish(struct dl_download *dl)
|
|||
return;
|
||||
}
|
||||
#else
|
||||
if (!NET_StringToSockaddr(server, 80, &serveraddr, &addressfamily, &addresssize))
|
||||
con->secure = false;
|
||||
if (https || !NET_StringToSockaddr(con->server, 80, &serveraddr, &addressfamily, &addresssize))
|
||||
{
|
||||
dl->status = DL_FAILED;
|
||||
return;
|
||||
|
@ -818,13 +994,13 @@ void HTTPDL_Establish(struct dl_download *dl)
|
|||
switch(err)
|
||||
{
|
||||
case NET_EACCES:
|
||||
Con_Printf("HTTP: connect(%s): access denied. Check firewall.\n", server);
|
||||
Con_Printf("HTTP: connect(%s): access denied. Check firewall.\n", con->server);
|
||||
break;
|
||||
case NET_ETIMEDOUT:
|
||||
Con_Printf("HTTP: connect(%s): timed out.\n", server);
|
||||
Con_Printf("HTTP: connect(%s): timed out.\n", con->server);
|
||||
break;
|
||||
default:
|
||||
Con_Printf("HTTP: connect(%s): %s", server, strerror(neterrno()));
|
||||
Con_Printf("HTTP: connect(%s): %s", con->server, strerror(neterrno()));
|
||||
break;
|
||||
}
|
||||
dl->status = DL_FAILED;
|
||||
|
@ -837,12 +1013,14 @@ void HTTPDL_Establish(struct dl_download *dl)
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
Cookie_Regurgitate(con->server, con->secure, cookies, sizeof(cookies));
|
||||
if (dl->postdata)
|
||||
{
|
||||
ExpandBuffer(con, 1024 + strlen(uri) + strlen(server) + strlen(dl->postmimetype) + dl->postlen);
|
||||
ExpandBuffer(con, 1024 + strlen(uri) + strlen(con->server) + strlen(cookies) + strlen(dl->postmimetype) + dl->postlen);
|
||||
Q_snprintfz(con->buffer, con->bufferlen,
|
||||
"POST %s HTTP/1.1\r\n"
|
||||
"Host: %s\r\n"
|
||||
/*Cookie:*/ "%s"
|
||||
"Content-Length: %u\r\n"
|
||||
"Content-Type: %s\r\n"
|
||||
"Connection: close\r\n"
|
||||
|
@ -850,7 +1028,7 @@ void HTTPDL_Establish(struct dl_download *dl)
|
|||
"Accept-Encoding: gzip\r\n"
|
||||
#endif
|
||||
"User-Agent: "FULLENGINENAME"\r\n"
|
||||
"\r\n", uri, server, (unsigned int)dl->postlen, dl->postmimetype);
|
||||
"\r\n", uri, con->server, cookies, (unsigned int)dl->postlen, dl->postmimetype);
|
||||
con->bufferused = strlen(con->buffer);
|
||||
memcpy(con->buffer + con->bufferused, dl->postdata, dl->postlen);
|
||||
con->bufferused += dl->postlen;
|
||||
|
@ -861,12 +1039,13 @@ void HTTPDL_Establish(struct dl_download *dl)
|
|||
Q_snprintfz(con->buffer, con->bufferlen,
|
||||
"GET %s HTTP/1.1\r\n"
|
||||
"Host: %s\r\n"
|
||||
/*Cookie:*/ "%s"
|
||||
"Connection: close\r\n" //theoretically, this is not needed. but as our code will basically do it anyway, it might as well be here FIXME: implement connection reuse.
|
||||
#if !defined(NPFTE) && defined(AVAIL_ZLIB)
|
||||
"Accept-Encoding: gzip\r\n"
|
||||
#endif
|
||||
"User-Agent: "FULLENGINENAME"\r\n"
|
||||
"\r\n", uri, server);
|
||||
"\r\n", uri, con->server, cookies);
|
||||
con->bufferused = strlen(con->buffer);
|
||||
}
|
||||
con->contentlength = -1;
|
||||
|
@ -1338,6 +1517,10 @@ void HTTP_CL_Terminate(void)
|
|||
DL_Close(dl);
|
||||
}
|
||||
HTTP_CL_Think();
|
||||
|
||||
#ifdef COOKIECOOKIECOOKIE
|
||||
Cookie_Monster();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif /*WEBCLIENT*/
|
||||
|
|
Loading…
Reference in a new issue