package = io.ktor.cinterop.winhttp
headers = wtypes.h winhttp.h
headerFilter = winhttp.h

compilerOpts = -DUNICODE
linkerOpts = -lwinhttp
---
// These WebSocket declarations are not present in our sysroots,
// so we add them here.
#define WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET            114

typedef enum _WINHTTP_WEB_SOCKET_OPERATION
{
    WINHTTP_WEB_SOCKET_SEND_OPERATION                   = 0,
    WINHTTP_WEB_SOCKET_RECEIVE_OPERATION                = 1,
    WINHTTP_WEB_SOCKET_CLOSE_OPERATION                  = 2,
    WINHTTP_WEB_SOCKET_SHUTDOWN_OPERATION               = 3
} WINHTTP_WEB_SOCKET_OPERATION;

typedef enum _WINHTTP_WEB_SOCKET_BUFFER_TYPE
{
    WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE      = 1,
    WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE       = 0,
    WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE         = 2,
    WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE        = 3,
    WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE                = 4
} WINHTTP_WEB_SOCKET_BUFFER_TYPE;

typedef enum _WINHTTP_WEB_SOCKET_CLOSE_STATUS
{
    WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS                = 1000,
    WINHTTP_WEB_SOCKET_ENDPOINT_TERMINATED_CLOSE_STATUS    = 1001,
    WINHTTP_WEB_SOCKET_PROTOCOL_ERROR_CLOSE_STATUS         = 1002,
    WINHTTP_WEB_SOCKET_INVALID_DATA_TYPE_CLOSE_STATUS      = 1003,
    WINHTTP_WEB_SOCKET_EMPTY_CLOSE_STATUS                  = 1005,
    WINHTTP_WEB_SOCKET_ABORTED_CLOSE_STATUS                = 1006,
    WINHTTP_WEB_SOCKET_INVALID_PAYLOAD_CLOSE_STATUS        = 1007,
    WINHTTP_WEB_SOCKET_POLICY_VIOLATION_CLOSE_STATUS       = 1008,
    WINHTTP_WEB_SOCKET_MESSAGE_TOO_BIG_CLOSE_STATUS        = 1009,
    WINHTTP_WEB_SOCKET_UNSUPPORTED_EXTENSIONS_CLOSE_STATUS = 1010,
    WINHTTP_WEB_SOCKET_SERVER_ERROR_CLOSE_STATUS           = 1011,
    WINHTTP_WEB_SOCKET_SECURE_HANDSHAKE_ERROR_CLOSE_STATUS = 1015
} WINHTTP_WEB_SOCKET_CLOSE_STATUS;

typedef struct _WINHTTP_WEB_SOCKET_ASYNC_RESULT
{
    WINHTTP_ASYNC_RESULT AsyncResult;
    WINHTTP_WEB_SOCKET_OPERATION Operation;
} WINHTTP_WEB_SOCKET_ASYNC_RESULT;

typedef struct _WINHTTP_WEB_SOCKET_STATUS
{
    DWORD dwBytesTransferred;
    WINHTTP_WEB_SOCKET_BUFFER_TYPE eBufferType;
} WINHTTP_WEB_SOCKET_STATUS;

#define WINHTTP_WEB_SOCKET_MAX_CLOSE_REASON_LENGTH 123
#define WINHTTP_WEB_SOCKET_MIN_KEEPALIVE_VALUE 15000

#define WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE          0x02000000
#define WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE       0x04000000

WINHTTPAPI
HINTERNET
WINAPI
WinHttpWebSocketCompleteUpgrade
(
    _In_ HINTERNET hRequest,
    _In_opt_ DWORD_PTR pContext
);

WINHTTPAPI
DWORD
WINAPI
WinHttpWebSocketSend
(
    _In_ HINTERNET hWebSocket,
    _In_ WINHTTP_WEB_SOCKET_BUFFER_TYPE eBufferType,
    _In_reads_opt_(dwBufferLength) PVOID pvBuffer,
    _In_ DWORD dwBufferLength
);

WINHTTPAPI
DWORD
WINAPI
WinHttpWebSocketReceive
(
    _In_ HINTERNET hWebSocket,
    _Out_writes_bytes_to_(dwBufferLength, *pdwBytesRead) PVOID pvBuffer,
    _In_ DWORD dwBufferLength,
    _Out_range_(0, dwBufferLength) DWORD *pdwBytesRead,
    _Out_ WINHTTP_WEB_SOCKET_BUFFER_TYPE *peBufferType
);

WINHTTPAPI
DWORD
WINAPI
WinHttpWebSocketShutdown
(
    _In_ HINTERNET hWebSocket,
    _In_ USHORT usStatus,
    _In_reads_bytes_opt_(dwReasonLength) PVOID pvReason,
    _In_range_(0, WINHTTP_WEB_SOCKET_MAX_CLOSE_REASON_LENGTH) DWORD dwReasonLength
);

WINHTTPAPI
DWORD
WINAPI
WinHttpWebSocketClose
(
    _In_ HINTERNET hWebSocket,
    _In_ USHORT usStatus,
    _In_reads_bytes_opt_(dwReasonLength) PVOID pvReason,
    _In_range_(0, WINHTTP_WEB_SOCKET_MAX_CLOSE_REASON_LENGTH) DWORD dwReasonLength
);

WINHTTPAPI
DWORD
WINAPI
WinHttpWebSocketQueryCloseStatus
(
    _In_ HINTERNET hWebSocket,
    _Out_ USHORT *pusStatus,
    _Out_writes_bytes_to_opt_(dwReasonLength, *pdwReasonLengthConsumed) PVOID pvReason,
    _In_range_(0, WINHTTP_WEB_SOCKET_MAX_CLOSE_REASON_LENGTH) DWORD dwReasonLength,
    _Out_range_(0, WINHTTP_WEB_SOCKET_MAX_CLOSE_REASON_LENGTH) DWORD *pdwReasonLengthConsumed
);
