/*---------------------------------------------------------------------------*/
/* webserverplugin.h                                                         */
/* copyright (c) innovaphone 2015 - 2023                                     */
/*                                                                           */
/*---------------------------------------------------------------------------*/

#define WS_MAX_PATH_LENGTH      8192
#define WS_MAX_DATA_SIZE        65535
#define WS_DISABLE_AUTH         nullptr

// The protocol for communication between the webserver and the IWebserverPlugin Interface exists in different
// version. Normally, an app doesn't have to take care of it. However, it might be usefull to use the version
// supported by the app and reported by the webserver as well as the differences in functionallity.
static const word WEBSERVER_PROTOCOL_VERSION_0 = 0x0000;
static const word WEBSERVER_PROTOCOL_VERSION_1 = 0x0001;
static const word WEBSERVER_PROTOCOL_VERSION_2 = 0x0002;
static const word WEBSERVER_PROTOCOL_VERSION_LATEST = WEBSERVER_PROTOCOL_VERSION_2;


// For additional notes to the structure of wsr_cancel_type_t and ws_webdav_result_t, look to
// webserver_internal.h, description to wsr_int_type_t. So before changing anything here, first
// read that description.
typedef enum {
    // Everything from 0 to 15 will be internal types
    WSP_CANCEL_NOT_FOUND = 0x10,
    WSP_CANCEL_BAD_REQUEST,
    WSP_CANCEL_UNAVAILABLE,
    WSP_CANCEL_MISSING_LENGTH,
    WSP_CANCEL_STREAM,
    WSP_CANCEL_ACCESS_DENIED,
    WSP_CANCEL_INTERNAL_ERROR
} wsr_cancel_type_t;


typedef enum {
    WSP_PATH_TYPE_HTTP,
    WSP_PATH_TYPE_WEBSOCKET,
    WSP_PATH_TYPE_PASSTHROUGH
} wsp_path_type_t;

constexpr dword HTTP_STATUS_100 = 100; // Continue
constexpr dword HTTP_STATUS_101 = 101; // Switching Protocols
constexpr dword HTTP_STATUS_102 = 102; // Processing
constexpr dword HTTP_STATUS_103 = 103; // Early Hints

constexpr dword HTTP_STATUS_200 = 200; // OK
constexpr dword HTTP_STATUS_201 = 201; // Created
constexpr dword HTTP_STATUS_202 = 202; // Accepted
constexpr dword HTTP_STATUS_203 = 203; // Non-Authoritative Information
constexpr dword HTTP_STATUS_204 = 204; // No Content
constexpr dword HTTP_STATUS_205 = 205; // Reset Content
constexpr dword HTTP_STATUS_206 = 206; // Partial Content
constexpr dword HTTP_STATUS_207 = 207; // Multi-Status
constexpr dword HTTP_STATUS_208 = 208; // Already Reported
constexpr dword HTTP_STATUS_226 = 226; // IM Used
constexpr dword HTTP_STATUS_300 = 300; // Multiple Choices
constexpr dword HTTP_STATUS_301 = 301; // Moved Permanently
constexpr dword HTTP_STATUS_302 = 302; // Found
constexpr dword HTTP_STATUS_303 = 303; // See Other
constexpr dword HTTP_STATUS_304 = 304; // Not Modified
constexpr dword HTTP_STATUS_305 = 305; // Use Proxy
constexpr dword HTTP_STATUS_307 = 307; // Temporary Redirect
constexpr dword HTTP_STATUS_308 = 308; // Permanent Redirect

constexpr dword HTTP_STATUS_400 = 400; // Bad Request
constexpr dword HTTP_STATUS_401 = 401; // Unauthorized
constexpr dword HTTP_STATUS_402 = 402; // Payment Required
constexpr dword HTTP_STATUS_403 = 403; // Forbidden
constexpr dword HTTP_STATUS_404 = 404; // Not Found
constexpr dword HTTP_STATUS_405 = 405; // Method Not Allowed
constexpr dword HTTP_STATUS_406 = 406; // Not Acceptable
constexpr dword HTTP_STATUS_407 = 407; // Proxy Authentication Required
constexpr dword HTTP_STATUS_408 = 408; // Request Timeout
constexpr dword HTTP_STATUS_409 = 409; // Conflict
constexpr dword HTTP_STATUS_410 = 410; // Gone
constexpr dword HTTP_STATUS_411 = 411; // Length Required
constexpr dword HTTP_STATUS_412 = 412; // Precondition Failed
constexpr dword HTTP_STATUS_413 = 413; // Payload Too Large
constexpr dword HTTP_STATUS_414 = 414; // URI Too Long
constexpr dword HTTP_STATUS_415 = 415; // Unsupported Media Type
constexpr dword HTTP_STATUS_416 = 416; // Range Not Satisfiable
constexpr dword HTTP_STATUS_417 = 417; // Expectation Failed
constexpr dword HTTP_STATUS_418 = 418; // I'm a teapot
constexpr dword HTTP_STATUS_421 = 421; // Misdirected Request
constexpr dword HTTP_STATUS_422 = 422; // Unprocessable Entity
constexpr dword HTTP_STATUS_423 = 423; // Locked
constexpr dword HTTP_STATUS_424 = 424; // Failed Dependency
constexpr dword HTTP_STATUS_425 = 425; // Too Early
constexpr dword HTTP_STATUS_426 = 426; // Upgrade Required
constexpr dword HTTP_STATUS_428 = 428; // Precondition Required
constexpr dword HTTP_STATUS_429 = 429; // Too many requests
constexpr dword HTTP_STATUS_431 = 431; // Request Header Fields Too Large
constexpr dword HTTP_STATUS_451 = 451; // Unavailable For Legal Reasons

constexpr dword HTTP_STATUS_500 = 500; // Internal Server Error
constexpr dword HTTP_STATUS_501 = 501; // Not Implemented
constexpr dword HTTP_STATUS_502 = 502; // Bad Gateway
constexpr dword HTTP_STATUS_503 = 503; // Service Unavailable
constexpr dword HTTP_STATUS_504 = 504; // Gateway Timeout
constexpr dword HTTP_STATUS_505 = 505; // HTTP Version Not Supported
constexpr dword HTTP_STATUS_506 = 506; // Variant Also Negotiates
constexpr dword HTTP_STATUS_507 = 507; // Insufficient Storage
constexpr dword HTTP_STATUS_508 = 508; // Loop Detected
constexpr dword HTTP_STATUS_509 = 509; // Bandwith Limit Exceeded
constexpr dword HTTP_STATUS_510 = 510; // Not Extended
constexpr dword HTTP_STATUS_511 = 511; // Network Authentication Required

inline const char * WSCancelTypeToStr(wsr_cancel_type_t c)
{
    switch (c)
    {
    case WSP_CANCEL_NOT_FOUND: return "WSP_CANCEL_NOT_FOUND";
    case WSP_CANCEL_BAD_REQUEST: return "WSP_CANCEL_BAD_REQUEST";
    case WSP_CANCEL_UNAVAILABLE: return "WSP_CANCEL_UNAVAILABLE";
    case WSP_CANCEL_MISSING_LENGTH: return "WSP_CANCEL_MISSING_LENGTH";
    case WSP_CANCEL_STREAM: return "WSP_CANCEL_STREAM";
    case WSP_CANCEL_ACCESS_DENIED: return "WSP_CANCEL_ACCESS_DENIED";
    case WSP_CANCEL_INTERNAL_ERROR: return "WSP_CANCEL_INTERNAL_ERROR";
    }
    return "<unkown wsr_cancel_type_t>"; //  Make the compiler happy
}


// Read the above commentar before changing anything here!
typedef enum {
    WEBDAV_RESULT_OK = 0x100,
    WEBDAV_RESULT_CREATED,
    WEBDAV_RESULT_NO_CONTENT,
    WEBDAV_RESULT_MULTIPLE_STATUS,
    WEBDAV_RESULT_FORBIDDEN,
    WEBDAV_RESULT_METHOD_NOT_ALLOWED,
    WEBDAV_RESULT_CONFLICT,
    WEBDAV_RESULT_PRECONDITION_FAILED,
    WEBDAV_RESULT_LOCKED,
    WEBDAV_RESULT_BAD_GATEWAY,
    WEBDAV_RESULT_INSUFFICIENT_STORAGE
} ws_webdav_result_t;


inline const char * WSWebdavResultToStr(ws_webdav_result_t r)
{
    switch (r)
    {
    case WEBDAV_RESULT_OK: return "WEBDAV_RESULT_OK";
    case WEBDAV_RESULT_CREATED: return "WEBDAV_RESULT_CREATED";
    case WEBDAV_RESULT_NO_CONTENT: return "WEBDAV_RESULT_NO_CONTENT";
    case WEBDAV_RESULT_MULTIPLE_STATUS: return "WEBDAV_RESULT_MULTIPLE_STATUS";
    case WEBDAV_RESULT_FORBIDDEN: return "WEBDAV_RESULT_FORBIDDEN";
    case WEBDAV_RESULT_METHOD_NOT_ALLOWED: return "WEBDAV_RESULT_METHOD_NOT_ALLOWED";
    case WEBDAV_RESULT_CONFLICT: return "WEBDAV_RESULT_CONFLICT";
    case WEBDAV_RESULT_PRECONDITION_FAILED: return "WEBDAV_RESULT_PRECONDITION_FAILED";
    case WEBDAV_RESULT_LOCKED: return "WEBDAV_RESULT_LOCKED";
    case WEBDAV_RESULT_BAD_GATEWAY: return "WEBDAV_RESULT_BAD_GATEWAY";
    case WEBDAV_RESULT_INSUFFICIENT_STORAGE: return "WEBDAV_RESULT_INSUFFICIENT_STORAGE";
    }
    return "<unkown ws_webdav_result_t>"; //  Make the compiler happy
}

inline int WSWebdavResultToStatusCode(ws_webdav_result_t r)
{
    switch (r)
    {
    case WEBDAV_RESULT_OK:                   return HTTP_STATUS_200;
    case WEBDAV_RESULT_CREATED:              return HTTP_STATUS_201;
    case WEBDAV_RESULT_NO_CONTENT:           return HTTP_STATUS_204;
    case WEBDAV_RESULT_MULTIPLE_STATUS:      return HTTP_STATUS_207;
    case WEBDAV_RESULT_FORBIDDEN:            return HTTP_STATUS_403;
    case WEBDAV_RESULT_METHOD_NOT_ALLOWED:   return HTTP_STATUS_405;
    case WEBDAV_RESULT_CONFLICT:             return HTTP_STATUS_409;
    case WEBDAV_RESULT_PRECONDITION_FAILED:  return HTTP_STATUS_412;
    case WEBDAV_RESULT_LOCKED:               return HTTP_STATUS_423;
    case WEBDAV_RESULT_BAD_GATEWAY:          return HTTP_STATUS_502;
    case WEBDAV_RESULT_INSUFFICIENT_STORAGE: return HTTP_STATUS_507;
    }
    return HTTP_STATUS_200;
}


typedef enum {
    // Start of resource file types
    // Only add new response types at the end of the enum to ensure compatibility
    WSP_RESPONSE_NO_TYPE = 0x100,
    WSP_RESPONSE_BINARY,
    WSP_RESPONSE_JAVA,
    WSP_RESPONSE_WAV,
    WSP_RESPONSE_OGG,
    WSP_RESPONSE_MP3,
    WSP_RESPONSE_GIF,
    WSP_RESPONSE_PNG,
    WSP_RESPONSE_BMP,
    WSP_RESPONSE_ICON,
    WSP_RESPONSE_TTF,
    WSP_RESPONSE_EOT,
    WSP_RESPONSE_PDF,
    WSP_RESPONSE_TEXT,
    WSP_RESPONSE_XML,
    WSP_RESPONSE_CSS,
    WSP_RESPONSE_JAVASCRIPT,
    WSP_RESPONSE_JSON,
    WSP_RESPONSE_HTML,
    WSP_RESPONSE_SVG,
    WSP_RESPONSE_WOFF,
    WSP_RESPONSE_G711,
    WSP_RESPONSE_G722,
    WSP_RESPONSE_G729,
    WSP_RESPONSE_JPEG,
    WSP_RESPONSE_MP4,
    WSP_RESPONSE_WEBM,
    WSP_RESPONSE_PEM,
    WSP_RESPONSE_MOBILECONFIG,
    WSP_RESPONSE_CACHE_MANIFEST,
    WSP_RESPONSE_OPUS,
    WSP_RESPONSE_CSV,
    WSP_RESPONSE_APPLICATION_XML,
    WSP_RESPONSE_MJS,
    WSP_RESPONSE_WASM,
    WSP_RESPONSE_TFLITE
} wsr_type_t;


typedef enum {
    WSP_FLAG_NONE = 0x00,
    WSP_FLAG_ENCODING_GZIP = 0x01,
    WSP_FLAG_SEND_RANGE = 0x02
    // Note that the values 0x10 and above are used internally and must not be used
} wsr_flags_t;


inline const char * WSRFlagToStr(wsr_flags_t flags)
{
    if ((flags & WSP_FLAG_ENCODING_GZIP) == WSP_FLAG_ENCODING_GZIP && (flags & WSP_FLAG_SEND_RANGE) == WSP_FLAG_SEND_RANGE) {
        return "WSP_FLAG_ENCODING_GZIP | WSP_FLAG_SEND_RANGE";
    }

    if ((flags & WSP_FLAG_ENCODING_GZIP) == WSP_FLAG_ENCODING_GZIP) {
        return "WSP_FLAG_ENCODING_GZIP";
    }

    if ((flags & WSP_FLAG_SEND_RANGE) == WSP_FLAG_SEND_RANGE) {
        return "WSP_FLAG_SEND_RANGE";
    }

    return "WSP_FLAG_NONE";
}


typedef struct {
    const char * sfx;
    wsr_type_t type;
} ws_type_sfx_t;


static const ws_type_sfx_t suffixes[] = {
    { "html", WSP_RESPONSE_HTML },
    { "htm", WSP_RESPONSE_HTML },
    { "css", WSP_RESPONSE_CSS },
    { "xml", WSP_RESPONSE_XML },
    { "xsl", WSP_RESPONSE_XML },
    { "js", WSP_RESPONSE_JAVASCRIPT },
    { "json", WSP_RESPONSE_JSON },
    { "ico", WSP_RESPONSE_ICON },
    { "bin", WSP_RESPONSE_BINARY },
    { "jar", WSP_RESPONSE_JAVA },
    { "png", WSP_RESPONSE_PNG },
    { "gif", WSP_RESPONSE_GIF },
    { "bmp", WSP_RESPONSE_BMP },
    { "pdf", WSP_RESPONSE_PDF },
    { "wav", WSP_RESPONSE_WAV },
    { "ogg", WSP_RESPONSE_OGG },
    { "mp3", WSP_RESPONSE_MP3 },
    { "txt", WSP_RESPONSE_TEXT },
    { "soap", WSP_RESPONSE_XML },
    { "svg", WSP_RESPONSE_SVG },
    { "ttf", WSP_RESPONSE_TTF },
    { "eot", WSP_RESPONSE_EOT },
    { "woff", WSP_RESPONSE_WOFF },
    { "woff2", WSP_RESPONSE_WOFF },
    { "g711a", WSP_RESPONSE_G711 },
    { "g711u", WSP_RESPONSE_G711 },
    { "g722", WSP_RESPONSE_G722 },
    { "g729", WSP_RESPONSE_G729 },
    { "jpeg", WSP_RESPONSE_JPEG },
    { "mp4", WSP_RESPONSE_MP4 },
    { "webm", WSP_RESPONSE_WEBM },
    { "pem", WSP_RESPONSE_PEM },
    { "mobileconfig", WSP_RESPONSE_MOBILECONFIG },
    { "appcache", WSP_RESPONSE_CACHE_MANIFEST },
    { "opus-nb", WSP_RESPONSE_OPUS },
    { "opus-wb", WSP_RESPONSE_OPUS },
    { "csv", WSP_RESPONSE_CSV },
    { "xml", WSP_RESPONSE_APPLICATION_XML },
    { "mjs", WSP_RESPONSE_MJS },
    { "wasm", WSP_RESPONSE_WASM },
    { "tflite", WSP_RESPONSE_TFLITE }
};


inline wsr_type_t GetResponseTypeForFileName(const char * fileName)
{
    char * p = strrchr(const_cast<char *>(fileName), '.');
    if (p != nullptr) {
        p++; // Remove '.'
        for (size_t i = 0; i < sizeof(suffixes) / sizeof(ws_type_sfx_t); i++) {
            if (strcmp(p, suffixes[i].sfx) == 0)
                return suffixes[i].type;
        }
    }

    return WSP_RESPONSE_NO_TYPE;
}


typedef enum {
    WSP_NORMAL_CLOSE,                // The app itself initiated the shutdown
    WSP_REGISTER_PATH_INVALID,       // The given path is invalid
    WSP_WEBSOCKET_PATH_INVALID,      // The given Websocket listen path is invalid.
    WSP_WEBSOCKET_PATH_ALREADY_LISTENING, // Someone alrady is listening to that path for websocekt connections
    WSP_PATH_ALREADY_REGISTERD,      // A data provider already registered to that resource
    WSP_ADDRESS_INVALID,             // The address the application tried to connect to was invalid
    WSP_CONNECTION_ERROR             // An connection error occured (see log, if exists),
} wsp_close_reason_t;


inline const char * WSPCloseReasonToStr(wsp_close_reason_t cr)
{
    const char * result;
    switch (cr)
    {
    case WSP_NORMAL_CLOSE: result = "WSP_NORMAL_CLOSE"; break;
    case WSP_REGISTER_PATH_INVALID: result = "WSP_REGISTER_PATH_INVALID"; break;
    case WSP_WEBSOCKET_PATH_INVALID: result = "WSP_WEBSOCKET_PATH_INVALID"; break;
    case WSP_WEBSOCKET_PATH_ALREADY_LISTENING: result = "WSP_WEBSOCKET_PATH_ALREADY_LISTENING"; break;
    case WSP_PATH_ALREADY_REGISTERD: result = "WSP_PATH_ALREADY_REGISTERD"; break;
    case WSP_ADDRESS_INVALID: result = "WSP_ADDRESS_INVALID"; break;
    case WSP_CONNECTION_ERROR: result = "WSP_CONNECTION_ERROR"; break;
    default: result = "<Unkown wsp_close_reason_t>"; break;
    }
    return result;
}


typedef enum {
    WSCR_NORMAL_CLOSE,
    WSCR_BUFFER_OVERFLOW,
    WSCR_SOCKET_LOST,
    WSCR_ERROR,
    WSCR_DOUBLE_RECV_CALL
} ws_close_reason_t;


typedef enum {
    WS_REQUEST_GET = 0x0001,
    WS_REQUEST_POST = 0x0002,
    WS_REQUEST_PUT = 0x0004,
    WS_REQUEST_PASSTHROUGH = 0x0008,
    WS_REQUEST_PROPFIND = 0x0010,
    WS_REQUEST_MOVE = 0x0020,
    WS_REQUEST_COPY = 0x0040,
    WS_REQUEST_MKCOL = 0x0080,
    WS_REQUEST_DELETE = 0x0100,
    WS_REQUEST_OPTIONS = 0x0200,
    WS_REQUEST_LOCK = 0x0400,
    WS_REQUEST_UNLOCK = 0x0800,
    WS_REQUEST_PROPPATCH = 0x1000
} ws_request_type_t;


typedef enum {
    WS_AUTH_DECACTIVATED,
    WS_AUTH_DYNAMIC,
    WS_AUTH_STATIC,
    WS_AUTH_ERR_PATH_NOT_LISTENING,
    WS_AUTH_ERR_PATH_INVALID
} ws_update_auth_result_t;

// Give this to SetTransferInfo as dataSize to tell the Webserver that your data
// will need to be sent chunk encoded.
static const ulong64 WS_RESPONSE_CHUNKED = 0xFFFFFFFFFFFFFFFF;

// Webserver Plugin
class IWebserverPluginProvider {
public:
    virtual ~IWebserverPluginProvider() {}
    virtual class IWebserverPlugin * CreateWebserverPlugin(class IIoMux * const iomux,
                                                           class ISocketProvider * localSocketProvider,
                                                           class UWebserverPlugin * const user,
                                                           const char * webserverAddress,
                                                           const char * appWebRoot,
                                                           class IInstanceLog * const log) = 0;

};

extern IWebserverPluginProvider * CreateWebserverPluginProvider();


class IWebserverPlugin {
public:
	virtual ~IWebserverPlugin() {}

    virtual bool Connected() = 0;
    virtual word ProtocolVersion() = 0;

	virtual void SendCertificate(const char * password, const byte * certBuf, size_t certLen, const char * hostName = nullptr, UWebserverPlugin * user = nullptr) = 0;
	virtual void HttpListen(const char * path = nullptr, UWebserverPlugin * user = nullptr, const char * authUser = nullptr, const char * authUserPwd = nullptr, const char * staticFilePrefix = nullptr) = 0;
	virtual void HttpListen(const char * path, UWebserverPlugin * user, bool dynamicAuth, const char * staticFilePrefix = nullptr) = 0;
	virtual void PassthroughListen(const char * path = nullptr, UWebserverPlugin * user = nullptr) = 0;
	virtual void WebsocketListen(const char * path = nullptr, UWebserverPlugin * user = nullptr) = 0;

	virtual void SetAuthConfig(const char * path, const char * authUser = nullptr, const char * authPwd = nullptr) = 0;
	virtual void SetAuthConfig(const char * path, bool enableDynAuth) = 0;
	virtual void SetDigestAuthenticationRealm(const char * realm) = 0;
	virtual const char * GetDigestAuthenticationRealm() = 0;

	virtual void Cancel(wsr_cancel_type_t reason) = 0;
	virtual void Redirect(const char * newDestination) = 0;
	virtual bool BuildRedirect(const char * resourceName, const char * build, unsigned buildLen) = 0;
	virtual bool BuildRedirectIP(const char * resourceName, const char * build, unsigned buildLen) = 0;

	virtual void Accept(class UWebserverGet * const user) = 0;
	virtual void Accept(class UWebserverPost * const user) = 0;
	virtual void Accept(class UWebserverPut * const user) = 0;
	virtual void Accept(class UWebserverPassthrough * const user) = 0;
	virtual void Accept(class UWebserverPropfind * const user) = 0;
	virtual void Accept(class UWebserverMove * const user) = 0;
	virtual void Accept(class UWebserverMkCol * const user) = 0;
	virtual void Accept(class UWebserverCopy * const user) = 0;
	virtual void Accept(class UWebserverDelete * const user) = 0;
	virtual void Accept(class UWebserverLock * const user) = 0;
	virtual void Accept(class UWebserverUnlock * const user) = 0;
	virtual void Accept(class UWebserverProppatch * const user) = 0;
	virtual void Accept(class UWebserverOptions * const  user) = 0;
	virtual void WebsocketAccept(class UWebsocket * user) = 0;

	virtual void RequestUserPasswordResult(dword connectionID, const char * user, const char * password) = 0;
	
	virtual void Close() = 0;
};


class UWebserverPlugin {
public:
	virtual ~UWebserverPlugin() {}

	virtual void WebserverPluginClose(class IWebserverPlugin * plugin, wsp_close_reason_t reason, bool lastUser)
	{
		if (lastUser) delete plugin;
	}

	virtual void WebserverPluginHttpListenResult(class IWebserverPlugin * plugin, ws_request_type_t requestType, char * resourceName, const char * registeredPathForRequest, ulong64 dataSize)
	{
		plugin->Cancel(WSP_CANCEL_NOT_FOUND);
	}

	virtual void WebserverPluginPassthroughListenResult(class IWebserverPlugin *plugin, char *resourceName, const char *registeredPathForRequest, ulong64 dataSize)
	{
		plugin->Cancel(WSP_CANCEL_NOT_FOUND);
	}

	virtual void WebserverPluginWebsocketListenResult(class IWebserverPlugin * plugin, const char * path, const char * registeredPathForRequest, const char * host)
	{
		plugin->WebsocketAccept(nullptr);
	}

	virtual void WebserverPluginConnected() {}
	virtual void WebserverPluginConnected(class IWebserverPlugin * plugin) { this->WebserverPluginConnected(); }
	virtual void WebserverPluginSendCertificateResult(class IWebserverPlugin * plugin, byte * certBuffer) {}
	virtual void WebserverPluginRegisterPathResult(class IWebserverPlugin * plugin, const char * pathName, wsp_path_type_t pathType) {}
	virtual void WebserverPluginRequestUserPassword(class IWebserverPlugin * plugin, dword connectionID, char * resourceName, const char * registeredPathForRequest, const char * host, const char * user) { ASSERT(false, "UWebserverPlugin::WebserverPluginRequestUserPassword() not implemented!"); }
	virtual void SetAuthConfigResult(const char * path, ws_update_auth_result_t result) {}
};

// Webserver Plugin - Get
class IWebserverGetRange {
public:
    IWebserverGetRange() {}
    virtual ~IWebserverGetRange() {}

    enum range_type_t {
        RANGE_NONE = 0x00,
        RANGE_START_END = 0x01,
        RANGE_START_ONLY = 0x02,
        RANGE_LAST_BYTES = 0x03
    } rangeType;

    ulong64 start;
    ulong64 end;
};


class IWebserverGet {
public:
    virtual ~IWebserverGet() {}

	virtual dword GetConnectionID() = 0;
    virtual const char * GetResourceName() = 0;
    virtual const char * GetRegisteredPathForRequest() = 0;
    virtual const char * GetETag() = 0;
    virtual size_t GetRangeCount() = 0;
    virtual IWebserverGetRange * GetRange(size_t idx) = 0;
    virtual const char * GetHeaderFieldValue(const char * fieldName) = 0;
	virtual class IDigestAuthenticator * GetAuthenticator() = 0;
    virtual const char * GetRemoteAddress() = 0;
    virtual word GetRemotePort() = 0;
    virtual bool IsEncryptedConnection() = 0;
    virtual bool IsSysClientAuthenticated() { return false; };

    virtual void Cancel(wsr_cancel_type_t reason) = 0;
    virtual void SetTransferInfo(wsr_type_t resourceType, ulong64 dataSize, wsr_flags_t flags = WSP_FLAG_NONE, const char * etag = nullptr) = 0;
	virtual void SetStatusCode(dword code, const char * description = nullptr) = 0;
    virtual void SetTransferRange(ulong64 rangeStart, ulong64 rangeEnd) = 0;
    virtual void SetHeaderField(const char * fname, const char * fvalue) = 0;
    virtual void ForceDownloadResponse(const char * fileName = nullptr) = 0;
    virtual void Send(const void * buffer, size_t len) = 0;
    virtual void Close() = 0;
};

class UWebserverGet {
public:
    virtual ~UWebserverGet() {}

    virtual void WebserverGetRequestAcceptComplete(IWebserverGet * const webserverGet) = 0;
    virtual void WebserverGetSendResult(IWebserverGet * const webserverGet) = 0;
    virtual void WebserverGetCloseComplete(IWebserverGet * const webserverGet) = 0;
};


// Webserver Plugin - Post
class IWebserverPost {
public:
    virtual ~IWebserverPost() {}

	virtual dword GetConnectionID() = 0;
    virtual const char * GetResourceName() = 0;
    virtual const char * GetRegisteredPathForRequest() = 0;
    virtual const char * GetHeaderFieldValue(const char * fieldName) = 0;
    virtual ulong64 GetDataSize() = 0;
	virtual class IDigestAuthenticator * GetAuthenticator() = 0;
    virtual const char * GetRemoteAddress() = 0;
    virtual word GetRemotePort() = 0;
    virtual bool IsEncryptedConnection() = 0;

    virtual bool IsSysClientAuthenticated() { return false; };
    virtual bool DataIsChunkEncoded() = 0;

    virtual void ForceDownloadResponse(const char * fileName = nullptr) = 0;
    virtual void SetTransferInfo(wsr_type_t resourceType, ulong64 dataSize, wsr_flags_t flags = WSP_FLAG_NONE, const char* etag = nullptr) = 0;
	virtual void SetStatusCode(dword code, const char * description = nullptr) = 0;
    virtual void SetHeaderField(const char * fname, const char * fvalue) = 0;
    virtual void Cancel(wsr_cancel_type_t reason) = 0;
    virtual void Send(const void * buffer, size_t len) = 0;
    virtual void Recv(void * buffer = nullptr, size_t len = 0) = 0;
    virtual void Close() = 0;
};


class UWebserverPost {
public:
    virtual ~UWebserverPost() {}

    virtual void WebserverPostRequestAcceptComplete(IWebserverPost * const webserverPost) = 0;
    virtual void WebserverPostSendResult(IWebserverPost * const webserverPost) {}
    virtual void WebserverPostRecvResult(IWebserverPost * const webserverPost, void * buffer, size_t len) = 0;
    virtual void * WebserverPostRecvBuffer(size_t len) { return nullptr; }
    virtual void WebserverPostRecvCanceled(IWebserverPost * const webserverPost, void * buffer) = 0;
    virtual void WebserverPostCloseComplete(IWebserverPost * const webserverPost) = 0;
};


// Webserver Plugin - Passthrough
class IWebserverPassthrough {
public:
    virtual ~IWebserverPassthrough() {}

	virtual dword GetConnectionID() = 0;
    virtual const char * GetResourceName() = 0;
    virtual const char * GetRegisteredPathForRequest() = 0;
    virtual const char * GetHeaderFieldValue(const char * fieldName) = 0;
    virtual const char * GetRemoteAddress() = 0;
    virtual word GetRemotePort() = 0;
    virtual bool IsEncryptedConnection() = 0;

    virtual void Cancel(wsr_cancel_type_t reason) = 0;
    virtual void Send(const void * buffer, size_t size) = 0;
    virtual void Recv(void * buffer = nullptr, size_t len = 0) = 0;
    virtual void Close() = 0;
};


class UWebserverPassthrough {
public:
    virtual ~UWebserverPassthrough() {}

    virtual void WebserverPassthroughRequestAcceptComplete(IWebserverPassthrough * const webserverPassthrough) = 0;
    virtual void WebserverPassthroughSendResult(IWebserverPassthrough * const webserverPassthrough) = 0;
    virtual void WebserverPassthroughRecvResult(IWebserverPassthrough * const webserverPassthrough, void * buffer, size_t len) = 0;
    virtual void * WebserverPassthroughRecvBuffer(size_t len) { return nullptr; }
    virtual void WebserverPassthroughRecvCanceled(IWebserverPassthrough * const webserverPassthrough, void * buffer) = 0;
    virtual void WebserverPassthroughCloseComplete(IWebserverPassthrough * const webserverPassthrough) = 0;
};


// Webserver Plugin - Put
class IWebserverPut {
public:
    virtual ~IWebserverPut() {}

	virtual dword GetConnectionID() = 0;
    virtual const char * GetResourceName() = 0;
    virtual const char * GetRegisteredPathForRequest() = 0;
    virtual const char * GetHeaderFieldValue(const char * fieldName) = 0;
    virtual ulong64 GetDataSize() = 0;
	virtual class IDigestAuthenticator * GetAuthenticator() = 0;
    virtual const char * GetRemoteAddress() = 0;
    virtual word GetRemotePort() = 0;
    virtual bool IsEncryptedConnection() = 0;
    virtual bool IsSysClientAuthenticated() { return false; };
    virtual bool DataIsChunkEncoded() = 0;

    virtual void SetResultCode(ws_webdav_result_t result, ulong64 dataSize = 0) = 0;
    virtual void SetTransferInfo(wsr_type_t resourceType, ulong64 dataSize, wsr_flags_t flags = WSP_FLAG_NONE, const char* etag = nullptr) = 0;
	virtual void SetStatusCode(dword code, const char * description = nullptr) = 0;
    virtual void SetHeaderField(const char * fname, const char * fvalue) = 0;
    virtual void Cancel(wsr_cancel_type_t reason) = 0;
    virtual void Send(const void * buffer, size_t len) = 0;
    virtual void Recv(void * buffer = nullptr, size_t len = 0) = 0;
    virtual void Close() = 0;
};


class UWebserverPut {
public:
    virtual ~UWebserverPut() {}

    virtual void WebserverPutRequestAcceptComplete(IWebserverPut * const webserverPut) = 0;
    virtual void WebserverPutSendResult(IWebserverPut * const webserverPut) = 0;
    virtual void WebserverPutRecvResult(IWebserverPut * const webserverPut, void * buffer, size_t len) = 0;
    virtual void * WebserverPutRecvBuffer(size_t len) { return nullptr; }
    virtual void WebserverPutRecvCanceled(IWebserverPut * const webserverPut, void * buffer) = 0;
    virtual void WebserverPutCloseComplete(IWebserverPut * const webserverPut) = 0;
};


// Webserver Plugin - Propfind
class IWebserverPropfind {
public:
    virtual ~IWebserverPropfind() {}

	virtual dword GetConnectionID() = 0;
    virtual const char * GetResourceName() = 0;
    virtual const char * GetRegisteredPathForRequest() = 0;
    virtual const char * GetHeaderFieldValue(const char * fieldName) = 0;
    virtual ulong64 GetDataSize() = 0;
	virtual class IDigestAuthenticator * GetAuthenticator() = 0;
    virtual const char * GetRemoteAddress() = 0;
    virtual word GetRemotePort() = 0;
    virtual bool IsEncryptedConnection() = 0;
    virtual bool DataIsChunkEncoded() = 0;

    virtual void SetResultCode(ws_webdav_result_t result, ulong64 dataSize = 0) = 0;
    virtual void SetTransferInfo(wsr_type_t resourceType, ulong64 dataSize, wsr_flags_t flags = WSP_FLAG_NONE, const char* etag = nullptr) = 0;
	virtual void SetStatusCode(dword code, const char * description = nullptr) = 0;
    virtual void SetHeaderField(const char * fname, const char * fvalue) = 0;
	virtual void Cancel(wsr_cancel_type_t reason) = 0;
    virtual void Recv(void * buffer = nullptr, size_t len = 0) = 0;
    virtual void Send(const void * buffer, size_t len) = 0;
    virtual void Close() = 0;
};


class UWebserverPropfind {
public:
    virtual ~UWebserverPropfind() {};
    virtual void WebserverPropfindRequestAcceptComplete(IWebserverPropfind * const webserverPropfind) = 0;
    virtual void WebserverPropfindSendResult(IWebserverPropfind * const webserverPropfind) = 0;
    virtual void WebserverPropfindRecvResult(IWebserverPropfind * const webserverPropfind, void * buffer, size_t len) = 0;
    virtual void * WebserverPropfindRecvBuffer(size_t len)
    {
        return nullptr;
    }
    virtual void WebserverPropfindRecvCanceled(IWebserverPropfind * const webserverPropfind, void * buffer) = 0;
    virtual void WebserverPropfindCloseComplete(IWebserverPropfind * const webserverPropfind) = 0;
};


// Webserver Plugin - Move
class IWebserverMove {
public:
    virtual ~IWebserverMove() {}

	virtual dword GetConnectionID() = 0;
    virtual const char * GetResourceName() = 0;
    virtual const char * GetRegisteredPathForRequest() = 0;
    virtual const char * GetHeaderFieldValue(const char * fieldName) = 0;
    virtual const char * GetRemoteAddress() = 0;
    virtual word GetRemotePort() = 0;
    virtual bool IsEncryptedConnection() = 0;
    virtual class IDigestAuthenticator * GetAuthenticator() = 0;

    virtual void SetResultCode(ws_webdav_result_t result, ulong64 dataSize = 0) = 0;
    virtual void SetLocation(const char * location) = 0;
    virtual void SetTransferInfo(wsr_type_t resourceType, ulong64 dataSize, wsr_flags_t flags = WSP_FLAG_NONE, const char* etag = nullptr) = 0;
	virtual void SetStatusCode(dword code, const char * description = nullptr) = 0;
    virtual void SetHeaderField(const char * fname, const char * fvalue) = 0;
	virtual void Cancel(wsr_cancel_type_t reason) = 0;
    virtual void Send(const void * buffer, size_t len) = 0;
    virtual void Close() = 0;
};


class UWebserverMove {
public:
    virtual ~UWebserverMove() {};
    virtual void WebserverMoveRequestAcceptComplete(IWebserverMove * const webserverMove) = 0;
    virtual void WebserverMoveSendResult(IWebserverMove * const webserverMove) = 0;
    virtual void WebserverMoveCloseComplete(IWebserverMove * const webserverMove) = 0;
};


// Webserver Plugin - MkCol
class IWebserverMkCol {
public:
    virtual ~IWebserverMkCol() {}

	virtual dword GetConnectionID() = 0;
    virtual const char * GetResourceName() = 0;
    virtual const char * GetRegisteredPathForRequest() = 0;
    virtual const char * GetHeaderFieldValue(const char * fieldName) = 0;
    virtual const char * GetRemoteAddress() = 0;
    virtual word GetRemotePort() = 0;
    virtual bool IsEncryptedConnection() = 0;
    virtual class IDigestAuthenticator * GetAuthenticator() = 0;

    virtual void SetResultCode(ws_webdav_result_t result, ulong64 dataSize = 0) = 0;
    virtual void SetLocation(const char * location) = 0;
    virtual void SetTransferInfo(wsr_type_t resourceType, ulong64 dataSize, wsr_flags_t flags = WSP_FLAG_NONE, const char* etag = nullptr) = 0;
	virtual void SetStatusCode(dword code, const char * description = nullptr) = 0;
    virtual void SetHeaderField(const char * fname, const char * fvalue) = 0;
	virtual void Cancel(wsr_cancel_type_t reason) = 0;
    virtual void Send(const void * buffer, size_t len) = 0;
    virtual void Close() = 0;
};


class UWebserverMkCol {
public:
    virtual ~UWebserverMkCol() {};
    virtual void WebserverMkColRequestAcceptComplete(IWebserverMkCol * const webserverMkCol) = 0;
    virtual void WebserverMkColSendResult(IWebserverMkCol * const webserverMkCol) = 0;
    virtual void WebserverMkColCloseComplete(IWebserverMkCol * const webserverMkCol) = 0;
};


// Webserver Plugin - Copy
class IWebserverCopy {
public:
    virtual ~IWebserverCopy() {}

	virtual dword GetConnectionID() = 0;
    virtual const char * GetResourceName() = 0;
    virtual const char * GetRegisteredPathForRequest() = 0;
    virtual const char * GetHeaderFieldValue(const char * fieldName) = 0;
    virtual const char * GetRemoteAddress() = 0;
    virtual word GetRemotePort() = 0;
    virtual bool IsEncryptedConnection() = 0;
    virtual class IDigestAuthenticator * GetAuthenticator() = 0;

    virtual void SetResultCode(ws_webdav_result_t result, ulong64 dataSize = 0) = 0;
    virtual void SetTransferInfo(wsr_type_t resourceType, ulong64 dataSize, wsr_flags_t flags = WSP_FLAG_NONE, const char* etag = nullptr) = 0;
	virtual void SetStatusCode(dword code, const char * description = nullptr) = 0;
    virtual void SetHeaderField(const char * fname, const char * fvalue) = 0;
	virtual void Cancel(wsr_cancel_type_t reason) = 0;
    virtual void Send(const void * buffer, size_t len) = 0;
    virtual void Close() = 0;
};


class UWebserverCopy {
public:
    virtual ~UWebserverCopy() {};
    virtual void WebserverCopyRequestAcceptComplete(IWebserverCopy * const webserverCopy) = 0;
    virtual void WebserverCopySendResult(IWebserverCopy * const webserverCopy) = 0;
    virtual void WebserverCopyCloseComplete(IWebserverCopy * const webserverCopy) = 0;
};


// Webserver Plugin - Delete
class IWebserverDelete {
public:
    virtual ~IWebserverDelete() {}

	virtual dword GetConnectionID() = 0;
    virtual const char * GetResourceName() = 0;
    virtual const char * GetRegisteredPathForRequest() = 0;
    virtual const char * GetHeaderFieldValue(const char * fieldName) = 0;
    virtual const char * GetRemoteAddress() = 0;
    virtual word GetRemotePort() = 0;
    virtual bool IsEncryptedConnection() = 0;
    virtual class IDigestAuthenticator * GetAuthenticator() = 0;

    virtual void SetResultCode(ws_webdav_result_t result, ulong64 dataSize = 0) = 0;
    virtual void SetTransferInfo(wsr_type_t resourceType, ulong64 dataSize, wsr_flags_t flags = WSP_FLAG_NONE, const char* etag = nullptr) = 0;
    virtual void SetStatusCode(dword code, const char * description = nullptr) = 0;
    virtual void SetHeaderField(const char * fname, const char * fvalue) = 0;
	virtual void Cancel(wsr_cancel_type_t reason) = 0;
    virtual void Send(const void * buffer, size_t len) = 0;
    virtual void Close() = 0;
};


class UWebserverDelete {
public:
    virtual ~UWebserverDelete() {};
    virtual void WebserverDeleteRequestAcceptComplete(IWebserverDelete * const webserverDelete) = 0;
    virtual void WebserverDeleteSendResult(IWebserverDelete * const webserverDelete) = 0;
    virtual void WebserverDeleteCloseComplete(IWebserverDelete * const webserverDelete) = 0;
};


// Webserver Plugin - Lock
class IWebserverLock {
public:
    virtual ~IWebserverLock() {}

	virtual dword GetConnectionID() = 0;
    virtual const char * GetResourceName() = 0;
    virtual const char * GetRegisteredPathForRequest() = 0;
    virtual const char * GetHeaderFieldValue(const char * fieldName) = 0;
    virtual const char * GetRemoteAddress() = 0;
    virtual word GetRemotePort() = 0;
    virtual bool IsEncryptedConnection() = 0;
    virtual class IDigestAuthenticator * GetAuthenticator() = 0;

    virtual void SetResultCode(ws_webdav_result_t result, ulong64 dataSize = 0) = 0;
    virtual void SetTransferInfo(wsr_type_t resourceType, ulong64 dataSize, wsr_flags_t flags = WSP_FLAG_NONE, const char* etag = nullptr) = 0;
    virtual void SetStatusCode(dword code, const char * description = nullptr) = 0;
    virtual void SetHeaderField(const char * fname, const char * fvalue) = 0;
	virtual void Cancel(wsr_cancel_type_t reason) = 0;
    virtual void Recv(void * buffer = nullptr, size_t len = 0) = 0;
    virtual void Send(const void * buffer, size_t len) = 0;
    virtual void Close() = 0;
};


class UWebserverLock {
public:
    virtual ~UWebserverLock() {};
    virtual void WebserverLockRequestAcceptComplete(IWebserverLock * const webserverLock) = 0;
    virtual void WebserverLockSendResult(IWebserverLock * const webserverLock) = 0;
    virtual void WebserverLockRecvResult(IWebserverLock * const webserverLock, void * buffer, size_t len) = 0;
    virtual void * WebserverLockRecvBuffer(size_t len)
    {
        return nullptr;
    }
    virtual void WebserverLockRecvCanceled(IWebserverLock * const webserverLock, void * buffer) = 0;
    virtual void WebserverLockCloseComplete(IWebserverLock * const webserverLock) = 0;
};


// Webserver Plugin - Unlock
class IWebserverUnlock {
public:
    virtual ~IWebserverUnlock() {}

	virtual dword GetConnectionID() = 0;
    virtual const char * GetResourceName() = 0;
    virtual const char * GetRegisteredPathForRequest() = 0;
    virtual const char * GetHeaderFieldValue(const char * fieldName) = 0;
    virtual const char * GetRemoteAddress() = 0;
    virtual word GetRemotePort() = 0;
    virtual bool IsEncryptedConnection() = 0;
    virtual class IDigestAuthenticator * GetAuthenticator() = 0;

    virtual void SetResultCode(ws_webdav_result_t result, ulong64 dataSize = 0) = 0;
    virtual void SetTransferInfo(wsr_type_t resourceType, ulong64 dataSize, wsr_flags_t flags = WSP_FLAG_NONE, const char* etag = nullptr) = 0;
    virtual void SetStatusCode(dword code, const char * description = nullptr) = 0;
    virtual void SetHeaderField(const char * fname, const char * fvalue) = 0;
	virtual void Cancel(wsr_cancel_type_t reason) = 0;
    virtual void Send(const void * buffer, size_t len) = 0;
    virtual void Close() = 0;
};


class UWebserverUnlock {
public:
    virtual ~UWebserverUnlock() {};
    virtual void WebserverUnlockRequestAcceptComplete(IWebserverUnlock * const webserverUnlock) = 0;
    virtual void WebserverUnlockSendResult(IWebserverUnlock * const webserverUnlock) = 0;
    virtual void WebserverUnlockCloseComplete(IWebserverUnlock * const webserverUnlock) = 0;
};


// Webserver Plugin - Proppatch
class IWebserverProppatch {
public:
    virtual ~IWebserverProppatch() {}

	virtual dword GetConnectionID() = 0;
    virtual const char * GetResourceName() = 0;
    virtual const char * GetRegisteredPathForRequest() = 0;
    virtual const char * GetHeaderFieldValue(const char * fieldName) = 0;
    virtual const char * GetRemoteAddress() = 0;
    virtual word GetRemotePort() = 0;
    virtual bool IsEncryptedConnection() = 0;
    virtual class IDigestAuthenticator * GetAuthenticator() = 0;

    virtual void SetResultCode(ws_webdav_result_t result, ulong64 dataSize = 0) = 0;
    virtual void SetTransferInfo(wsr_type_t resourceType, ulong64 dataSize, wsr_flags_t flags = WSP_FLAG_NONE, const char* etag = nullptr) = 0;
    virtual void SetStatusCode(dword code, const char * description = nullptr) = 0;
    virtual void SetHeaderField(const char * fname, const char * fvalue) = 0;
	virtual void Cancel(wsr_cancel_type_t reason) = 0;
    virtual void Recv(void * buffer = nullptr, size_t len = 0) = 0;
    virtual void Send(const void * buffer, size_t len) = 0;
    virtual void Close() = 0;
};


class UWebserverProppatch {
public:
    virtual ~UWebserverProppatch() {};
    virtual void WebserverProppatchRequestAcceptComplete(IWebserverProppatch * const webserverProppatch) = 0;
    virtual void WebserverProppatchSendResult(IWebserverProppatch * const webserverProppatch) = 0;
    virtual void WebserverProppatchRecvResult(IWebserverProppatch * const webserverProppatch, void * buffer, size_t len) = 0;
    virtual void * WebserverProppatchRecvBuffer(size_t len)
    {
        return nullptr;
    }
    virtual void WebserverProppatchRecvCanceled(IWebserverProppatch * const webserverProppatch, void * buffer) = 0;
    virtual void WebserverProppatchCloseComplete(IWebserverProppatch * const webserverProppatch) = 0;
};


// Webserver Plugin - Options
class IWebserverOptions {
public:
    virtual ~IWebserverOptions() {}

	virtual dword GetConnectionID() = 0;
    virtual const char * GetResourceName() = 0;
    virtual const char * GetRegisteredPathForRequest() = 0;
    virtual const char * GetHeaderFieldValue(const char * fieldName) = 0;
    virtual const char * GetRemoteAddress() = 0;
    virtual word GetRemotePort() = 0;
    virtual bool IsEncryptedConnection() = 0;
    virtual class IDigestAuthenticator * GetAuthenticator() = 0;

    virtual void SetSupportedRequests(dword requestList) = 0;
    virtual void SetTransferInfo(wsr_type_t resourceType, ulong64 dataSize, wsr_flags_t flags = WSP_FLAG_NONE, const char* etag = nullptr) = 0;
    virtual void SetStatusCode(dword code, const char * description = nullptr) = 0;
    virtual void SetHeaderField(const char * fname, const char * fvalue) = 0;
    virtual void Send(const void* buffer, size_t len) = 0;
    virtual void Close() = 0;
};


class UWebserverOptions {
public:
    virtual ~UWebserverOptions() {}
    virtual void WebserverOptionsRequestAcceptComplete(IWebserverOptions * const webserverOptions)
    {
        webserverOptions->SetSupportedRequests(WS_REQUEST_GET | WS_REQUEST_POST | WS_REQUEST_PUT |
            WS_REQUEST_PROPFIND | WS_REQUEST_MOVE | WS_REQUEST_COPY |
            WS_REQUEST_MKCOL | WS_REQUEST_DELETE | WS_REQUEST_OPTIONS |
            WS_REQUEST_LOCK | WS_REQUEST_UNLOCK | WS_REQUEST_PROPPATCH);
        webserverOptions->Close();
    }

    virtual void WebserverOptionsSendResult(IWebserverOptions * const webserverOptions) {}
    virtual void WebserverOptionsCloseComplete(IWebserverOptions * const webserverOptions) = 0;
};


// Webserver Plugin - Websocket
class IWebsocket {
public:
    virtual ~IWebsocket() {}

	virtual dword GetConnectionID() = 0;
    virtual const char * GetHost() = 0;
    virtual const char * GetPath() = 0;
    virtual const char * GetHeaderFieldValue(const char * fieldName) = 0;
    virtual const char * GetRemoteAddress() = 0;
    virtual word GetRemotePort() = 0;
    virtual bool IsSysClientAuthenticated() { return false; };
    virtual bool IsLocalHost() = 0;
    virtual bool IsEncryptedConnection() = 0;

    virtual void Send(const void * buffer, size_t len, bool text = true) = 0;
    virtual void Recv(void * buf = nullptr, size_t len = 0) = 0;
    virtual void Close() = 0;
};


class UWebsocket {
public:
    virtual ~UWebsocket() {}
    virtual void WebsocketAcceptComplete(class IWebsocket * websocket) = 0;
    virtual void WebsocketSendResult(class IWebsocket * websocket) = 0;
    virtual void WebsocketRecvResult(class IWebsocket * websocket, void * buffer, size_t len, bool text, bool isFragmented) = 0;
    virtual void * WebsocketRecvBuffer(size_t len) { return nullptr; }
    virtual void WebsocketRecvCanceled(class IWebsocket * websocket, void * buffer) = 0;
    virtual void WebsocketCloseComplete(class IWebsocket * websocket, ws_close_reason_t reason) = 0;
};


class IDigestAuthenticator {
protected:
	virtual ~IDigestAuthenticator()	{}
	
public:
	
	virtual const char * User() = 0;
	virtual const char * RequestTarget() = 0;
	virtual const char * AuthenticationHeaderField() = 0;
	virtual bool IsAuthenticated(const char * user, const char * password) = 0;
	virtual void SendAuthenticationRequest() = 0;
	virtual void SendAuthenticationRequest(const char * body, size_t bodySize, wsr_type_t respopnseType = WSP_RESPONSE_HTML) = 0;
};
