winhttp: Implement WinHttpWebSocketCompleteUpgrade.
Signed-off-by: Hans Leidekker <hans@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
a6de059eef
commit
0b48050da5
|
@ -33,6 +33,7 @@
|
||||||
#include "httprequestid.h"
|
#include "httprequestid.h"
|
||||||
#include "schannel.h"
|
#include "schannel.h"
|
||||||
#include "winhttp.h"
|
#include "winhttp.h"
|
||||||
|
#include "ntsecapi.h"
|
||||||
|
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
#include "winhttp_private.h"
|
#include "winhttp_private.h"
|
||||||
|
@ -2098,6 +2099,25 @@ static char *build_wire_request( struct request *request, DWORD *len )
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static WCHAR *create_websocket_key(void)
|
||||||
|
{
|
||||||
|
WCHAR *ret;
|
||||||
|
char buf[16];
|
||||||
|
DWORD base64_len = ((sizeof(buf) + 2) * 4) / 3;
|
||||||
|
if (!RtlGenRandom( buf, sizeof(buf) )) return NULL;
|
||||||
|
if ((ret = heap_alloc( (base64_len + 1) * sizeof(WCHAR) ))) encode_base64( buf, sizeof(buf), ret );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD add_websocket_key_header( struct request *request )
|
||||||
|
{
|
||||||
|
WCHAR *key = create_websocket_key();
|
||||||
|
if (!key) return ERROR_OUTOFMEMORY;
|
||||||
|
process_header( request, L"Sec-WebSocket-Key", key, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE, TRUE );
|
||||||
|
heap_free( key );
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static DWORD send_request( struct request *request, const WCHAR *headers, DWORD headers_len, void *optional,
|
static DWORD send_request( struct request *request, const WCHAR *headers, DWORD headers_len, void *optional,
|
||||||
DWORD optional_len, DWORD total_len, DWORD_PTR context, BOOL async )
|
DWORD optional_len, DWORD total_len, DWORD_PTR context, BOOL async )
|
||||||
{
|
{
|
||||||
|
@ -2125,7 +2145,14 @@ static DWORD send_request( struct request *request, const WCHAR *headers, DWORD
|
||||||
swprintf( length, ARRAY_SIZE(length), L"%ld", total_len );
|
swprintf( length, ARRAY_SIZE(length), L"%ld", total_len );
|
||||||
process_header( request, L"Content-Length", length, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE );
|
process_header( request, L"Content-Length", length, WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE );
|
||||||
}
|
}
|
||||||
if (!(request->hdr.disable_flags & WINHTTP_DISABLE_KEEP_ALIVE))
|
if (request->flags & REQUEST_FLAG_WEBSOCKET_UPGRADE)
|
||||||
|
{
|
||||||
|
process_header( request, L"Upgrade", L"websocket", WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE );
|
||||||
|
process_header( request, L"Connection", L"Upgrade", WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE );
|
||||||
|
process_header( request, L"Sec-WebSocket-Version", L"13", WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE );
|
||||||
|
if ((ret = add_websocket_key_header( request ))) return ret;
|
||||||
|
}
|
||||||
|
else if (!(request->hdr.disable_flags & WINHTTP_DISABLE_KEEP_ALIVE))
|
||||||
{
|
{
|
||||||
process_header( request, L"Connection", L"Keep-Alive", WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE );
|
process_header( request, L"Connection", L"Keep-Alive", WINHTTP_ADDREQ_FLAG_ADD_IF_NEW, TRUE );
|
||||||
}
|
}
|
||||||
|
@ -3016,10 +3043,78 @@ BOOL WINAPI WinHttpWriteData( HINTERNET hrequest, LPCVOID buffer, DWORD to_write
|
||||||
return !ret;
|
return !ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL socket_query_option( struct object_header *hdr, DWORD option, void *buffer, DWORD *buflen )
|
||||||
|
{
|
||||||
|
FIXME("unimplemented option %u\n", option);
|
||||||
|
SetLastError( ERROR_WINHTTP_INVALID_OPTION );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void socket_destroy( struct object_header *hdr )
|
||||||
|
{
|
||||||
|
struct socket *socket = (struct socket *)hdr;
|
||||||
|
|
||||||
|
TRACE("%p\n", socket);
|
||||||
|
|
||||||
|
release_object( &socket->request->hdr );
|
||||||
|
heap_free( socket );
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL socket_set_option( struct object_header *hdr, DWORD option, void *buffer, DWORD buflen )
|
||||||
|
{
|
||||||
|
FIXME("unimplemented option %u\n", option);
|
||||||
|
SetLastError( ERROR_WINHTTP_INVALID_OPTION );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct object_vtbl socket_vtbl =
|
||||||
|
{
|
||||||
|
socket_destroy,
|
||||||
|
socket_query_option,
|
||||||
|
socket_set_option,
|
||||||
|
};
|
||||||
|
|
||||||
HINTERNET WINAPI WinHttpWebSocketCompleteUpgrade( HINTERNET hrequest, DWORD_PTR context )
|
HINTERNET WINAPI WinHttpWebSocketCompleteUpgrade( HINTERNET hrequest, DWORD_PTR context )
|
||||||
{
|
{
|
||||||
FIXME("%p, %08lx\n", hrequest, context);
|
struct socket *socket;
|
||||||
return NULL;
|
struct request *request;
|
||||||
|
HINTERNET hsocket = NULL;
|
||||||
|
|
||||||
|
TRACE("%p, %08lx\n", hrequest, context);
|
||||||
|
|
||||||
|
if (!(request = (struct request *)grab_object( hrequest )))
|
||||||
|
{
|
||||||
|
SetLastError( ERROR_INVALID_HANDLE );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
|
||||||
|
{
|
||||||
|
release_object( &request->hdr );
|
||||||
|
SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!(socket = heap_alloc_zero( sizeof(struct socket) )))
|
||||||
|
{
|
||||||
|
release_object( &request->hdr );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
socket->hdr.type = WINHTTP_HANDLE_TYPE_SOCKET;
|
||||||
|
socket->hdr.vtbl = &socket_vtbl;
|
||||||
|
socket->hdr.refs = 1;
|
||||||
|
socket->hdr.context = context;
|
||||||
|
list_init( &socket->hdr.children );
|
||||||
|
|
||||||
|
addref_object( &request->hdr );
|
||||||
|
socket->request = request;
|
||||||
|
list_add_head( &request->hdr.children, &socket->hdr.entry );
|
||||||
|
|
||||||
|
if ((hsocket = alloc_handle( &socket->hdr ))) socket->hdr.handle = hsocket;
|
||||||
|
|
||||||
|
release_object( &socket->hdr );
|
||||||
|
release_object( &request->hdr );
|
||||||
|
TRACE("returning %p\n", hsocket);
|
||||||
|
if (hsocket) SetLastError( ERROR_SUCCESS );
|
||||||
|
return hsocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, void *buf, DWORD len )
|
DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, void *buf, DWORD len )
|
||||||
|
|
|
@ -63,9 +63,6 @@ BOOL WINAPI WinHttpCheckPlatform( void )
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* session_destroy (internal)
|
|
||||||
*/
|
|
||||||
static void session_destroy( struct object_header *hdr )
|
static void session_destroy( struct object_header *hdr )
|
||||||
{
|
{
|
||||||
struct session *session = (struct session *)hdr;
|
struct session *session = (struct session *)hdr;
|
||||||
|
@ -296,9 +293,6 @@ end:
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* connect_destroy (internal)
|
|
||||||
*/
|
|
||||||
static void connect_destroy( struct object_header *hdr )
|
static void connect_destroy( struct object_header *hdr )
|
||||||
{
|
{
|
||||||
struct connect *connect = (struct connect *)hdr;
|
struct connect *connect = (struct connect *)hdr;
|
||||||
|
@ -581,9 +575,6 @@ end:
|
||||||
return hconnect;
|
return hconnect;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* request_destroy (internal)
|
|
||||||
*/
|
|
||||||
static void request_destroy( struct object_header *hdr )
|
static void request_destroy( struct object_header *hdr )
|
||||||
{
|
{
|
||||||
struct request *request = (struct request *)hdr;
|
struct request *request = (struct request *)hdr;
|
||||||
|
@ -1038,6 +1029,10 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET:
|
||||||
|
request->flags |= REQUEST_FLAG_WEBSOCKET_UPGRADE;
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
case WINHTTP_OPTION_CONNECT_RETRIES:
|
case WINHTTP_OPTION_CONNECT_RETRIES:
|
||||||
FIXME("WINHTTP_OPTION_CONNECT_RETRIES\n");
|
FIXME("WINHTTP_OPTION_CONNECT_RETRIES\n");
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
|
@ -3119,7 +3119,7 @@ static void test_websocket(int port)
|
||||||
ok(request != NULL, "got %u\n", GetLastError());
|
ok(request != NULL, "got %u\n", GetLastError());
|
||||||
|
|
||||||
ret = WinHttpSetOption(request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0);
|
ret = WinHttpSetOption(request, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0);
|
||||||
todo_wine ok(ret, "got %u\n", GetLastError());
|
ok(ret, "got %u\n", GetLastError());
|
||||||
|
|
||||||
size = sizeof(header);
|
size = sizeof(header);
|
||||||
SetLastError(0xdeadbeef);
|
SetLastError(0xdeadbeef);
|
||||||
|
@ -3175,41 +3175,41 @@ static void test_websocket(int port)
|
||||||
size = sizeof(buf);
|
size = sizeof(buf);
|
||||||
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
|
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
|
||||||
L"Sec-WebSocket-Key", buf, &size, &index);
|
L"Sec-WebSocket-Key", buf, &size, &index);
|
||||||
todo_wine ok(ret, "got %u\n", GetLastError());
|
ok(ret, "got %u\n", GetLastError());
|
||||||
|
|
||||||
index = 0;
|
index = 0;
|
||||||
buf[0] = 0;
|
buf[0] = 0;
|
||||||
size = sizeof(buf);
|
size = sizeof(buf);
|
||||||
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
|
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
|
||||||
L"Sec-WebSocket-Version", buf, &size, &index);
|
L"Sec-WebSocket-Version", buf, &size, &index);
|
||||||
todo_wine ok(ret, "got %u\n", GetLastError());
|
ok(ret, "got %u\n", GetLastError());
|
||||||
|
|
||||||
ret = WinHttpReceiveResponse(request, NULL);
|
ret = WinHttpReceiveResponse(request, NULL);
|
||||||
todo_wine ok(ret, "got %u\n", GetLastError());
|
ok(ret, "got %u\n", GetLastError());
|
||||||
|
|
||||||
count = 0xdeadbeef;
|
count = 0xdeadbeef;
|
||||||
ret = WinHttpQueryDataAvailable(request, &count);
|
ret = WinHttpQueryDataAvailable(request, &count);
|
||||||
ok(ret, "got %u\n", GetLastError());
|
ok(ret, "got %u\n", GetLastError());
|
||||||
todo_wine ok(!count, "got %u\n", count);
|
ok(!count, "got %u\n", count);
|
||||||
|
|
||||||
header[0] = 0;
|
header[0] = 0;
|
||||||
size = sizeof(header);
|
size = sizeof(header);
|
||||||
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_UPGRADE, NULL, &header, &size, NULL);
|
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_UPGRADE, NULL, &header, &size, NULL);
|
||||||
todo_wine ok(ret, "got %u\n", GetLastError());
|
ok(ret, "got %u\n", GetLastError());
|
||||||
todo_wine ok(!wcscmp( header, L"websocket" ), "got %s\n", wine_dbgstr_w(header));
|
ok(!wcscmp( header, L"websocket" ), "got %s\n", wine_dbgstr_w(header));
|
||||||
|
|
||||||
header[0] = 0;
|
header[0] = 0;
|
||||||
size = sizeof(header);
|
size = sizeof(header);
|
||||||
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CONNECTION, NULL, &header, &size, NULL);
|
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CONNECTION, NULL, &header, &size, NULL);
|
||||||
todo_wine ok(ret, "got %u\n", GetLastError());
|
ok(ret, "got %u\n", GetLastError());
|
||||||
todo_wine ok(!wcscmp( header, L"Upgrade" ), "got %s\n", wine_dbgstr_w(header));
|
ok(!wcscmp( header, L"Upgrade" ), "got %s\n", wine_dbgstr_w(header));
|
||||||
|
|
||||||
status = 0xdeadbeef;
|
status = 0xdeadbeef;
|
||||||
size = sizeof(status);
|
size = sizeof(status);
|
||||||
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status,
|
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status,
|
||||||
&size, NULL);
|
&size, NULL);
|
||||||
ok(ret, "got %u\n", GetLastError());
|
ok(ret, "got %u\n", GetLastError());
|
||||||
todo_wine ok(status == HTTP_STATUS_SWITCH_PROTOCOLS, "got %u\n", status);
|
ok(status == HTTP_STATUS_SWITCH_PROTOCOLS, "got %u\n", status);
|
||||||
|
|
||||||
len = 0xdeadbeef;
|
len = 0xdeadbeef;
|
||||||
size = sizeof(len);
|
size = sizeof(len);
|
||||||
|
@ -3220,27 +3220,27 @@ static void test_websocket(int port)
|
||||||
index = 0;
|
index = 0;
|
||||||
size = sizeof(buf);
|
size = sizeof(buf);
|
||||||
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM, L"Sec-WebSocket-Accept", buf, &size, &index);
|
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM, L"Sec-WebSocket-Accept", buf, &size, &index);
|
||||||
todo_wine ok(ret, "got %u\n", GetLastError());
|
ok(ret, "got %u\n", GetLastError());
|
||||||
|
|
||||||
socket = pWinHttpWebSocketCompleteUpgrade(request, 0);
|
socket = pWinHttpWebSocketCompleteUpgrade(request, 0);
|
||||||
todo_wine ok(socket != NULL, "got %u\n", GetLastError());
|
ok(socket != NULL, "got %u\n", GetLastError());
|
||||||
|
|
||||||
header[0] = 0;
|
header[0] = 0;
|
||||||
size = sizeof(header);
|
size = sizeof(header);
|
||||||
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_UPGRADE, NULL, &header, &size, NULL);
|
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_UPGRADE, NULL, &header, &size, NULL);
|
||||||
todo_wine ok(ret, "got %u\n", GetLastError());
|
ok(ret, "got %u\n", GetLastError());
|
||||||
todo_wine ok(!wcscmp( header, L"websocket" ), "got %s\n", wine_dbgstr_w(header));
|
ok(!wcscmp( header, L"websocket" ), "got %s\n", wine_dbgstr_w(header));
|
||||||
|
|
||||||
header[0] = 0;
|
header[0] = 0;
|
||||||
size = sizeof(header);
|
size = sizeof(header);
|
||||||
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CONNECTION, NULL, &header, &size, NULL);
|
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CONNECTION, NULL, &header, &size, NULL);
|
||||||
todo_wine ok(ret, "got %u\n", GetLastError());
|
ok(ret, "got %u\n", GetLastError());
|
||||||
todo_wine ok(!wcscmp( header, L"Upgrade" ), "got %s\n", wine_dbgstr_w(header));
|
ok(!wcscmp( header, L"Upgrade" ), "got %s\n", wine_dbgstr_w(header));
|
||||||
|
|
||||||
index = 0;
|
index = 0;
|
||||||
size = sizeof(buf);
|
size = sizeof(buf);
|
||||||
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM, L"Sec-WebSocket-Accept", buf, &size, &index);
|
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM, L"Sec-WebSocket-Accept", buf, &size, &index);
|
||||||
todo_wine ok(ret, "got %u\n", GetLastError());
|
ok(ret, "got %u\n", GetLastError());
|
||||||
|
|
||||||
/* Send/Receive on websock */
|
/* Send/Receive on websock */
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
#include "sspi.h"
|
#include "sspi.h"
|
||||||
#include "wincrypt.h"
|
#include "wincrypt.h"
|
||||||
|
|
||||||
|
#define WINHTTP_HANDLE_TYPE_SOCKET 4
|
||||||
|
|
||||||
struct object_header;
|
struct object_header;
|
||||||
struct object_vtbl
|
struct object_vtbl
|
||||||
{
|
{
|
||||||
|
@ -154,10 +156,16 @@ struct authinfo
|
||||||
BOOL finished; /* finished authenticating */
|
BOOL finished; /* finished authenticating */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum request_flags
|
||||||
|
{
|
||||||
|
REQUEST_FLAG_WEBSOCKET_UPGRADE = 0x01,
|
||||||
|
};
|
||||||
|
|
||||||
struct request
|
struct request
|
||||||
{
|
{
|
||||||
struct object_header hdr;
|
struct object_header hdr;
|
||||||
struct connect *connect;
|
struct connect *connect;
|
||||||
|
enum request_flags flags;
|
||||||
WCHAR *verb;
|
WCHAR *verb;
|
||||||
WCHAR *path;
|
WCHAR *path;
|
||||||
WCHAR *version;
|
WCHAR *version;
|
||||||
|
@ -201,6 +209,12 @@ struct request
|
||||||
} creds[TARGET_MAX][SCHEME_MAX];
|
} creds[TARGET_MAX][SCHEME_MAX];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct socket
|
||||||
|
{
|
||||||
|
struct object_header hdr;
|
||||||
|
struct request *request;
|
||||||
|
};
|
||||||
|
|
||||||
struct task_header
|
struct task_header
|
||||||
{
|
{
|
||||||
struct list entry;
|
struct list entry;
|
||||||
|
|
Loading…
Reference in New Issue