Signed-off-by: Hans Leidekker hans@codeweavers.com --- dlls/webservices/channel.c | 141 ++++++++++-- dlls/webservices/msg.c | 297 +++++++++++++++++++++---- dlls/webservices/proxy.c | 2 +- dlls/webservices/tests/proxy.c | 118 +++++++++- dlls/webservices/webservices.spec | 2 +- dlls/webservices/webservices_private.h | 3 +- 6 files changed, 501 insertions(+), 62 deletions(-)
diff --git a/dlls/webservices/channel.c b/dlls/webservices/channel.c index 4afa884820..71207bee6b 100644 --- a/dlls/webservices/channel.c +++ b/dlls/webservices/channel.c @@ -330,6 +330,26 @@ static void reset_channel( struct channel *channel ) } }
+static void free_header_mappings( WS_HTTP_HEADER_MAPPING **mappings, ULONG count ) +{ + ULONG i; + for (i = 0; i < count; i++) heap_free( mappings[i] ); + heap_free( mappings ); +} + +static void free_message_mapping( const WS_HTTP_MESSAGE_MAPPING *mapping ) +{ + free_header_mappings( mapping->requestHeaderMappings, mapping->requestHeaderMappingCount ); + free_header_mappings( mapping->responseHeaderMappings, mapping->responseHeaderMappingCount ); +} + +static void free_props( struct channel *channel ) +{ + struct prop *prop = &channel->prop[WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING]; + WS_HTTP_MESSAGE_MAPPING *mapping = (WS_HTTP_MESSAGE_MAPPING *)prop->value; + free_message_mapping( mapping ); +} + static void free_channel( struct channel *channel ) { reset_channel( channel ); @@ -338,6 +358,7 @@ static void free_channel( struct channel *channel ) WsFreeReader( channel->reader );
heap_free( channel->read_buf ); + free_props( channel );
channel->send_q.cs.DebugInfo->Spare[0] = 0; channel->recv_q.cs.DebugInfo->Spare[0] = 0; @@ -348,6 +369,58 @@ static void free_channel( struct channel *channel ) heap_free( channel ); }
+static WS_HTTP_HEADER_MAPPING *dup_header_mapping( const WS_HTTP_HEADER_MAPPING *src ) +{ + WS_HTTP_HEADER_MAPPING *dst; + + if (!(dst = heap_alloc( sizeof(*dst) + src->headerName.length ))) return NULL; + + dst->headerName.bytes = (BYTE *)(dst + 1); + memcpy( dst->headerName.bytes, src->headerName.bytes, src->headerName.length ); + dst->headerName.length = src->headerName.length; + dst->headerMappingOptions = src->headerMappingOptions; + return dst; +} + +static HRESULT dup_message_mapping( const WS_HTTP_MESSAGE_MAPPING *src, WS_HTTP_MESSAGE_MAPPING *dst ) +{ + ULONG i, size; + + size = src->requestHeaderMappingCount * sizeof(*dst->responseHeaderMappings); + if (!(dst->requestHeaderMappings = heap_alloc( size ))) return E_OUTOFMEMORY; + + for (i = 0; i < src->requestHeaderMappingCount; i++) + { + if (!(dst->requestHeaderMappings[i] = dup_header_mapping( src->requestHeaderMappings[i] ))) + { + free_header_mappings( dst->requestHeaderMappings, i ); + return E_OUTOFMEMORY; + } + } + + size = src->responseHeaderMappingCount * sizeof(*dst->responseHeaderMappings); + if (!(dst->responseHeaderMappings = heap_alloc( size ))) + { + heap_free( dst->responseHeaderMappings ); + return E_OUTOFMEMORY; + } + + for (i = 0; i < src->responseHeaderMappingCount; i++) + { + if (!(dst->responseHeaderMappings[i] = dup_header_mapping( src->responseHeaderMappings[i] ))) + { + free_header_mappings( dst->responseHeaderMappings, i ); + return E_OUTOFMEMORY; + } + } + + dst->requestMappingOptions = src->requestMappingOptions; + dst->responseMappingOptions = src->responseMappingOptions; + dst->requestHeaderMappingCount = src->requestHeaderMappingCount; + dst->responseHeaderMappingCount = src->responseHeaderMappingCount; + return S_OK; +} + static HRESULT create_channel( WS_CHANNEL_TYPE type, WS_CHANNEL_BINDING binding, const WS_CHANNEL_PROPERTY *properties, ULONG count, struct channel **ret ) { @@ -390,25 +463,47 @@ static HRESULT create_channel( WS_CHANNEL_TYPE type, WS_CHANNEL_BINDING binding,
for (i = 0; i < count; i++) { - TRACE( "property id %u value ptr %p size %u\n", properties[i].id, properties[i].value, - properties[i].valueSize ); - if (properties[i].valueSize == sizeof(ULONG) && properties[i].value) - TRACE( " value %08x\n", *(ULONG *)properties[i].value ); + const WS_CHANNEL_PROPERTY *prop = &properties[i]; + + TRACE( "property id %u value %p size %u\n", prop->id, prop->value, prop->valueSize ); + if (prop->valueSize == sizeof(ULONG) && prop->value) TRACE( " value %08x\n", *(ULONG *)prop->value );
- switch (properties[i].id) + switch (prop->id) { case WS_CHANNEL_PROPERTY_ENCODING: - if (!properties[i].value || properties[i].valueSize != sizeof(channel->encoding)) + if (!prop->value || prop->valueSize != sizeof(channel->encoding)) + { + free_channel( channel ); + return E_INVALIDARG; + } + channel->encoding = *(WS_ENCODING *)prop->value; + break; + + case WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING: + { + const WS_HTTP_MESSAGE_MAPPING *src = (WS_HTTP_MESSAGE_MAPPING *)prop->value; + WS_HTTP_MESSAGE_MAPPING dst; + + if (!prop->value || prop->valueSize != sizeof(*src)) { free_channel( channel ); return E_INVALIDARG; } - channel->encoding = *(WS_ENCODING *)properties[i].value; + + if ((hr = dup_message_mapping( src, &dst )) != S_OK) return hr; + + if ((hr = prop_set( channel->prop, channel->prop_count, WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING, &dst, + sizeof(dst) )) != S_OK) + { + free_message_mapping( &dst ); + free_channel( channel ); + return hr; + } break;
+ } default: - if ((hr = prop_set( channel->prop, channel->prop_count, properties[i].id, properties[i].value, - properties[i].valueSize )) != S_OK) + if ((hr = prop_set( channel->prop, channel->prop_count, prop->id, prop->value, prop->valueSize )) != S_OK) { free_channel( channel ); return hr; @@ -1517,13 +1612,27 @@ static HRESULT init_reader( struct channel *channel ) return WsSetInput( channel->reader, encoding, input, NULL, 0, NULL ); }
+static const WS_HTTP_MESSAGE_MAPPING *get_http_message_mapping( struct channel *channel ) +{ + const struct prop *prop = &channel->prop[WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING]; + return (const WS_HTTP_MESSAGE_MAPPING *)prop->value; +} + +static HRESULT map_http_response_headers( struct channel *channel, WS_MESSAGE *msg ) +{ + const WS_HTTP_MESSAGE_MAPPING *mapping = get_http_message_mapping( channel ); + return message_map_http_response_headers( msg, channel->u.http.request, mapping ); +} + #define INITIAL_READ_BUFFER_SIZE 4096 -static HRESULT receive_message_http( struct channel *channel ) +static HRESULT receive_message_http( struct channel *channel, WS_MESSAGE *msg ) { DWORD len, bytes_read, offset = 0, size = INITIAL_READ_BUFFER_SIZE; ULONG max_len; 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) );
@@ -1814,7 +1923,7 @@ static HRESULT receive_message_session( struct channel *channel ) return S_OK; }
-static HRESULT receive_message_bytes( struct channel *channel ) +static HRESULT receive_message_bytes( struct channel *channel, WS_MESSAGE *msg ) { HRESULT hr; if ((hr = connect_channel( channel )) != S_OK) return hr; @@ -1822,7 +1931,7 @@ static HRESULT receive_message_bytes( struct channel *channel ) switch (channel->binding) { case WS_HTTP_CHANNEL_BINDING: - return receive_message_http( channel ); + return receive_message_http( channel, msg );
case WS_TCP_CHANNEL_BINDING: if (channel->type & WS_CHANNEL_TYPE_SESSION) @@ -1853,7 +1962,7 @@ static HRESULT receive_message_bytes( struct channel *channel ) } }
-HRESULT channel_receive_message( WS_CHANNEL *handle ) +HRESULT channel_receive_message( WS_CHANNEL *handle, WS_MESSAGE *msg ) { struct channel *channel = (struct channel *)handle; HRESULT hr; @@ -1866,7 +1975,7 @@ HRESULT channel_receive_message( WS_CHANNEL *handle ) return E_INVALIDARG; }
- if ((hr = receive_message_bytes( channel )) == S_OK) hr = init_reader( channel ); + if ((hr = receive_message_bytes( channel, msg )) == S_OK) hr = init_reader( channel );
LeaveCriticalSection( &channel->cs ); return hr; @@ -1906,7 +2015,7 @@ static HRESULT receive_message( struct channel *channel, WS_MESSAGE *msg, const HRESULT hr; ULONG i;
- if ((hr = receive_message_bytes( channel )) != S_OK) return hr; + if ((hr = receive_message_bytes( channel, msg )) != S_OK) return hr; if ((hr = init_reader( channel )) != S_OK) return hr;
for (i = 0; i < count; i++) @@ -2148,7 +2257,7 @@ HRESULT WINAPI WsReadMessageStart( WS_CHANNEL *handle, WS_MESSAGE *msg, const WS return E_INVALIDARG; }
- if ((hr = receive_message_bytes( channel )) == S_OK) + if ((hr = receive_message_bytes( channel, msg )) == S_OK) { if ((hr = init_reader( channel )) == S_OK) hr = WsReadEnvelopeStart( msg, channel->reader, NULL, NULL, NULL ); diff --git a/dlls/webservices/msg.c b/dlls/webservices/msg.c index d6906cb5de..a006841be6 100644 --- a/dlls/webservices/msg.c +++ b/dlls/webservices/msg.c @@ -652,6 +652,16 @@ static HRESULT write_headers( struct msg *msg, WS_XML_WRITER *writer, const WS_X return WsWriteEndElement( writer, NULL ); /* </s:Header> */ }
+static ULONG count_envelope_headers( struct msg *msg ) +{ + ULONG i, ret = 0; + for (i = 0; i < msg->header_count; i++) + { + if (!msg->header[i]->mapped) ret++; + } + return ret; +} + static HRESULT write_headers_transport( struct msg *msg, WS_XML_WRITER *writer, const WS_XML_STRING *prefix, const WS_XML_STRING *ns ) { @@ -659,16 +669,19 @@ static HRESULT write_headers_transport( struct msg *msg, WS_XML_WRITER *writer, HRESULT hr = S_OK; ULONG i;
- if ((msg->header_count || !msg->action) && - (hr = WsWriteStartElement( writer, prefix, &header, ns, NULL )) != S_OK) return hr; - - for (i = 0; i < msg->header_count; i++) + if (count_envelope_headers( msg ) || !msg->action) { - if (msg->header[i]->mapped) continue; - if ((hr = WsWriteXmlBuffer( writer, msg->header[i]->u.buf, NULL )) != S_OK) return hr; + if ((hr = WsWriteStartElement( writer, prefix, &header, ns, NULL )) != S_OK) return hr; + + for (i = 0; i < msg->header_count; i++) + { + if (msg->header[i]->mapped) continue; + if ((hr = WsWriteXmlBuffer( writer, msg->header[i]->u.buf, NULL )) != S_OK) return hr; + } + + hr = WsWriteEndElement( writer, NULL ); /* </s:Header> */ }
- if (msg->header_count || !msg->action) hr = WsWriteEndElement( writer, NULL ); /* </s:Header> */ return hr; }
@@ -1435,37 +1448,14 @@ static HRESULT build_mapped_header( const WS_XML_STRING *name, WS_TYPE type, WS_ return S_OK; }
-/************************************************************************** - * WsAddMappedHeader [webservices.@] - */ -HRESULT WINAPI WsAddMappedHeader( WS_MESSAGE *handle, const WS_XML_STRING *name, WS_TYPE type, - WS_WRITE_OPTION option, const void *value, ULONG size, WS_ERROR *error ) +static HRESULT add_mapped_header( struct msg *msg, const WS_XML_STRING *name, WS_TYPE type, + WS_WRITE_OPTION option, const void *value, ULONG size ) { - struct msg *msg = (struct msg *)handle; struct header *header; BOOL found = FALSE; HRESULT hr; ULONG i;
- TRACE( "%p %s %u %08x %p %u %p\n", handle, debugstr_xmlstr(name), type, option, value, size, error ); - if (error) FIXME( "ignoring error parameter\n" ); - - if (!msg || !name) return E_INVALIDARG; - - EnterCriticalSection( &msg->cs ); - - if (msg->magic != MSG_MAGIC) - { - LeaveCriticalSection( &msg->cs ); - return E_INVALIDARG; - } - - if (msg->state < WS_MESSAGE_STATE_INITIALIZED) - { - hr = WS_E_INVALID_OPERATION; - goto done; - } - for (i = 0; i < msg->header_count; i++) { if (msg->header[i]->type || !msg->header[i]->mapped) continue; @@ -1478,18 +1468,44 @@ HRESULT WINAPI WsAddMappedHeader( WS_MESSAGE *handle, const WS_XML_STRING *name,
if (!found) { - if ((hr = grow_header_array( msg, msg->header_count + 1 )) != S_OK) goto done; + if ((hr = grow_header_array( msg, msg->header_count + 1 )) != S_OK) return hr; i = msg->header_count; }
- if ((hr = build_mapped_header( name, type, option, value, size, &header )) != S_OK) goto done; + if ((hr = build_mapped_header( name, type, option, value, size, &header )) != S_OK) return hr;
if (!found) msg->header_count++; else free_header( msg->header[i] );
msg->header[i] = header; + return S_OK; +} + +/************************************************************************** + * WsAddMappedHeader [webservices.@] + */ +HRESULT WINAPI WsAddMappedHeader( WS_MESSAGE *handle, const WS_XML_STRING *name, WS_TYPE type, + WS_WRITE_OPTION option, const void *value, ULONG size, WS_ERROR *error ) +{ + struct msg *msg = (struct msg *)handle; + HRESULT hr; + + TRACE( "%p %s %u %08x %p %u %p\n", handle, debugstr_xmlstr(name), type, option, value, size, error ); + if (error) FIXME( "ignoring error parameter\n" ); + + if (!msg || !name) return E_INVALIDARG; + + EnterCriticalSection( &msg->cs ); + + if (msg->magic != MSG_MAGIC) + { + LeaveCriticalSection( &msg->cs ); + return E_INVALIDARG; + } + + if (msg->state < WS_MESSAGE_STATE_INITIALIZED) hr = WS_E_INVALID_OPERATION; + else hr = add_mapped_header( msg, name, type, option, value, size );
-done: LeaveCriticalSection( &msg->cs ); TRACE( "returning %08x\n", hr ); return hr; @@ -1536,6 +1552,111 @@ HRESULT WINAPI WsRemoveMappedHeader( WS_MESSAGE *handle, const WS_XML_STRING *na return hr; }
+static HRESULT xmlstring_to_wsz( const WS_XML_STRING *str, WS_HEAP *heap, WCHAR **ret ) +{ + int len = MultiByteToWideChar( CP_UTF8, 0, (char *)str->bytes, str->length, NULL, 0 ); + if (!(*ret = ws_alloc( heap, (len + 1) * sizeof(WCHAR) ))) return WS_E_QUOTA_EXCEEDED; + MultiByteToWideChar( CP_UTF8, 0, (char *)str->bytes, str->length, *ret, len ); + (*ret)[len] = 0; + return S_OK; +} + +static HRESULT get_header_value_wsz( struct header *header, WS_READ_OPTION option, WS_HEAP *heap, WCHAR **ret, + ULONG size ) +{ + WCHAR *str = NULL; + HRESULT hr; + + if (header && (hr = xmlstring_to_wsz( header->u.text, heap, &str )) != S_OK) return hr; + + switch (option) + { + case WS_READ_REQUIRED_POINTER: + if (!str && !(str = ws_alloc_zero( heap, sizeof(*str) ))) return WS_E_QUOTA_EXCEEDED; + /* fall through */ + + case WS_READ_OPTIONAL_POINTER: + case WS_READ_NILLABLE_POINTER: + if (size != sizeof(str)) return E_INVALIDARG; + *ret = str; + break; + + default: + FIXME( "read option %u not supported\n", option ); + return E_NOTIMPL; + } + + return S_OK; +} + +static HRESULT get_mapped_header( struct msg *msg, const WS_XML_STRING *name, WS_TYPE type, WS_READ_OPTION option, + WS_HEAP *heap, void *value, ULONG size ) +{ + struct header *header = NULL; + HRESULT hr; + ULONG i; + + for (i = 0; i < msg->header_count; i++) + { + if (msg->header[i]->type || !msg->header[i]->mapped) continue; + if (WsXmlStringEquals( name, &msg->header[i]->name, NULL ) == S_OK) + { + header = msg->header[i]; + break; + } + } + + switch (type) + { + case WS_WSZ_TYPE: + hr = get_header_value_wsz( header, option, heap, value, size ); + break; + + default: + FIXME( "type %u not supported\n", option ); + return WS_E_NOT_SUPPORTED; + } + + return hr; +} + +/************************************************************************** + * WsGetMappedHeader [webservices.@] + */ +HRESULT WINAPI WsGetMappedHeader( WS_MESSAGE *handle, const WS_XML_STRING *name, WS_REPEATING_HEADER_OPTION option, + ULONG index, WS_TYPE type, WS_READ_OPTION read_option, WS_HEAP *heap, void *value, + ULONG size, WS_ERROR *error ) +{ + struct msg *msg = (struct msg *)handle; + HRESULT hr; + + TRACE( "%p %s %u %u %u %u %p %p %u %p\n", handle, debugstr_xmlstr(name), option, index, type, read_option, + heap, value, size, error ); + if (error) FIXME( "ignoring error parameter\n" ); + if (option != WS_SINGLETON_HEADER) + { + FIXME( "option %u not supported\n", option ); + return E_NOTIMPL; + } + + if (!msg || !name) return E_INVALIDARG; + + EnterCriticalSection( &msg->cs ); + + if (msg->magic != MSG_MAGIC) + { + LeaveCriticalSection( &msg->cs ); + return E_INVALIDARG; + } + + if (msg->state < WS_MESSAGE_STATE_INITIALIZED) hr = WS_E_INVALID_OPERATION; + else hr = get_mapped_header( msg, name, type, read_option, heap, value, size ); + + LeaveCriticalSection( &msg->cs ); + TRACE( "returning %08x\n", hr ); + return hr; +} + static HRESULT write_custom_header( WS_XML_WRITER *writer, const WS_XML_STRING *name, const WS_XML_STRING *ns, WS_TYPE type, const void *desc, WS_WRITE_OPTION option, const void *value, ULONG size ) @@ -1717,10 +1838,12 @@ HRESULT WINAPI WsRemoveCustomHeader( WS_MESSAGE *handle, const WS_XML_STRING *na static WCHAR *build_http_header( const WCHAR *name, const WCHAR *value, ULONG *ret_len ) { int len_name = lstrlenW( name ), len_value = lstrlenW( value ); - WCHAR *ret = heap_alloc( (len_name + len_value) * sizeof(WCHAR) ); + WCHAR *ret = heap_alloc( (len_name + len_value + 2) * sizeof(WCHAR) );
if (!ret) return NULL; memcpy( ret, name, len_name * sizeof(WCHAR) ); + ret[len_name++] = ':'; + ret[len_name++] = ' '; memcpy( ret + len_name, value, len_value * sizeof(WCHAR) ); *ret_len = len_name + len_value; return ret; @@ -1732,10 +1855,48 @@ static inline HRESULT insert_http_header( HINTERNET req, const WCHAR *header, UL return HRESULT_FROM_WIN32( GetLastError() ); }
+static WCHAR *from_xml_string( const WS_XML_STRING *str ) +{ + WCHAR *ret; + int len = MultiByteToWideChar( CP_UTF8, 0, (char *)str->bytes, str->length, NULL, 0 ); + if (!(ret = heap_alloc( (len + 1) * sizeof(*ret) ))) return NULL; + MultiByteToWideChar( CP_UTF8, 0, (char *)str->bytes, str->length, ret, len ); + ret[len] = 0; + return ret; +} + +static HRESULT insert_mapped_headers( struct msg *msg, HINTERNET req ) +{ + WCHAR *name, *value, *header; + ULONG i, len; + HRESULT hr; + + for (i = 0; i < msg->header_count; i++) + { + if (!msg->header[i]->mapped) continue; + + if (!(name = from_xml_string( &msg->header[i]->name ))) return E_OUTOFMEMORY; + if (!(value = from_xml_string( msg->header[i]->u.text ))) + { + heap_free( name ); + return E_OUTOFMEMORY; + } + header = build_http_header( name, value, &len ); + heap_free( name ); + heap_free( value ); + if (!header) return E_OUTOFMEMORY; + + hr = insert_http_header( req, header, len, WINHTTP_ADDREQ_FLAG_ADD|WINHTTP_ADDREQ_FLAG_REPLACE ); + heap_free( header ); + if (hr != S_OK) return hr; + } + return S_OK; +} + HRESULT message_insert_http_headers( WS_MESSAGE *handle, HINTERNET req ) { static const WCHAR contenttypeW[] = - {'C','o','n','t','e','n','t','-','T','y','p','e',':',' ',0}; + {'C','o','n','t','e','n','t','-','T','y','p','e',0}; static const WCHAR soapxmlW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','s','o','a','p','+','x','m','l',0}; static const WCHAR textxmlW[] = @@ -1785,7 +1946,7 @@ HRESULT message_insert_http_headers( WS_MESSAGE *handle, HINTERNET req ) { case WS_ENVELOPE_VERSION_SOAP_1_1: { - static const WCHAR soapactionW[] = {'S','O','A','P','A','c','t','i','o','n',':',' ',0}; + static const WCHAR soapactionW[] = {'S','O','A','P','A','c','t','i','o','n',0};
if (!(len = MultiByteToWideChar( CP_UTF8, 0, (char *)msg->action->bytes, msg->action->length, NULL, 0 ))) break; @@ -1832,6 +1993,8 @@ HRESULT message_insert_http_headers( WS_MESSAGE *handle, HINTERNET req ) hr = E_NOTIMPL; }
+ if (hr == S_OK) hr = insert_mapped_headers( msg, req ); + done: heap_free( header ); LeaveCriticalSection( &msg->cs ); @@ -1839,6 +2002,64 @@ done: return hr; }
+static HRESULT map_http_response_headers( struct msg *msg, HINTERNET req, const WS_HTTP_MESSAGE_MAPPING *mapping ) +{ + ULONG i; + for (i = 0; i < mapping->responseHeaderMappingCount; i++) + { + WCHAR *name, *value; + DWORD size; + + if (!(name = from_xml_string( &mapping->responseHeaderMappings[i]->headerName ))) return E_OUTOFMEMORY; + + if (!WinHttpQueryHeaders( req, WINHTTP_QUERY_CUSTOM, name, NULL, &size, NULL ) && + GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + HRESULT hr; + if (!(value = heap_alloc( size ))) + { + heap_free( name ); + return E_OUTOFMEMORY; + } + if (!WinHttpQueryHeaders( req, WINHTTP_QUERY_CUSTOM, name, value, &size, NULL )) + { + heap_free( name ); + return HRESULT_FROM_WIN32( GetLastError() ); + } + hr = add_mapped_header( msg, &mapping->responseHeaderMappings[i]->headerName, WS_WSZ_TYPE, + WS_WRITE_REQUIRED_POINTER, &value, sizeof(value) ); + heap_free( value ); + if (hr != S_OK) + { + heap_free( name ); + return hr; + } + } + heap_free( name ); + } + return S_OK; +} + +HRESULT message_map_http_response_headers( WS_MESSAGE *handle, HINTERNET req, const WS_HTTP_MESSAGE_MAPPING *mapping ) +{ + struct msg *msg = (struct msg *)handle; + HRESULT hr; + + EnterCriticalSection( &msg->cs ); + + if (msg->magic != MSG_MAGIC) + { + LeaveCriticalSection( &msg->cs ); + return E_INVALIDARG; + } + + hr = map_http_response_headers( msg, req, mapping ); + + LeaveCriticalSection( &msg->cs ); + TRACE( "returning %08x\n", hr ); + return hr; +} + void message_set_send_context( WS_MESSAGE *handle, const WS_PROXY_MESSAGE_CALLBACK_CONTEXT *ctx ) { struct msg *msg = (struct msg *)handle; diff --git a/dlls/webservices/proxy.c b/dlls/webservices/proxy.c index b07b3c7a26..b6278a6354 100644 --- a/dlls/webservices/proxy.c +++ b/dlls/webservices/proxy.c @@ -455,7 +455,7 @@ static HRESULT receive_message( WS_CHANNEL *channel, WS_MESSAGE *msg, WS_MESSAGE HRESULT hr;
if ((hr = message_set_action( msg, desc->action )) != S_OK) return hr; - if ((hr = channel_receive_message( channel )) != S_OK) return hr; + if ((hr = channel_receive_message( channel, msg )) != S_OK) return hr; if ((hr = channel_get_reader( channel, &reader )) != S_OK) return hr; return read_message( msg, reader, heap, desc->bodyElementDescription, params, count, args ); } diff --git a/dlls/webservices/tests/proxy.c b/dlls/webservices/tests/proxy.c index 3fe92367e9..07610ac70e 100644 --- a/dlls/webservices/tests/proxy.c +++ b/dlls/webservices/tests/proxy.c @@ -361,13 +361,34 @@ static void test_WsReceiveMessage( int port ) WsFreeMessage( msg ); }
+static WS_HTTP_HEADER_MAPPING mapped_request_header = +{ + {19, (BYTE *)"MappedRequestHeader"} +}; + +static WS_HTTP_HEADER_MAPPING *request_header_mappings[] = +{ + &mapped_request_header +}; + +static WS_HTTP_HEADER_MAPPING mapped_response_header = +{ + {20, (BYTE *)"MappedResponseHeader"} +}; + +static WS_HTTP_HEADER_MAPPING *response_header_mappings[] = +{ + &mapped_response_header +}; + static HRESULT create_proxy( int port, WS_SERVICE_PROXY **ret ) { static const WCHAR fmt[] = {'h','t','t','p',':','/','/','1','2','7','.','0','.','0','.','1',':','%','u','/',0}; WS_ENVELOPE_VERSION env_version; WS_ADDRESSING_VERSION addr_version; - WS_CHANNEL_PROPERTY prop[2]; + WS_HTTP_MESSAGE_MAPPING mapping; + WS_CHANNEL_PROPERTY prop[3]; WS_ENDPOINT_ADDRESS addr; WS_SERVICE_PROXY *proxy; WCHAR url[64]; @@ -383,6 +404,17 @@ static HRESULT create_proxy( int port, WS_SERVICE_PROXY **ret ) prop[1].value = &addr_version; prop[1].valueSize = sizeof(addr_version);
+ mapping.requestMappingOptions = 0; + mapping.responseMappingOptions = 0; + mapping.requestHeaderMappings = request_header_mappings; + mapping.requestHeaderMappingCount = ARRAY_SIZE(request_header_mappings); + mapping.responseHeaderMappings = response_header_mappings; + mapping.responseHeaderMappingCount = ARRAY_SIZE(response_header_mappings); + + prop[2].id = WS_CHANNEL_PROPERTY_HTTP_MESSAGE_MAPPING; + prop[2].value = &mapping; + prop[2].valueSize = sizeof(mapping); + *ret = NULL; hr = WsCreateServiceProxy( WS_CHANNEL_TYPE_REQUEST, WS_HTTP_CHANNEL_BINDING, NULL, NULL, 0, prop, ARRAY_SIZE( prop ), &proxy, NULL ); @@ -397,6 +429,38 @@ static HRESULT create_proxy( int port, WS_SERVICE_PROXY **ret ) return hr; }
+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 void check_output_headers( WS_MESSAGE *msg ) +{ + WS_XML_WRITER *writer; + WS_XML_BUFFER *buf; + WS_BYTES bytes; + HRESULT hr; + + hr = WsCreateWriter( NULL, 0, &writer, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + + hr = set_output( writer ); + ok( hr == S_OK, "got %08x\n", hr ); + + hr = WsGetMessageProperty( msg, WS_MESSAGE_PROPERTY_HEADER_BUFFER, &buf, sizeof(buf), NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + + hr = WsWriteXmlBuffer( writer, buf, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + + memset( &bytes, 0, sizeof(bytes) ); + hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, sizeof(bytes), NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + WsFreeWriter( writer ); +} + static const char req_test2[] = "<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/%5C%22%3E<s:Body>" "<req_test2 xmlns="ns"><val>1</val><str>test</str><str>test2</str></req_test2>" @@ -407,6 +471,32 @@ static const char resp_test2[] = "<resp_test2 xmlns="ns"><str>test</str><val>1</val><val>2</val></resp_test2>" "</s:Body></s:Envelope>";
+static HRESULT CALLBACK send_callback( WS_MESSAGE *msg, WS_HEAP *heap, void *state, WS_ERROR *error ) +{ + static const WS_XML_STRING header = {19, (BYTE *)"MappedRequestHeader"}, value = {5, (BYTE *)"value"}; + HRESULT hr; + + hr = WsAddMappedHeader( msg, &header, WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, &value, sizeof(value), NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + check_output_headers( msg ); + return S_OK; +} + +static HRESULT CALLBACK recv_callback( WS_MESSAGE *msg, WS_HEAP *heap, void *state, WS_ERROR *error ) +{ + static const WS_XML_STRING header = {20, (BYTE *)"MappedResponseHeader"}; + static const WCHAR valueW[] = {'v','a','l','u','e',0}; + WCHAR *str; + HRESULT hr; + + check_output_headers( msg ); + hr = WsGetMappedHeader( msg, &header, WS_SINGLETON_HEADER, 0, WS_WSZ_TYPE, WS_READ_OPTIONAL_POINTER, heap, + &str, sizeof(str), NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + ok( !lstrcmpW(str, valueW), "wrong value %s\n", wine_dbgstr_w(str) ); + return S_OK; +} + static void test_WsCall( int port ) { static const WCHAR testW[] = {'t','e','s','t',0}, test2W[] = {'t','e','s','t','2',0}; @@ -421,6 +511,9 @@ static void test_WsCall( int port ) WS_XML_STRING ns = {2, (BYTE *)"ns"}; HRESULT hr; WS_SERVICE_PROXY *proxy; + WS_PROXY_MESSAGE_CALLBACK_CONTEXT ctx_send; + WS_PROXY_MESSAGE_CALLBACK_CONTEXT ctx_recv; + WS_CALL_PROPERTY prop[2]; WS_OPERATION_DESCRIPTION op; WS_MESSAGE_DESCRIPTION input_msg, output_msg; WS_ELEMENT_DESCRIPTION input_elem, output_elem; @@ -511,7 +604,21 @@ static void test_WsCall( int port ) args[4] = &val_ptr; args[5] = &count_ptr;
- hr = WsCall( proxy, &op, args, heap, NULL, 0, NULL, NULL ); + ctx_send.callback = send_callback; + ctx_send.state = NULL; + + prop[0].id = WS_CALL_PROPERTY_SEND_MESSAGE_CONTEXT; + prop[0].value = &ctx_send; + prop[0].valueSize = sizeof(ctx_send); + + ctx_recv.callback = recv_callback; + ctx_recv.state = NULL; + + prop[1].id = WS_CALL_PROPERTY_RECEIVE_MESSAGE_CONTEXT; + prop[1].value = &ctx_recv; + prop[1].valueSize = sizeof(ctx_recv); + + hr = WsCall( proxy, &op, args, heap, prop, ARRAY_SIZE(prop), NULL, NULL ); ok( hr == S_OK, "got %08x\n", hr ); ok( !lstrcmpW( out.str, testW ), "wrong data\n" ); ok( out.count == 2, "got %u\n", out.count ); @@ -616,7 +723,7 @@ tests[] = static void send_response( int c, const char *status, const char *data, unsigned int len ) { static const char headers[] = - "Content-Type: text/xml; charset=utf-8\r\nConnection: close\r\n"; + "Content-Type: text/xml; charset=utf-8\r\nConnection: close\r\nMappedResponseHeader: value\r\n"; static const char fmt[] = "Content-Length: %u\r\n\r\n"; char buf[128]; @@ -694,10 +801,11 @@ static DWORD CALLBACK server_proc( void *arg ) if (tests[j].req_data) { int data_len = strlen( buf ); - ok( tests[j].req_len == data_len, "%u: unexpected data length %u %u\n", + ok( tests[j].req_len == data_len, "%u: got data length %u expected %u\n", j, data_len, tests[j].req_len ); if (tests[j].req_len == data_len) - ok( !memcmp( tests[j].req_data, buf, tests[j].req_len ), "%u: unexpected data %s\n", j, buf ); + ok( !memcmp( tests[j].req_data, buf, tests[j].req_len ), + "%u: got data '%s' expected '%s'\n", j, buf, tests[j].req_data ); } send_response( c, tests[j].resp_status, tests[j].resp_data, tests[j].resp_len ); break; diff --git a/dlls/webservices/webservices.spec b/dlls/webservices/webservices.spec index c8db3a0375..3fe1f4d427 100644 --- a/dlls/webservices/webservices.spec +++ b/dlls/webservices/webservices.spec @@ -70,7 +70,7 @@ @ stub WsGetHeaderAttributes @ stdcall WsGetHeapProperty(ptr long ptr long ptr) @ stdcall WsGetListenerProperty(ptr long ptr long ptr) -@ stub WsGetMappedHeader +@ stdcall WsGetMappedHeader(ptr ptr long long long long ptr ptr long ptr) @ stdcall WsGetMessageProperty(ptr long ptr long ptr) @ stub WsGetMetadataEndpoints @ stub WsGetMetadataProperty diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h index 6a6f65dbec..9ca470c82b 100644 --- a/dlls/webservices/webservices_private.h +++ b/dlls/webservices/webservices_private.h @@ -161,9 +161,10 @@ void message_set_receive_context( WS_MESSAGE *, const WS_PROXY_MESSAGE_CALLBACK_ void message_do_send_callback( WS_MESSAGE * ) DECLSPEC_HIDDEN; void message_do_receive_callback( WS_MESSAGE * ) DECLSPEC_HIDDEN; HRESULT message_insert_http_headers( WS_MESSAGE *, HINTERNET ) DECLSPEC_HIDDEN; +HRESULT message_map_http_response_headers( WS_MESSAGE *, HINTERNET, const WS_HTTP_MESSAGE_MAPPING * ) DECLSPEC_HIDDEN;
HRESULT channel_send_message( WS_CHANNEL *, WS_MESSAGE * ) DECLSPEC_HIDDEN; -HRESULT channel_receive_message( WS_CHANNEL * ) DECLSPEC_HIDDEN; +HRESULT channel_receive_message( WS_CHANNEL *, WS_MESSAGE * ) DECLSPEC_HIDDEN; HRESULT channel_get_reader( WS_CHANNEL *, WS_XML_READER ** ) DECLSPEC_HIDDEN;
HRESULT parse_url( const WS_STRING *, WS_URL_SCHEME_TYPE *, WCHAR **, USHORT * ) DECLSPEC_HIDDEN;