Signed-off-by: Hans Leidekker hans@codeweavers.com --- dlls/webservices/channel.c | 132 +++++++++++++++++++++++++------------ 1 file changed, 89 insertions(+), 43 deletions(-)
diff --git a/dlls/webservices/channel.c b/dlls/webservices/channel.c index b894b0f61ba..0a1f1f3199b 100644 --- a/dlls/webservices/channel.c +++ b/dlls/webservices/channel.c @@ -234,6 +234,9 @@ struct channel char *read_buf; ULONG read_buflen; ULONG read_size; + char *send_buf; + ULONG send_buflen; + ULONG send_size; ULONG prop_count; struct prop prop[ARRAY_SIZE( channel_props )]; }; @@ -328,6 +331,7 @@ static void reset_channel( struct channel *channel ) clear_dict( &channel->dict_recv ); channel->msg = NULL; channel->read_size = 0; + channel->send_size = 0;
switch (channel->binding) { @@ -386,6 +390,7 @@ static void free_channel( struct channel *channel ) WsFreeReader( channel->reader );
heap_free( channel->read_buf ); + heap_free( channel->send_buf ); free_props( channel );
channel->send_q.cs.DebugInfo->Spare[0] = 0; @@ -1262,26 +1267,44 @@ static HRESULT send_message_http( HINTERNET request, BYTE *data, ULONG len ) return S_OK; }
-static HRESULT send_bytes( SOCKET socket, BYTE *bytes, int len ) +static ULONG get_max_buffer_size( struct channel *channel ) { - int count = send( socket, (char *)bytes, len, 0 ); - if (count < 0) return HRESULT_FROM_WIN32( WSAGetLastError() ); - if (count != len) return WS_E_OTHER; + ULONG size; + prop_get( channel->prop, channel->prop_count, WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE, &size, sizeof(size) ); + return size; +} + +static HRESULT write_bytes( struct channel *channel, BYTE *bytes, ULONG len ) +{ + if (!channel->send_buf) + { + channel->send_buflen = get_max_buffer_size( channel ); + if (!(channel->send_buf = heap_alloc( channel->send_buflen ))) return E_OUTOFMEMORY; + } + if (channel->send_size + len >= channel->send_buflen) return WS_E_QUOTA_EXCEEDED; + + memcpy( channel->send_buf + channel->send_size, bytes, len ); + channel->send_size += len; return S_OK; }
-static HRESULT send_size( SOCKET socket, ULONG size ) +static inline HRESULT write_byte( struct channel *channel, BYTE byte ) +{ + return write_bytes( channel, &byte, 1 ); +} + +static HRESULT write_size( struct channel *channel, 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 ); + if (size < 0x80) return write_byte( channel, size ); + if ((hr = write_byte( channel, (size & 0x7f) | 0x80 )) != S_OK) return hr; + if ((size >>= 7) < 0x80) return write_byte( channel, size ); + if ((hr = write_byte( channel, (size & 0x7f) | 0x80 )) != S_OK) return hr; + if ((size >>= 7) < 0x80) return write_byte( channel, size ); + if ((hr = write_byte( channel, (size & 0x7f) | 0x80 )) != S_OK) return hr; + if ((size >>= 7) < 0x80) return write_byte( channel, size ); + if ((hr = write_byte( channel, (size & 0x7f) | 0x80 )) != S_OK) return hr; + if ((size >>= 7) < 0x08) return write_byte( channel, size ); return E_INVALIDARG; }
@@ -1305,15 +1328,15 @@ static ULONG string_table_size( const struct dictionary *dict ) return size; }
-static HRESULT send_string_table( SOCKET socket, const struct dictionary *dict ) +static HRESULT write_string_table( struct channel *channel, const struct dictionary *dict ) { ULONG i; HRESULT hr; for (i = 0; i < dict->dict.stringCount; i++) { if (dict->sequence[i] != dict->current_sequence) continue; - if ((hr = send_size( socket, dict->dict.strings[i].length )) != S_OK) return hr; - if ((hr = send_bytes( socket, dict->dict.strings[i].bytes, dict->dict.strings[i].length )) != S_OK) return hr; + if ((hr = write_size( channel, dict->dict.strings[i].length )) != S_OK) return hr; + if ((hr = write_bytes( channel, dict->dict.strings[i].bytes, dict->dict.strings[i].length )) != S_OK) return hr; } return S_OK; } @@ -1395,33 +1418,50 @@ static enum known_encoding map_channel_encoding( struct channel *channel ) #define FRAME_VERSION_MAJOR 1 #define FRAME_VERSION_MINOR 1
-static HRESULT send_preamble( struct channel *channel ) +static HRESULT write_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 = write_byte( channel, FRAME_RECORD_TYPE_VERSION )) != S_OK) return hr; + if ((hr = write_byte( channel, FRAME_VERSION_MAJOR )) != S_OK) return hr; + if ((hr = write_byte( channel, 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 = write_byte( channel, FRAME_RECORD_TYPE_MODE )) != S_OK) return hr; + if ((hr = write_byte( channel, 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 = write_byte( channel, 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 = write_size( channel, len )) != S_OK) goto done; + if ((hr = write_bytes( channel, 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 ); + if ((hr = write_byte( channel, FRAME_RECORD_TYPE_KNOWN_ENCODING )) != S_OK) goto done; + if ((hr = write_byte( channel, map_channel_encoding(channel) )) != S_OK) goto done; + hr = write_byte( channel, FRAME_RECORD_TYPE_PREAMBLE_END );
done: heap_free( url ); return hr; }
+static HRESULT send_bytes( SOCKET socket, char *bytes, int len ) +{ + int count = send( socket, bytes, len, 0 ); + if (count < 0) return HRESULT_FROM_WIN32( WSAGetLastError() ); + if (count != len) return WS_E_OTHER; + return S_OK; +} + +static HRESULT send_preamble( struct channel *channel ) +{ + HRESULT hr; + if ((hr = write_preamble( channel )) != S_OK) return hr; + if ((hr = send_bytes( channel->u.tcp.socket, channel->send_buf, channel->send_size )) != S_OK) return hr; + channel->send_size = 0; + return S_OK; +} + static HRESULT receive_bytes( struct channel *channel, unsigned char *bytes, int len ) { int count = recv( channel->u.tcp.socket, (char *)bytes, len, 0 ); @@ -1441,16 +1481,25 @@ static HRESULT receive_preamble_ack( struct channel *channel ) return S_OK; }
-static HRESULT send_sized_envelope( struct channel *channel, BYTE *data, ULONG len ) +static HRESULT write_sized_envelope( struct channel *channel, BYTE *data, ULONG len ) { ULONG table_size = string_table_size( &channel->dict_send ); 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_send )) != S_OK) return hr; - return send_bytes( channel->u.tcp.socket, data, len ); + if ((hr = write_byte( channel, FRAME_RECORD_TYPE_SIZED_ENVELOPE )) != S_OK) return hr; + if ((hr = write_size( channel, size_length(table_size) + table_size + len )) != S_OK) return hr; + if ((hr = write_size( channel, table_size )) != S_OK) return hr; + if ((hr = write_string_table( channel, &channel->dict_send )) != S_OK) return hr; + return write_bytes( channel, data, len ); +} + +static HRESULT send_sized_envelope( struct channel *channel, BYTE *data, ULONG len ) +{ + HRESULT hr; + if ((hr = write_sized_envelope( channel, data, len )) != S_OK) return hr; + if ((hr = send_bytes( channel->u.tcp.socket, channel->send_buf, channel->send_size )) != S_OK) return hr; + channel->send_size = 0; + return S_OK; }
static HRESULT open_http_request( struct channel *channel, HINTERNET *req ) @@ -1880,17 +1929,14 @@ static HRESULT map_http_response_headers( struct channel *channel, WS_MESSAGE *m }
#define INITIAL_READ_BUFFER_SIZE 4096 -static HRESULT receive_message_http( struct channel *channel, WS_MESSAGE *msg ) +static HRESULT receive_message_bytes_http( struct channel *channel, WS_MESSAGE *msg ) { DWORD len, bytes_read, offset = 0, size = INITIAL_READ_BUFFER_SIZE; - ULONG max_len; + ULONG max_len = get_max_buffer_size( channel ); HRESULT hr;
if ((hr = map_http_response_headers( channel, msg )) != S_OK) return hr;
- prop_get( channel->prop, channel->prop_count, WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE, - &max_len, sizeof(max_len) ); - if ((hr = resize_read_buffer( channel, size )) != S_OK) return hr; channel->read_size = 0; for (;;) @@ -2162,7 +2208,7 @@ static HRESULT send_preamble_ack( struct channel *channel ) return S_OK; }
-static HRESULT receive_message_session( struct channel *channel ) +static HRESULT receive_message_bytes_session( struct channel *channel ) { HRESULT hr;
@@ -2184,7 +2230,7 @@ static HRESULT receive_message_bytes( struct channel *channel, WS_MESSAGE *msg ) switch (channel->binding) { case WS_HTTP_CHANNEL_BINDING: - return receive_message_http( channel, msg ); + return receive_message_bytes_http( channel, msg );
case WS_TCP_CHANNEL_BINDING: if (channel->type & WS_CHANNEL_TYPE_SESSION) @@ -2198,7 +2244,7 @@ static HRESULT receive_message_bytes( struct channel *channel, WS_MESSAGE *msg ) /* fall through */
case SESSION_STATE_SETUP_COMPLETE: - return receive_message_session( channel ); + return receive_message_bytes_session( channel );
default: ERR( "unhandled session state %u\n", channel->session_state );