From 0cfb026c73585061b3e8a09f073e8668f175dc2c Mon Sep 17 00:00:00 2001
From: Paul Fox
Date: Fri, 4 Jan 2019 23:29:16 +1000
Subject: [PATCH] Added a very dodgy HTTP request handler
---
.gitignore | 3 +
src/comms/lorHTTP.cpp | 178 +++++++++++++++++++++++++++--------
src/comms/lorHTTP.h | 9 +-
src/lorMemory.h | 5 +-
src/lorString.h | 29 ++++++
src/lorWindow.cpp | 4 -
tests/src/lorHTTPTests.cpp | 65 +++++++++++++
tests/src/lorStringTests.cpp | 3 +
8 files changed, 245 insertions(+), 51 deletions(-)
create mode 100644 tests/src/lorHTTPTests.cpp
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));