241 lines
5.5 KiB
C++
241 lines
5.5 KiB
C++
#include "http/http.h"
|
|
#include "tier1/interface.h"
|
|
#include "tier1/utlstring.h"
|
|
#include "netdb.h"
|
|
#include "unistd.h"
|
|
#include "fcntl.h"
|
|
#include "openssl/ssl.h"
|
|
#include "openssl/err.h"
|
|
|
|
abstract_class CHTTPClient: public IHTTPClient
|
|
{
|
|
public:
|
|
virtual void Post( const char *szResource, HTTPHeader_t *pHeader, uint32_t uDataSize, const char *data ) override;
|
|
virtual void Get( const char *szResource, HTTPHeader_t *pHeader ) override;
|
|
virtual HTTPResponse_t GetResponse() override;
|
|
|
|
HTTPResponse_t ParseResponse( const char *szMessage );
|
|
const char *GetVersion();
|
|
|
|
const char *m_szHostName;
|
|
bool m_bIsSecure;
|
|
SSL *m_pSSL;
|
|
SSL_CTX *m_pSSLCtx;
|
|
|
|
int m_iFileDescriptor;
|
|
};
|
|
|
|
void CHTTPClient::Post( const char *szResource, HTTPHeader_t *pHeader, uint32_t uDataSize, const char *data )
|
|
{
|
|
|
|
}
|
|
|
|
void CHTTPClient::Get( const char *szResource, HTTPHeader_t *pHeader )
|
|
{
|
|
if (pHeader == NULL)
|
|
return;
|
|
|
|
CUtlString szMessage = CUtlString(
|
|
"GET %s HTTP/%s\r\n",
|
|
szResource, GetVersion());
|
|
CUtlString szHeader = CUtlString(
|
|
"Host: %s\r\n",
|
|
m_szHostName
|
|
);
|
|
|
|
CUtlString szCombined;
|
|
int i = 0;
|
|
|
|
for ( i = 0; i < pHeader->m_nParamCount; i++ )
|
|
{
|
|
szHeader.AppendTail(CUtlString("%s: %s\r\n", pHeader->m_params[i].m_szParamName, pHeader->m_params[i].m_szValue));
|
|
}
|
|
|
|
szCombined = szMessage;
|
|
szCombined.AppendTail(szHeader);
|
|
szCombined.AppendTail("\r\n");
|
|
|
|
if (m_bIsSecure)
|
|
SSL_write(m_pSSL, szCombined.GetString(), szCombined.GetLenght());
|
|
else
|
|
write(m_iFileDescriptor, szCombined.GetString(), szCombined.GetLenght());
|
|
}
|
|
|
|
HTTPResponse_t CHTTPClient::GetResponse()
|
|
{
|
|
CUtlResizableBuffer<char> szCharBuffer(0);
|
|
char response[4096];
|
|
int n;
|
|
int nPreviousSize = 0;
|
|
|
|
if (m_bIsSecure)
|
|
{
|
|
secureRead:
|
|
n = SSL_read(m_pSSL, response, sizeof(response));
|
|
szCharBuffer.Resize(nPreviousSize+n);
|
|
V_memcpy((char*)szCharBuffer.GetMemory()+nPreviousSize, response, n);
|
|
nPreviousSize += n;
|
|
if (SSL_pending(m_pSSL)>0)
|
|
goto secureRead;
|
|
}
|
|
else {
|
|
httpRead:
|
|
n = read(m_iFileDescriptor, response, sizeof(response));
|
|
V_printf("%i\n",n);
|
|
szCharBuffer.Resize(nPreviousSize+n+1);
|
|
szCharBuffer[nPreviousSize+n] = 0;
|
|
V_memcpy((char*)szCharBuffer.GetMemory()+nPreviousSize, response, n);
|
|
nPreviousSize += n;
|
|
goto httpRead;
|
|
}
|
|
|
|
|
|
szCharBuffer.Resize(n+1);
|
|
return ParseResponse(szCharBuffer);
|
|
}
|
|
|
|
HTTPResponse_t CHTTPClient::ParseResponse( const char *szMessage )
|
|
{
|
|
char cPreviousCharacter = 0;
|
|
char cCurrentCharacter = 0;
|
|
const char *pcCurrentCharacter = szMessage;
|
|
CUtlString szBuffer = "";
|
|
bool bIsMessage = true;
|
|
HTTPResponse_t response = {};
|
|
CUtlVector<HTTPHeaderParam_t> headers = {};
|
|
CUtlBuffer<char> data = {};
|
|
// Parse header
|
|
while (*pcCurrentCharacter)
|
|
{
|
|
cCurrentCharacter = *pcCurrentCharacter;
|
|
if ( cPreviousCharacter == '\r')
|
|
{
|
|
if ( cCurrentCharacter == '\n')
|
|
{
|
|
if (bIsMessage)
|
|
{
|
|
uint32_t uResult = 0;
|
|
V_sscanf(szBuffer, "HTTP/1.1 %i", &uResult);
|
|
response.m_uCode = uResult;
|
|
}
|
|
bIsMessage = false;
|
|
if (szBuffer == "")
|
|
break;
|
|
szBuffer = "";
|
|
cPreviousCharacter = 0;
|
|
cCurrentCharacter = *pcCurrentCharacter++;
|
|
continue;
|
|
}
|
|
}
|
|
if (cPreviousCharacter != 0)
|
|
szBuffer.AppendTail(cPreviousCharacter);
|
|
pcCurrentCharacter++;
|
|
|
|
cPreviousCharacter = cCurrentCharacter;
|
|
};
|
|
pcCurrentCharacter++;
|
|
uint32_t nDataLen = V_strlen(pcCurrentCharacter);
|
|
data = CUtlBuffer<char>(nDataLen+1);
|
|
V_strcpy(data.GetMemory(), pcCurrentCharacter);
|
|
data[nDataLen] = 0;
|
|
response.m_message = data;
|
|
|
|
return response;
|
|
}
|
|
|
|
const char *CHTTPClient::GetVersion()
|
|
{
|
|
|
|
return "1.1";
|
|
}
|
|
abstract_class CHTTPClientManager: public IHTTPClientManager
|
|
{
|
|
public:
|
|
CHTTPClientManager();
|
|
virtual IHTTPClient *Connect( const char *szUrl, bool bSecure ) override;
|
|
virtual void Disconnect( IHTTPClient *szConnection ) override;
|
|
};
|
|
|
|
IHTTPClient *CHTTPClientManager::Connect( const char *szUrl, bool bSecure )
|
|
{
|
|
struct hostent *pServerHostName = NULL;
|
|
struct sockaddr_in serverAddress;
|
|
int fd = 0;
|
|
int err;
|
|
CHTTPClient *pClient;
|
|
SSL_CTX *ctx;
|
|
SSL *ssl;
|
|
|
|
pServerHostName = gethostbyname(szUrl);
|
|
if (!pServerHostName)
|
|
return NULL;
|
|
|
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
if ( fd < 0 )
|
|
return NULL;
|
|
|
|
V_memset(&serverAddress, 0, sizeof(serverAddress));
|
|
serverAddress.sin_family = AF_INET;
|
|
V_memcpy(&serverAddress.sin_addr.s_addr, pServerHostName->h_addr, pServerHostName->h_length);
|
|
|
|
// https
|
|
if ( bSecure )
|
|
serverAddress.sin_port = htons(443);
|
|
else
|
|
serverAddress.sin_port = htons(80);
|
|
|
|
err = connect(fd, (struct sockaddr *)&serverAddress, sizeof(serverAddress));
|
|
if (err < 0)
|
|
return NULL;
|
|
|
|
if (bSecure)
|
|
{
|
|
ctx = SSL_CTX_new(TLS_client_method());
|
|
if (!ctx)
|
|
return NULL;
|
|
ssl =SSL_new(ctx);
|
|
if (!ssl)
|
|
return NULL;
|
|
|
|
SSL_set_fd(ssl, fd);
|
|
SSL_set_tlsext_host_name(ssl, szUrl);
|
|
|
|
int r = SSL_connect(ssl);
|
|
if (r <= 0)
|
|
{
|
|
ERR_print_errors_fp(stdout);
|
|
SSL_free(ssl);
|
|
SSL_CTX_free(ctx);
|
|
return NULL;
|
|
}
|
|
};
|
|
|
|
pClient = new CHTTPClient();
|
|
pClient->m_iFileDescriptor = fd;
|
|
pClient->m_szHostName = szUrl;
|
|
if (bSecure)
|
|
{
|
|
pClient->m_bIsSecure = bSecure;
|
|
pClient->m_pSSL = ssl;
|
|
pClient->m_pSSLCtx = ctx;
|
|
}
|
|
return pClient;
|
|
}
|
|
|
|
void CHTTPClientManager::Disconnect( IHTTPClient *pClient )
|
|
{
|
|
CHTTPClient *pC = (CHTTPClient*)pClient;
|
|
close(pC->m_iFileDescriptor);
|
|
}
|
|
|
|
CHTTPClientManager::CHTTPClientManager()
|
|
{
|
|
SSL_library_init();
|
|
SSL_load_error_strings();
|
|
OpenSSL_add_all_algorithms();
|
|
}
|
|
|
|
|
|
CHTTPClientManager s_HttpClientManager;
|
|
EXPOSE_INTERFACE_GLOBALVAR(IHTTPClientManager, CHTTPClientManager, HTTP_CLIENT_INTERFACE_VERSION, s_HttpClientManager);
|