mirror of
https://github.com/tribes2/engine.git
synced 2026-01-21 04:04:46 +00:00
320 lines
7.1 KiB
C++
320 lines
7.1 KiB
C++
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// V12 Engine
|
||
|
|
//
|
||
|
|
// Copyright (c) 2001 GarageGames.Com
|
||
|
|
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
#include "Platform/platform.h"
|
||
|
|
#include "console/simBase.h"
|
||
|
|
#include "Platform/event.h"
|
||
|
|
#include "console/consoleInternal.h"
|
||
|
|
#include "game/httpObject.h"
|
||
|
|
#include "Core/fileStream.h"
|
||
|
|
|
||
|
|
IMPLEMENT_CONOBJECT(HTTPObject);
|
||
|
|
|
||
|
|
//--------------------------------------
|
||
|
|
|
||
|
|
HTTPObject::HTTPObject()
|
||
|
|
{
|
||
|
|
mHostName = 0;
|
||
|
|
mPath = 0;
|
||
|
|
mQuery = 0;
|
||
|
|
mPost = 0;
|
||
|
|
mBufferSave = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
HTTPObject::~HTTPObject()
|
||
|
|
{
|
||
|
|
dFree(mHostName);
|
||
|
|
dFree(mPath);
|
||
|
|
dFree(mQuery);
|
||
|
|
dFree(mPost);
|
||
|
|
|
||
|
|
mHostName = 0;
|
||
|
|
mPath = 0;
|
||
|
|
mQuery = 0;
|
||
|
|
mPost = 0;
|
||
|
|
dFree(mBufferSave);
|
||
|
|
}
|
||
|
|
|
||
|
|
//--------------------------------------
|
||
|
|
//--------------------------------------
|
||
|
|
void HTTPObject::get(const char *host, const char *path, const char *query)
|
||
|
|
{
|
||
|
|
if(mHostName)
|
||
|
|
dFree(mHostName);
|
||
|
|
if(mPath)
|
||
|
|
dFree(mPath);
|
||
|
|
if(mQuery)
|
||
|
|
dFree(mQuery);
|
||
|
|
if(mPost)
|
||
|
|
dFree(mPost);
|
||
|
|
if(mBufferSave)
|
||
|
|
dFree(mBufferSave);
|
||
|
|
|
||
|
|
mBufferSave = 0;
|
||
|
|
mHostName = dStrdup(host);
|
||
|
|
mPath = dStrdup(path);
|
||
|
|
if(query)
|
||
|
|
mQuery = dStrdup(query);
|
||
|
|
else
|
||
|
|
mQuery = NULL;
|
||
|
|
mPost = NULL;
|
||
|
|
|
||
|
|
connect(host);
|
||
|
|
}
|
||
|
|
|
||
|
|
void HTTPObject::post(const char *host, const char *path, const char *query, const char *post)
|
||
|
|
{
|
||
|
|
if(mHostName)
|
||
|
|
dFree(mHostName);
|
||
|
|
if(mPath)
|
||
|
|
dFree(mPath);
|
||
|
|
if(mQuery)
|
||
|
|
dFree(mQuery);
|
||
|
|
if(mPost)
|
||
|
|
dFree(mPost);
|
||
|
|
if(mBufferSave)
|
||
|
|
dFree(mBufferSave);
|
||
|
|
|
||
|
|
mBufferSave = 0;
|
||
|
|
mHostName = dStrdup(host);
|
||
|
|
mPath = dStrdup(path);
|
||
|
|
if(query && query[0])
|
||
|
|
mQuery = dStrdup(query);
|
||
|
|
else
|
||
|
|
mQuery = NULL;
|
||
|
|
mPost = dStrdup(post);
|
||
|
|
connect(host);
|
||
|
|
}
|
||
|
|
|
||
|
|
static char getHex(char c)
|
||
|
|
{
|
||
|
|
if(c <= 9)
|
||
|
|
return c + '0';
|
||
|
|
return c - 10 + 'A';
|
||
|
|
}
|
||
|
|
|
||
|
|
static S32 getHexVal(char c)
|
||
|
|
{
|
||
|
|
if(c >= '0' && c <= '9')
|
||
|
|
return c - '0';
|
||
|
|
else if(c >= 'A' && c <= 'Z')
|
||
|
|
return c - 'A' + 10;
|
||
|
|
else if(c >= 'a' && c <= 'z')
|
||
|
|
return c - 'a' + 10;
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
void HTTPObject::expandPath(char *dest, const char *path, U32 destSize)
|
||
|
|
{
|
||
|
|
static bool asciiEscapeTableBuilt = false;
|
||
|
|
static bool asciiEscapeTable[256];
|
||
|
|
if(!asciiEscapeTableBuilt)
|
||
|
|
{
|
||
|
|
asciiEscapeTableBuilt = true;
|
||
|
|
U32 i;
|
||
|
|
for(i = 0; i <= ' '; i++)
|
||
|
|
asciiEscapeTable[i] = true;
|
||
|
|
for(;i <= 0x7F; i++)
|
||
|
|
asciiEscapeTable[i] = false;
|
||
|
|
for(;i <= 0xFF; i++)
|
||
|
|
asciiEscapeTable[i] = true;
|
||
|
|
asciiEscapeTable['\"'] = true;
|
||
|
|
asciiEscapeTable['_'] = true;
|
||
|
|
asciiEscapeTable['\''] = true;
|
||
|
|
asciiEscapeTable['#'] = true;
|
||
|
|
asciiEscapeTable['$'] = true;
|
||
|
|
asciiEscapeTable['%'] = true;
|
||
|
|
asciiEscapeTable['&'] = true;
|
||
|
|
asciiEscapeTable['+'] = true;
|
||
|
|
asciiEscapeTable['-'] = true;
|
||
|
|
asciiEscapeTable['~'] = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
U32 destIndex = 0;
|
||
|
|
U32 srcIndex = 0;
|
||
|
|
while(path[srcIndex] && destIndex < destSize - 3)
|
||
|
|
{
|
||
|
|
char c = path[srcIndex++];
|
||
|
|
if(asciiEscapeTable[c])
|
||
|
|
{
|
||
|
|
dest[destIndex++] = '%';
|
||
|
|
dest[destIndex++] = getHex((c >> 4) & 0xF);
|
||
|
|
dest[destIndex++] = getHex(c & 0xF);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
dest[destIndex++] = c;
|
||
|
|
}
|
||
|
|
dest[destIndex] = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--------------------------------------
|
||
|
|
void HTTPObject::onConnected()
|
||
|
|
{
|
||
|
|
Parent::onConnected();
|
||
|
|
char expPath[8192];
|
||
|
|
char buffer[8192];
|
||
|
|
|
||
|
|
if(mQuery)
|
||
|
|
{
|
||
|
|
dSprintf(buffer, sizeof(buffer), "%s?%s", mPath, mQuery);
|
||
|
|
expandPath(expPath, buffer, sizeof(expPath));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
expandPath(expPath, mPath, sizeof(expPath));
|
||
|
|
|
||
|
|
char *pt = dStrchr(mHostName, ':');
|
||
|
|
if(pt)
|
||
|
|
*pt = 0;
|
||
|
|
dSprintf(buffer, sizeof(buffer), "GET %s HTTP/1.1\r\nHost: %s\r\n\r\n", expPath, mHostName);
|
||
|
|
if(pt)
|
||
|
|
*pt = ':';
|
||
|
|
|
||
|
|
send((U8*)buffer, dStrlen(buffer));
|
||
|
|
mParseState = ParsingStatusLine;
|
||
|
|
mChunkedEncoding = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
void HTTPObject::onConnectFailed()
|
||
|
|
{
|
||
|
|
dFree(mHostName);
|
||
|
|
dFree(mPath);
|
||
|
|
dFree(mQuery);
|
||
|
|
mHostName = 0;
|
||
|
|
mPath = 0;
|
||
|
|
mQuery = 0;
|
||
|
|
Parent::onConnectFailed();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void HTTPObject::onDisconnect()
|
||
|
|
{
|
||
|
|
dFree(mHostName);
|
||
|
|
dFree(mPath);
|
||
|
|
dFree(mQuery);
|
||
|
|
mHostName = 0;
|
||
|
|
mPath = 0;
|
||
|
|
mQuery = 0;
|
||
|
|
Parent::onDisconnect();
|
||
|
|
}
|
||
|
|
|
||
|
|
bool HTTPObject::processLine(U8 *line)
|
||
|
|
{
|
||
|
|
if(mParseState == ParsingStatusLine)
|
||
|
|
{
|
||
|
|
mParseState = ParsingHeader;
|
||
|
|
}
|
||
|
|
else if(mParseState == ParsingHeader)
|
||
|
|
{
|
||
|
|
if(!dStricmp((char *) line, "transfer-encoding: chunked"))
|
||
|
|
mChunkedEncoding = true;
|
||
|
|
if(line[0] == 0)
|
||
|
|
{
|
||
|
|
if(mChunkedEncoding)
|
||
|
|
mParseState = ParsingChunkHeader;
|
||
|
|
else
|
||
|
|
mParseState = ProcessingBody;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if(mParseState == ParsingChunkHeader)
|
||
|
|
{
|
||
|
|
if(line[0]) // strip off the crlf if necessary
|
||
|
|
{
|
||
|
|
mChunkSize = 0;
|
||
|
|
S32 hexVal;
|
||
|
|
while((hexVal = getHexVal(*line++)) != -1)
|
||
|
|
{
|
||
|
|
mChunkSize *= 16;
|
||
|
|
mChunkSize += hexVal;
|
||
|
|
}
|
||
|
|
if(mBufferSave)
|
||
|
|
{
|
||
|
|
mBuffer = mBufferSave;
|
||
|
|
mBufferSize = mBufferSaveSize;
|
||
|
|
mBufferSave = 0;
|
||
|
|
}
|
||
|
|
if(mChunkSize)
|
||
|
|
mParseState = ProcessingBody;
|
||
|
|
else
|
||
|
|
{
|
||
|
|
mParseState = ProcessingDone;
|
||
|
|
finishLastLine();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return Parent::processLine(line);
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
U32 HTTPObject::onDataReceive(U8 *buffer, U32 bufferLen)
|
||
|
|
{
|
||
|
|
U32 start = 0;
|
||
|
|
parseLine(buffer, &start, bufferLen);
|
||
|
|
return start;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--------------------------------------
|
||
|
|
U32 HTTPObject::onReceive(U8 *buffer, U32 bufferLen)
|
||
|
|
{
|
||
|
|
if(mParseState == ProcessingBody)
|
||
|
|
{
|
||
|
|
if(mChunkedEncoding && bufferLen >= mChunkSize)
|
||
|
|
{
|
||
|
|
U32 ret = onDataReceive(buffer, mChunkSize);
|
||
|
|
mChunkSize -= ret;
|
||
|
|
if(mChunkSize == 0)
|
||
|
|
{
|
||
|
|
if(mBuffer)
|
||
|
|
{
|
||
|
|
mBufferSaveSize = mBufferSize;
|
||
|
|
mBufferSave = mBuffer;
|
||
|
|
mBuffer = 0;
|
||
|
|
mBufferSize = 0;
|
||
|
|
}
|
||
|
|
mParseState = ParsingChunkHeader;
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
U32 ret = onDataReceive(buffer, bufferLen);
|
||
|
|
mChunkSize -= ret;
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if(mParseState != ProcessingDone)
|
||
|
|
{
|
||
|
|
U32 start = 0;
|
||
|
|
parseLine(buffer, &start, bufferLen);
|
||
|
|
return start;
|
||
|
|
}
|
||
|
|
return bufferLen;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--------------------------------------
|
||
|
|
static void cHTTPObjectGet(SimObject *obj, S32 argc, const char **argv)
|
||
|
|
{
|
||
|
|
((HTTPObject *) obj)->get(argv[2], argv[3], argc == 4 ? NULL : argv[4]);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void cHTTPObjectPost(SimObject *obj, S32, const char **argv)
|
||
|
|
{
|
||
|
|
((HTTPObject *) obj)->post(argv[2], argv[3], argv[4], argv[5]);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
//--------------------------------------
|
||
|
|
void HTTPObject::consoleInit()
|
||
|
|
{
|
||
|
|
Con::addCommand("HTTPObject", "get", cHTTPObjectGet, "obj.get(addr, request-uri, <query>)", 4, 5);
|
||
|
|
Con::addCommand("HTTPObject", "post", cHTTPObjectPost, "obj.post(addr, request-uri, query, post)", 6, 6);
|
||
|
|
}
|
||
|
|
|