openmohaa/code/gamespy/ghttp/ghttpMain.c
2023-02-04 21:00:01 +01:00

1485 lines
33 KiB
C

/*
GameSpy GHTTP SDK
Dan "Mr. Pants" Schoenblum
dan@gamespy.com
Copyright 1999-2001 GameSpy Industries, Inc
18002 Skypark Circle
Irvine, California 92614
949.798.4200 (Tel)
949.798.4299 (Fax)
devsupport@gamespy.com
*/
#include "ghttpMain.h"
#include "ghttpASCII.h"
#include "ghttpConnection.h"
#include "ghttpCallbacks.h"
#include "ghttpProcess.h"
#include "ghttpPost.h"
#include "ghttpCommon.h"
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Ascii versions which must be available even in the unicode build
GHTTPRequest ghttpGetExA(const char * URL, const char * headers, char * buffer, int bufferSize, GHTTPPost post, GHTTPBool throttle, GHTTPBool blocking, ghttpProgressCallback progressCallback, ghttpCompletedCallback completedCallback, void * param);
GHTTPRequest ghttpSaveExA(const char * URL, const char * filename, const char * headers, GHTTPPost post, GHTTPBool throttle, GHTTPBool blocking, ghttpProgressCallback progressCallback, ghttpCompletedCallback completedCallback, void * param);
GHTTPRequest ghttpStreamExA(const char * URL, const char * headers, GHTTPPost post, GHTTPBool throttle, GHTTPBool blocking, ghttpProgressCallback progressCallback, ghttpCompletedCallback completedCallback, void * param);
GHTTPRequest ghttpHeadExA(const char * URL, const char * headers, GHTTPBool throttle, GHTTPBool blocking, ghttpProgressCallback progressCallback, ghttpCompletedCallback completedCallback, void * param);
GHTTPRequest ghttpPostExA(const char * URL, const char * headers, GHTTPPost post, GHTTPBool throttle, GHTTPBool blocking, ghttpProgressCallback progressCallback, ghttpCompletedCallback completedCallback, void * param);
// Reference count.
///////////////////
static int ghiReferenceCount;
// Called right before callback is called.
// Sets result based on response status code.
/////////////////////////////////////////////
static void ghiHandleStatus
(
GHIConnection * connection
)
{
// Check the status code.
/////////////////////////
switch(connection->statusCode / 100)
{
case 1: // Informational.
return;
case 2: // Successful.
return;
case 3: // Redirection.
return;
case 4: // Client Error.
switch(connection->statusCode)
{
case 401:
connection->result = GHTTPUnauthorized;
break;
case 403:
connection->result = GHTTPForbidden;
break;
case 404:
case 410:
connection->result = GHTTPFileNotFound;
break;
default:
connection->result = GHTTPRequestRejected;
break;
}
return;
case 5: // Internal Server Error.
connection->result = GHTTPServerError;
return;
}
}
// Processes a single connection based on its state.
// Returns true if the connection is finished.
////////////////////////////////////////////////////
static GHTTPBool ghiProcessConnection
(
GHIConnection * connection
)
{
GHTTPBool completed;
assert(connection);
assert(ghiRequestToConnection(connection->request) == connection);
// Don't process if already processing this connection.
// Happens if, for example, ghttpThink is called from a callback.
/////////////////////////////////////////////////////////////////
if(connection->processing)
return GHTTPFalse;
// We're now processing.
////////////////////////
connection->processing = GHTTPTrue;
// Process based on state.
// else-if is not used so that if one ghiDo*()
// finishes the one after it can start.
//////////////////////////////////////////////
if(connection->state == GHTTPSocketInit)
ghiDoSocketInit(connection);
if(connection->state == GHTTPHostLookup)
ghiDoHostLookup(connection);
if(connection->state == GHTTPLookupPending)
ghiDoLookupPending(connection);
if(connection->state == GHTTPConnecting)
ghiDoConnecting(connection);
if(connection->state == GHTTPSecuringSession)
ghiDoSecuringSession(connection);
if(connection->state == GHTTPSendingRequest)
ghiDoSendingRequest(connection);
if(connection->state == GHTTPPosting)
ghiDoPosting(connection);
if(connection->state == GHTTPWaiting)
ghiDoWaiting(connection);
if(connection->state == GHTTPReceivingStatus)
ghiDoReceivingStatus(connection);
if(connection->state == GHTTPReceivingHeaders)
ghiDoReceivingHeaders(connection);
if(connection->state == GHTTPReceivingFile)
ghiDoReceivingFile(connection);
// Check for a redirect.
////////////////////////
if(connection->redirectURL)
ghiRedirectConnection(connection);
// Grab completed before we possibly free it.
/////////////////////////////////////////////
completed = connection->completed;
// Graceful shutdown support.
// Close connection when there is no more data
if (connection->result == GHTTPRequestCancelled && !connection->completed && !CanReceiveOnSocket(connection->socket))
{
connection->completed = GHTTPTrue;
}
// Is it finished?
//////////////////
if(connection->completed)
{
// Set result based on status code.
///////////////////////////////////
ghiHandleStatus(connection);
// If we're saving to file, close it before the callback.
/////////////////////////////////////////////////////////
#ifndef NOFILE
if(connection->saveFile)
{
fclose(connection->saveFile);
connection->saveFile = NULL;
}
#endif
// Log buffer data
ghiLogResponse(connection->getFileBuffer.data, connection->getFileBuffer.len);
// Call the callback.
/////////////////////
ghiCallCompletedCallback(connection);
// Free it.
///////////
ghiFreeConnection(connection);
}
else
{
// Done processing. This is in the else,
// because we don't want to set it if the
// connection has already been freed.
/////////////////////////////////////////
connection->processing = GHTTPFalse;
}
return completed;
}
void ghttpStartup
(
void
)
{
// This will just return if we haven't created the lock yet.
////////////////////////////////////////////////////////////
ghiLock();
// One more startup.
////////////////////
ghiReferenceCount++;
// Check if we are the first.
/////////////////////////////
if(ghiReferenceCount == 1)
{
// Create the lock.
///////////////////
ghiCreateLock();
// Set some defaults.
/////////////////////
ghiThrottleBufferSize = GHI_DEFAULT_THROTTLE_BUFFER_SIZE;
ghiThrottleTimeDelay = GHI_DEFAULT_THROTTLE_TIME_DELAY;
}
else
{
// Unlock the lock.
///////////////////
ghiUnlock();
}
}
void ghttpCleanup
(
void
)
{
// Lockdown for cleanup.
////////////////////////
ghiLock();
// One less.
////////////
ghiReferenceCount--;
// Should we cleanup?
/////////////////////
if(!ghiReferenceCount)
{
// Cleanup the connections.
///////////////////////////
ghiCleanupConnections();
// Cleanup proxy.
/////////////////
if(ghiProxyAddress)
{
gsifree(ghiProxyAddress);
ghiProxyAddress = NULL;
}
// Unlock the lock before freeing it.
/////////////////////////////////////
ghiUnlock();
// Free the lock.
/////////////////
ghiFreeLock();
}
else
{
// Unlock our lock.
///////////////////
ghiUnlock();
}
}
GHTTPRequest ghttpGetA
(
const char * URL,
GHTTPBool blocking,
ghttpCompletedCallback completedCallback,
void * param
)
{
return ghttpGetExA(URL, NULL, NULL, 0, NULL, GHTTPFalse, blocking, NULL, completedCallback, param);
}
#ifdef GSI_UNICODE
GHTTPRequest ghttpGetW
(
const unsigned short * URL,
GHTTPBool blocking,
ghttpCompletedCallback completedCallback,
void * param
)
{
char URL_A[1024];
assert(URL != NULL);
UCS2ToAsciiString(URL, (char*)URL_A);
return ghttpGetA(URL_A, blocking, completedCallback, param);
}
#endif
GHTTPRequest ghttpGetExA
(
const char * URL,
const char * headers,
char * buffer,
int bufferSize,
GHTTPPost post,
GHTTPBool throttle,
GHTTPBool blocking,
ghttpProgressCallback progressCallback,
ghttpCompletedCallback completedCallback,
void * param
)
{
GHTTPBool bResult;
GHIConnection * connection;
assert(URL && URL[0]);
assert(bufferSize >= 0);
assert(!buffer || bufferSize);
// Check args.
//////////////
if(!URL || !URL[0])
return GHTTPInvalidURL;
if(bufferSize < 0)
return GHTTPInvalidBufferSize;
if(buffer && !bufferSize)
return GHTTPInvalidBufferSize;
// Startup if it hasn't been done.
//////////////////////////////////
if(!ghiReferenceCount)
ghttpStartup();
// Get a new connection object.
///////////////////////////////
connection = ghiNewConnection();
if(!connection)
return GHTTPInsufficientMemory;
// Fill in the necessary info.
//////////////////////////////
connection->type = GHIGET;
connection->URL = goastrdup(URL);
if(!connection->URL)
{
ghiFreeConnection(connection);
return GHTTPInsufficientMemory;
}
if(headers && *headers)
{
connection->sendHeaders = goastrdup(headers);
if(!connection->sendHeaders)
{
ghiFreeConnection(connection);
return GHTTPInsufficientMemory;
}
}
connection->post = post;
connection->blocking = blocking;
connection->progressCallback = progressCallback;
connection->completedCallback = completedCallback;
connection->callbackParam = param;
connection->throttle = throttle;
connection->userBufferSupplied = (buffer != NULL)?GHTTPTrue:GHTTPFalse;
if(connection->userBufferSupplied)
bResult = ghiInitFixedBuffer(connection, &connection->getFileBuffer, buffer, bufferSize);
else
bResult = ghiInitBuffer(connection, &connection->getFileBuffer, GET_FILE_BUFFER_INITIAL_SIZE, GET_FILE_BUFFER_INCREMENT_SIZE);
if(!bResult)
{
ghiFreeConnection(connection);
return GHTTPUnspecifiedError;
}
// Setup the post state if needed.
//////////////////////////////////
if(post && !ghiPostInitState(connection))
{
ghiFreeConnection(connection);
return GHTTPInvalidPost;
}
// Check blocking.
//////////////////
if(blocking)
{
// Loop until completed.
////////////////////////
while(!ghiProcessConnection(connection))
msleep(10);
// Done.
////////
return 0;
}
return connection->request;
}
#ifdef GSI_UNICODE
GHTTPRequest ghttpGetExW
(
const unsigned short * URL,
const unsigned short * headers,
char * buffer,
int bufferSize,
GHTTPPost post,
GHTTPBool throttle,
GHTTPBool blocking,
ghttpProgressCallback progressCallback,
ghttpCompletedCallback completedCallback,
void * param
)
{
char URL_A[1024];
char headers_A[1024] = { '\0' };
assert(URL != NULL);
UCS2ToAsciiString(URL, (char*)URL_A);
if (headers != NULL)
UCS2ToAsciiString(headers, headers_A);
return ghttpGetExA((char*)URL_A, (char*)headers_A, buffer, bufferSize, post, throttle, blocking, progressCallback, completedCallback, param);
}
#endif
GHTTPRequest ghttpSaveA
(
const char * URL,
const char * filename,
GHTTPBool blocking,
ghttpCompletedCallback completedCallback,
void * param
)
{
return ghttpSaveExA(URL, filename, NULL, NULL, GHTTPFalse, blocking, NULL, completedCallback, param);
}
#ifdef GSI_UNICODE
GHTTPRequest ghttpSaveW
(
const unsigned short * URL,
const unsigned short * filename,
GHTTPBool blocking,
ghttpCompletedCallback completedCallback,
void * param
)
{
char URL_A[1024] = { '\0' };
char filename_A[1024] = { '\0' };
assert(URL != NULL);
UCS2ToAsciiString(URL, URL_A);
UCS2ToAsciiString(filename, filename_A);
return ghttpSaveA(URL_A, filename_A, blocking, completedCallback, param);
}
#endif
static GHTTPRequest _ghttpSaveEx
(
const char * URL,
const gsi_char * filename,
const char * headers,
GHTTPPost post,
GHTTPBool throttle,
GHTTPBool blocking,
ghttpProgressCallback progressCallback,
ghttpCompletedCallback completedCallback,
void * param
)
{
GHIConnection * connection;
assert(URL && URL[0]);
assert(filename && filename[0]);
// Check args.
//////////////
if(!URL || !URL[0])
return GHTTPInvalidURL;
if(!filename || !filename[0])
return GHTTPInvalidFileName;
// Startup if it hasn't been done.
//////////////////////////////////
if(!ghiReferenceCount)
ghttpStartup();
// Get a new connection object.
///////////////////////////////
connection = ghiNewConnection();
if(!connection)
return GHTTPInsufficientMemory;
// Fill in the necessary info.
//////////////////////////////
connection->type = GHISAVE;
connection->URL = goastrdup(URL);
if(!connection->URL)
{
ghiFreeConnection(connection);
return GHTTPInsufficientMemory;
}
if(headers && *headers)
{
connection->sendHeaders = goastrdup(headers);
if(!connection->sendHeaders)
{
ghiFreeConnection(connection);
return GHTTPInsufficientMemory;
}
}
connection->post = post;
connection->blocking = blocking;
connection->progressCallback = progressCallback;
connection->completedCallback = completedCallback;
connection->callbackParam = param;
connection->throttle = throttle;
// Setup the post state if needed.
//////////////////////////////////
if(post && !ghiPostInitState(connection))
{
ghiFreeConnection(connection);
return GHTTPInvalidPost;
}
// Open the file we're saving to.
/////////////////////////////////
#ifdef NOFILE
connection->saveFile = NULL;
#else
connection->saveFile = _tfopen(filename, _T("wb"));
#endif
if(!connection->saveFile)
{
ghiFreeConnection(connection);
return GHTTPFailedToOpenFile;
}
// Check blocking.
//////////////////
if(blocking)
{
// Loop until completed.
////////////////////////
while(!ghiProcessConnection(connection))
msleep(10);
// Done.
////////
return 0;
}
return connection->request;
}
GHTTPRequest ghttpSaveExA
(
const char * URL,
const char * filename,
const char * headers,
GHTTPPost post,
GHTTPBool throttle,
GHTTPBool blocking,
ghttpProgressCallback progressCallback,
ghttpCompletedCallback completedCallback,
void * param
)
{
#ifdef GSI_UNICODE
unsigned short filename_W[1024];
AsciiToUCS2String(filename, filename_W);
return _ghttpSaveEx(URL, filename_W, headers, post, throttle, blocking, progressCallback, completedCallback, param);
#else
return _ghttpSaveEx(URL, filename, headers, post, throttle, blocking, progressCallback, completedCallback, param);
#endif
}
#ifdef GSI_UNICODE
GHTTPRequest ghttpSaveExW
(
const unsigned short * URL,
const unsigned short * filename,
const unsigned short * headers,
GHTTPPost post,
GHTTPBool throttle,
GHTTPBool blocking,
ghttpProgressCallback progressCallback,
ghttpCompletedCallback completedCallback,
void * param
)
{
char URL_A[1024];
//char filename_A[1024] = { '\0' };
char headers_A[1024] = { '\0' };
assert(URL_A != NULL);
UCS2ToAsciiString(URL, URL_A);
//if (filename != NULL)
// UCS2ToAsciiString(filename, filename_A);
if (headers != NULL)
UCS2ToAsciiString(headers, headers_A);
return _ghttpSaveEx(URL_A, filename, headers_A, post, throttle, blocking, progressCallback, completedCallback, param);
}
#endif
GHTTPRequest ghttpStreamA
(
const char * URL,
GHTTPBool blocking,
ghttpProgressCallback progressCallback,
ghttpCompletedCallback completedCallback,
void * param
)
{
return ghttpStreamExA(URL, NULL, NULL, GHTTPFalse, blocking, progressCallback, completedCallback, param);
}
#ifdef GSI_UNICODE
GHTTPRequest ghttpStreamW
(
const unsigned short * URL,
GHTTPBool blocking,
ghttpProgressCallback progressCallback,
ghttpCompletedCallback completedCallback,
void * param
)
{
char* URL_A = { '\0' };
UCS2ToAsciiString(URL, URL_A);
return ghttpStreamA(URL_A, blocking, progressCallback, completedCallback, param);
}
#endif
GHTTPRequest ghttpStreamExA
(
const char * URL,
const char * headers,
GHTTPPost post,
GHTTPBool throttle,
GHTTPBool blocking,
ghttpProgressCallback progressCallback,
ghttpCompletedCallback completedCallback,
void * param
)
{
GHIConnection * connection;
assert(URL && URL[0]);
// Check args.
//////////////
if(!URL || !URL[0])
return GHTTPInvalidURL;
// Startup if it hasn't been done.
//////////////////////////////////
if(!ghiReferenceCount)
ghttpStartup();
// Get a new connection object.
///////////////////////////////
connection = ghiNewConnection();
if(!connection)
return GHTTPInsufficientMemory;
// Fill in the necessary info.
//////////////////////////////
connection->type = GHISTREAM;
connection->URL = goastrdup(URL);
if(!connection->URL)
{
ghiFreeConnection(connection);
return GHTTPInsufficientMemory;
}
if(headers && *headers)
{
connection->sendHeaders = goastrdup(headers);
if(!connection->sendHeaders)
{
ghiFreeConnection(connection);
return GHTTPInsufficientMemory;
}
}
connection->post = post;
connection->blocking = blocking;
connection->progressCallback = progressCallback;
connection->completedCallback = completedCallback;
connection->callbackParam = param;
connection->throttle = throttle;
// Setup the post state if needed.
//////////////////////////////////
if(post && !ghiPostInitState(connection))
{
ghiFreeConnection(connection);
return GHTTPInvalidPost;
}
// Check blocking.
//////////////////
if(blocking)
{
// Loop until completed.
////////////////////////
while(!ghiProcessConnection(connection))
msleep(10);
// Done.
////////
return 0;
}
return connection->request;
}
#ifdef GSI_UNICODE
GHTTPRequest ghttpStreamExW
(
const unsigned short * URL,
const unsigned short * headers,
GHTTPPost post,
GHTTPBool throttle,
GHTTPBool blocking,
ghttpProgressCallback progressCallback,
ghttpCompletedCallback completedCallback,
void * param
)
{
char URL_A[1024] = {'\0'};
char headers_A[1024] = {'\0'};
UCS2ToAsciiString(URL, URL_A);
if(headers != NULL)
UCS2ToAsciiString(headers, headers_A);
return ghttpStreamExA(URL_A, headers_A, post, throttle, blocking, progressCallback, completedCallback, param);
}
#endif
GHTTPRequest ghttpHeadA
(
const char * URL,
GHTTPBool blocking,
ghttpCompletedCallback completedCallback,
void * param
)
{
return ghttpHeadExA(URL, NULL, GHTTPFalse, blocking, NULL, completedCallback, param);
}
#ifdef GSI_UNICODE
GHTTPRequest ghttpHeadW
(
const unsigned short * URL,
GHTTPBool blocking,
ghttpCompletedCallback completedCallback,
void * param
)
{
char URL_A[1024] = {'\0'};
UCS2ToAsciiString(URL, URL_A);
return ghttpHeadA(URL_A, blocking, completedCallback, param);
}
#endif
GHTTPRequest ghttpHeadExA
(
const char * URL,
const char * headers,
GHTTPBool throttle,
GHTTPBool blocking,
ghttpProgressCallback progressCallback,
ghttpCompletedCallback completedCallback,
void * param
)
{
GHIConnection * connection;
assert(URL && URL[0]);
// Check args.
//////////////
if(!URL || !URL[0])
return GHTTPInvalidURL;
// Startup if it hasn't been done.
//////////////////////////////////
if(!ghiReferenceCount)
ghttpStartup();
// Get a new connection object.
///////////////////////////////
connection = ghiNewConnection();
if(!connection)
return GHTTPInsufficientMemory;
// Fill in the necessary info.
//////////////////////////////
connection->type = GHIHEAD;
connection->URL = goastrdup(URL);
if(!connection->URL)
{
ghiFreeConnection(connection);
return GHTTPInsufficientMemory;
}
if(headers && *headers)
{
connection->sendHeaders = goastrdup(headers);
if(!connection->sendHeaders)
{
ghiFreeConnection(connection);
return GHTTPInsufficientMemory;
}
}
connection->blocking = blocking;
connection->progressCallback = progressCallback;
connection->completedCallback = completedCallback;
connection->callbackParam = param;
connection->throttle = throttle;
// Check blocking.
//////////////////
if(blocking)
{
// Loop until completed.
////////////////////////
while(!ghiProcessConnection(connection))
msleep(10);
// Done.
////////
return 0;
}
return connection->request;
}
#ifdef GSI_UNICODE
GHTTPRequest ghttpHeadExW
(
const unsigned short * URL,
const unsigned short * headers,
GHTTPBool throttle,
GHTTPBool blocking,
ghttpProgressCallback progressCallback,
ghttpCompletedCallback completedCallback,
void * param
)
{
char URL_A[1024] = {'\0'};
char headers_A[1024] = {'\0'};
if (URL != NULL)
UCS2ToAsciiString(URL, URL_A);
if (headers != NULL)
UCS2ToAsciiString(headers, headers_A);
return ghttpHeadExA(URL_A, headers_A, throttle, blocking, progressCallback, completedCallback, param);
}
#endif
GHTTPRequest ghttpPostA
(
const char * URL,
GHTTPPost post,
GHTTPBool blocking,
ghttpCompletedCallback completedCallback,
void * param
)
{
return ghttpPostExA(URL, NULL, post, GHTTPFalse, blocking, NULL, completedCallback, param);
}
#ifdef GSI_UNICODE
GHTTPRequest ghttpPostW
(
const unsigned short * URL,
GHTTPPost post,
GHTTPBool blocking,
ghttpCompletedCallback completedCallback,
void * param
)
{
char URL_A[1024] = {'\0'};
UCS2ToAsciiString(URL, URL_A);
return ghttpPostA(URL_A, post, blocking, completedCallback, param);
}
#endif
GHTTPRequest ghttpPostExA
(
const char * URL,
const char * headers,
GHTTPPost post,
GHTTPBool throttle,
GHTTPBool blocking,
ghttpProgressCallback progressCallback,
ghttpCompletedCallback completedCallback,
void * param
)
{
GHIConnection * connection;
assert(URL && URL[0]);
assert(post);
// Check args.
//////////////
if(!URL || !URL[0])
return GHTTPInvalidURL;
if(!post)
return GHTTPInvalidPost;
// Startup if it hasn't been done.
//////////////////////////////////
if(!ghiReferenceCount)
ghttpStartup();
// Get a new connection object.
///////////////////////////////
connection = ghiNewConnection();
if(!connection)
return GHTTPInsufficientMemory;
// Fill in the necessary info.
//////////////////////////////
connection->type = GHIPOST;
connection->URL = goastrdup(URL);
if(!connection->URL)
{
ghiFreeConnection(connection);
return GHTTPInsufficientMemory;
}
if(headers && *headers)
{
connection->sendHeaders = goastrdup(headers);
if(!connection->sendHeaders)
{
ghiFreeConnection(connection);
return GHTTPInsufficientMemory;
}
}
connection->post = post;
connection->blocking = blocking;
connection->progressCallback = progressCallback;
connection->completedCallback = completedCallback;
connection->callbackParam = param;
connection->throttle = throttle;
// Setup the post state if needed.
//////////////////////////////////
if(post && !ghiPostInitState(connection))
{
ghiFreeConnection(connection);
return GHTTPInvalidPost;
}
// Check blocking.
//////////////////
if(blocking)
{
// Loop until completed.
////////////////////////
while(!ghiProcessConnection(connection))
msleep(10);
// Done.
////////
return 0;
}
return connection->request;
}
#ifdef GSI_UNICODE
GHTTPRequest ghttpPostExW
(
const unsigned short * URL,
const unsigned short * headers,
GHTTPPost post,
GHTTPBool throttle,
GHTTPBool blocking,
ghttpProgressCallback progressCallback,
ghttpCompletedCallback completedCallback,
void * param
)
{
char URL_A[1024] = {'\0'};
char headers_A[1024] = {'\0'};
UCS2ToAsciiString(URL, URL_A);
if (headers != NULL)
UCS2ToAsciiString(headers, headers_A);
return ghttpPostExA(URL_A, headers_A, post, throttle, blocking, progressCallback, completedCallback, param);
}
#endif
void ghttpThink
(
void
)
{
// Process all the connections.
///////////////////////////////
ghiEnumConnections(ghiProcessConnection);
}
GHTTPBool ghttpRequestThink
(
GHTTPRequest request
)
{
GHIConnection * connection;
// Get the connection object for this request.
//////////////////////////////////////////////
connection = ghiRequestToConnection(request);
if(!connection)
return GHTTPFalse;
// Think.
/////////
ghiProcessConnection(connection);
return GHTTPTrue;
}
void ghttpCancelRequest
(
GHTTPRequest request
)
{
GHIConnection * connection;
// Get the connection object for this request.
//////////////////////////////////////////////
connection = ghiRequestToConnection(request);
if(!connection)
return;
// Free it.
///////////
ghiFreeConnection(connection);
}
#if !defined(INSOCK)
// INSOCK does not support partial shutdown
void ghttpCloseRequest
(
GHTTPRequest request
)
{
GHIConnection * connection;
connection = ghiRequestToConnection(request);
if (!connection)
return;
if (connection->socket)
{
// Gracefully close the connection
// SDK will dispatch a "request cancelled" callback when all data
// has been received
shutdown(connection->socket, 1);
connection->result = GHTTPRequestCancelled;
}
}
#endif
GHTTPState ghttpGetState
(
GHTTPRequest request
)
{
GHIConnection * connection;
// Get the connection object for this request.
//////////////////////////////////////////////
connection = ghiRequestToConnection(request);
if(!connection)
return (GHTTPState)0;
return connection->state;
}
const char * ghttpGetResponseStatus
(
GHTTPRequest request,
int * statusCode
)
{
GHIConnection * connection;
// Get the connection object for this request.
//////////////////////////////////////////////
connection = ghiRequestToConnection(request);
if(!connection)
return NULL;
// Check if we don't have the status yet.
/////////////////////////////////////////
if(connection->state <= GHTTPReceivingStatus)
return NULL;
// Set the status code.
///////////////////////
if(statusCode)
*statusCode = connection->statusCode;
return (connection->recvBuffer.data + connection->statusStringIndex);
}
const char * ghttpGetHeaders
(
GHTTPRequest request
)
{
GHIConnection * connection;
// Get the connection object for this request.
//////////////////////////////////////////////
connection = ghiRequestToConnection(request);
if(!connection)
return NULL;
// Check if we don't have the headers yet.
//////////////////////////////////////////
if(connection->state < GHTTPReceivingHeaders)
return NULL;
// Verify we have headers.
//////////////////////////
if(connection->headerStringIndex >= connection->recvBuffer.len)
return NULL;
return (connection->recvBuffer.data + connection->headerStringIndex);
}
const char * ghttpGetURL
(
GHTTPRequest request
)
{
GHIConnection * connection;
// Get the connection object for this request.
//////////////////////////////////////////////
connection = ghiRequestToConnection(request);
if(!connection)
return NULL;
return connection->URL;
}
GHTTPBool ghttpSetProxy
(
const char * server
)
{
return ghiSetProxy(server);
}
GHTTPBool ghttpSetRequestProxy
(
GHTTPRequest request,
const char * server
)
{
return ghiSetRequestProxy(request, server);
}
void ghttpSetThrottle
(
GHTTPRequest request,
GHTTPBool throttle
)
{
GHIConnection * connection;
// Get the connection object for this request.
//////////////////////////////////////////////
connection = ghiRequestToConnection(request);
if(!connection)
return;
connection->throttle = throttle;
// Set the buffer size based on the throttle setting.
/////////////////////////////////////////////////////
if(connection->socket != INVALID_SOCKET)
SetReceiveBufferSize(connection->socket, throttle?ghiThrottleBufferSize:(8 * 1024));
}
void ghttpThrottleSettings
(
int bufferSize,
gsi_time timeDelay
)
{
ghiThrottleSettings(bufferSize, timeDelay);
}
void ghttpSetMaxRecvTime
(
GHTTPRequest request,
gsi_time maxRecvTime
)
{
GHIConnection* connection = ghiRequestToConnection(request);
if (connection == NULL)
return;
connection->maxRecvTime = maxRecvTime;
}
// Internal prototypes for persistent HTTP connections
// Prevents warnings from strict compilers
//////////////////////////////////////////////////////
SOCKET ghttpGetSocket(GHTTPRequest request);
GHTTPBool ghttpReuseSocket(GHTTPRequest request, SOCKET socket);
// For use in persistent HTTP connections
// Call this in the completed callback to obtain the socket, which can be used with
// ghttpReuseSocket to make a second request to the same host
///////////////////////////////////////////////////////////////////
SOCKET ghttpGetSocket
(
GHTTPRequest request
)
{
GHIConnection * connection;
SOCKET ret;
// Get the connection object for this request.
//////////////////////////////////////////////
connection = ghiRequestToConnection(request);
if(!connection)
return INVALID_SOCKET;
// Only allow them to grab the socket during the competion callback (not while a request is in process)
/////////////////////////////////////////////////////////
if (!connection->completed)
return INVALID_SOCKET;
ret = connection->socket;
// Mark the connection as invalid so that it doesn't get closed
connection->socket = INVALID_SOCKET;
return ret;
}
// For use in persistent HTTP connections
// Call this after creating a request, but before calling think the first time in order to reuse
// an existing connection to the same server
// If the socket passed is INVALID_SOCKET, a new connection will be created and marked as persistent
///////////////////////////////////////////////////////////////////
GHTTPBool ghttpReuseSocket
(
GHTTPRequest request,
SOCKET socket
)
{
GHIConnection * connection;
// Get the connection object for this request.
//////////////////////////////////////////////
connection = ghiRequestToConnection(request);
if(!connection)
return GHTTPFalse;
if (connection->state != GHTTPSocketInit)
return GHTTPFalse;
if (connection->socket != INVALID_SOCKET)
return GHTTPFalse;
connection->persistConnection = GHTTPTrue;
connection->socket = socket;
/*
if (socket == INVALID_SOCKET)
{
// The connection is marked as persistent, but we still need to lookup and connect, so don't advance the state
/////////////////////////////////////////////////////////////////////
return GHTTPTrue;
}
// Skip the host lookup & connect - send data once the socket is writable
//////////////////////////////////////////////
connection->state = GHTTPConnecting;
*/
return GHTTPTrue;
}
GHTTPPost ghttpNewPost
(
void
)
{
return ghiNewPost();
}
void ghttpPostSetAutoFree
(
GHTTPPost post,
GHTTPBool autoFree
)
{
assert(post);
if(!post)
return;
ghiPostSetAutoFree(post, autoFree);
}
void ghttpFreePost
(
GHTTPPost post
)
{
assert(post);
if(!post)
return;
ghiFreePost(post);
}
GHTTPBool ghttpPostAddStringA
(
GHTTPPost post,
const char * name,
const char * string
)
{
assert(post);
assert(name && name[0]);
if(!post)
return GHTTPFalse;
if(!name || !name[0])
return GHTTPFalse;
if(!string)
string = "";
return ghiPostAddString(post, name, string);
}
#ifdef GSI_UNICODE
GHTTPBool ghttpPostAddStringW
(
GHTTPPost post,
const unsigned short * name,
const unsigned short * string
)
{
char name_A[1024] = {'\0'};
char string_A[1024] = {'\0'};
if (name != NULL)
UCS2ToAsciiString(name, name_A);
if (string != NULL)
UCS2ToAsciiString(string, string_A);
return ghttpPostAddStringA(post, name_A, string_A);
}
#endif
GHTTPBool ghttpPostAddFileFromDiskA
(
GHTTPPost post,
const char * name,
const char * filename,
const char * reportFilename,
const char * contentType
)
{
assert(post);
assert(name && name[0]);
assert(filename && filename[0]);
if(!post)
return GHTTPFalse;
if(!name || !name[0])
return GHTTPFalse;
if(!filename || !filename[0])
return GHTTPFalse;
if(!reportFilename || !reportFilename[0])
reportFilename = filename;
if(!contentType)
contentType = "application/octet-stream";
return ghiPostAddFileFromDisk(post, name, filename, reportFilename, contentType);
}
#ifdef GSI_UNICODE
GHTTPBool ghttpPostAddFileFromDiskW
(
GHTTPPost post,
const unsigned short * name,
const unsigned short * filename,
const unsigned short * reportFilename,
const unsigned short * contentType
)
{
char name_A[1024] = {'\0'};
char filename_A[1024] = {'\0'};
char reportFilename_A[1024] = {'\0'};
char contentType_A[1024] = {'\0'};
if (name != NULL) UCS2ToAsciiString(name, name_A);
if (filename != NULL) UCS2ToAsciiString(filename, filename_A);
if (reportFilename != NULL) UCS2ToAsciiString(reportFilename, reportFilename_A);
if (contentType != NULL) UCS2ToAsciiString(contentType, contentType_A);
return ghttpPostAddFileFromDiskA(post, name_A, filename_A, reportFilename_A, contentType_A);
}
#endif
GHTTPBool ghttpPostAddFileFromMemoryA
(
GHTTPPost post,
const char * name,
const char * buffer,
int bufferLen,
const char * reportFilename,
const char * contentType
)
{
assert(post);
assert(name && name[0]);
assert(bufferLen >= 0);
#ifdef _DEBUG
if(bufferLen > 0)
assert(buffer);
#endif
assert(reportFilename && reportFilename[0]);
if(!post)
return GHTTPFalse;
if(!name || !name[0])
return GHTTPFalse;
if(bufferLen < 0)
return GHTTPFalse;
if(!bufferLen && !buffer)
return GHTTPFalse;
if(!contentType)
contentType = "application/octet-stream";
return ghiPostAddFileFromMemory(post, name, buffer, bufferLen, reportFilename, contentType);
}
#ifdef GSI_UNICODE
GHTTPBool ghttpPostAddFileFromMemoryW
(
GHTTPPost post,
const unsigned short * name,
const char * buffer,
int bufferLen,
const unsigned short * reportFilename,
const unsigned short * contentType
)
{
char name_A[1024] = { '\0' };
char reportFilename_A[1024] = { '\0' };
char contentType_A[1024] = { '\0' };
if (name != NULL)
UCS2ToAsciiString(name, name_A);
if (reportFilename != NULL)
UCS2ToAsciiString(reportFilename, reportFilename_A);
if (contentType != NULL)
UCS2ToAsciiString(contentType, contentType_A);
return ghttpPostAddFileFromMemoryA(post, name_A, buffer, bufferLen, reportFilename_A, contentType_A);
GSI_UNUSED(reportFilename);
GSI_UNUSED(contentType);
}
#endif
GHTTPBool ghttpPostAddXml
(
GHTTPPost post,
GSXmlStreamWriter soap
)
{
GS_ASSERT(post != NULL);
GS_ASSERT(soap != NULL);
return ghiPostAddXml(post, soap);
}
void ghttpPostSetCallback
(
GHTTPPost post,
ghttpPostCallback callback,
void * param
)
{
assert(post);
if(!post)
return;
ghiPostSetCallback(post, callback, param);
}