[PATCH 1/2] webservices: Buffer whole messages to be sent.

Hans Leidekker hans at codeweavers.com
Mon May 24 08:53:48 CDT 2021


Signed-off-by: Hans Leidekker <hans at 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 );
-- 
2.30.2




More information about the wine-devel mailing list