diff --git a/.gitignore b/.gitignore index da29782..c8626bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ /intermediate/ /builds/ *.vcxproj* +*.sln +*.VC.* +*.suo diff --git a/src/comms/lorHTTP.cpp b/src/comms/lorHTTP.cpp index 302063f..fe0f7aa 100644 --- a/src/comms/lorHTTP.cpp +++ b/src/comms/lorHTTP.cpp @@ -2,49 +2,145 @@ #include "lorPlatform.h" #include -//#include "curl/curl.h" +#include "lorSocket.h" -void lorAuth_Init() +bool lorHTTP_Request(const char **ppResponse, const char *pAddress, const char *pPayload /*= nullptr*/) { - //curl_global_init(CURL_GLOBAL_DEFAULT); -} + if (ppResponse == nullptr || pAddress == nullptr) + return false; -void lorAuth_Close() -{ - //curl_global_cleanup(); -} + lorSocket *pSocket = nullptr; + lorSocketConnectionFlags connFlags = lSCFNone; -void lorAuth_Test() -{ - //CURL *curl; - //CURLcode res; - // - //curl = curl_easy_init(); - //if (curl) - //{ - // char buffer[256]; - // lorSprintf(buffer, 256, "tok=getsession&os=%s&ram=%d&cpucores=%d", SDL_GetPlatform(), SDL_GetSystemRAM(), SDL_GetCPUCount()); - // - // curl_easy_setopt(curl, CURLOPT_URL, "https://lorgames.com/pusher/analytics.php"); - // curl_easy_setopt(curl, CURLOPT_POSTFIELDS, buffer); - // - // if(curl_easy_setopt(curl, CURLOPT_CAINFO, ASSETDIR "LORgamesSSLCACertificate.pem") != CURLE_OK) - // lorLog("Bad CA Cert!"); - // - // /* Perform the request, res will get the return code */ - // res = curl_easy_perform(curl); - // - // /* Check for errors */ - // if (res != CURLE_OK) - // { - // lorLog("curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); - // } - // else - // { - // lorLog("Got Message!\n"); - // } - // - // /* always cleanup */ - // curl_easy_cleanup(curl); - //} + char addressBuffer[128]; + int portNumber = 0; + int skipChars = 0; + + *ppResponse = nullptr; + + if (lorStrBeginsWith(pAddress, "http://")) + { + skipChars = 7; + portNumber = 80; + } + else if (lorStrBeginsWith(pAddress, "https://")) + { + skipChars = 8; + connFlags = (connFlags | lSCFUseTLS); + portNumber = 443; + } + + const char *pRelPath = lorStrchr(&pAddress[skipChars], '/'); + const char *pPortStr = lorStrchr(&pAddress[skipChars], ':'); + + // Get port number + if (pPortStr != nullptr && ((pPortStr < pRelPath) || pRelPath == nullptr)) + portNumber = lorStrAtoI(&pPortStr[1]); + + // Get address + if (pPortStr != nullptr && ((pPortStr < pRelPath) || pRelPath == nullptr)) + lorStrncpy(addressBuffer, sizeof(addressBuffer), &pAddress[skipChars], pPortStr - pAddress - skipChars); + else if (pRelPath != nullptr) + lorStrncpy(addressBuffer, sizeof(addressBuffer), &pAddress[skipChars], pRelPath - pAddress - skipChars); + else + lorStrcpy(addressBuffer, sizeof(addressBuffer), &pAddress[skipChars]); + + if (pRelPath == nullptr) + pRelPath = "/"; + + if (lorSocket_Init(&pSocket, addressBuffer, portNumber, connFlags)) + { + bool sent = true; + + const char *msgs[] = { "GET ", "POST ", " HTTP/1.0\r\nHost: ", "\r\nContent-Length: ", "\r\nConnection: close\r\n\r\n" }; + + // Request: + if (pPayload == nullptr) + sent &= lorSocket_SendData(pSocket, (uint8_t*)msgs[0], (uint16_t)lorStrlen(msgs[0])); + else + sent &= lorSocket_SendData(pSocket, (uint8_t*)msgs[1], (uint16_t)lorStrlen(msgs[1])); + sent &= lorSocket_SendData(pSocket, (uint8_t*)pRelPath, (uint16_t)lorStrlen(pRelPath)); + + // Host + sent &= lorSocket_SendData(pSocket, (uint8_t*)msgs[2], (uint16_t)lorStrlen(msgs[2])); + sent &= lorSocket_SendData(pSocket, (uint8_t*)addressBuffer, (uint16_t)lorStrlen(addressBuffer)); + + if (pPayload != nullptr) + { + char contentSize[8]; + lorSprintf(contentSize, sizeof(contentSize), "%zu", lorStrlen(pPayload)); + sent &= lorSocket_SendData(pSocket, (uint8_t*)msgs[3], (uint16_t)lorStrlen(msgs[3])); + sent &= lorSocket_SendData(pSocket, (uint8_t*)contentSize, (uint16_t)lorStrlen(contentSize)); + } + + sent &= lorSocket_SendData(pSocket, (uint8_t*)msgs[4], (uint16_t)lorStrlen(msgs[4])); + + if (pPayload != nullptr) + sent &= lorSocket_SendData(pSocket, (uint8_t*)pPayload, (uint16_t)lorStrlen(pPayload)); + + // Read reply + const uint16_t perReadAmt = 1024; + size_t currentSize = perReadAmt * 4; // *4 to give a bit of a buffer before resizing + char *pReply = lorAllocType(char, currentSize); + size_t totalRead = 0; + + if (sent) + { + int currentRead = 0; + + int failsInARow = 0; + + do + { + currentRead = lorSocket_ReceiveData(pSocket, (uint8_t*)&pReply[totalRead], lorMin(perReadAmt, (uint16_t)(currentSize-totalRead)), true); + if (currentRead > 0) + { + failsInARow = 0; + totalRead += currentRead; + + const char *pData = strstr(pReply, "\r\n\r\n"); + + if (pData != nullptr) // We have a payload + { + const char *pLengthStr = strstr(pReply, "Content-Length: "); + + if (pLengthStr) + { + int expectedLength = lorStrAtoI(&pLengthStr[16]); + if (expectedLength > 0 && totalRead == (uint32_t)(expectedLength + (pData - pReply) + 4)) // +4 = "\r\n\r\n" + break; // We've read everything + } + } + + // Resize the internal buffer + if (totalRead + perReadAmt > currentSize) + { + char *pTempReadBuffer = lorAllocType(char, currentSize+(perReadAmt*2)); + if (pTempReadBuffer) + { + memcpy(pTempReadBuffer, pReply, currentSize); + lorFree(pReply); + pReply = pTempReadBuffer; + currentSize = currentSize + (perReadAmt * 2); + } + } + } + else + { + ++failsInARow; + } + } while (currentRead >= 0 && currentSize-totalRead != 0 && failsInARow < 10); + + pReply[totalRead] = '\0'; + const char *pCpyPoint = strstr(pReply, "\r\n\r\n"); + if (pCpyPoint != nullptr) + *ppResponse = lorStrdup(&pCpyPoint[4]); + } + + lorFree(pReply); + } + + lorSocket_Deinit(&pSocket); + + return (*ppResponse != nullptr); } diff --git a/src/comms/lorHTTP.h b/src/comms/lorHTTP.h index 024240c..1a339c9 100644 --- a/src/comms/lorHTTP.h +++ b/src/comms/lorHTTP.h @@ -1,7 +1,6 @@ -#ifndef LOR_AUTH -#define LOR_AUTH +#ifndef LOR_HTTP +#define LOR_HTTP -void lorAuth_Init(); -void lorAuth_Close(); +bool lorHTTP_Request(const char **ppResponse, const char *pAddress, const char *pPayload = nullptr); -#endif // LOR_AUTH \ No newline at end of file +#endif // LOR_HTTP diff --git a/src/lorMemory.h b/src/lorMemory.h index ffb4692..b5e1948 100644 --- a/src/lorMemory.h +++ b/src/lorMemory.h @@ -27,7 +27,7 @@ inline void* lorAlloc(size_t numBytes, bool zero = true MEMORY_LINEFILE) void* pMemory = malloc(numBytes); #endif - if (zero) + if (zero && pMemory != nullptr) memset(pMemory, 0, numBytes); return pMemory; @@ -37,6 +37,9 @@ inline void* lorAlloc(size_t numBytes, bool zero = true MEMORY_LINEFILE) inline void _lorFree(void *&pPtr) { + if (pPtr == nullptr) + return; + #if TRACK_MEMORY free((char*)pPtr - MemoryPadding); #else diff --git a/src/lorString.h b/src/lorString.h index fdde9ca..57d1c99 100644 --- a/src/lorString.h +++ b/src/lorString.h @@ -63,6 +63,19 @@ inline void lorStrcpy(char *strDestination, size_t destinationSize, const char * strDestination[i] = '\0'; } +inline void lorStrncpy(char *strDestination, size_t destinationSize, const char *strSource, size_t numBytesCopy) +{ + size_t i = 0; + + while (i < destinationSize && i < numBytesCopy && strSource[i] != '\0') + { + strDestination[i] = strSource[i]; + ++i; + } + + strDestination[i] = '\0'; +} + inline void lorStrcat(char *strDestination, size_t destinationSize, const char *strSource) { size_t writePos = strlen(strDestination); @@ -107,6 +120,22 @@ inline bool lorStrEquals(const char *pStrA, const char *pStrB) return result; } +inline bool lorStrBeginsWith(const char *pStrA, const char *pStrB) +{ + const char *pA = (pStrA == nullptr) ? "" : pStrA; + const char *pB = (pStrB == nullptr) ? "" : pStrB; + + bool result = true; + + while (result && *pA++ && *pB++) + result = (*pA == *pB); + + if (*pB == '\0') + return true; + + return result; +} + inline int lorStrAtoI(const char *pStr, int radix = 10) { if (pStr == nullptr || radix < 2 || (size_t)radix > sizeof(radixAlphabet)) diff --git a/src/lorWindow.cpp b/src/lorWindow.cpp index 7fdfaee..7c50202 100644 --- a/src/lorWindow.cpp +++ b/src/lorWindow.cpp @@ -166,8 +166,6 @@ bool lorWindow_Init(lorWindow **ppCore, lorWindowSettings *pAppSettings, uint32_ pCore->now = SDL_GetTicks(); pCore->nextTime = (float)pCore->now + pAppSettings->FrameMilliseconds; - lorAuth_Init(); - pCore->pAppSettings = pAppSettings; SDL_GetWindowSize(pCore->gWindow, &pAppSettings->Width, &pAppSettings->Height); @@ -212,8 +210,6 @@ bool lorWindow_Exit(lorWindow **ppCore) lorGraphicsCore_Destroy(&pCore->pGLCore); lorFree(pCore); - lorAuth_Close(); - if (!lorSocket_DeinitSystem()) return false; diff --git a/tests/src/lorHTTPTests.cpp b/tests/src/lorHTTPTests.cpp new file mode 100644 index 0000000..0e84324 --- /dev/null +++ b/tests/src/lorHTTPTests.cpp @@ -0,0 +1,65 @@ +#include "lorTests.h" +#include "comms/lorSocket.h" +#include "comms/lorHTTP.h" + +#define HTTP_ENDPOINT "http://lorgames.com/dev/unittests/" +#define HTTPS_ENDPOINT "https://lorgames.com/dev/unittests/" + +static const char s_ComodoCert[] = R"pem(-----BEGIN CERTIFICATE----- +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 +LaZRfyHBNVOFBkpdn627G190 +-----END CERTIFICATE-----)pem"; + +TEST(lorHTTP, BasicTests) +{ + ASSERT_TRUE(lorSocket_InitSystem(s_ComodoCert)); + + const char *pResponse = nullptr; + + // HTTP GET TEST + EXPECT_TRUE(lorHTTP_Request(&pResponse, HTTP_ENDPOINT)); + EXPECT_STREQ(pResponse, "TEST SUCCESS") << "HTTP GET FAILED"; + lorFree(pResponse); + + // HTTPS GET TEST + EXPECT_TRUE(lorHTTP_Request(&pResponse, HTTPS_ENDPOINT)); + EXPECT_STREQ(pResponse, "TEST SUCCESS") << "HTTPS GET FAILED"; + lorFree(pResponse); + + // HTTP POST TEST + EXPECT_TRUE(lorHTTP_Request(&pResponse, HTTP_ENDPOINT, "What does the Wolf say?")); + EXPECT_STREQ(pResponse, "POST RECV 23 BYTES") << "HTTP POST FAILED"; + lorFree(pResponse); + + // HTTPS POST TEST + EXPECT_TRUE(lorHTTP_Request(&pResponse, HTTPS_ENDPOINT, "What big glasses you have!")); + EXPECT_STREQ(pResponse, "POST RECV 26 BYTES") << "HTTPS POST FAILED"; + lorFree(pResponse); + + lorSocket_DeinitSystem(); +} diff --git a/tests/src/lorStringTests.cpp b/tests/src/lorStringTests.cpp index 0449786..8a12f75 100644 --- a/tests/src/lorStringTests.cpp +++ b/tests/src/lorStringTests.cpp @@ -16,6 +16,9 @@ TEST(lorString, BasicTests) EXPECT_TRUE(lorStrEquals(helloStr, buffer)); EXPECT_EQ(0, lorStrcmp(helloStr, buffer)); + EXPECT_TRUE(lorStrBeginsWith(fullStr, helloStr)); + EXPECT_FALSE(lorStrBeginsWith(helloStr, extraStr)); + lorStrcat(buffer, sizeof(buffer), " "); lorStrcat(buffer, sizeof(buffer), extraStr); EXPECT_TRUE(lorStrEquals(buffer, fullStr));