
/*---------------------------------------------------------------------------*/
/* http_data_consumer.cpp                                                    */
/* copyright (c) innovaphone 2023                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

#include "platform/platform.h"
#include "common/os/iomux.h"

#include <stdint.h>

#include "common/interface/time.h"
#include "common/interface/socket.h"
#include "common/interface/webserver_plugin.h"
#include "common/interface/websocket_client.h"

#include "common/lib/httplib.h"
#include "common/lib/appservice.h"

#include "common/service/webserver_shared/webserver_internal.h"
#include "common/service/webserver_shared/http_auth_digest.h"
#include "common/service/webserver_shared/http_digest_host.h"

#include "types.h"
#include "apparguments.h"
#include "webserver.h"
#include "set_certificate_handler.h"
#include "http_vfs_entry.h"
#include "http_method_handler.h"
#include "http_connection.h"
#include "http_datasource.h"
#include "http_data_consumer.h"

#define DO_RECV_DATA reinterpret_cast<void *>(0x0042)


//-----------------------------------------------------------------------------
// class HTTPDummyPathObject
//-----------------------------------------------------------------------------

HTTPDummyPathObject::HTTPDummyPathObject()
	: HTTPRegisteredPath(nullptr, 0)
{	
	this->EnableHTTPListen();
	this->EnableWebsocketSupport();
}


//-----------------------------------------------------------------------------
// class HTTPDataConsumer
//-----------------------------------------------------------------------------

HTTPDataConsumer::HTTPDataConsumer(class Webserver * const webserver)
	: HTTPDataSource(webserver)
{
	this->protocolVersion = WEBSERVER_PROTOCOL_VERSION_LATEST;
}

HTTPDataConsumer::~HTTPDataConsumer()
{
}

void HTTPDataConsumer::SendMessage(const char * name, dword connectionID, ws_message_t message, dword gp, const byte * buffer, size_t bufSize)
{
	HTTPConnection * connection;

	switch (message) {
	case WSM_NONE: // Should not happen...
		ASSERT(false, "HTTPDataConsumer::SendMessage(): Unexpected message WSM_NONE");
		break;

	case WSM_REGISTER:
	case WSM_REGISTER_RESULT:
	case WSM_REGISTER_PASSTHROUGH:
	case WSM_WEBSOCKET_LISTEN:
	case WSM_SET_CERTIFICATE:
	case WSM_REQUEST_USER_PASSWORD:
	case WSM_REQUEST_USER_PASSWORD_RESULT:
	case WSM_SET_PLUGINS_WEB_ROOT:
	case WSM_SET_AUTH_CONFIG:
	case WSM_SET_AUTH_CONFIG_RESULT:
	case WSM_SET_PLUGINS_WEB_ROOT_RESULT:
	case WSM_SEND:
	case WSM_SEND_RESULT:
	case WSM_SEND_META_DATA:
	case WSM_RECV:
	case WSM_WEBSOCKET_MESSAGE:
	case WSM_SHUTDOWN:
		// This messages won't be called and will be ignored.
		break;

	case WSM_GET_REQUEST:
	case WSM_POST_REQUEST:
	case WSM_PUT_REQUEST:
	case WSM_PASSTHROUGH_REQUEST:
	case WSM_PROPFIND_REQUEST:
	case WSM_MOVE_REQUEST:
	case WSM_COPY_REQUEST:
	case WSM_MKCOL_REQUEST:
	case WSM_DELETE_REQUEST:
	case WSM_OPTIONS_REQUEST:
	case WSM_LOCK_REQUEST:
	case WSM_UNLOCK_REQUEST:
	case WSM_PROPPATCH_REQUEST:
	case WSM_WEBSOCKET_LISTEN_RESULT:
		{
			ExtendedHeader exHeader(this->log, WEBSERVER_PROTOCOL_VERSION_LATEST);
			exHeader.Decode(0, const_cast<byte *>(buffer), bufSize);
			bool needRecvData = exHeader.DataSize() > 0 || exHeader.ChunkEncodedTransfer();
			connection = this->webserver->GetConnectionByID(connectionID);
			this->methodHandler = connection->GetCurrentMethodHandler();
			this->webserver->IoMux()->SetExec(this, needRecvData ? DO_RECV_DATA : nullptr);
		}
		break;

	case WSM_RECV_RESULT:
		this->webserver->IoMux()->SetExec(this, bufSize != 0 ? DO_RECV_DATA : nullptr);
		break;
	
	case WSM_SHUTDOWN_COMPLETE:
	case WSM_MESSAGE_HANDLER_CLOSED:
		// This messages won't be called and will be ignored.
		break;
	}
}

void HTTPDataConsumer::RemoveConnectionUsingDataSource(class HTTPConnection * connection)
{
	HTTPDataSource::RemoveConnectionUsingDataSource(connection);
	delete this;
}

void HTTPDataConsumer::IoExec(void * execContext)
{
	if (execContext == DO_RECV_DATA) this->methodHandler->AppResponse(WSM_RECV, 0, nullptr, 0);
	else this->methodHandler->AppResponse(WSM_SEND_META_DATA, WSP_CANCEL_NOT_FOUND, nullptr, 0);
}