winhttp: Add support for WebSocket fragment buffers.
Signed-off-by: Hans Leidekker <hans@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
938b3e5771
commit
6d564bd53e
|
@ -3156,33 +3156,16 @@ static DWORD send_bytes( struct netconn *netconn, char *bytes, int len )
|
||||||
return (count == len) ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR;
|
return (count == len) ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* rfc6455 */
|
static enum socket_opcode map_buffer_type( WINHTTP_WEB_SOCKET_BUFFER_TYPE type )
|
||||||
enum opcode
|
|
||||||
{
|
|
||||||
OPCODE_CONTINUE = 0x00,
|
|
||||||
OPCODE_TEXT = 0x01,
|
|
||||||
OPCODE_BINARY = 0x02,
|
|
||||||
OPCODE_RESERVED3 = 0x03,
|
|
||||||
OPCODE_RESERVED4 = 0x04,
|
|
||||||
OPCODE_RESERVED5 = 0x05,
|
|
||||||
OPCODE_RESERVED6 = 0x06,
|
|
||||||
OPCODE_RESERVED7 = 0x07,
|
|
||||||
OPCODE_CLOSE = 0x08,
|
|
||||||
OPCODE_PING = 0x09,
|
|
||||||
OPCODE_PONG = 0x0a,
|
|
||||||
OPCODE_INVALID = 0xff,
|
|
||||||
};
|
|
||||||
|
|
||||||
static enum opcode map_buffer_type( WINHTTP_WEB_SOCKET_BUFFER_TYPE type )
|
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE: return OPCODE_TEXT;
|
case WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE: return SOCKET_OPCODE_TEXT;
|
||||||
case WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE: return OPCODE_BINARY;
|
case WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE: return SOCKET_OPCODE_BINARY;
|
||||||
case WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE: return OPCODE_CLOSE;
|
case WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE: return SOCKET_OPCODE_CLOSE;
|
||||||
default:
|
default:
|
||||||
FIXME("buffer type %u not supported\n", type);
|
FIXME("buffer type %u not supported\n", type);
|
||||||
return OPCODE_INVALID;
|
return SOCKET_OPCODE_INVALID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3194,10 +3177,10 @@ static DWORD send_frame( struct netconn *netconn, WINHTTP_WEB_SOCKET_BUFFER_TYPE
|
||||||
DWORD buflen, BOOL final )
|
DWORD buflen, BOOL final )
|
||||||
{
|
{
|
||||||
DWORD i = 0, j, ret, offset = 2, len = buflen;
|
DWORD i = 0, j, ret, offset = 2, len = buflen;
|
||||||
enum opcode opcode = map_buffer_type( type );
|
enum socket_opcode opcode = map_buffer_type( type );
|
||||||
char hdr[14], byte, *mask;
|
char hdr[14], byte, *mask;
|
||||||
|
|
||||||
if (opcode == OPCODE_CLOSE) len += sizeof(status);
|
if (opcode == SOCKET_OPCODE_CLOSE) len += sizeof(status);
|
||||||
|
|
||||||
hdr[0] = final ? (char)FIN_BIT : 0;
|
hdr[0] = final ? (char)FIN_BIT : 0;
|
||||||
hdr[0] |= opcode;
|
hdr[0] |= opcode;
|
||||||
|
@ -3224,7 +3207,7 @@ static DWORD send_frame( struct netconn *netconn, WINHTTP_WEB_SOCKET_BUFFER_TYPE
|
||||||
RtlGenRandom( mask, 4 );
|
RtlGenRandom( mask, 4 );
|
||||||
if ((ret = send_bytes( netconn, hdr, offset + 4 ))) return ret;
|
if ((ret = send_bytes( netconn, hdr, offset + 4 ))) return ret;
|
||||||
|
|
||||||
if (opcode == OPCODE_CLOSE) /* prepend status code */
|
if (opcode == SOCKET_OPCODE_CLOSE) /* prepend status code */
|
||||||
{
|
{
|
||||||
byte = (status >> 8) ^ mask[i++ % 4];
|
byte = (status >> 8) ^ mask[i++ % 4];
|
||||||
if ((ret = send_bytes( netconn, &byte, 1 ))) return ret;
|
if ((ret = send_bytes( netconn, &byte, 1 ))) return ret;
|
||||||
|
@ -3331,34 +3314,39 @@ static DWORD receive_bytes( struct netconn *netconn, char *buf, DWORD len, DWORD
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WINHTTP_WEB_SOCKET_BUFFER_TYPE map_opcode( enum opcode opcode )
|
static WINHTTP_WEB_SOCKET_BUFFER_TYPE map_opcode( enum socket_opcode opcode, BOOL fragment )
|
||||||
{
|
{
|
||||||
switch (opcode)
|
switch (opcode)
|
||||||
{
|
{
|
||||||
case OPCODE_TEXT: return WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE;
|
case SOCKET_OPCODE_TEXT:
|
||||||
case OPCODE_BINARY: return WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE;
|
if (fragment) return WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE;
|
||||||
case OPCODE_CLOSE: return WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE;
|
return WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE;
|
||||||
|
|
||||||
|
case SOCKET_OPCODE_BINARY:
|
||||||
|
if (fragment) return WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE;
|
||||||
|
return WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE;
|
||||||
|
|
||||||
|
case SOCKET_OPCODE_CLOSE:
|
||||||
|
return WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ERR("opcode %u not handled\n", opcode);
|
FIXME("opcode %u not handled\n", opcode);
|
||||||
return ~0u;
|
return ~0u;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD receive_frame( struct netconn *netconn, DWORD *ret_len, WINHTTP_WEB_SOCKET_BUFFER_TYPE *ret_type )
|
static DWORD receive_frame( struct netconn *netconn, DWORD *ret_len, enum socket_opcode *opcode )
|
||||||
{
|
{
|
||||||
WINHTTP_WEB_SOCKET_BUFFER_TYPE type;
|
|
||||||
DWORD ret, len, count;
|
DWORD ret, len, count;
|
||||||
enum opcode opcode;
|
|
||||||
char hdr[2];
|
char hdr[2];
|
||||||
|
|
||||||
if ((ret = receive_bytes( netconn, hdr, sizeof(hdr), &count ))) return ret;
|
if ((ret = receive_bytes( netconn, hdr, sizeof(hdr), &count ))) return ret;
|
||||||
if (count != sizeof(hdr) || (hdr[0] & RESERVED_BIT) || (hdr[1] & MASK_BIT))
|
if (count != sizeof(hdr) || (hdr[0] & RESERVED_BIT) || (hdr[1] & MASK_BIT) ||
|
||||||
|
(map_opcode( hdr[0] & 0xf, FALSE ) == ~0u))
|
||||||
{
|
{
|
||||||
return ERROR_WINHTTP_INVALID_SERVER_RESPONSE;
|
return ERROR_WINHTTP_INVALID_SERVER_RESPONSE;
|
||||||
}
|
}
|
||||||
|
*opcode = hdr[0] & 0xf;
|
||||||
opcode = hdr[0] & 0xf;
|
|
||||||
type = map_opcode( opcode );
|
|
||||||
|
|
||||||
len = hdr[1] & ~MASK_BIT;
|
len = hdr[1] & ~MASK_BIT;
|
||||||
if (len == 126)
|
if (len == 126)
|
||||||
|
@ -3378,7 +3366,6 @@ static DWORD receive_frame( struct netconn *netconn, DWORD *ret_len, WINHTTP_WEB
|
||||||
}
|
}
|
||||||
|
|
||||||
*ret_len = len;
|
*ret_len = len;
|
||||||
*ret_type = type;
|
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3387,7 +3374,7 @@ static DWORD socket_receive( struct socket *socket, void *buf, DWORD len, DWORD
|
||||||
{
|
{
|
||||||
DWORD count, ret = ERROR_SUCCESS;
|
DWORD count, ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
if (!socket->read_size) ret = receive_frame( socket->request->netconn, &socket->read_size, &socket->buf_type );
|
if (!socket->read_size) ret = receive_frame( socket->request->netconn, &socket->read_size, &socket->opcode );
|
||||||
if (!ret) ret = receive_bytes( socket->request->netconn, buf, min(len, socket->read_size), &count );
|
if (!ret) ret = receive_bytes( socket->request->netconn, buf, min(len, socket->read_size), &count );
|
||||||
if (!ret)
|
if (!ret)
|
||||||
{
|
{
|
||||||
|
@ -3395,7 +3382,7 @@ static DWORD socket_receive( struct socket *socket, void *buf, DWORD len, DWORD
|
||||||
if (!async)
|
if (!async)
|
||||||
{
|
{
|
||||||
*ret_len = count;
|
*ret_len = count;
|
||||||
*ret_type = socket->buf_type;
|
*ret_type = map_opcode( socket->opcode, socket->read_size != 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3405,7 +3392,7 @@ static DWORD socket_receive( struct socket *socket, void *buf, DWORD len, DWORD
|
||||||
{
|
{
|
||||||
WINHTTP_WEB_SOCKET_STATUS status;
|
WINHTTP_WEB_SOCKET_STATUS status;
|
||||||
status.dwBytesTransferred = count;
|
status.dwBytesTransferred = count;
|
||||||
status.eBufferType = socket->buf_type;
|
status.eBufferType = map_opcode( socket->opcode, socket->read_size != 0 );
|
||||||
send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, &status, sizeof(status) );
|
send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, &status, sizeof(status) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -3558,8 +3545,8 @@ static DWORD socket_close( struct socket *socket, USHORT status, const void *rea
|
||||||
socket->state = SOCKET_STATE_SHUTDOWN;
|
socket->state = SOCKET_STATE_SHUTDOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ret = receive_frame( netconn, &count, &socket->buf_type ))) goto done;
|
if ((ret = receive_frame( netconn, &count, &socket->opcode ))) goto done;
|
||||||
if (socket->buf_type != WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE || (count && count > sizeof(socket->reason)))
|
if (socket->opcode != SOCKET_OPCODE_CLOSE || (count && count > sizeof(socket->reason)))
|
||||||
{
|
{
|
||||||
ret = ERROR_WINHTTP_INVALID_SERVER_RESPONSE;
|
ret = ERROR_WINHTTP_INVALID_SERVER_RESPONSE;
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
@ -221,6 +221,23 @@ enum socket_state
|
||||||
SOCKET_STATE_CLOSED = 2,
|
SOCKET_STATE_CLOSED = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* rfc6455 */
|
||||||
|
enum socket_opcode
|
||||||
|
{
|
||||||
|
SOCKET_OPCODE_CONTINUE = 0x00,
|
||||||
|
SOCKET_OPCODE_TEXT = 0x01,
|
||||||
|
SOCKET_OPCODE_BINARY = 0x02,
|
||||||
|
SOCKET_OPCODE_RESERVED3 = 0x03,
|
||||||
|
SOCKET_OPCODE_RESERVED4 = 0x04,
|
||||||
|
SOCKET_OPCODE_RESERVED5 = 0x05,
|
||||||
|
SOCKET_OPCODE_RESERVED6 = 0x06,
|
||||||
|
SOCKET_OPCODE_RESERVED7 = 0x07,
|
||||||
|
SOCKET_OPCODE_CLOSE = 0x08,
|
||||||
|
SOCKET_OPCODE_PING = 0x09,
|
||||||
|
SOCKET_OPCODE_PONG = 0x0a,
|
||||||
|
SOCKET_OPCODE_INVALID = 0xff,
|
||||||
|
};
|
||||||
|
|
||||||
struct socket
|
struct socket
|
||||||
{
|
{
|
||||||
struct object_header hdr;
|
struct object_header hdr;
|
||||||
|
@ -228,7 +245,7 @@ struct socket
|
||||||
enum socket_state state;
|
enum socket_state state;
|
||||||
struct queue send_q;
|
struct queue send_q;
|
||||||
struct queue recv_q;
|
struct queue recv_q;
|
||||||
WINHTTP_WEB_SOCKET_BUFFER_TYPE buf_type;
|
enum socket_opcode opcode;
|
||||||
DWORD read_size;
|
DWORD read_size;
|
||||||
USHORT status;
|
USHORT status;
|
||||||
char reason[128];
|
char reason[128];
|
||||||
|
|
Loading…
Reference in New Issue