tge/engine/game/net/httpObject.cc
2017-04-17 06:17:10 -06:00

310 lines
7.1 KiB
C++
Executable File

//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "game/net/httpObject.h"
#include "platform/platform.h"
#include "platform/event.h"
#include "core/fileStream.h"
#include "console/simBase.h"
#include "console/consoleInternal.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;
}
//--------------------------------------
ConsoleMethod( HTTPObject, get, void, 4, 5, "(TransportAddress addr, string requirstURI, string query=NULL)")
{
object->get(argv[2], argv[3], argc == 4 ? NULL : argv[4]);
}
ConsoleMethod( HTTPObject, post, void, 6, 6, "(TransportAddress addr, string requestURI, string query, string post)")
{
object->post(argv[2], argv[3], argv[4], argv[5]);
}