[4/4] webservices: Implement the Message Framing Protocol.
Hans Leidekker
hans at codeweavers.com
Thu Jul 20 08:01:56 CDT 2017
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
dlls/webservices/channel.c | 625 +++++++++++++++++++++++++++++++--
dlls/webservices/proxy.c | 7 +
dlls/webservices/string.c | 47 ++-
dlls/webservices/webservices_private.h | 6 +-
4 files changed, 641 insertions(+), 44 deletions(-)
diff --git a/dlls/webservices/channel.c b/dlls/webservices/channel.c
index 5abd394..09cfd80 100644
--- a/dlls/webservices/channel.c
+++ b/dlls/webservices/channel.c
@@ -21,6 +21,7 @@
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
+#include "rpc.h"
#include "webservices.h"
#include "wine/debug.h"
@@ -85,6 +86,12 @@ static const struct prop_desc channel_props[] =
{ sizeof(ULONG), FALSE } /* WS_CHANNEL_PROPERTY_MAX_HTTP_REQUEST_HEADERS_BUFFER_SIZE */
};
+enum session_state
+{
+ SESSION_STATE_UNINITIALIZED,
+ SESSION_STATE_SETUP_COMPLETE,
+};
+
struct channel
{
ULONG magic;
@@ -97,6 +104,8 @@ struct channel
WS_XML_READER *reader;
WS_MESSAGE *msg;
WS_ENCODING encoding;
+ enum session_state session_state;
+ struct dictionary dict;
union
{
struct
@@ -142,12 +151,14 @@ static struct channel *alloc_channel(void)
static void reset_channel( struct channel *channel )
{
- channel->state = WS_CHANNEL_STATE_CREATED;
+ channel->state = WS_CHANNEL_STATE_CREATED;
heap_free( channel->addr.url.chars );
- channel->addr.url.chars = NULL;
- channel->addr.url.length = 0;
- channel->msg = NULL;
- channel->read_size = 0;
+ channel->addr.url.chars = NULL;
+ channel->addr.url.length = 0;
+ channel->msg = NULL;
+ channel->read_size = 0;
+ channel->session_state = SESSION_STATE_UNINITIALIZED;
+ clear_dict( &channel->dict );
switch (channel->binding)
{
@@ -761,13 +772,218 @@ static HRESULT send_message_http( HANDLE request, BYTE *data, ULONG len )
return S_OK;
}
-static HRESULT send_message_sock( SOCKET socket, BYTE *data, ULONG len )
+static HRESULT send_byte( SOCKET socket, BYTE byte )
{
- if (send( socket, (const char *)data, len, 0 ) < 0)
- return HRESULT_FROM_WIN32( WSAGetLastError() );
+ int count = send( socket, (char *)&byte, 1, 0 );
+ if (count < 0) return HRESULT_FROM_WIN32( WSAGetLastError() );
+ if (count != 1) return WS_E_OTHER;
return S_OK;
}
+static HRESULT send_bytes( SOCKET socket, BYTE *bytes, int len )
+{
+ int count = send( socket, (char *)bytes, len, 0 );
+ if (count < 0) return HRESULT_FROM_WIN32( WSAGetLastError() );
+ if (count != len) return WS_E_OTHER;
+ return S_OK;
+}
+
+static HRESULT send_size( SOCKET socket, ULONG size )
+{
+ HRESULT hr;
+ if (size < 0x80) return send_byte( socket, size );
+ if ((hr = send_byte( socket, (size & 0x7f) | 0x80 )) != S_OK) return hr;
+ if ((size >>= 7) < 0x80) return send_byte( socket, size );
+ if ((hr = send_byte( socket, (size & 0x7f) | 0x80 )) != S_OK) return hr;
+ if ((size >>= 7) < 0x80) return send_byte( socket, size );
+ if ((hr = send_byte( socket, (size & 0x7f) | 0x80 )) != S_OK) return hr;
+ if ((size >>= 7) < 0x80) return send_byte( socket, size );
+ if ((hr = send_byte( socket, (size & 0x7f) | 0x80 )) != S_OK) return hr;
+ if ((size >>= 7) < 0x08) return send_byte( socket, size );
+ return E_INVALIDARG;
+}
+
+enum frame_record_type
+{
+ FRAME_RECORD_TYPE_VERSION,
+ FRAME_RECORD_TYPE_MODE,
+ FRAME_RECORD_TYPE_VIA,
+ FRAME_RECORD_TYPE_KNOWN_ENCODING,
+ FRAME_RECORD_TYPE_EXTENSIBLE_ENCODING,
+ FRAME_RECORD_TYPE_UNSIZED_ENVELOPE,
+ FRAME_RECORD_TYPE_SIZED_ENVELOPE,
+ FRAME_RECORD_TYPE_END,
+ FRAME_RECORD_TYPE_FAULT,
+ FRAME_RECORD_TYPE_UPGRADE_REQUEST,
+ FRAME_RECORD_TYPE_UPGRADE_RESPONSE,
+ FRAME_RECORD_TYPE_PREAMBLE_ACK,
+ FRAME_RECORD_TYPE_PREAMBLE_END,
+};
+
+static inline ULONG size_length( ULONG size )
+{
+ if (size < 0x80) return 1;
+ if (size < 0x4000) return 2;
+ if (size < 0x200000) return 3;
+ if (size < 0x10000000) return 4;
+ return 5;
+}
+
+static ULONG string_table_size( const WS_XML_DICTIONARY *dict )
+{
+ ULONG i, size = 0;
+ for (i = 0; i < dict->stringCount; i++)
+ size += size_length( dict->strings[i].length ) + dict->strings[i].length;
+ return size;
+}
+
+static HRESULT send_string_table( SOCKET socket, const WS_XML_DICTIONARY *dict )
+{
+ ULONG i;
+ HRESULT hr;
+ for (i = 0; i < dict->stringCount; i++)
+ {
+ if ((hr = send_size( socket, dict->strings[i].length )) != S_OK) return hr;
+ if ((hr = send_bytes( socket, dict->strings[i].bytes, dict->strings[i].length )) != S_OK) return hr;
+ }
+ return S_OK;
+}
+
+static HRESULT string_to_utf8( const WS_STRING *str, unsigned char **ret, int *len )
+{
+ *len = WideCharToMultiByte( CP_UTF8, 0, str->chars, str->length, NULL, 0, NULL, NULL );
+ if (!(*ret = heap_alloc( *len ))) return E_OUTOFMEMORY;
+ WideCharToMultiByte( CP_UTF8, 0, str->chars, str->length, (char *)*ret, *len, NULL, NULL );
+ return S_OK;
+}
+
+enum session_mode
+{
+ SESSION_MODE_INVALID = 0,
+ SESSION_MODE_SINGLETON = 1,
+ SESSION_MODE_DUPLEX = 2,
+ SESSION_MODE_SIMPLEX = 3,
+};
+
+static enum session_mode map_channel_type( struct channel *channel )
+{
+ switch (channel->type)
+ {
+ case WS_CHANNEL_TYPE_DUPLEX_SESSION: return SESSION_MODE_DUPLEX;
+ default:
+ FIXME( "unhandled channel type %08x\n", channel->type );
+ return SESSION_MODE_INVALID;
+ }
+}
+
+enum known_encoding
+{
+ KNOWN_ENCODING_SOAP11_UTF8 = 0x00,
+ KNOWN_ENCODING_SOAP11_UTF16 = 0x01,
+ KNOWN_ENCODING_SOAP11_UTF16LE = 0x02,
+ KNOWN_ENCODING_SOAP12_UTF8 = 0x03,
+ KNOWN_ENCODING_SOAP12_UTF16 = 0x04,
+ KNOWN_ENCODING_SOAP12_UTF16LE = 0x05,
+ KNOWN_ENCODING_SOAP12_MTOM = 0x06,
+ KNOWN_ENCODING_SOAP12_BINARY = 0x07,
+ KNOWN_ENCODING_SOAP12_BINARY_SESSION = 0x08,
+};
+
+static enum known_encoding map_channel_encoding( struct channel *channel )
+{
+ WS_ENVELOPE_VERSION version;
+
+ prop_get( channel->prop, channel->prop_count, WS_CHANNEL_PROPERTY_ENVELOPE_VERSION, &version, sizeof(version) );
+
+ switch (version)
+ {
+ case WS_ENVELOPE_VERSION_SOAP_1_1:
+ switch (channel->encoding)
+ {
+ case WS_ENCODING_XML_UTF8: return KNOWN_ENCODING_SOAP11_UTF8;
+ case WS_ENCODING_XML_UTF16LE: return KNOWN_ENCODING_SOAP11_UTF16LE;
+ default:
+ FIXME( "unhandled version/encoding %u/%u\n", version, channel->encoding );
+ return 0;
+ }
+ case WS_ENVELOPE_VERSION_SOAP_1_2:
+ switch (channel->encoding)
+ {
+ case WS_ENCODING_XML_UTF8: return KNOWN_ENCODING_SOAP12_UTF8;
+ case WS_ENCODING_XML_UTF16LE: return KNOWN_ENCODING_SOAP12_UTF16LE;
+ case WS_ENCODING_XML_BINARY_1: return KNOWN_ENCODING_SOAP12_BINARY;
+ case WS_ENCODING_XML_BINARY_SESSION_1: return KNOWN_ENCODING_SOAP12_BINARY_SESSION;
+ default:
+ FIXME( "unhandled version/encoding %u/%u\n", version, channel->encoding );
+ return 0;
+ }
+ default:
+ ERR( "unhandled version %u\n", version );
+ return 0;
+ }
+}
+
+#define FRAME_VERSION_MAJOR 1
+#define FRAME_VERSION_MINOR 1
+
+static HRESULT send_preamble( struct channel *channel )
+{
+ unsigned char *url;
+ HRESULT hr;
+ int len;
+
+ if ((hr = send_byte( channel->u.tcp.socket, FRAME_RECORD_TYPE_VERSION )) != S_OK) return hr;
+ if ((hr = send_byte( channel->u.tcp.socket, FRAME_VERSION_MAJOR )) != S_OK) return hr;
+ if ((hr = send_byte( channel->u.tcp.socket, FRAME_VERSION_MINOR )) != S_OK) return hr;
+
+ if ((hr = send_byte( channel->u.tcp.socket, FRAME_RECORD_TYPE_MODE )) != S_OK) return hr;
+ if ((hr = send_byte( channel->u.tcp.socket, map_channel_type(channel) )) != S_OK) return hr;
+
+ if ((hr = send_byte( channel->u.tcp.socket, FRAME_RECORD_TYPE_VIA )) != S_OK) return hr;
+ if ((hr = string_to_utf8( &channel->addr.url, &url, &len )) != S_OK) return hr;
+ if ((hr = send_size( channel->u.tcp.socket, len )) != S_OK) goto done;
+ if ((hr = send_bytes( channel->u.tcp.socket, url, len )) != S_OK) goto done;
+
+ if ((hr = send_byte( channel->u.tcp.socket, FRAME_RECORD_TYPE_KNOWN_ENCODING )) != S_OK) goto done;
+ if ((hr = send_byte( channel->u.tcp.socket, map_channel_encoding(channel) )) != S_OK) goto done;
+ hr = send_byte( channel->u.tcp.socket, FRAME_RECORD_TYPE_PREAMBLE_END );
+
+done:
+ heap_free( url );
+ return hr;
+}
+
+static HRESULT receive_bytes( struct channel *channel, unsigned char *bytes, int len )
+{
+ int count = recv( channel->u.tcp.socket, (char *)bytes, len, 0 );
+ if (count < 0) return HRESULT_FROM_WIN32( WSAGetLastError() );
+ if (count != len) return WS_E_INVALID_FORMAT;
+ return S_OK;
+}
+
+static HRESULT receive_preamble_ack( struct channel *channel )
+{
+ unsigned char byte;
+ HRESULT hr;
+
+ if ((hr = receive_bytes( channel, &byte, 1 )) != S_OK) return hr;
+ if (byte != FRAME_RECORD_TYPE_PREAMBLE_ACK) return WS_E_INVALID_FORMAT;
+ channel->session_state = SESSION_STATE_SETUP_COMPLETE;
+ return S_OK;
+}
+
+static HRESULT send_sized_envelope( struct channel *channel, BYTE *data, ULONG len )
+{
+ ULONG table_size = string_table_size( &channel->dict.dict );
+ HRESULT hr;
+
+ if ((hr = send_byte( channel->u.tcp.socket, FRAME_RECORD_TYPE_SIZED_ENVELOPE )) != S_OK) return hr;
+ if ((hr = send_size( channel->u.tcp.socket, size_length(table_size) + table_size + len )) != S_OK) return hr;
+ if ((hr = send_size( channel->u.tcp.socket, table_size )) != S_OK) return hr;
+ if ((hr = send_string_table( channel->u.tcp.socket, &channel->dict.dict )) != S_OK) return hr;
+ return send_bytes( channel->u.tcp.socket, data, len );
+}
+
static HRESULT send_message( struct channel *channel, WS_MESSAGE *msg )
{
WS_XML_WRITER *writer;
@@ -786,10 +1002,27 @@ static HRESULT send_message( struct channel *channel, WS_MESSAGE *msg )
return send_message_http( channel->u.http.request, buf.bytes, buf.length );
case WS_TCP_CHANNEL_BINDING:
- return send_message_sock( channel->u.tcp.socket, buf.bytes, buf.length );
+ if (channel->encoding == WS_ENCODING_XML_BINARY_SESSION_1)
+ {
+ switch (channel->session_state)
+ {
+ case SESSION_STATE_UNINITIALIZED:
+ if ((hr = send_preamble( channel )) != S_OK) return hr;
+ if ((hr = receive_preamble_ack( channel )) != S_OK) return hr;
+ /* fall through */
+
+ case SESSION_STATE_SETUP_COMPLETE:
+ return send_sized_envelope( channel, buf.bytes, buf.length );
+
+ default:
+ ERR( "unhandled session state %u\n", channel->session_state );
+ return WS_E_OTHER;
+ }
+ }
+ return send_bytes( channel->u.tcp.socket, buf.bytes, buf.length );
case WS_UDP_CHANNEL_BINDING:
- return send_message_sock( channel->u.udp.socket, buf.bytes, buf.length );
+ return send_bytes( channel->u.udp.socket, buf.bytes, buf.length );
default:
ERR( "unhandled binding %u\n", channel->binding );
@@ -816,18 +1049,37 @@ HRESULT channel_send_message( WS_CHANNEL *handle, WS_MESSAGE *msg )
return hr;
}
-HRESULT set_output( WS_XML_WRITER *writer )
-{
- WS_XML_WRITER_TEXT_ENCODING text = { {WS_XML_WRITER_ENCODING_TYPE_TEXT}, WS_CHARSET_UTF8 };
- WS_XML_WRITER_BUFFER_OUTPUT buf = { {WS_XML_WRITER_OUTPUT_TYPE_BUFFER} };
- return WsSetOutput( writer, &text.encoding, &buf.output, NULL, 0, NULL );
-}
-
static HRESULT init_writer( struct channel *channel )
{
+ WS_XML_WRITER_BUFFER_OUTPUT buf = {{WS_XML_WRITER_OUTPUT_TYPE_BUFFER}};
+ WS_XML_WRITER_TEXT_ENCODING text = {{WS_XML_WRITER_ENCODING_TYPE_TEXT}};
+ WS_XML_WRITER_BINARY_ENCODING bin = {{WS_XML_WRITER_ENCODING_TYPE_BINARY}};
+ WS_XML_WRITER_ENCODING *encoding;
HRESULT hr;
+
if (!channel->writer && (hr = WsCreateWriter( NULL, 0, &channel->writer, NULL )) != S_OK) return hr;
- return set_output( channel->writer );
+
+ switch (channel->encoding)
+ {
+ case WS_ENCODING_XML_UTF8:
+ text.charSet = WS_CHARSET_UTF8;
+ encoding = &text.encoding;
+ break;
+
+ case WS_ENCODING_XML_BINARY_SESSION_1:
+ bin.staticDictionary = (WS_XML_DICTIONARY *)&dict_builtin_static.dict;
+ /* fall through */
+
+ case WS_ENCODING_XML_BINARY_1:
+ encoding = &bin.encoding;
+ break;
+
+ default:
+ FIXME( "unhandled encoding %u\n", channel->encoding );
+ return WS_E_NOT_SUPPORTED;
+ }
+
+ return WsSetOutput( channel->writer, encoding, &buf.output, NULL, 0, NULL );
}
/**************************************************************************
@@ -887,22 +1139,40 @@ static HRESULT resize_read_buffer( struct channel *channel, ULONG size )
return S_OK;
}
-static HRESULT set_input( WS_XML_READER *reader, char *data, ULONG size )
-{
- WS_XML_READER_TEXT_ENCODING text = {{WS_XML_READER_ENCODING_TYPE_TEXT}, WS_CHARSET_UTF8};
- WS_XML_READER_BUFFER_INPUT buf;
-
- buf.input.inputType = WS_XML_READER_INPUT_TYPE_BUFFER;
- buf.encodedData = data;
- buf.encodedDataSize = size;
- return WsSetInput( reader, &text.encoding, &buf.input, NULL, 0, NULL );
-}
-
static HRESULT init_reader( struct channel *channel )
{
+ WS_XML_READER_BUFFER_INPUT buf = {{WS_XML_READER_INPUT_TYPE_BUFFER}};
+ WS_XML_READER_TEXT_ENCODING text = {{WS_XML_READER_ENCODING_TYPE_TEXT}};
+ WS_XML_READER_BINARY_ENCODING bin = {{WS_XML_READER_ENCODING_TYPE_BINARY}};
+ WS_XML_READER_ENCODING *encoding;
HRESULT hr;
+
if (!channel->reader && (hr = WsCreateReader( NULL, 0, &channel->reader, NULL )) != S_OK) return hr;
- return set_input( channel->reader, channel->read_buf, channel->read_size );
+
+ switch (channel->encoding)
+ {
+ case WS_ENCODING_XML_UTF8:
+ text.charSet = WS_CHARSET_UTF8;
+ encoding = &text.encoding;
+ break;
+
+ case WS_ENCODING_XML_BINARY_SESSION_1:
+ bin.staticDictionary = (WS_XML_DICTIONARY *)&dict_builtin_static.dict;
+ bin.dynamicDictionary = &channel->dict.dict;
+ /* fall through */
+
+ case WS_ENCODING_XML_BINARY_1:
+ encoding = &bin.encoding;
+ break;
+
+ default:
+ FIXME( "unhandled encoding %u\n", channel->encoding );
+ return WS_E_NOT_SUPPORTED;
+ }
+
+ buf.encodedData = channel->read_buf;
+ buf.encodedDataSize = channel->read_size;
+ return WsSetInput( channel->reader, encoding, &buf.input, NULL, 0, NULL );
}
#define INITIAL_READ_BUFFER_SIZE 4096
@@ -939,7 +1209,7 @@ static HRESULT receive_message_http( struct channel *channel )
return init_reader( channel );
}
-static HRESULT receive_message_sock( struct channel *channel, SOCKET socket )
+static HRESULT receive_message_unsized( struct channel *channel, SOCKET socket )
{
int bytes_read;
ULONG max_len;
@@ -956,14 +1226,290 @@ static HRESULT receive_message_sock( struct channel *channel, SOCKET socket )
return HRESULT_FROM_WIN32( WSAGetLastError() );
}
channel->read_size = bytes_read;
+ return S_OK;
+}
+
+static HRESULT receive_message_sized( struct channel *channel, unsigned int size )
+{
+ unsigned int offset = 0, to_read = size;
+ int bytes_read;
+ HRESULT hr;
+
+ if ((hr = resize_read_buffer( channel, size )) != S_OK) return hr;
+
+ channel->read_size = 0;
+ while (channel->read_size < size)
+ {
+ if ((bytes_read = recv( channel->u.tcp.socket, channel->read_buf + offset, to_read, 0 )) < 0)
+ {
+ return HRESULT_FROM_WIN32( WSAGetLastError() );
+ }
+ if (!bytes_read) break;
+ channel->read_size += bytes_read;
+ to_read -= bytes_read;
+ offset += bytes_read;
+ }
+ if (channel->read_size != size) return WS_E_INVALID_FORMAT;
+ return S_OK;
+}
+
+static HRESULT receive_size( struct channel *channel, unsigned int *size )
+{
+ unsigned char byte;
+ HRESULT hr;
+
+ if ((hr = receive_bytes( channel, &byte, 1 )) != S_OK) return hr;
+ *size = byte & 0x7f;
+ if (!(byte & 0x80)) return S_OK;
+
+ if ((hr = receive_bytes( channel, &byte, 1 )) != S_OK) return hr;
+ *size += (byte & 0x7f) << 7;
+ if (!(byte & 0x80)) return S_OK;
+
+ if ((hr = receive_bytes( channel, &byte, 1 )) != S_OK) return hr;
+ *size += (byte & 0x7f) << 14;
+ if (!(byte & 0x80)) return S_OK;
+
+ if ((hr = receive_bytes( channel, &byte, 1 )) != S_OK) return hr;
+ *size += (byte & 0x7f) << 21;
+ if (!(byte & 0x80)) return S_OK;
+
+ if ((hr = receive_bytes( channel, &byte, 1 )) != S_OK) return hr;
+ if (byte & ~0x0f) return WS_E_INVALID_FORMAT;
+ *size += byte << 28;
+ return S_OK;
+}
+
+static WS_ENCODING map_known_encoding( enum known_encoding encoding )
+{
+ switch (encoding)
+ {
+ case KNOWN_ENCODING_SOAP11_UTF8:
+ case KNOWN_ENCODING_SOAP12_UTF8: return WS_ENCODING_XML_UTF8;
+ case KNOWN_ENCODING_SOAP11_UTF16:
+ case KNOWN_ENCODING_SOAP12_UTF16: return WS_ENCODING_XML_UTF16BE;
+ case KNOWN_ENCODING_SOAP11_UTF16LE:
+ case KNOWN_ENCODING_SOAP12_UTF16LE: return WS_ENCODING_XML_UTF16LE;
+ case KNOWN_ENCODING_SOAP12_BINARY: return WS_ENCODING_XML_BINARY_1;
+ case KNOWN_ENCODING_SOAP12_BINARY_SESSION: return WS_ENCODING_XML_BINARY_SESSION_1;
+ default:
+ WARN( "unhandled encoding %u, assuming UTF8\n", encoding );
+ return WS_ENCODING_XML_UTF8;
+ }
+}
+
+static HRESULT receive_preamble( struct channel *channel )
+{
+ unsigned char type;
+ HRESULT hr;
+
+ for (;;)
+ {
+ if ((hr = receive_bytes( channel, &type, 1 )) != S_OK) return hr;
+ if (type == FRAME_RECORD_TYPE_PREAMBLE_END) break;
+ switch (type)
+ {
+ case FRAME_RECORD_TYPE_VERSION:
+ {
+ unsigned char major, minor;
+ if ((hr = receive_bytes( channel, &major, 1 )) != S_OK) return hr;
+ if ((hr = receive_bytes( channel, &minor, 1 )) != S_OK) return hr;
+ TRACE( "major %u minor %u\n", major, major );
+ break;
+ }
+ case FRAME_RECORD_TYPE_MODE:
+ {
+ unsigned char mode;
+ if ((hr = receive_bytes( channel, &mode, 1 )) != S_OK) return hr;
+ TRACE( "mode %u\n", mode );
+ break;
+ }
+ case FRAME_RECORD_TYPE_VIA:
+ {
+ unsigned int size;
+ unsigned char *url;
+
+ if ((hr = receive_size( channel, &size )) != S_OK) return hr;
+ if (!(url = heap_alloc( size ))) return E_OUTOFMEMORY;
+ if ((hr = receive_bytes( channel, url, size )) != S_OK)
+ {
+ heap_free( url );
+ return hr;
+ }
+ TRACE( "transport URL %s\n", debugstr_an((char *)url, size) );
+ heap_free( url ); /* FIXME: verify */
+ break;
+ }
+ case FRAME_RECORD_TYPE_KNOWN_ENCODING:
+ {
+ unsigned char encoding;
+ if ((hr = receive_bytes( channel, &encoding, 1 )) != S_OK) return hr;
+ TRACE( "encoding %u\n", encoding );
+ channel->encoding = map_known_encoding( encoding );
+ break;
+ }
+ default:
+ WARN( "unhandled record type %u\n", type );
+ return WS_E_INVALID_FORMAT;
+ }
+ }
+
+ return S_OK;
+}
+
+static HRESULT receive_sized_envelope( struct channel *channel )
+{
+ unsigned char type;
+ unsigned int size;
+ HRESULT hr;
+
+ if ((hr = receive_bytes( channel, &type, 1 )) != S_OK) return hr;
+ if (type != FRAME_RECORD_TYPE_SIZED_ENVELOPE) return WS_E_INVALID_FORMAT;
+ if ((hr = receive_size( channel, &size )) != S_OK) return hr;
+ if ((hr = receive_message_sized( channel, size )) != S_OK) return hr;
+ return S_OK;
+}
+
+static HRESULT read_size( const BYTE **ptr, ULONG len, ULONG *size )
+{
+ const BYTE *buf = *ptr;
+
+ if (len < 1) return WS_E_INVALID_FORMAT;
+ *size = buf[0] & 0x7f;
+ if (!(buf[0] & 0x80))
+ {
+ *ptr += 1;
+ return S_OK;
+ }
+ if (len < 2) return WS_E_INVALID_FORMAT;
+ *size += (buf[1] & 0x7f) << 7;
+ if (!(buf[1] & 0x80))
+ {
+ *ptr += 2;
+ return S_OK;
+ }
+ if (len < 3) return WS_E_INVALID_FORMAT;
+ *size += (buf[2] & 0x7f) << 14;
+ if (!(buf[2] & 0x80))
+ {
+ *ptr += 3;
+ return S_OK;
+ }
+ if (len < 4) return WS_E_INVALID_FORMAT;
+ *size += (buf[3] & 0x7f) << 21;
+ if (!(buf[3] & 0x80))
+ {
+ *ptr += 4;
+ return S_OK;
+ }
+ if (len < 5 || (buf[4] & ~0x07)) return WS_E_INVALID_FORMAT;
+ *size += buf[4] << 28;
+ *ptr += 5;
+ return S_OK;
+}
+
+static HRESULT build_dict( const BYTE *buf, ULONG buflen, struct dictionary *dict, ULONG *used )
+{
+ ULONG size, strings_size, strings_offset;
+ const BYTE *ptr = buf;
+ BYTE *bytes;
+ int index;
+ HRESULT hr;
+
+ if ((hr = read_size( &ptr, buflen, &strings_size )) != S_OK) return hr;
+ strings_offset = ptr - buf;
+ if (buflen < strings_offset + strings_size) return WS_E_INVALID_FORMAT;
+ *used = strings_offset + strings_size;
+ if (!strings_size) return S_OK;
+
+ UuidCreate( &dict->dict.guid );
+ dict->dict.isConst = FALSE;
+
+ buflen -= strings_offset;
+ ptr = buf + strings_offset;
+ while (ptr < buf + strings_size)
+ {
+ if ((hr = read_size( &ptr, buflen, &size )) != S_OK)
+ {
+ clear_dict( dict );
+ return hr;
+ }
+ if (size > buflen)
+ {
+ clear_dict( dict );
+ return WS_E_INVALID_FORMAT;
+ }
+ buflen -= size;
+ if (!(bytes = heap_alloc( size )))
+ {
+ hr = E_OUTOFMEMORY;
+ goto error;
+ }
+ memcpy( bytes, ptr, size );
+ if ((index = find_string( dict, bytes, size, NULL )) == -1) /* duplicate */
+ {
+ heap_free( bytes );
+ ptr += size;
+ continue;
+ }
+ if (!insert_string( dict, bytes, size, index, NULL ))
+ {
+ clear_dict( dict );
+ return E_OUTOFMEMORY;
+ }
+ ptr += size;
+ }
+ return S_OK;
+
+error:
+ clear_dict( dict );
+ return hr;
+}
+
+static HRESULT send_preamble_ack( struct channel *channel )
+{
+ HRESULT hr;
+ if ((hr = send_byte( channel->u.tcp.socket, FRAME_RECORD_TYPE_PREAMBLE_ACK )) != S_OK) return hr;
+ channel->session_state = SESSION_STATE_SETUP_COMPLETE;
+ return S_OK;
+}
+
+static HRESULT receive_message_session_setup( struct channel *channel )
+{
+ HRESULT hr;
+
+ if ((hr = receive_preamble( channel )) != S_OK) return hr;
+ if ((hr = send_preamble_ack( channel )) != S_OK) return hr;
+ if ((hr = receive_sized_envelope( channel )) != S_OK) return hr;
+ if (channel->encoding == WS_ENCODING_XML_BINARY_SESSION_1)
+ {
+ ULONG size;
+ if ((hr = build_dict( (const BYTE *)channel->read_buf, channel->read_size, &channel->dict, &size )) != S_OK)
+ return hr;
+ channel->read_size -= size;
+ memmove( channel->read_buf, channel->read_buf + size, channel->read_size );
+ }
return init_reader( channel );
}
-static HRESULT receive_message( struct channel *channel )
+static HRESULT receive_message_session( struct channel *channel )
+{
+ HRESULT hr;
+ if ((hr = receive_sized_envelope( channel )) != S_OK) return hr;
+ return init_reader( channel );
+}
+
+static HRESULT receive_message_sock( struct channel *channel, SOCKET socket )
{
HRESULT hr;
+ if ((hr = receive_message_unsized( channel, socket )) != S_OK) return hr;
+ return init_reader( channel );
+}
+static HRESULT receive_message( struct channel *channel )
+{
+ HRESULT hr;
if ((hr = connect_channel( channel )) != S_OK) return hr;
switch (channel->binding)
@@ -972,6 +1518,21 @@ static HRESULT receive_message( struct channel *channel )
return receive_message_http( channel );
case WS_TCP_CHANNEL_BINDING:
+ if (channel->encoding == WS_ENCODING_XML_BINARY_SESSION_1)
+ {
+ switch (channel->session_state)
+ {
+ case SESSION_STATE_UNINITIALIZED:
+ return receive_message_session_setup( channel );
+
+ case SESSION_STATE_SETUP_COMPLETE:
+ return receive_message_session( channel );
+
+ default:
+ ERR( "unhandled session state %u\n", channel->session_state );
+ return WS_E_OTHER;
+ }
+ }
return receive_message_sock( channel, channel->u.tcp.socket );
case WS_UDP_CHANNEL_BINDING:
diff --git a/dlls/webservices/proxy.c b/dlls/webservices/proxy.c
index d463899..3b3d2da 100644
--- a/dlls/webservices/proxy.c
+++ b/dlls/webservices/proxy.c
@@ -400,6 +400,13 @@ static HRESULT write_message( WS_MESSAGE *msg, WS_XML_WRITER *writer, const WS_E
return WsWriteEnvelopeEnd( msg, NULL );
}
+static HRESULT set_output( WS_XML_WRITER *writer )
+{
+ WS_XML_WRITER_TEXT_ENCODING text = { {WS_XML_WRITER_ENCODING_TYPE_TEXT}, WS_CHARSET_UTF8 };
+ WS_XML_WRITER_BUFFER_OUTPUT buf = { {WS_XML_WRITER_OUTPUT_TYPE_BUFFER} };
+ return WsSetOutput( writer, &text.encoding, &buf.output, NULL, 0, NULL );
+}
+
static HRESULT send_message( WS_CHANNEL *channel, WS_MESSAGE *msg, WS_MESSAGE_DESCRIPTION *desc,
WS_PARAMETER_DESCRIPTION *params, ULONG count, const void **args )
{
diff --git a/dlls/webservices/string.c b/dlls/webservices/string.c
index 8fc2b6a..1d1ef61 100644
--- a/dlls/webservices/string.c
+++ b/dlls/webservices/string.c
@@ -17,6 +17,7 @@
*/
#include <stdarg.h>
+#include <assert.h>
#include "windef.h"
#include "winbase.h"
@@ -62,21 +63,21 @@ static inline int cmp_string( const unsigned char *str, ULONG len, const unsigne
}
/* return -1 and string id if found, sort index if not found */
-static int find_string( const WS_XML_DICTIONARY *dict, const ULONG *sorted, const unsigned char *data,
- ULONG len, ULONG *ret_id )
+int find_string( const struct dictionary *dict, const unsigned char *data, ULONG len, ULONG *id )
{
- int i, c, min = 0, max = dict->stringCount - 1;
+ int i, c, min = 0, max = dict->dict.stringCount - 1;
+ const WS_XML_STRING *strings = dict->dict.strings;
while (min <= max)
{
i = (min + max) / 2;
- c = cmp_string( data, len, dict->strings[sorted[i]].bytes, dict->strings[sorted[i]].length );
+ c = cmp_string( data, len, strings[dict->sorted[i]].bytes, strings[dict->sorted[i]].length );
if (c < 0)
max = i - 1;
else if (c > 0)
min = i + 1;
else
{
- *ret_id = dict->strings[sorted[i]].id;
+ if (id) *id = strings[dict->sorted[i]].id;
return -1;
}
}
@@ -91,6 +92,7 @@ static BOOL grow_dict( struct dictionary *dict, ULONG size )
WS_XML_STRING *tmp;
ULONG new_size, *tmp_sorted;
+ assert( !dict->dict.isConst );
if (dict->size >= dict->dict.stringCount + size) return TRUE;
if (dict->size + size > MAX_DICTIONARY_SIZE) return FALSE;
@@ -118,9 +120,23 @@ static BOOL grow_dict( struct dictionary *dict, ULONG size )
return TRUE;
}
-static BOOL insert_string( struct dictionary *dict, unsigned char *data, ULONG len, int i, ULONG *ret_id )
+void clear_dict( struct dictionary *dict )
+{
+ ULONG i;
+ assert( !dict->dict.isConst );
+ for (i = 0; i < dict->dict.stringCount; i++) heap_free( dict->dict.strings[i].bytes );
+ heap_free( dict->dict.strings );
+ dict->dict.strings = NULL;
+ dict->dict.stringCount = 0;
+ heap_free( dict->sorted );
+ dict->sorted = NULL;
+ dict->size = 0;
+}
+
+BOOL insert_string( struct dictionary *dict, unsigned char *data, ULONG len, int i, ULONG *ret_id )
{
ULONG id = dict->dict.stringCount;
+ assert( !dict->dict.isConst );
if (!grow_dict( dict, 1 )) return FALSE;
memmove( &dict->sorted[i] + 1, &dict->sorted[i], (dict->dict.stringCount - i) * sizeof(*dict->sorted) );
dict->sorted[i] = id;
@@ -130,19 +146,29 @@ static BOOL insert_string( struct dictionary *dict, unsigned char *data, ULONG l
dict->dict.strings[id].dictionary = &dict->dict;
dict->dict.strings[id].id = id;
dict->dict.stringCount++;
- *ret_id = id;
+ if (ret_id) *ret_id = id;
return TRUE;
}
+HRESULT CALLBACK insert_string_cb( void *state, const WS_XML_STRING *str, BOOL *found, ULONG *id, WS_ERROR *error )
+{
+ struct dictionary *dict = state;
+ int index = find_string( dict, str->bytes, str->length, id );
+
+ assert( !dict->dict.isConst );
+ if (index == -1 || insert_string( dict, str->bytes, str->length, index, id )) *found = TRUE;
+ else *found = FALSE;
+ return S_OK;
+}
+
HRESULT add_xml_string( WS_XML_STRING *str )
{
int index;
ULONG id;
if (str->dictionary) return S_OK;
-
EnterCriticalSection( &dict_cs );
- if ((index = find_string( &dict_builtin.dict, dict_builtin.sorted, str->bytes, str->length, &id )) == -1)
+ if ((index = find_string( &dict_builtin, str->bytes, str->length, &id )) == -1)
{
heap_free( str->bytes );
*str = dict_builtin.dict.strings[id];
@@ -197,9 +223,8 @@ WS_XML_STRING *dup_xml_string( const WS_XML_STRING *src )
*ret = *src;
return ret;
}
-
EnterCriticalSection( &dict_cs );
- if ((index = find_string( &dict_builtin.dict, dict_builtin.sorted, src->bytes, src->length, &id )) == -1)
+ if ((index = find_string( &dict_builtin, src->bytes, src->length, &id )) == -1)
{
*ret = dict_builtin.dict.strings[id];
LeaveCriticalSection( &dict_cs );
diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h
index 5557d32..5ce88b2 100644
--- a/dlls/webservices/webservices_private.h
+++ b/dlls/webservices/webservices_private.h
@@ -44,6 +44,11 @@ struct dictionary
struct dictionary dict_builtin DECLSPEC_HIDDEN;
const struct dictionary dict_builtin_static DECLSPEC_HIDDEN;
+int find_string( const struct dictionary *, const unsigned char *, ULONG, ULONG * ) DECLSPEC_HIDDEN;
+BOOL insert_string( struct dictionary *, unsigned char *, ULONG, int, ULONG * ) DECLSPEC_HIDDEN;
+HRESULT CALLBACK insert_string_cb( void *, const WS_XML_STRING *, BOOL *, ULONG *, WS_ERROR * ) DECLSPEC_HIDDEN;
+void clear_dict( struct dictionary * ) DECLSPEC_HIDDEN;
+
const char *debugstr_xmlstr( const WS_XML_STRING * ) DECLSPEC_HIDDEN;
WS_XML_STRING *alloc_xml_string( const unsigned char *, ULONG ) DECLSPEC_HIDDEN;
WS_XML_STRING *dup_xml_string( const WS_XML_STRING * ) DECLSPEC_HIDDEN;
@@ -54,7 +59,6 @@ void free_attribute( WS_XML_ATTRIBUTE * ) DECLSPEC_HIDDEN;
WS_TYPE map_value_type( WS_VALUE_TYPE ) DECLSPEC_HIDDEN;
BOOL set_fpword( unsigned short, unsigned short * ) DECLSPEC_HIDDEN;
void restore_fpword( unsigned short ) DECLSPEC_HIDDEN;
-HRESULT set_output( WS_XML_WRITER * ) DECLSPEC_HIDDEN;
ULONG get_type_size( WS_TYPE, const void * ) DECLSPEC_HIDDEN;
HRESULT read_header( WS_XML_READER *, const WS_XML_STRING *, const WS_XML_STRING *, WS_TYPE,
const void *, WS_READ_OPTION, WS_HEAP *, void *, ULONG ) DECLSPEC_HIDDEN;
--
2.1.4
More information about the wine-patches
mailing list