How to: Work with Asynchronous Streams (C++ REST SDK)

The C++ REST SDK (codename "Casablanca") provides stream functionality that enables you to more easily work with TCP sockets, files on disk, and memory. C++ REST SDK streams resemble those provided by the C++ Standard Library except that the C++ REST SDK versions make use of asynchrony. The library returns pplx::task, and not the value directly, for I/O operations that can potentially block. This page shows two examples. The first shows how to write to and read from a stream by using both STL containers and raw memory. The second example creates an HTTP GET request and prints part of its response stream to the console.

Warning

This topic contains information for the C++ REST SDK 1.0 (codename "Casablanca"). If you are using a later version from the Codeplex Casablanca web page, then use the local documentation at http://casablanca.codeplex.com/documentation.

A more complete example that shows #include and using statements follows these examples.

To use streams together with STL containers and raw memory

This example demonstrates how to read to and write from a stream by using both STL containers and raw memory.

// Shows how to read from and write to a stream with an STL container or raw pointer. 
void ReadWriteStream(istream inStream, ostream outStream)
{
    // Write a string to the stream.
    std::string strData("test string to write\n");
    container_buffer<std::string> outStringBuffer(std::move(strData));
    outStream.write(outStringBuffer, outStringBuffer.collection().size()).then([](size_t bytesWritten)
    {
        // Perform actions here once the string has been written...
    });

    // Read a line from the stream into a string.
    container_buffer<std::string> inStringBuffer;
    inStream.read_line(inStringBuffer).then([inStringBuffer](size_t bytesRead)
    {
        const std::string &line = inStringBuffer.collection();

        // Perform actions here after reading line into a string...
    });

    // Write data from a raw chunk of contiguous memory to the stream. 
    // The raw data must stay alive until write operation has finished. 
    // In this case we will place on the heap to avoid any issues. 
    const size_t rawDataSize = 8;
    unsigned char* rawData = new unsigned char[rawDataSize];
    memcpy(&rawData[0], "raw data", rawDataSize);
    rawptr_buffer<unsigned char> rawOutBuffer(rawData, rawDataSize, std::ios::in);
    outStream.write(rawOutBuffer, rawDataSize).then([rawData](size_t bytesWritten)
    {
        delete []rawData;

        // Perform actions here once the string as been written...
    });
}

To access an HTTP response stream

Here’s how to use the web::http::http_response::body method to retrieve a concurrency::streams::istream object that data can be read from. For simplicity, this example prints only the first few characters of the response to the console. For a more basic version that retrieves a server response but doesn’t work with the response stream, see How to: Connect to HTTP servers.

// Creates an HTTP request and prints part of its response stream.
pplx::task<void> HTTPStreamingAsync()
{
    http_client client(L"https://www.fourthcoffee.com");

    return client.request(methods::GET).then([](http_response response)
    {
        if(response.status_code() != status_codes::OK)
        {
            // Handle error cases... 
            return pplx::task_from_result();
        }

        // Perform actions here reading from the response stream... 
        // In this example, we print the first 15 characters of the response to the console.
        istream bodyStream = response.body();
        container_buffer<std::string> inStringBuffer;
        return bodyStream.read(inStringBuffer, 15).then([inStringBuffer](size_t bytesRead)
        {
            const std::string &text = inStringBuffer.collection();

            // For demonstration, convert the response text to a wide-character string.
            std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> utf16conv;
            std::wostringstream ss;
            ss << utf16conv.from_bytes(text.c_str()) << std::endl;
            std::wcout << ss.str();
        });
    });

    /* Output:
    <!DOCTYPE html>
    */
}

Complete example

Here’s the complete example.

#include <codecvt>
#include <containerstream.h>
#include <http_client.h>
#include <iostream>
#include <producerconsumerstream.h>
#include <rawptrstream.h>

using namespace concurrency;
using namespace concurrency::streams;
using namespace web::http;
using namespace web::http::client;

// Shows how to read from and write to a stream with an STL container or raw pointer. 
void ReadWriteStream(istream inStream, ostream outStream)
{
    // Write a string to the stream.
    std::string strData("test string to write\n");
    container_buffer<std::string> outStringBuffer(std::move(strData));
    outStream.write(outStringBuffer, outStringBuffer.collection().size()).then([](size_t bytesWritten)
    {
        // Perform actions here once the string has been written...
    });

    // Read a line from the stream into a string.
    container_buffer<std::string> inStringBuffer;
    inStream.read_line(inStringBuffer).then([inStringBuffer](size_t bytesRead)
    {
        const std::string &line = inStringBuffer.collection();

        // Perform actions here after reading line into a string...
    });

    // Write data from a raw chunk of contiguous memory to the stream. 
    // The raw data must stay alive until write operation has finished. 
    // In this case we will place on the heap to avoid any issues. 
    const size_t rawDataSize = 8;
    unsigned char* rawData = new unsigned char[rawDataSize];
    memcpy(&rawData[0], "raw data", rawDataSize);
    rawptr_buffer<unsigned char> rawOutBuffer(rawData, rawDataSize, std::ios::in);
    outStream.write(rawOutBuffer, rawDataSize).then([rawData](size_t bytesWritten)
    {
        delete []rawData;

        // Perform actions here once the string as been written...
    });
}

// Creates an HTTP request and prints part of its response stream.
pplx::task<void> HTTPStreamingAsync()
{
    http_client client(L"https://www.fourthcoffee.com");

    return client.request(methods::GET).then([](http_response response)
    {
        if(response.status_code() != status_codes::OK)
        {
            // Handle error cases... 
            return pplx::task_from_result();
        }

        // Perform actions here reading from the response stream... 
        // In this example, we print the first 15 characters of the response to the console.
        istream bodyStream = response.body();
        container_buffer<std::string> inStringBuffer;
        return bodyStream.read(inStringBuffer, 15).then([inStringBuffer](size_t bytesRead)
        {
            const std::string &text = inStringBuffer.collection();

            // For demonstration, convert the response text to a wide-character string.
            std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> utf16conv;
            std::wostringstream ss;
            ss << utf16conv.from_bytes(text.c_str()) << std::endl;
            std::wcout << ss.str();
        });
    });

    /* Output:
    <!DOCTYPE html>
    */
}

int wmain()
{
    // This example uses the task::wait method to ensure that async operations complete before the app exits.  
    // In most apps, you typically don�t wait for async operations to complete.

    streams::producer_consumer_buffer<uint8_t> buffer;
    //ReadWriteStream(buffer.create_istream(), buffer.create_ostream());

    HTTPStreamingAsync().wait();
}

See Also

Other Resources

C++ REST SDK (Codename "Casablanca")