Kawe Mazidjatari b3a68ed095 Add EABase, EAThread and DirtySDK to R5sdk
DirtySDK (EA's Dirty Sockets library) will be used for the LiveAPI implementation, and depends on: EABase, EAThread.
2024-04-05 18:29:03 +02:00

905 lines
28 KiB
C

/*H********************************************************************************/
/*!
\File httpserv.c
\Description
Implements basic http server using ProtoHttpServ
\Copyright
Copyright (c) 2012 Electronic Arts Inc.
\Version 09/11/2012 (jbrookes) First Version
*/
/********************************************************************************H*/
/*** Include files ****************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#ifdef __linux__
#include <sys/time.h> // gettimeofday
#endif
#include "DirtySDK/platform.h"
#include "DirtySDK/dirtysock.h"
#include "DirtySDK/dirtyvers.h"
#include "DirtySDK/dirtysock/netconn.h" // NetConnSleep
#include "DirtySDK/proto/protossl.h"
#include "DirtySDK/proto/protohttpserv.h"
#include "libsample/zlib.h"
#include "libsample/zmem.h"
#include "libsample/zfile.h"
#include "testermodules.h"
/*** Defines **********************************************************************/
#define HTTPSERV_RATE (1)
#define HTTPSERV_LISTENPORT (9000)
/*** Function Prototypes **********************************************************/
/*** Type Definitions *************************************************************/
typedef struct HttpServT
{
ProtoHttpServRefT *pHttpServ;
char *pServerCert;
int32_t iServerCertLen;
char *pServerKey;
int32_t iServerKeyLen;
int32_t iChunkLen;
char strServerName[128];
char strFileDir[512];
} HttpServT;
/*** Variables ********************************************************************/
static HttpServT _HttpServ_Ref;
static uint8_t _HttpServ_bInitialized = FALSE;
//! map of filename extensions to content-types
static const char *_ProtoHttpServ_strContentTypes[][2] =
{
{ ".htm", "text/html" },
{ ".html", "text/html" },
{ ".css", "text/css" },
{ ".xml", "text/xml" },
{ ".jpg", "image/jpeg" },
{ ".gif", "image/gif" },
{ ".png", "image/png" },
{ ".mp3", "audio/mpeg" }
};
/*** Private Functions ************************************************************/
/*F********************************************************************************/
/*!
\Function _GetIntArg
\Description
Get fourcc/integer from command-line argument
\Input *pArg - pointer to argument
\Version 10/20/2011 (jbrookes)
*/
/********************************************************************************F*/
static int32_t _GetIntArg(const char *pArg)
{
int32_t iValue;
// check for possible fourcc value
if ((strlen(pArg) == 4) && (isalpha(pArg[0]) || isalpha(pArg[1]) || isalpha(pArg[2]) || isalpha(pArg[3])))
{
iValue = pArg[0] << 24;
iValue |= pArg[1] << 16;
iValue |= pArg[2] << 8;
iValue |= pArg[3];
}
else
{
iValue = (signed)strtol(pArg, NULL, 10);
}
return(iValue);
}
/*F********************************************************************************/
/*!
\Function _HttpServGetCurrentTime
\Description
Gets and parses the current time into components
\Input *uYear - pointer to uint32_t var to store 'year' in
\Input *uMonth - pointer to uint8_t var to store 'month' in
\Input *uDay - pointer to uint8_t var to store 'day' in
\Input *uHour - pointer to uint8_t var to store 'hour' in
\Input *uMin - pointer to uint8_t var to store 'min' in
\Input *uSec - pointer to uint8_t var to store 'sec' in
\Input *uMillis - pointer to uint32_t var to store 'milliseconds' in
\Version 10/30/2013 (jbrookes) Borrowed from eafn logger
*/
/********************************************************************************F*/
static void _HttpServGetCurrentTime(uint32_t *uYear, uint8_t *uMonth, uint8_t *uDay, uint8_t *uHour, uint8_t *uMin, uint8_t *uSec, uint32_t *uMillis)
{
#if DIRTYCODE_PC
SYSTEMTIME SystemTime;
GetLocalTime(&SystemTime);
*uYear = SystemTime.wYear;
*uMonth = SystemTime.wMonth;
*uDay = SystemTime.wDay;
*uHour = SystemTime.wHour;
*uMin = SystemTime.wMinute;
*uSec = SystemTime.wSecond;
*uMillis = SystemTime.wMilliseconds;
#else // all non-pc
#if DIRTYCODE_LINUX
struct timeval tv;
struct tm *pTime;
gettimeofday(&tv, NULL);
pTime = gmtime((time_t *)&tv.tv_sec);
*uMillis = tv.tv_usec / 1000;
#else
//$$TODO: plat-time doesn't have anything to get millis
struct tm TmTime, *pTime;
pTime = ds_secstotime(&TmTime, ds_timeinsecs());
*uMillis = 0;
#endif
*uYear = 1900 + pTime->tm_year;
*uMonth = pTime->tm_mon + 1;
*uDay = pTime->tm_mday;
*uHour = pTime->tm_hour;
*uMin = pTime->tm_min;
*uSec = pTime->tm_sec;
#endif // !DIRTYCODE_PC
}
/*F********************************************************************************/
/*!
\Function _HttpServGetContentType
\Description
Get content-type based on target url
\Input *strUrl - full url including file
\Output
const char * - content type
\Version 07/09/2013 (jbrookes)
*/
/********************************************************************************F*/
static const char *_HttpServGetContentType(const char *strUrl)
{
const char *pContentType = _ProtoHttpServ_strContentTypes[0][1];
int32_t iType;
for (iType = 0; iType < (signed)(sizeof(_ProtoHttpServ_strContentTypes)/sizeof(_ProtoHttpServ_strContentTypes[0])); iType += 1)
{
if (ds_stristr(strUrl, _ProtoHttpServ_strContentTypes[iType][0]))
{
pContentType = _ProtoHttpServ_strContentTypes[iType][1];
break;
}
}
return(pContentType);
}
/*F********************************************************************************/
/*!
\Function _HttpServLoadCertificate
\Description
Load pem certificate file and trim begin/end text.
\Input *pFilename - name of certificate file to open
\Input *pCertSize - [out] storage for size of certificate
\Output
const char * - certificate data
\Version 10/11/2013 (jbrookes)
*/
/********************************************************************************F*/
static char *_HttpServLoadCertificate(const char *pFilename, int32_t *pCertSize)
{
char *pCertBuf;
int32_t iFileSize;
// load certificate file
if ((pCertBuf = (char *)ZFileLoad(pFilename, &iFileSize, ZFILE_OPENFLAG_RDONLY)) == NULL)
{
return(NULL);
}
// set size and return buffer to caller
*pCertSize = iFileSize;
return(pCertBuf);
}
/*F********************************************************************************/
/*!
\Function _HttpServProcessGet
\Description
Process GET/HEAD request
\Input *pServerState - module state
\Input *pRequest - request information
\Input *pResponse - [out] response information
\Output
int32_t - response code
\Version 12/12/2012 (jbrookes)
*/
/********************************************************************************F*/
static int32_t _HttpServProcessGet(HttpServT *pServerState, const ProtoHttpServRequestT *pRequest, ProtoHttpServResponseT *pResponse)
{
const char* pHdr = pRequest->strHeader;
char strFilePath[4096], strName[128], strValue[4*1024];
ZFileStatT FileStat;
int32_t iFileLen, iResult;
ZFileT iFileId;
uint32_t uModifiedSince = 0, uUnmodifiedSince = 0;
struct tm TmTime;
char strTime[64];
// if empty url, substitute default
if (*(pRequest->strUrl+1) == '\0')
{
ds_snzprintf(strFilePath, sizeof(strFilePath), "%s/index.html", pServerState->strFileDir, pRequest->strUrl + 1);
}
else
{
ds_snzprintf(strFilePath, sizeof(strFilePath), "%s/%s", pServerState->strFileDir, pRequest->strUrl + 1);
}
// stat the file
if ((iResult = ZFileStat(strFilePath, &FileStat)) != ZFILE_ERROR_NONE)
{
// no file
ZPrintf("httpserv: could not stat file '%s'\n", strFilePath);
pResponse->eResponseCode = PROTOHTTP_RESPONSE_NOTFOUND;
return(-1);
}
// see if url refers to a file
if ((iFileId = ZFileOpen(strFilePath, ZFILE_OPENFLAG_RDONLY|ZFILE_OPENFLAG_BINARY)) == ZFILE_INVALID)
{
ZPrintf("httpserv: could not open file '%s' for reading\n", strFilePath);
pResponse->eResponseCode = PROTOHTTP_RESPONSE_INTERNALSERVERERROR;
return(-2);
}
// get the file size
if ((iFileLen = (int32_t)ZFileSize(iFileId)) < 0)
{
ZPrintf("httpserv: error %d getting file size\n", iFileLen);
pResponse->eResponseCode = PROTOHTTP_RESPONSE_INTERNALSERVERERROR;
return(-3);
}
// parse the header for request specific data
while (ProtoHttpGetNextHeader(NULL, pHdr, strName, sizeof(strName), strValue, sizeof(strValue), &pHdr) == 0)
{
if (ds_stricmp(strName, "if-modified-since") == 0)
{
uModifiedSince = (uint32_t)ds_strtotime(strValue);
}
else if (ds_stricmp(strName, "if-unmodified-since") == 0)
{
uUnmodifiedSince = (uint32_t)ds_strtotime(strValue);
}
}
if (uModifiedSince != 0 && ((int32_t)(FileStat.uTimeModify-uModifiedSince) <= 0))
{
pResponse->eResponseCode = PROTOHTTP_RESPONSE_NOTMODIFIED;
ZPrintf("httpserv: file not modified (%d-%d=%d)\n", uModifiedSince, FileStat.uTimeModify,
(int32_t)(FileStat.uTimeModify-uModifiedSince));
return(0);
}
if (uUnmodifiedSince != 0 && ((int32_t)(FileStat.uTimeModify-uUnmodifiedSince) > 0))
{
ZPrintf("httpserv: file modified since (%d-%d=%d)\n", uUnmodifiedSince, FileStat.uTimeModify,
(int32_t)(FileStat.uTimeModify-uUnmodifiedSince));
pResponse->eResponseCode = PROTOHTTP_RESPONSE_PRECONFAILED;
return(-4);
}
// set last modified time
ds_secstotime(&TmTime, FileStat.uTimeModify);
pResponse->iHeaderLen += ds_snzprintf(pResponse->strHeader, sizeof(pResponse->strHeader)-pResponse->iHeaderLen, "Last-Modified: %s\r\n",
ds_timetostr(&TmTime, TIMETOSTRING_CONVERSION_RFC_0822, FALSE, strTime, sizeof(strTime)));
// set content-type
ds_strnzcpy(pResponse->strContentType, _HttpServGetContentType(pRequest->strUrl), sizeof(pResponse->strContentType));
// set request info
pResponse->iContentLength = iFileLen;
pResponse->iChunkLength = pServerState->iChunkLen;
pResponse->pData = (void *)iFileId;
pResponse->eResponseCode = PROTOHTTP_RESPONSE_OK;
return(0);
}
/*F********************************************************************************/
/*!
\Function _HttpServProcessPut
\Description
Process PUT/POST request
\Input *pServerState - module state
\Input *pRequest - request information
\Input *pResponse - [out] response information
\Output
int32_t - response code
\Version 12/12/2012 (jbrookes)
*/
/********************************************************************************F*/
static int32_t _HttpServProcessPut(HttpServT *pServerState, const ProtoHttpServRequestT *pRequest, ProtoHttpServResponseT *pResponse)
{
ZFileT iFileId = (ZFileT)(uintptr_t)pRequest->pData;
if (iFileId == 0 || iFileId == ZFILE_INVALID)
{
pResponse->eResponseCode = PROTOHTTP_RESPONSE_INTERNALSERVERERROR;
return(-1);
}
// we've processed the request
pResponse->pData = (void *)(uintptr_t)iFileId;
pResponse->eResponseCode = PROTOHTTP_RESPONSE_CREATED;
return(0);
}
/*F********************************************************************************/
/*!
\Function _HttpServRequestCb
\Description
ProtoHttpServ request callback handler
\Input *pRequest - request information
\Input *pResponse - [out] response information
\Input *pUserData - callback user data
\Output
int32_t - response code
\Version 12/12/2012 (jbrookes)
*/
/********************************************************************************F*/
static int32_t _HttpServRequestCb(ProtoHttpServRequestT *pRequest, ProtoHttpServResponseT *pResponse, void *pUserData)
{
HttpServT *pServerState = (HttpServT *)pUserData;
int32_t iResult = -1;
// init default response values
pResponse->eResponseCode = PROTOHTTP_RESPONSE_NOTIMPLEMENTED;
// handle the request
if ((pRequest->eRequestType == PROTOHTTP_REQUESTTYPE_GET) || (pRequest->eRequestType == PROTOHTTP_REQUESTTYPE_HEAD))
{
iResult = _HttpServProcessGet(pServerState, pRequest, pResponse);
}
if ((pRequest->eRequestType == PROTOHTTP_REQUESTTYPE_PUT) || (pRequest->eRequestType == PROTOHTTP_REQUESTTYPE_PATCH) || (pRequest->eRequestType == PROTOHTTP_REQUESTTYPE_POST))
{
iResult = _HttpServProcessPut(pServerState, pRequest, pResponse);
}
// return result to caller
return(iResult);
}
/*F********************************************************************************/
/*!
\Function _HttpServReceiveCb
\Description
ProtoHttpServ inbound data callback handler
\Input *pServerState- module state
\Input *pBuffer - data to write
\Input iBufSize - size of the data
\Input *pUserData - user data
\Output
int32_t - negative=failure, else bytes written
\Version 12/12/2012 (jbrookes)
*/
/********************************************************************************F*/
static int32_t _HttpServReceiveCb(ProtoHttpServRequestT *pRequest, const char *pBuffer, int32_t iBufSize, void *pUserData)
{
ZFileT iFileId = (ZFileT)(uintptr_t)pRequest->pData;
int32_t iResult = 0;
// if the file failed to load previously or
// not the correct request type
// then early out
if (iFileId == ZFILE_INVALID)
{
return(-1);
}
if (pRequest->eRequestType != PROTOHTTP_REQUESTTYPE_POST && pRequest->eRequestType != PROTOHTTP_REQUESTTYPE_PUT && pRequest->eRequestType != PROTOHTTP_REQUESTTYPE_PATCH)
{
return(iBufSize);
}
// check for upload completion
if (pBuffer == NULL)
{
ZFileClose(iFileId);
}
else if ((iResult = ZFileWrite(iFileId, (void *)pBuffer, iBufSize)) < 0)
{
NetPrintf(("httpserv: error %d writing to file\n", iResult));
}
// return result
return(iResult);
}
/*F********************************************************************************/
/*!
\Function _HttpServHeaderCb
\Description
ProtoHttpServ inbound data callback handler
\Input *pRequest - [in/out] data used to process the request
\Input *pResponse - [out] data used to send the response
\Input *pUserData - user data
\Output
int32_t - negative=failure, zero=success
*/
/********************************************************************************F*/
static int32_t _HttpServHeaderCb(ProtoHttpServRequestT *pRequest, ProtoHttpServResponseT *pResponse, void *pUserData)
{
HttpServT *pServerState = (HttpServT *)pUserData;
char strFilePath[1024];
ZFileT iFileId = ZFILE_INVALID;
if (pRequest->eRequestType == PROTOHTTP_REQUESTTYPE_POST ||
pRequest->eRequestType == PROTOHTTP_REQUESTTYPE_PUT ||
pRequest->eRequestType == PROTOHTTP_REQUESTTYPE_PATCH)
{
// create filepath
ds_snzprintf(strFilePath, sizeof(strFilePath), "%s\\%s", pServerState->strFileDir, pRequest->strUrl + 1);
// try to open the file
if ((iFileId = ZFileOpen(strFilePath, ZFILE_OPENFLAG_WRONLY | ZFILE_OPENFLAG_BINARY)) == ZFILE_INVALID)
{
ZPrintf("httpserv: could not open file '%s' for writing\n", strFilePath);
pResponse->eResponseCode = PROTOHTTP_RESPONSE_INTERNALSERVERERROR;
return(-1);
}
}
// set the file id for use during receiving/sending
pRequest->pData = (void *)(uintptr_t)iFileId;
return(0);
}
/*F********************************************************************************/
/*!
\Function _HttpServSendCb
\Description
ProtoHttpServ outbound callback handler
\Input *pServerState - module state
\Input *pBuffer - data to write to
\Input iBufSize - size of the data
\Input *pUserData - user data
\Output
int32_t - positive=success, zero=in progress, negative=failure
\Version 12/12/2012 (jbrookes)
*/
/********************************************************************************F*/
static int32_t _HttpServSendCb(ProtoHttpServResponseT *pResponse, char *pBuffer, int32_t iBufSize, void *pUserData)
{
//HttpServT *pServerState = (HttpServT *)pUserData;
ZFileT iFileId = (ZFileT)(uintptr_t)pResponse->pData;
int32_t iResult = 0;
if (iFileId == ZFILE_INVALID)
{
return(0);
}
// check for download completion
if (pBuffer == NULL)
{
ZFileClose(iFileId);
}
else if ((iResult = ZFileRead(iFileId, pBuffer, iBufSize)) < 0)
{
ZPrintf("httpserv: error %d reading from file\n", iResult);
}
// return result
return(iResult);
}
/*F********************************************************************************/
/*!
\Function _HttpServLogCb
\Description
ProtoHttpServ logging function
\Input *pText - text to print
\Input *pUserData - user data (module state)
\Output
int32_t - zero
\Version 12/12/2012 (jbrookes)
*/
/********************************************************************************F*/
static void _HttpServLogCb(const char *pText, void *pUserData)
{
uint32_t uYear, uMillis;
uint8_t uMonth, uDay, uHour, uMin, uSec;
// format prefix to output buffer
_HttpServGetCurrentTime(&uYear, &uMonth, &uDay, &uHour, &uMin, &uSec, &uMillis);
ZPrintf("%02u/%02u/%02u %02u:%02u:%02u.%03u %s", uYear, uMonth, uDay, uHour, uMin, uSec, uMillis, pText);
}
/*F********************************************************************************/
/*!
\Function _CmdHttpServIdleCB
\Description
Callback to process while idle
\Input *argz -
\Input argc -
\Input *argv[] -
\Output int32_t -
\Version 09/26/2007 (jbrookes)
*/
/********************************************************************************F*/
static int32_t _CmdHttpServIdleCB(ZContext *argz, int32_t argc, char *argv[])
{
HttpServT *pRef = &_HttpServ_Ref;
// shut down?
if (argc == 0)
{
if (pRef->pHttpServ != NULL)
{
ProtoHttpServDestroy(pRef->pHttpServ);
pRef->pHttpServ = NULL;
}
return(0);
}
// httpserv destroyed?
if (pRef->pHttpServ == NULL)
{
return(0);
}
// update protohttpserv module
ProtoHttpServUpdate(pRef->pHttpServ);
// keep on idling
return(ZCallback(&_CmdHttpServIdleCB, HTTPSERV_RATE));
}
/*F********************************************************************************/
/*!
\Function _CmdHttpServUsage
\Description
Display usage information.
\Input argc - argument count
\Input *argv[] - argument list
\Version 09/13/2012 (jbrookes)
*/
/********************************************************************************F*/
static void _CmdHttpServUsage(int argc, char *argv[])
{
if (argc <= 2)
{
ZPrintf("httpserv: basic http server\n");
ZPrintf("httpserv: usage: %s [alpn|cert|chunked|ciph|filedir|listen|setcert|setkey|stop|vers|vmin]", argv[0]);
}
else if (argc == 3)
{
if (!strcmp(argv[2], "alpn"))
{
ZPrintf("httpserv: usage: %s alpn [alpnstr]\n", argv[0]);
}
if (!strcmp(argv[2], "ccrt"))
{
ZPrintf("httpserv: usage: %s ccrt [level]\n", argv[0]);
}
else if (!strcmp(argv[2], "cert"))
{
ZPrintf("httpserv: usage: %s cert [cacertfile]\n", argv[0]);
}
else if (!strcmp(argv[2], "chunked"))
{
ZPrintf("httpserv: usage: %s chunked [chunklen]\n", argv[0]);
}
else if (!strcmp(argv[2], "ciph"))
{
ZPrintf("httpserv: usage: %s ciph [ciphers]\n", argv[0]);
}
else if (!strcmp(argv[2], "filedir"))
{
ZPrintf("httpserv: usage: %s filedir <directory>\n", argv[0]);
}
else if (!strcmp(argv[2], "listen"))
{
ZPrintf("httpserv: usage: %s listen [listenport] <secure>\n", argv[0]);
}
else if (!strcmp(argv[2], "setcert"))
{
ZPrintf("httpserv: usage: %s setcert [certfile]\n", argv[0]);
}
else if (!strcmp(argv[2], "setkey"))
{
ZPrintf("httpserv: usage: %s setkey [certkey]\n", argv[0]);
}
else if (!strcmp(argv[2], "stop"))
{
ZPrintf("httpserv: usage: %s stop\n", argv[0]);
}
else if (!strcmp(argv[2], "vers"))
{
ZPrintf("httpserv: usage: %s vers [version]\n", argv[0]);
}
else if (!strcmp(argv[2], "vmin"))
{
ZPrintf("httpserv: usage: %s vmin [version]\n", argv[0]);
}
}
}
/*** Public Functions *************************************************************/
/*F********************************************************************************/
/*!
\Function CmdHttpServ
\Description
Simple HTTP server
\Input *argz - context
\Input argc - command count
\Input *argv[] - command arguments
\Output int32_t -
\Version 09/11/2012 (jbrookes)
*/
/********************************************************************************F*/
int32_t CmdHttpServ(ZContext *argz, int32_t argc, char *argv[])
{
HttpServT *pServerState = &_HttpServ_Ref;
int32_t iResult = 0;
if ((argc < 2) || !ds_stricmp(argv[1], "help"))
{
_CmdHttpServUsage(argc, argv);
return(iResult);
}
// if not initialized yet, do so now
if (_HttpServ_bInitialized == FALSE)
{
ds_memclr(pServerState, sizeof(*pServerState));
ds_strnzcpy(pServerState->strServerName, "HttpServ", sizeof(pServerState->strServerName));
ds_strnzcpy(pServerState->strFileDir, "c:\\temp\\httpserv", sizeof(pServerState->strFileDir));
_HttpServ_bInitialized = TRUE;
}
// check for filedir set
if ((argc == 3) && !ds_stricmp(argv[1], "filedir"))
{
ds_strnzcpy(pServerState->strFileDir, argv[2], sizeof(pServerState->strFileDir));
return(iResult);
}
// check for listen
if ((argc >= 2) && (argc < 5) && !ds_stricmp(argv[1], "listen"))
{
int32_t iPort = HTTPSERV_LISTENPORT;
int32_t iSecure = 0; // insecure by default
if ((argc > 3) && !ds_stricmp(argv[3], "secure"))
{
iSecure = 1;
}
if (argc > 2)
{
iPort = (int32_t)strtol(argv[2], NULL, 10);
if ((iPort < 1) || (iPort > 65535))
{
ZPrintf("httpserv: invalid port %d specified in listen request\n", iPort);
return(-1);
}
}
// destroy previous httpserv ref, if any
if (pServerState->pHttpServ != NULL)
{
ProtoHttpServDestroy(pServerState->pHttpServ);
}
// create new httpserv ref
if ((pServerState->pHttpServ = ProtoHttpServCreate(iPort, iSecure, pServerState->strServerName)) == NULL)
{
ZPrintf("httpserv: could not create httpserv state on port %d\n", iPort);
return(-2);
}
// set up httpserv callbacks
ProtoHttpServCallback(pServerState->pHttpServ, _HttpServRequestCb, _HttpServReceiveCb, _HttpServSendCb, _HttpServHeaderCb, _HttpServLogCb, pServerState);
// install recurring update
iResult = ZCallback(_CmdHttpServIdleCB, HTTPSERV_RATE);
}
// the following functions require http serv state
if (pServerState->pHttpServ == NULL)
{
ZPrintf("%s: '%s' requires httpserv creation (use 'listen' command)\n", argv[0], argv[1]);
return(iResult);
}
// check for server stop
if ((argc == 2) && !ds_stricmp(argv[1], "stop"))
{
ProtoHttpServDestroy(pServerState->pHttpServ);
pServerState->pHttpServ = NULL;
ZPrintf("httpserv: protohttpserv stopped listening\n");
}
// check for setting alpn
if ((argc == 3) && !ds_stricmp(argv[1], "alpn"))
{
return(ProtoHttpServControl(pServerState->pHttpServ, 'alpn', 0, 0, argv[2]));
}
// check for client cert level specification
if ((argc == 3) && !ds_stricmp(argv[1], "ccrt"))
{
return(ProtoHttpServControl(pServerState->pHttpServ, 'ccrt', (int32_t)strtol(argv[2], NULL, 10), 0, NULL));
}
// check for cacert load
if ((argc == 3) && !ds_stricmp(argv[1], "cert"))
{
const uint8_t *pFileData;
int32_t iFileSize;
// try and open file
if ((pFileData = (const uint8_t *)ZFileLoad(argv[2], &iFileSize, ZFILE_OPENFLAG_RDONLY|ZFILE_OPENFLAG_BINARY)) != NULL)
{
iResult = ProtoSSLSetCACert(pFileData, iFileSize);
ZMemFree((void *)pFileData);
}
else
{
ZPrintf("%s: unable to load certificate file '%s'\n", argv[0], argv[2]);
}
return((iResult > 0) ? 0 : -1);
}
// check for chunked transfer (download) enable
if ((argc >= 2) && !ds_stricmp(argv[1], "chunked"))
{
int32_t iChunkLen = 4096;
if (argc > 2)
{
iChunkLen = (int32_t)strtol(argv[2], NULL, 10);
}
ZPrintf("httpserv: enabling chunked transfers and setting chunk size to %d\n", iChunkLen);
pServerState->iChunkLen = iChunkLen;
return(iResult);
}
// check for cipher set
if ((argc == 3) && !ds_stricmp(argv[1], "ciph"))
{
return(ProtoHttpServControl(pServerState->pHttpServ, 'ciph', (int32_t)strtol(argv[2], NULL, 16), 0, NULL));
}
// check for server certificate
if ((argc == 3) && !ds_stricmp(argv[1], "setcert"))
{
if ((pServerState->pServerCert = _HttpServLoadCertificate(argv[2], &pServerState->iServerCertLen)) != NULL)
{
iResult = ProtoHttpServControl(pServerState->pHttpServ, 'scrt', pServerState->iServerCertLen, 0, pServerState->pServerCert);
}
else
{
ZPrintf("%s: could not load certificate '%s'\n", argv[0], argv[2]);
iResult = -1;
}
return(iResult);
}
// check for server private key
if ((argc == 3) && !ds_stricmp(argv[1], "setkey"))
{
if ((pServerState->pServerKey = _HttpServLoadCertificate(argv[2], &pServerState->iServerKeyLen)) != NULL)
{
iResult = ProtoHttpServControl(pServerState->pHttpServ, 'skey', pServerState->iServerKeyLen, 0, pServerState->pServerKey);
}
else
{
ZPrintf("httpserv: could not load private key '%s'\n", argv[2]);
iResult = -1;
}
return(iResult);
}
// check for version set
if ((argc == 3) && !ds_stricmp(argv[1], "vers"))
{
return(ProtoHttpServControl(pServerState->pHttpServ, 'vers', (int32_t)strtol(argv[2], NULL, 16), 0, NULL));
}
// check for min version set
if ((argc == 3) && !ds_stricmp(argv[1], "vmin"))
{
return(ProtoHttpServControl(pServerState->pHttpServ, 'vmin', (int32_t)strtol(argv[2], NULL, 16), 0, NULL));
}
// check for control
if ((argc > 3) && (!ds_stricmp(argv[1], "ctrl")))
{
int32_t iCmd, iThread, iValue = 0, iValue2 = 0;
const char *pValue = NULL;
iCmd = _GetIntArg(argv[2]);
iThread = _GetIntArg(argv[3]);
if (argc > 4)
{
iValue = _GetIntArg(argv[3]);
}
if (argc > 5)
{
iValue2 = _GetIntArg(argv[4]);
}
if (argc > 6)
{
pValue = argv[5];
}
return(ProtoHttpServControl2(pServerState->pHttpServ, iThread, iCmd, iValue, iValue2, (void *)pValue));
}
return(iResult);
}