
/*---------------------------------------------------------------------------*/
/* webserver_webdav_message_handler.h                                        */
/* copyright (c) innovaphone 2016                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

#include <platform.h>
#include <string>

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

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

#include "webserver_message_handler.h"
#include "webserver_webdav_message_handler.h"

// This is the base class used by all webdav related message handlers.
WebserverWebdavMessageHandler::WebserverWebdavMessageHandler(const char* interfaceName,
                                                             msg_handler_type_t handlerType,
                                                             UWebserverMessageHandler * baseUser,
                                                             byte * extHeaderBuffer,
                                                             dword connectionID,
                                                             ulong64 dataSize,
                                                             IWebserverMessage * const webserverMessageSend,
                                                             char * resourceName,
                                                             char * reqRegPath,
                                                             class ExtendedHeader & extHeader,
                                                             class IInstanceLog * const log,
                                                             word protocolVersion)
    : WebserverMessageHandler(interfaceName, handlerType, baseUser, extHeaderBuffer, connectionID, dataSize, webserverMessageSend, resourceName, reqRegPath, log, extHeader, protocolVersion)
{
}
    
WebserverWebdavMessageHandler::~WebserverWebdavMessageHandler()
{
}

void WebserverWebdavMessageHandler::SetResultCode(ws_webdav_result_t result, ulong64 dataSize)
{
    if (protocolVersion < WEBSERVER_PROTOCOL_VERSION_2) {
        if (this->log->LogFlagSet(LOG_WEBSERVER_PLUGIN)) {
            std::string ds = dataSize == WS_RESPONSE_CHUNKED ? "WSP_FLAG_SEND_RANGE" : std::to_string(dataSize);
            this->log->Log(LOG_WEBSERVER_PLUGIN, "WebserverWebdavMessageHandler(%08x,%08x, %s, %u)::SetResultCode(): result = %s, dataSize = %s",
                this, this->baseUser, this->interfaceName, this->connectionID, WSWebdavResultToStr(result), ds.c_str());
        }

        this->needSetTransferInfoV1 = true;
        this->webdavResultV1 = result;
        this->dataSizeV1 = dataSize;
    }
    else {
        int statusCode = WSWebdavResultToStatusCode(result);
        this->WebserverMessageHandler::SetStatusCode(statusCode);
        this->WebserverMessageHandler::SetTransferInfo(WSP_RESPONSE_APPLICATION_XML, dataSize, WSP_FLAG_NONE);
    }
}

void WebserverWebdavMessageHandler::SetTransferInfo(wsr_type_t resourceType, ulong64 dataSize, wsr_flags_t flags, const char * etag)
{
    if (this->protocolVersion < WEBSERVER_PROTOCOL_VERSION_2) {
        this->log->Log(LOG_WEBSERVER_PLUGIN, "WebserverWebdavMessageHandler(%08x,%08x, %s, %u)::SetTransferInfo(): webserver uses protocol version %u, SetTransferInfo() for WebDAV is not supported. Please update your webserver. Falling back to SetResultCode()",
            this, this->baseUser, this->interfaceName, this->connectionID, this->protocolVersion);

        this->needSetTransferInfoV1 = true;
        this->dataSizeV1 = dataSize;
    }
    else {
        this->WebserverMessageHandler::SetTransferInfo(resourceType, dataSize, flags, etag);
    }
}


void WebserverWebdavMessageHandler::SetStatusCode(dword code, const char * description)
{
    if (this->protocolVersion < WEBSERVER_PROTOCOL_VERSION_2) {
        this->log->Log(LOG_WEBSERVER_PLUGIN, "WebserverWebdavMessageHandler(%08x,%08x, %s, %u)::SetStatusCode(): webserver uses protocol version %u, SetStatusCode() for WebDAV is not supported. Please update your webserver. Falling back to SetResultCode()",
            this, this->baseUser, this->interfaceName, this->connectionID, this->protocolVersion);

        switch (code)
        {
        case HTTP_STATUS_200: this->webdavResultV1 = WEBDAV_RESULT_OK; break;
        case HTTP_STATUS_201: this->webdavResultV1 = WEBDAV_RESULT_CREATED; break;
        case HTTP_STATUS_204: this->webdavResultV1 = WEBDAV_RESULT_NO_CONTENT; break;
        case HTTP_STATUS_207: this->webdavResultV1 = WEBDAV_RESULT_MULTIPLE_STATUS; break;
        case HTTP_STATUS_403: this->webdavResultV1 = WEBDAV_RESULT_FORBIDDEN; break;
        case HTTP_STATUS_405: this->webdavResultV1 = WEBDAV_RESULT_METHOD_NOT_ALLOWED; break;
        case HTTP_STATUS_409: this->webdavResultV1 = WEBDAV_RESULT_CONFLICT; break;
        case HTTP_STATUS_412: this->webdavResultV1 = WEBDAV_RESULT_PRECONDITION_FAILED; break;
        case HTTP_STATUS_423: this->webdavResultV1 = WEBDAV_RESULT_LOCKED; break;
        case HTTP_STATUS_502: this->webdavResultV1 = WEBDAV_RESULT_BAD_GATEWAY; break;
        case HTTP_STATUS_507: this->webdavResultV1 = WEBDAV_RESULT_INSUFFICIENT_STORAGE; break;
        default:
            this->log->Log(LOG_WEBSERVER_PLUGIN, "WebserverWebdavMessageHandler(%08x,%08x, %s, %u)::SetStatusCode(): code %u doesn't have a correspondign WEBDAV_RESULT constant - using fallback to WEBDAV_RESULT_OK (HTTP 200)",
                this, this->baseUser, this->interfaceName, this->connectionID, code);
            this->webdavResultV1 = WEBDAV_RESULT_OK;
            break;
        }
    }
    else {
        this->WebserverMessageHandler::SetStatusCode(code, description);
    }
}

void WebserverWebdavMessageHandler::SetTransferInfoV1()
{
    if (this->needSetTransferInfoV1) {
        this->needSetTransferInfoV1 = false;
        this->extHeader.SetTransferInfo(WSP_RESPONSE_NO_TYPE, wsr_flags_t(this->webdavResultV1), this->dataSizeV1);
    }
}

void WebserverWebdavMessageHandler::Send(const void* buffer, size_t len)
{
    this->SetTransferInfoV1();
    this->WebserverMessageHandler::Send(buffer, len);
}

void WebserverWebdavMessageHandler::Cancel(wsr_cancel_type_t reason)
{
    this->SetTransferInfoV1();
    this->WebserverMessageHandler::Cancel(reason);
}

void WebserverWebdavMessageHandler::Close()
{
    this->SetTransferInfoV1();
    this->WebserverMessageHandler::Close();
}
