static HRESULT read_message( WS_MESSAGE *handle, WS_XML_READER *reader, const WS_ELEMENT_DESCRIPTION *desc, WS_READ_OPTION option, WS_HEAP *heap, void *body, ULONG size ) { HRESULT hr; if ((hr = WsReadEnvelopeStart( handle, reader, NULL, NULL, NULL )) != S_OK) return hr; if ((hr = WsReadBody( handle, desc, option, heap, body, size, NULL )) != S_OK) return hr; return WsReadEnvelopeEnd( handle, NULL ); }
// The server version of ProcessMessage. This is the entry point for the application-specific code. HRESULT CFileRepServer::ProcessMessage( __in CRequest* request, __in const WS_XML_STRING* receivedAction) { PrintVerbose(L"Entering CFileRepServer::ProcessMessage"); HRESULT hr = S_OK; FileRequest* fileRequest = NULL; WS_MESSAGE* requestMessage = request->GetRequestMessage(); WS_CHANNEL* channel = request->GetChannel(); WS_ERROR* error = request->GetError(); // Make sure action is what we expect if (WsXmlStringEquals(receivedAction, &fileRequestAction, error) != S_OK) { PrintInfo(L"Illegal action"); hr = WS_E_ENDPOINT_ACTION_NOT_SUPPORTED; } else { // Read file request WS_HEAP* heap; IfFailedExit(WsGetMessageProperty(requestMessage, WS_MESSAGE_PROPERTY_HEAP, &heap, sizeof(heap), error)); IfFailedExit(WsReadBody(requestMessage, &fileRequestElement, WS_READ_REQUIRED_POINTER, heap, &fileRequest, sizeof(fileRequest), error)); IfFailedExit(WsReadMessageEnd(channel, requestMessage, NULL, error)); IfFailedExit(ReadAndSendFile(request, fileRequest->fileName, fileRequest->filePosition, error)); } EXIT // We do not print error messages here. That is handled in the caller. PrintVerbose(L"Leaving CFileRepServer::ProcessMessage"); return hr; }
// Main entry point int __cdecl wmain() { HRESULT hr = S_OK; WS_ERROR* error = NULL; WS_CHANNEL* channel = NULL; WS_LISTENER* listener = NULL; WS_HEAP* heap = NULL; WS_MESSAGE* requestMessage = NULL; WS_MESSAGE* replyMessage = NULL; static const WS_STRING uri = WS_STRING_VALUE(L"http://+:80/example"); // Create an error object for storing rich error information hr = WsCreateError( NULL, 0, &error); if (FAILED(hr)) { goto Exit; } // Create a listener hr = WsCreateListener( WS_CHANNEL_TYPE_REPLY, WS_HTTP_CHANNEL_BINDING, NULL, 0, NULL, &listener, error); if (FAILED(hr)) { goto Exit; } // Open listener hr = WsOpenListener( listener, &uri, NULL, error); if (FAILED(hr)) { goto Exit; } // Set up a property indicating streamined input and output WS_TRANSFER_MODE transferMode = WS_STREAMED_TRANSFER_MODE; WS_CHANNEL_PROPERTY transferModeProperty; transferModeProperty.id = WS_CHANNEL_PROPERTY_TRANSFER_MODE; transferModeProperty.value = &transferMode; transferModeProperty.valueSize = sizeof(transferMode); // Create a channel suitable for accepting from the listener hr = WsCreateChannelForListener( listener, &transferModeProperty, 1, &channel, error); if (FAILED(hr)) { goto Exit; } hr = WsCreateMessageForChannel( channel, NULL, 0, &requestMessage, error); if (FAILED(hr)) { goto Exit; } hr = WsCreateMessageForChannel( channel, NULL, 0, &replyMessage, error); if (FAILED(hr)) { goto Exit; } // Create a heap to store deserialized data hr = WsCreateHeap( /*maxSize*/ 2048, /*trimSize*/ 512, NULL, 0, &heap, error); if (FAILED(hr)) { goto Exit; } // Receive messages and send replies for (int i = 0; i < 10; i++) { // Accept a channel from the client hr = WsAcceptChannel(listener, channel, NULL, error); if (FAILED(hr)) { goto Exit; } // Receive the message start (headers) hr = WsReadMessageStart( channel, requestMessage, NULL, error); if (FAILED(hr)) { goto Exit; } // Get action value WS_XML_STRING receivedAction; hr = WsGetHeader( requestMessage, WS_ACTION_HEADER, WS_XML_STRING_TYPE, WS_READ_REQUIRED_VALUE, NULL, &receivedAction, sizeof(receivedAction), error); if (FAILED(hr)) { goto Exit; } // Make sure action is what we expect hr = WsXmlStringEquals( &receivedAction, PurchaseOrder_wsdl.messages.PurchaseOrder.action, error); if (hr != S_OK) { hr = WS_E_ENDPOINT_ACTION_NOT_SUPPORTED; goto Exit; } // Initialize the reply message based on the request hr = WsInitializeMessage( replyMessage, WS_REPLY_MESSAGE, requestMessage, error); if (FAILED(hr)) { goto Exit; } // Write the start of the reply message (headers) hr = WsWriteMessageStart( channel, replyMessage, NULL, error); if (FAILED(hr)) { goto Exit; } // Read the contents of the request body, and send response body for (;;) { // Make sure we have at least one purchase order buffered in the request message. // Each purchase order may be up to 1024 bytes in size. hr = WsFillBody( requestMessage, 1024, NULL, error); if (FAILED(hr)) { goto Exit; } // Deserialize purchase order into heap (if any more) _PurchaseOrderType* purchaseOrder; hr = WsReadBody( requestMessage, &PurchaseOrder_wsdl.globalElements.PurchaseOrderType, WS_READ_OPTIONAL_POINTER, heap, &purchaseOrder, sizeof(purchaseOrder), error); if (FAILED(hr)) { goto Exit; } // NULL indicates no more purchase orders if (purchaseOrder == NULL) { break; } // Print out purchase order contents wprintf(L"%ld, %s\n", purchaseOrder->quantity, purchaseOrder->productName); // Serialize a confirmation into the reply message _OrderConfirmationType orderConfirmation; orderConfirmation.expectedShipDate = L"1/1/2006"; orderConfirmation.orderID = 123; hr = WsWriteBody( replyMessage, &PurchaseOrder_wsdl.globalElements.OrderConfirmationType, WS_WRITE_REQUIRED_VALUE, &orderConfirmation, sizeof(orderConfirmation), error); if (FAILED(hr)) { goto Exit; } // Flush the confirmation data if at least 4096 bytes have been accumulated hr = WsFlushBody( replyMessage, 4096, NULL, error); if (FAILED(hr)) { goto Exit; } // Free purchase order hr = WsResetHeap( heap, error); if (FAILED(hr)) { goto Exit; } } // Read the end of the message hr = WsReadMessageEnd( channel, requestMessage, NULL, error); if (FAILED(hr)) { goto Exit; } // Write the end of the message hr = WsWriteMessageEnd( channel, replyMessage, NULL, error); if (FAILED(hr)) { goto Exit; } // Reset the message so it can be used again hr = WsResetMessage( requestMessage, error); if (FAILED(hr)) { goto Exit; } // Reset the message so it can be used again hr = WsResetMessage( replyMessage, error); if (FAILED(hr)) { goto Exit; } if (channel != NULL) { // Close the channel WsCloseChannel(channel, NULL, error); } // Reset the channel so it can be used again hr = WsResetChannel( channel, error); if (FAILED(hr)) { goto Exit; } } Exit: if (FAILED(hr)) { // Print out the error PrintError(hr, error); } if (channel != NULL) { // Close the channel WsCloseChannel(channel, NULL, error); } if (listener != NULL) { // Close the listener if it was opened WsCloseListener(listener, NULL, error); } if (channel != NULL) { WsFreeChannel(channel); } if (listener != NULL) { WsFreeListener(listener); } if (requestMessage != NULL) { WsFreeMessage(requestMessage); } if (replyMessage != NULL) { WsFreeMessage(replyMessage); } if (heap != NULL) { WsFreeHeap(heap); } if (error != NULL) { WsFreeError(error); } fflush(stdout); return SUCCEEDED(hr) ? 0 : -1; }
HRESULT CALLBACK ProcessMessage( __in const WS_OPERATION_CONTEXT* context, __in_opt const WS_ASYNC_CONTEXT* asyncContext, __in_opt WS_ERROR* error) { UNREFERENCED_PARAMETER(asyncContext); WS_CHANNEL* channel = NULL; HRESULT hr = NOERROR; WS_HEAP* heap = NULL; WS_MESSAGE* replyMessage = NULL; hr = WsGetOperationContextProperty( context, WS_OPERATION_CONTEXT_PROPERTY_HEAP, &heap, sizeof(heap), error); if (FAILED(hr)) { goto Exit; } WS_MESSAGE* requestMessage = NULL; hr = WsGetOperationContextProperty( context, WS_OPERATION_CONTEXT_PROPERTY_INPUT_MESSAGE, &requestMessage, sizeof(requestMessage), error); if (FAILED(hr)) { goto Exit; } hr = WsGetOperationContextProperty( context, WS_OPERATION_CONTEXT_PROPERTY_CHANNEL, &channel, sizeof(channel), error); if (FAILED(hr)) { goto Exit; } hr = WsCreateMessageForChannel( channel, NULL, 0, &replyMessage, error); if (FAILED(hr)) { goto Exit; } // Get action value WS_XML_STRING receivedAction; hr = WsGetHeader( requestMessage, WS_ACTION_HEADER, WS_XML_STRING_TYPE, WS_READ_REQUIRED_VALUE, NULL, &receivedAction, sizeof(receivedAction), error); if (FAILED(hr)) { goto Exit; } // Make sure action is what we expect if (WsXmlStringEquals( &receivedAction, PurchaseOrder_wsdl.messages.PurchaseOrder.action, error) != S_OK) { hr = WS_E_ENDPOINT_ACTION_NOT_SUPPORTED; goto Exit; } // Read purchase order _PurchaseOrderType purchaseOrder; hr = WsReadBody( requestMessage, &PurchaseOrder_wsdl.globalElements.PurchaseOrderType, WS_READ_REQUIRED_VALUE, heap, &purchaseOrder, sizeof(purchaseOrder), error); if (FAILED(hr)) { goto Exit; } // Read end of message hr = WsReadMessageEnd( channel, requestMessage, NULL, error); if (FAILED(hr)) { goto Exit; } // Print out purchase order contents wprintf(L"%ld, %s\n", purchaseOrder.quantity, purchaseOrder.productName); // Initialize order confirmation data _OrderConfirmationType orderConfirmation; orderConfirmation.expectedShipDate = L"1/1/2006"; orderConfirmation.orderID = 123; // Send a reply message hr = WsSendReplyMessage( channel, replyMessage, &PurchaseOrder_wsdl.messages.OrderConfirmation, WS_WRITE_REQUIRED_VALUE, &orderConfirmation, sizeof(orderConfirmation), requestMessage, NULL, error); if (FAILED(hr)) { goto Exit; } hr = WS_S_END; Exit: fflush(stdout); if (replyMessage != NULL) { WsFreeMessage( replyMessage); } return hr; }
// Main entry point int __cdecl wmain() { HRESULT hr = S_OK; WS_ERROR* error = NULL; WS_CHANNEL* channel = NULL; WS_MESSAGE* requestMessage = NULL; WS_MESSAGE* replyMessage = NULL; WS_HEAP* heap = NULL; static const WS_STRING serviceUrl = WS_STRING_VALUE(L"http://localhost/example"); WS_ENDPOINT_ADDRESS address = {}; // Create an error object for storing rich error information hr = WsCreateError( NULL, 0, &error); if (FAILED(hr)) { goto Exit; } // Set up a property indicating streamined input and output WS_TRANSFER_MODE transferMode = WS_STREAMED_TRANSFER_MODE; WS_CHANNEL_PROPERTY transferModeProperty; transferModeProperty.id = WS_CHANNEL_PROPERTY_TRANSFER_MODE; transferModeProperty.value = &transferMode; transferModeProperty.valueSize = sizeof(transferMode); // Create a HTTP request channel hr = WsCreateChannel( WS_CHANNEL_TYPE_REQUEST, WS_HTTP_CHANNEL_BINDING, &transferModeProperty, 1, NULL, &channel, error); if (FAILED(hr)) { goto Exit; } // Initialize address of service address.url = serviceUrl; // Open channel to address hr = WsOpenChannel( channel, &address, NULL, error); if (FAILED(hr)) { goto Exit; } hr = WsCreateMessageForChannel( channel, NULL, 0, &requestMessage, error); if (FAILED(hr)) { goto Exit; } hr = WsCreateMessageForChannel( channel, NULL, 0, &replyMessage, error); if (FAILED(hr)) { goto Exit; } // Create a heap to store deserialized data hr = WsCreateHeap( /*maxSize*/ 2048, /*trimSize*/ 512, NULL, 0, &heap, error); if (FAILED(hr)) { goto Exit; } // Send request messages and receive reply messages for (int i = 0; i < 10; i++) { // Initialize message headers of the request message hr = WsInitializeMessage( requestMessage, WS_BLANK_MESSAGE, NULL, error); if (FAILED(hr)) { goto Exit; } // Add the action header to the request message hr = WsSetHeader( requestMessage, WS_ACTION_HEADER, WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, PurchaseOrder_wsdl.messages.PurchaseOrder.action, sizeof(*PurchaseOrder_wsdl.messages.PurchaseOrder.action), error); if (FAILED(hr)) { goto Exit; } // Generate a unique message ID that will be used for the request message WS_UNIQUE_ID messageID; ZeroMemory( &messageID, sizeof(messageID)); DWORD status = UuidCreate( &messageID.guid); if (status != RPC_S_OK) { hr = E_FAIL; goto Exit; } // Add the message ID to the request message hr = WsSetHeader( requestMessage, WS_MESSAGE_ID_HEADER, WS_UNIQUE_ID_TYPE, WS_WRITE_REQUIRED_VALUE, &messageID, sizeof(messageID), error); if (FAILED(hr)) { goto Exit; } // Send the message headers of the request message hr = WsWriteMessageStart( channel, requestMessage, NULL, error); if (FAILED(hr)) { goto Exit; } // Stream out some purchase orders for (int j = 0; j < 10; j++) { // Initialize body data _PurchaseOrderType purchaseOrder; purchaseOrder.quantity = 1; purchaseOrder.productName = L"Pencil"; // Serialize body data into message hr = WsWriteBody( requestMessage, &PurchaseOrder_wsdl.globalElements.PurchaseOrderType, WS_WRITE_REQUIRED_VALUE, &purchaseOrder, sizeof(purchaseOrder), error); if (FAILED(hr)) { goto Exit; } // Send accumulated message data once at least 4096 bytes have been accumulated hr = WsFlushBody( requestMessage, 4096, NULL, error); if (FAILED(hr)) { goto Exit; } } // Send the end of the request message hr = WsWriteMessageEnd( channel, requestMessage, NULL, error); if (FAILED(hr)) { goto Exit; } // Receive the headers of the reply message hr = WsReadMessageStart( channel, replyMessage, NULL, error); if (FAILED(hr)) { goto Exit; } // Stream in all the confirmations for (;;) { // Make sure we have at least once confirmation buffered. Each confirmation // may be up to 1024 bytes in size. hr = WsFillBody( replyMessage, 1024, NULL, error); if (FAILED(hr)) { goto Exit; } // Try to deserialize a confirmation into the heap _OrderConfirmationType* orderConfirmation; hr = WsReadBody( replyMessage, &PurchaseOrder_wsdl.globalElements.OrderConfirmationType, WS_READ_OPTIONAL_POINTER, heap, &orderConfirmation, sizeof(orderConfirmation), error); if (FAILED(hr)) { goto Exit; } // If there are no more confirmations, break out of the loop if (orderConfirmation == NULL) { break; } // Print out confirmation contents wprintf(L"%s\n", orderConfirmation->expectedShipDate); // Reset the heap which frees the confirmation data that was deserialized hr = WsResetHeap( heap, error); if (FAILED(hr)) { goto Exit; } } // Receive the end of the reply message hr = WsReadMessageEnd( channel, replyMessage, NULL, error); if (FAILED(hr)) { goto Exit; } // Reset message so it can be used again hr = WsResetMessage( replyMessage, error); if (FAILED(hr)) { goto Exit; } // Reset message so it can be used again hr = WsResetMessage( requestMessage, error); if (FAILED(hr)) { goto Exit; } } Exit: if (FAILED(hr)) { // Print out the error PrintError(hr, error); } if (channel != NULL) { // Close the channel WsCloseChannel(channel, NULL, error); } if (requestMessage != NULL) { WsFreeMessage(requestMessage); } if (replyMessage != NULL) { WsFreeMessage(replyMessage); } if (channel != NULL) { WsFreeChannel(channel); } if (error != NULL) { WsFreeError(error); } if (heap != NULL) { WsFreeHeap(heap); } fflush(stdout); return SUCCEEDED(hr) ? 0 : -1; }
// This thread is used to recieve reply messages DWORD WINAPI ReceiverThread( __in void* parameter) { HRESULT hr = S_OK; THREAD_INFO* threadInfo = (THREAD_INFO*)parameter; WS_CHANNEL* channel = threadInfo->channel; WS_MESSAGE* message = NULL; WS_ERROR* error = NULL; WS_HEAP* heap = NULL; // Create an error object for storing rich error information hr = WsCreateError( NULL, 0, &error); if (FAILED(hr)) { goto Exit; } // Create a heap to store deserialized data hr = WsCreateHeap( /*maxSize*/ 2048, /*trimSize*/ 512, NULL, 0, &heap, error); if (FAILED(hr)) { goto Exit; } hr = WsCreateMessageForChannel( channel, NULL, 0, &message, error); if (FAILED(hr)) { goto Exit; } // Go into a receive loop. The loop terminates when the // main thread aborts the channel (causing subsequent receives // to fail). for (;;) { // Receive start of reply message (headers) hr = WsReadMessageStart(channel, message, NULL, error); if (FAILED(hr)) { goto Exit; } // Get action value WS_XML_STRING receivedAction; hr = WsGetHeader( message, WS_ACTION_HEADER, WS_XML_STRING_TYPE, WS_READ_REQUIRED_VALUE, NULL, &receivedAction, sizeof(receivedAction), error); if (FAILED(hr)) { goto Exit; } // Make sure action is what we expect if (WsXmlStringEquals(&receivedAction, PurchaseOrder_wsdl.messages.OrderConfirmation.action, error) != S_OK) { hr = WS_E_ENDPOINT_ACTION_NOT_SUPPORTED; goto Exit; } // Read the order confirmation from the body _OrderConfirmationType* orderConfirmation; hr = WsReadBody(message, &PurchaseOrder_wsdl.globalElements.OrderConfirmationType, WS_READ_REQUIRED_POINTER, heap, &orderConfirmation, sizeof(orderConfirmation), error); if (FAILED(hr)) { goto Exit; } // Receive end of message hr = WsReadMessageEnd(channel, message, NULL, error); if (FAILED(hr)) { goto Exit; } // Print out confirmation contents wprintf(L"%s\n", orderConfirmation->expectedShipDate); // Reset message so it can used again hr = WsResetMessage(message, error); if (FAILED(hr)) { goto Exit; } // Reset heap hr = WsResetHeap(heap, error); if (FAILED(hr)) { goto Exit; } } Exit: // Print out the error. Ignore aborted errors, which are // caused by the client thread aborting the channel. if (FAILED(hr) && hr != WS_E_OPERATION_ABORTED) { PrintError(hr, error); } if (message != NULL) { WsFreeMessage(message); } if (error != NULL) { WsFreeError(error); } if (heap != NULL) { WsFreeHeap(heap); } return hr; }
// Messages arrive on this thread from the relay thread DWORD WINAPI ReceiverThread(void* parameter) { HRESULT hr; THREADINFO* threadInfo = (THREADINFO*) parameter; HANDLE receiverReadyEvent = threadInfo->event; WS_ERROR* error = NULL; WS_CHANNEL* receiveChannel = NULL; WS_MESSAGE* receiveMessage = NULL; WS_LISTENER* listener = NULL; WS_HEAP* heap = NULL; // Create an error object for storing rich error information hr = WsCreateError( NULL, 0, &error); if (FAILED(hr)) { goto Exit; } // Create a heap to store deserialized data hr = WsCreateHeap( /*maxSize*/ 2048, /*trimSize*/ 512, NULL, 0, &heap, error); if (FAILED(hr)) { goto Exit; } // Create a listener hr = WsCreateListener(WS_CHANNEL_TYPE_DUPLEX_SESSION, WS_TCP_CHANNEL_BINDING, NULL, 0, NULL, &listener, error); if (FAILED(hr)) { goto Exit; } // Open listener using TCP duplex session hr = WsOpenListener(listener, &serviceUrl, NULL, error); if (FAILED(hr)) { goto Exit; } // Create a channel hr = WsCreateChannelForListener(listener, NULL, 0, &receiveChannel, error); if (FAILED(hr)) { goto Exit; } // Notify that thread is ready threadInfo->hr = NOERROR; SetEvent(receiverReadyEvent); // Accept a channel from the client hr = WsAcceptChannel(listener, receiveChannel, NULL, error); if (FAILED(hr)) { goto Exit; } hr = WsCreateMessageForChannel( receiveChannel, NULL, 0, &receiveMessage, error); if (FAILED(hr)) { goto Exit; } // Receive all messages for (;;) { // Receive start of message (headers) hr = WsReadMessageStart(receiveChannel, receiveMessage, NULL, error); if (FAILED(hr)) { goto Exit; } if (hr == WS_S_END) { // No more messages on this channel break; } // Get action value WS_XML_STRING receivedAction; hr = WsGetHeader( receiveMessage, WS_ACTION_HEADER, WS_XML_STRING_TYPE, WS_READ_REQUIRED_VALUE, NULL, &receivedAction, sizeof(receivedAction), error); if (FAILED(hr)) { goto Exit; } // Make sure action is what we expect if (WsXmlStringEquals(&receivedAction, PurchaseOrder_wsdl.messages.PurchaseOrder.action, error) != S_OK) { hr = WS_E_ENDPOINT_ACTION_NOT_SUPPORTED; goto Exit; } // Read the body of the message as a purchase order _PurchaseOrderType* purchaseOrder; hr = WsReadBody(receiveMessage, &PurchaseOrder_wsdl.globalElements.PurchaseOrderType, WS_READ_REQUIRED_POINTER, heap, &purchaseOrder, sizeof(purchaseOrder), error); if (FAILED(hr)) { goto Exit; } // Print out purchase order wprintf(L"%ld, %s\n", purchaseOrder->quantity, purchaseOrder->productName); // Receive message end hr = WsReadMessageEnd(receiveChannel, receiveMessage, NULL, error); if (FAILED(hr)) { goto Exit; } // Reset message so we can use it again hr = WsResetMessage(receiveMessage, error); if (FAILED(hr)) { goto Exit; } // Reset heap hr = WsResetHeap(heap, error); if (FAILED(hr)) { goto Exit; } } Exit: if (FAILED(hr)) { // Print out the error PrintError(hr, error); } fflush( stdout); if (receiveChannel != NULL) { // Close the channel WsCloseChannel(receiveChannel, NULL, error); } if (receiveChannel != NULL) { WsFreeChannel(receiveChannel); } if (listener != NULL) { // Close the listener if it was opened WsCloseListener(listener, NULL, error); } if (listener != NULL) { WsFreeListener(listener); } if (receiveMessage != NULL) { WsFreeMessage(receiveMessage); } if (error != NULL) { WsFreeError(error); } if (heap != NULL) { WsFreeHeap(heap); } if (FAILED(hr)) { // Notify that thread is ready SetEvent(receiverReadyEvent); threadInfo->hr = hr; } return 1; }
HRESULT CALLBACK ProcessMessage( __in const WS_OPERATION_CONTEXT* context, __in_opt const WS_ASYNC_CONTEXT* asyncContext, __in_opt WS_ERROR* error) { UNREFERENCED_PARAMETER(asyncContext); WS_CHANNEL* channel = NULL; HRESULT hr = S_OK; WS_MESSAGE* requestMessage = NULL; WS_MESSAGE* replyMessage = NULL; WS_HEAP* heap; // Get the request mesasge hr = WsGetOperationContextProperty( context, WS_OPERATION_CONTEXT_PROPERTY_INPUT_MESSAGE, &requestMessage, sizeof(requestMessage), error); if (FAILED(hr)) { return hr; } // Get the channel hr = WsGetOperationContextProperty( context, WS_OPERATION_CONTEXT_PROPERTY_CHANNEL, &channel, sizeof(channel), error); if (FAILED(hr)) { return hr; } // Get the heap hr = WsGetOperationContextProperty( context, WS_OPERATION_CONTEXT_PROPERTY_HEAP, &heap, sizeof(heap), error); if (FAILED(hr)) { return hr; } // Create a reply message hr = WsCreateMessageForChannel( channel, NULL, 0, &replyMessage, error); if (FAILED(hr)) { goto Exit; } // Initialize reply message hr = WsInitializeMessage(replyMessage, WS_REPLY_MESSAGE, requestMessage, error); if (FAILED(hr)) { goto Exit; } // Get the HTTP Verb WS_STRING verb; hr = WsGetMappedHeader( requestMessage, &verbHeaderName, WS_SINGLETON_HEADER, 0, WS_STRING_TYPE, WS_READ_REQUIRED_VALUE, NULL, &verb, sizeof(verb), error); if (FAILED(hr)) { goto Exit; } wprintf(L"Verb: %.*s\n", verb.length, verb.chars); // Check the verb if (CompareString( LOCALE_INVARIANT, NORM_IGNORECASE, verb.chars, verb.length, L"POST", 4) == CSTR_EQUAL) { // It is a POST, so read the body // Get the content type WS_STRING contentType; hr = WsGetMappedHeader( requestMessage, &contentTypeHeaderMapping.headerName, WS_SINGLETON_HEADER, 0, WS_STRING_TYPE, WS_READ_REQUIRED_VALUE, NULL, &contentType, sizeof(contentType), error); if (FAILED(hr)) { goto Exit; } wprintf(L"Content-Type: %.*s\n", contentType.length, contentType.chars); // Read the bytes of the message body WS_BYTES body; hr = WsReadBody( requestMessage, &bytesBodyDescription, WS_READ_REQUIRED_VALUE, heap, &body, sizeof(body), error); if (FAILED(hr)) { goto Exit; } wprintf(L"%.*S\n", body.length, body.bytes); } else if (CompareString( LOCALE_INVARIANT, NORM_IGNORECASE, verb.chars, verb.length, L"GET", 3) == CSTR_EQUAL) { // It is a GET, so the message body is empty } else { // Unrecognized verb hr = SendFailureMessage( channel, replyMessage, 405, L"Method Not Allowed", error); goto Exit; } // Read end of request message hr = WsReadMessageEnd( channel, requestMessage, NULL, error); if (FAILED(hr)) { goto Exit; } // Set content type header of reply hr = WsAddMappedHeader( replyMessage, &contentTypeHeaderMapping.headerName, WS_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, &replyContentType, sizeof(replyContentType), error); if (FAILED(hr)) { goto Exit; } // Set status of reply hr = SetStatus(replyMessage, 200, L"OK", error); if (FAILED(hr)) { goto Exit; } // Set up the bytes to return in the HTTP body WS_BYTES body; body.bytes = const_cast<BYTE*>(replyBodyBytes); body.length = sizeof(replyBodyBytes); // Send the reply message hr = WsSendMessage( channel, replyMessage, &bytesMessageDescription, WS_WRITE_REQUIRED_VALUE, &body, sizeof(body), NULL, error); if (FAILED(hr)) { goto Exit; } Exit: if (replyMessage != NULL) { WsFreeMessage( replyMessage); } return hr; }