mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-27 16:07:22 +00:00
190 lines
4.6 KiB
C++
190 lines
4.6 KiB
C++
|
/// \file
|
||
|
/// \brief Contains HTTPConnection, used to communicate with web servers
|
||
|
///
|
||
|
/// This file is part of RakNet Copyright 2008 Kevin Jenkins.
|
||
|
///
|
||
|
/// Usage of RakNet is subject to the appropriate license agreement.
|
||
|
/// Creative Commons Licensees are subject to the
|
||
|
/// license found at
|
||
|
/// http://creativecommons.org/licenses/by-nc/2.5/
|
||
|
/// Single application licensees are subject to the license found at
|
||
|
/// http://www.jenkinssoftware.com/SingleApplicationLicense.html
|
||
|
/// Custom license users are subject to the terms therein.
|
||
|
/// GPL license users are subject to the GNU General Public
|
||
|
/// License as published by the Free
|
||
|
/// Software Foundation; either version 2 of the License, or (at your
|
||
|
/// option) any later version.
|
||
|
|
||
|
#include "TCPInterface.h"
|
||
|
#include "HTTPConnection.h"
|
||
|
#include "RakSleep.h"
|
||
|
#include "RakString.h"
|
||
|
#include "RakAssert.h"
|
||
|
#include <string.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
using namespace RakNet;
|
||
|
|
||
|
HTTPConnection::HTTPConnection(TCPInterface& _tcp, const char *_host, unsigned short _port)
|
||
|
: tcp(_tcp), host(_host), port(_port), state(RAK_HTTP_INITIAL) {}
|
||
|
|
||
|
void HTTPConnection::Post(const char *remote_path, const char *data, const char *_contentType)
|
||
|
{
|
||
|
if(state == RAK_HTTP_IDLE)
|
||
|
state = RAK_HTTP_ESTABLISHED;
|
||
|
else if(state == RAK_HTTP_INITIAL)
|
||
|
state = RAK_HTTP_STARTING;
|
||
|
else
|
||
|
return;
|
||
|
|
||
|
outgoing = data;
|
||
|
path = remote_path;
|
||
|
contentType=_contentType;
|
||
|
|
||
|
incoming.Clear();
|
||
|
}
|
||
|
|
||
|
bool HTTPConnection::HasBadResponse(int *code, RakNet::RakString *data)
|
||
|
{
|
||
|
if(badResponses.IsEmpty())
|
||
|
return false;
|
||
|
|
||
|
if (code)
|
||
|
*code = badResponses.Peek().code;
|
||
|
if (data)
|
||
|
*data = badResponses.Pop().data;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool HTTPConnection::InList(StatusCheckFunction func)
|
||
|
{
|
||
|
SystemAddress address = (tcp.*func)();
|
||
|
|
||
|
if(address == UNASSIGNED_SYSTEM_ADDRESS)
|
||
|
return false;
|
||
|
|
||
|
server = address;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void HTTPConnection::Update(void)
|
||
|
{
|
||
|
if(InList(&TCPInterface::HasCompletedConnectionAttempt))
|
||
|
state = RAK_HTTP_ESTABLISHED;
|
||
|
|
||
|
if(InList(&TCPInterface::HasFailedConnectionAttempt))
|
||
|
state = RAK_HTTP_STARTING; // retry
|
||
|
|
||
|
// normally, HTTP servers close the stream after sending data
|
||
|
if(InList(&TCPInterface::HasLostConnection))
|
||
|
state = RAK_HTTP_INITIAL;
|
||
|
|
||
|
if(state == RAK_HTTP_STARTING)
|
||
|
{
|
||
|
server = tcp.Connect(host, port, false);
|
||
|
state = RAK_HTTP_CONNECTING;
|
||
|
}
|
||
|
|
||
|
if(state == RAK_HTTP_ESTABLISHED)
|
||
|
{
|
||
|
RakString request("POST %s HTTP/1.0\r\n"
|
||
|
"Host: %s\r\n"
|
||
|
"Content-Type: %s\r\n"
|
||
|
"Content-Length: %u\r\n"
|
||
|
"\r\n"
|
||
|
"%s",
|
||
|
path.C_String(),
|
||
|
host.C_String(),
|
||
|
contentType.C_String(),
|
||
|
(unsigned) outgoing.GetLength(),
|
||
|
outgoing.C_String());
|
||
|
tcp.Send(request, (unsigned int) strlen(request), server);
|
||
|
|
||
|
state = RAK_HTTP_REQUEST_SENT;
|
||
|
}
|
||
|
}
|
||
|
RakString HTTPConnection::Read(void)
|
||
|
{
|
||
|
const char *start_of_body = strstr(incoming, "\r\n\r\n");
|
||
|
|
||
|
if(! start_of_body)
|
||
|
{
|
||
|
badResponses.Push(BadResponse(incoming, HTTPConnection::NoBody));
|
||
|
return RakString();
|
||
|
}
|
||
|
|
||
|
return RakString(start_of_body + 4);
|
||
|
}
|
||
|
SystemAddress HTTPConnection::GetServerAddress(void) const
|
||
|
{
|
||
|
return server;
|
||
|
}
|
||
|
bool HTTPConnection::ProcessFinalTCPPacket(Packet *packet)
|
||
|
{
|
||
|
RakAssert(packet);
|
||
|
|
||
|
// read all the packets possible
|
||
|
if(packet->systemAddress == server)
|
||
|
{
|
||
|
if(incoming.GetLength() == 0)
|
||
|
{
|
||
|
int response_code = atoi((char *)packet->data + strlen("HTTP/1.0 "));
|
||
|
|
||
|
if(response_code > 299)
|
||
|
badResponses.Push(BadResponse(packet->data, response_code));
|
||
|
}
|
||
|
incoming += (char *)packet->data; // safe because TCPInterface Null-terminates
|
||
|
|
||
|
assert(strlen((char *)packet->data) == packet->length); // otherwise it contains Null bytes
|
||
|
|
||
|
|
||
|
const char *start_of_body = strstr(incoming, "\r\n\r\n");
|
||
|
|
||
|
// besides having the server close the connection, they may
|
||
|
// provide a length header and supply that many bytes
|
||
|
if(start_of_body && state == RAK_HTTP_REQUEST_SENT)
|
||
|
{
|
||
|
if (strstr((const char*) packet->data, "\r\nConnection: close\r\n"))
|
||
|
{
|
||
|
state = RAK_HTTP_IDLE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
long length_of_headers = (long)(start_of_body + 4 - incoming.C_String());
|
||
|
|
||
|
const char *length_header = strstr(incoming, "\r\nLength: ");
|
||
|
if(length_header)
|
||
|
{
|
||
|
long length = atol(length_header + 10) + length_of_headers;
|
||
|
|
||
|
if((long) incoming.GetLength() >= length)
|
||
|
state = RAK_HTTP_IDLE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return IsBusy()==false;
|
||
|
}
|
||
|
|
||
|
bool HTTPConnection::IsBusy(void) const
|
||
|
{
|
||
|
return state != RAK_HTTP_IDLE && state != RAK_HTTP_INITIAL;
|
||
|
}
|
||
|
|
||
|
int HTTPConnection::GetState(void) const
|
||
|
{
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
|
||
|
HTTPConnection::~HTTPConnection(void)
|
||
|
{
|
||
|
tcp.CloseConnection(server);
|
||
|
}
|
||
|
|
||
|
|