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 "schannel.h"
|
||||
#include "winhttp.h"
|
||||
#include "ntsecapi.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
#include "winhttp_private.h"
|
||||
|
@ -2098,6 +2099,25 @@ static char *build_wire_request( struct request *request, DWORD *len )
|
|||
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,
|
||||
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 );
|
||||
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 );
|
||||
}
|
||||
|
@ -3016,10 +3043,78 @@ BOOL WINAPI WinHttpWriteData( HINTERNET hrequest, LPCVOID buffer, DWORD to_write
|
|||
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 )
|
||||
{
|
||||
FIXME("%p, %08lx\n", hrequest, context);
|
||||
return NULL;
|
||||
struct socket *socket;
|
||||
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 )
|
||||
|
|
|
@ -63,9 +63,6 @@ BOOL WINAPI WinHttpCheckPlatform( void )
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* session_destroy (internal)
|
||||
*/
|
||||
static void session_destroy( struct object_header *hdr )
|
||||
{
|
||||
struct session *session = (struct session *)hdr;
|
||||
|
@ -296,9 +293,6 @@ end:
|
|||
return handle;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* connect_destroy (internal)
|
||||
*/
|
||||
static void connect_destroy( struct object_header *hdr )
|
||||
{
|
||||
struct connect *connect = (struct connect *)hdr;
|
||||
|
@ -581,9 +575,6 @@ end:
|
|||
return hconnect;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* request_destroy (internal)
|
||||
*/
|
||||
static void request_destroy( struct object_header *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;
|
||||
}
|
||||
|
||||
case WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET:
|
||||
request->flags |= REQUEST_FLAG_WEBSOCKET_UPGRADE;
|
||||
return TRUE;
|
||||
|
||||
case WINHTTP_OPTION_CONNECT_RETRIES:
|
||||
FIXME("WINHTTP_OPTION_CONNECT_RETRIES\n");
|
||||
return TRUE;
|
||||
|
|
|
@ -3119,7 +3119,7 @@ static void test_websocket(int port)
|
|||
ok(request != NULL, "got %u\n", GetLastError());
|
||||
|
||||
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);
|
||||
SetLastError(0xdeadbeef);
|
||||
|
@ -3175,41 +3175,41 @@ static void test_websocket(int port)
|
|||
size = sizeof(buf);
|
||||
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
|
||||
L"Sec-WebSocket-Key", buf, &size, &index);
|
||||
todo_wine ok(ret, "got %u\n", GetLastError());
|
||||
ok(ret, "got %u\n", GetLastError());
|
||||
|
||||
index = 0;
|
||||
buf[0] = 0;
|
||||
size = sizeof(buf);
|
||||
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_REQUEST_HEADERS,
|
||||
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);
|
||||
todo_wine ok(ret, "got %u\n", GetLastError());
|
||||
ok(ret, "got %u\n", GetLastError());
|
||||
|
||||
count = 0xdeadbeef;
|
||||
ret = WinHttpQueryDataAvailable(request, &count);
|
||||
ok(ret, "got %u\n", GetLastError());
|
||||
todo_wine ok(!count, "got %u\n", count);
|
||||
ok(!count, "got %u\n", count);
|
||||
|
||||
header[0] = 0;
|
||||
size = sizeof(header);
|
||||
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_UPGRADE, NULL, &header, &size, NULL);
|
||||
todo_wine ok(ret, "got %u\n", GetLastError());
|
||||
todo_wine ok(!wcscmp( header, L"websocket" ), "got %s\n", wine_dbgstr_w(header));
|
||||
ok(ret, "got %u\n", GetLastError());
|
||||
ok(!wcscmp( header, L"websocket" ), "got %s\n", wine_dbgstr_w(header));
|
||||
|
||||
header[0] = 0;
|
||||
size = sizeof(header);
|
||||
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CONNECTION, NULL, &header, &size, NULL);
|
||||
todo_wine ok(ret, "got %u\n", GetLastError());
|
||||
todo_wine ok(!wcscmp( header, L"Upgrade" ), "got %s\n", wine_dbgstr_w(header));
|
||||
ok(ret, "got %u\n", GetLastError());
|
||||
ok(!wcscmp( header, L"Upgrade" ), "got %s\n", wine_dbgstr_w(header));
|
||||
|
||||
status = 0xdeadbeef;
|
||||
size = sizeof(status);
|
||||
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &status,
|
||||
&size, NULL);
|
||||
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;
|
||||
size = sizeof(len);
|
||||
|
@ -3220,27 +3220,27 @@ static void test_websocket(int port)
|
|||
index = 0;
|
||||
size = sizeof(buf);
|
||||
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);
|
||||
todo_wine ok(socket != NULL, "got %u\n", GetLastError());
|
||||
ok(socket != NULL, "got %u\n", GetLastError());
|
||||
|
||||
header[0] = 0;
|
||||
size = sizeof(header);
|
||||
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_UPGRADE, NULL, &header, &size, NULL);
|
||||
todo_wine ok(ret, "got %u\n", GetLastError());
|
||||
todo_wine ok(!wcscmp( header, L"websocket" ), "got %s\n", wine_dbgstr_w(header));
|
||||
ok(ret, "got %u\n", GetLastError());
|
||||
ok(!wcscmp( header, L"websocket" ), "got %s\n", wine_dbgstr_w(header));
|
||||
|
||||
header[0] = 0;
|
||||
size = sizeof(header);
|
||||
ret = WinHttpQueryHeaders(request, WINHTTP_QUERY_CONNECTION, NULL, &header, &size, NULL);
|
||||
todo_wine ok(ret, "got %u\n", GetLastError());
|
||||
todo_wine ok(!wcscmp( header, L"Upgrade" ), "got %s\n", wine_dbgstr_w(header));
|
||||
ok(ret, "got %u\n", GetLastError());
|
||||
ok(!wcscmp( header, L"Upgrade" ), "got %s\n", wine_dbgstr_w(header));
|
||||
|
||||
index = 0;
|
||||
size = sizeof(buf);
|
||||
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 */
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "sspi.h"
|
||||
#include "wincrypt.h"
|
||||
|
||||
#define WINHTTP_HANDLE_TYPE_SOCKET 4
|
||||
|
||||
struct object_header;
|
||||
struct object_vtbl
|
||||
{
|
||||
|
@ -154,10 +156,16 @@ struct authinfo
|
|||
BOOL finished; /* finished authenticating */
|
||||
};
|
||||
|
||||
enum request_flags
|
||||
{
|
||||
REQUEST_FLAG_WEBSOCKET_UPGRADE = 0x01,
|
||||
};
|
||||
|
||||
struct request
|
||||
{
|
||||
struct object_header hdr;
|
||||
struct connect *connect;
|
||||
enum request_flags flags;
|
||||
WCHAR *verb;
|
||||
WCHAR *path;
|
||||
WCHAR *version;
|
||||
|
@ -201,6 +209,12 @@ struct request
|
|||
} creds[TARGET_MAX][SCHEME_MAX];
|
||||
};
|
||||
|
||||
struct socket
|
||||
{
|
||||
struct object_header hdr;
|
||||
struct request *request;
|
||||
};
|
||||
|
||||
struct task_header
|
||||
{
|
||||
struct list entry;
|
||||
|
|
Loading…
Reference in New Issue