
/*---------------------------------------------------------------------------*/
/* webserver_set_certificate_handler.cpp                                     */
/* copyright (c) innovaphone 2017                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

#include <platform.h>

#include "sdk/common/interface/webserver_plugin.h"

#include "common/ilib/str.h"

#include "sdk/common/service/webserver_shared/webserver_internal.h"

#include "webserver_message_handler.h"
#include "webserver_set_certificate_handler.h"


WebserverSetCertificateHandler::WebserverSetCertificateHandler(UWebserverMessageHandler * baseUser,
                                                               IWebserverMessage * const webserverMessageSend,
                                                               IInstanceLog * const log,
                                                               class ExtendedHeader & extHeader,
                                                               word protocolVersion)
    : WebserverMessageHandler("WebserverSetCertificate", MSG_HANDLER_SET_CERTIFICATE, baseUser, nullptr, CONNECTION_ID_SET_CERT, 0, webserverMessageSend, nullptr, nullptr, log, extHeader, protocolVersion)
{
    this->plugIn = nullptr;
    this->curCert = nullptr;
    this->curBufPos = nullptr;
}


WebserverSetCertificateHandler::~WebserverSetCertificateHandler()
{
    this->log->Log(LOG_WEBSERVER_PLUGIN, "WebserverSetCertificateHandler(0x%08x)::~WebserverSetCertificateHandler", this);
    delete this->curCert;
}


void WebserverSetCertificateHandler::SendCert(const char * password, const char * hostName, const byte * certBuffer, size_t certSize, UWebserverPlugin * user)
{
    CertData * pd = new CertData();
    pd->user = user;
    pd->password = password != nullptr ? _strdup(password) : nullptr;
    pd->hostName = hostName != nullptr ? _strdup(hostName) : nullptr;
    pd->certBuffer = const_cast<byte *>(certBuffer);
    pd->certSize = certSize;
    this->certStack.push_back(pd);
    if (this->curCert == nullptr && this->webserverMessageSend) // just send if webserverMessageSend is set, aka WebseverPlugin is connected
        this->SendNextCert();
}


void WebserverSetCertificateHandler::SendNextCert()
{
    if (this->certStack.empty()) {
        //++this->sendCount;
        this->webserverMessageSend->Send("WebserverSetCertificateHandler", CONNECTION_ID_SET_CERT, WSM_SET_CERTIFICATE, GP_SEND_CERT_DONE);
        // The baseUser is the instance of the Webserver Plugin, so it will be enough to
        // cast this->baseUser to IWebserverPlugin.
        this->log->Log(LOG_WEBSERVER_PLUGIN, "WebserverPlugin(%08x,%08x)::WebserverPluginSendCertificateResult", this, this->curCert->user);
        this->curCert->user->WebserverPluginSendCertificateResult(reinterpret_cast<IWebserverPlugin *>(this->baseUser), this->curCert->certBuffer);
        this->closeHandler = true;
        delete this->curCert;
        this->curCert = nullptr;
    }
    else {
        delete this->curCert;

        this->curCert = this->certStack.front();
        this->certStack.pop_front();

        this->curBufPos = this->curCert->certBuffer;

        ExtendedHeader extHeader(this->log, this->protocolVersion);
        extHeader.SetCertificateHeader(this->curCert->hostName, this->curCert->password, (dword)this->curCert->certSize);

        // Until 512 bytes we can risk to write to the stack....
        extHeader.Encode(this->connectionID, extHeader.BufferSize() <= 512 ? static_cast<byte *>(alloca(extHeader.BufferSize())) : nullptr);

        ++this->sendCount;
        this->webserverMessageSend->Send("WebserverSetCertificateHandler", this->connectionID, WSM_SET_CERTIFICATE, GP_SEND_CERT_HOST_NAME, extHeader.Buffer(), extHeader.BufferSize());
    }
}


void WebserverSetCertificateHandler::SendResult()
{
    if (this->curCert->certSize == 0) {
        this->SendNextCert();
    }
    else {
        // Wenn sending here, the header had already been sent. So directly set the data flag to the general purpos parameter.
        size_t toSend = this->curCert->certSize > WS_MAX_DATA_SIZE ? WS_MAX_DATA_SIZE : this->curCert->certSize;
        ++this->sendCount;
        this->webserverMessageSend->Send("WebserverSetCertificateHandler", this->connectionID, WSM_SET_CERTIFICATE, GP_SEND_CERT_DATA, this->curBufPos, toSend);
        this->curBufPos += toSend;
        this->curCert->certSize -= toSend;
    }
}
