Click here to Skip to main content
14,388,768 members

Basic internet requests

Rate this:
4.20 (9 votes)
Please Sign up or sign in to vote.
4.20 (9 votes)
24 Jul 2011CPOL
Classes for making simple internet calls using Wininet.


The last few days in the office I've been hearing tons of curses regarding how cumbersome it is to do some internet requests. Basically, a colleague wrote some Qt code wanting to do some simple GET. QNetworkAccessManager, QNetworkReply, signals, slots, deleteLater(), some 3-7 classes were involved - a little bit too much. So I grabbed some simple classes I was using on a personal project and threw them to Vlad (the screaming colleague, not the impaler) and voila - problem solved.


Familiarity with Wininet is useful and very basic C++ classes usage (wstring, stream). For understanding the Justin.TV REST API - please go to the documentation page here.

Starting: From backwards

We'll start here with what we want to do. In this case, I'm writing a stream player and I'm implementing support - I'm making the stream/summary API call.

int __cdecl 
wmain(int argc, wchar_t** argv) {
    // get stream summary
    return 0;

The stream/summary call is calling in turn a "" API call - implemented in the jtv_api class (see below).

void jtv_test_streamsummary() {
    std::wstring data;
    if(jtv_api::streamsummary(data, L"", L"", L"")) {
        std::wcout << data << std::endl;

The jtv_api class (trimmed version for this purpose) implements a public call streamsearch; I won't get into the details of the jtv REST API - stream/search returns XML or JSON with aggregate information about all live channels. (The HTTP call composing is minimal - simply appends to the base bath /api/stream/summary the arguments of this call - channel, category, and language which filters the result to the specified values, if any - so don't expect this to work on special non-escaped cases or so. Remember - it is a sample.)

class jtv_api {
        jtv_api() {
        ~jtv_api() {
        jtv_api(const jtv_api&);
        jtv_api& operator=(const jtv_api&);
    static bool streamsummary(std::wstring& data, 
        const std::wstring& channel, 
        const std::wstring& category, 
        const std::wstring& language
    ) {
        //    compose request relative url
        std::wstring rpath = L"/api/stream/summary";
        rpath += L".xml";
        //    add query part
        std::wstring qry = L"";
        if(!channel.empty()) {
            if(!qry.empty()) {
                qry += L"&"; }
            qry += L"channel=";
            qry += channel;
        if(!category.empty()) {
            if(!qry.empty()) {
                qry += L"&"; }
            qry += L"category=";
            qry += category;
        if(!language.empty()) {
            if(!qry.empty()) {
                qry += L"&"; }
            qry += L"language=";
            qry += language;
        //    append query part, if any
        if(!qry.empty()) {
            rpath += L"?";
            rpath += qry;
        return _execute_request(data, rpath);

In turn, all the public calls - the public call, in this version :) - routes to the _execute_request private helper which does all the HTTP and converts the byte response to std::wstring using the _response_to_string helper:

    static bool _response_to_string(std::wstring& data, const vector_t<BYTE>& response) {
        int cv = ::MultiByteToWideChar(CP_UTF8, 0, 
           (LPCSTR)response.operator const BYTE *(), response.size(), NULL, 0);
        if(cv != 0) {
            wchar_t* wz = new wchar_t[cv];
            if(!wz) {
                return false; }
            memset(wz, 0, cv * sizeof(wchar_t));
            int cv2 = ::MultiByteToWideChar(CP_UTF8, 0, 
               (LPCSTR)response.operator const BYTE *(), response.size(), wz, cv);
            data = wz;
            delete []wz;
            return true;
        return false;

Our point of interest is the _execute_request call:

static bool _execute_request(std::wstring& data, 
    const std::wstring& request, const std::wstring& verb = L"GET") {
/*1*/    internet_api api;
/*2*/    internet_session session(&api); 
    if(! {
        return false; }
/*3*/    internet_connection connection(&api, &session, L""); 
    if(! {
        return false; }
    //    do request
/*4*/    internet_request req(&api, &connection); 
    if(!, request.c_str())) {
        return false; }
    std::wstring status;
    vector_t<BYTE> response;
    if(!req.get_response(status, response)) {
        return false; }
    if(!_response_to_string(data, response)) {
        return false; }
    return true;

which condenses all the internet work. These calls use the internet classes as described below (all classes except internet_api are derived from the internet_handle HINTERNET wrapper class).

  1. internet_api api object: nothing more than a fancy dynamic wrapper over wininet.dll used calls: InternetConnectW, InternetOpenW, InternetCloseHandle, etc.; loads wininet.dll, resolves all APIs using GetProcAddress, and is passed to all the other classes needing API calls.
  2. instantiates and opens the session object, which calls InternetOpenW;
  3. class internet_session
        : public internet_handle {
        internet_session(internet_api* api) 
            : internet_handle(api) {
        virtual ~internet_session() {
        internet_session(const internet_session&);
        internet_session& operator=(const internet_session&);
        virtual bool open() {
            HINTERNET h = _api->api_InternetOpenW(
                NULL, NULL, 0);
            if(h == NULL) {
                return false; }
            return true; }
  4. instantiates the connection object, which calls InternetConnectW to connect to the host:
  5. class internet_connection
        : public internet_handle {
        pointer_t<internet_session, false> _session;
        std::wstring                       _host;    
        internet_connection(internet_api* api, 
                 internet_session *session, const std::wstring& host) 
            : internet_handle(api)
            , _session(session)
            , _host(host) {
        virtual ~internet_connection() {
        internet_connection(const internet_connection&);
        internet_connection& operator=(const internet_connection&);
        const std::wstring& host() const {
            return _host; }
        virtual bool open() {
            if(!_session) {
                return false; }
            HINTERNET h = _api->api_InternetConnectW(
                *_session, _host.c_str(), 
                0, 0);
            if(h == NULL) {
                return false; }
            return true; }
  6. instantiates the internet_request req object, which calls HttpOpenRequestW to perform the request open (using the default verb GET), gets the request response (HttpSendRequestW), status, and data (HttpQueryInfoW, InternetReadFile), and converts the response to std::wstring.
  7. class internet_request
        : public internet_handle {
        pointer_t<internet_connection, false> _connection;
        internet_request(internet_api* api, internet_connection *connection) 
            : internet_handle(api)
            , _connection(connection) {
        virtual ~internet_request() {
        internet_request(const internet_request&);
        internet_request& operator=(const internet_request&);
        virtual bool open(LPCWSTR verb, LPCWSTR object) {
            if(!_connection) {
                return false; }
            HINTERNET h = _api->api_HttpOpenRequestW(
                NULL, NULL, 
                |   INTERNET_FLAG_NO_UI
                |   INTERNET_FLAG_KEEP_CONNECTION    
                |   INTERNET_FLAG_DONT_CACHE
                |   INTERNET_FLAG_RELOAD, 0);
            if(h == NULL) {
                return false; }
            return true; }
        bool get_response(std::wstring& status, 
            vector_t<BYTE>& response) {
            status = L"";
            if(!_api->api_HttpSendRequestW(_h, NULL, 0, NULL, 0)) {
                return false; }
            WCHAR sz[128] = L"";
            DWORD buflen = _countof(sz);
                _h, HTTP_QUERY_STATUS_CODE, 
                (LPVOID)sz, &buflen, NULL)) {
                return false; }
            status = sz;
            //    read response
            DWORD bufrd = 0;
            do {
                BYTE respp[8192 + 1];
                memset(respp, 0, _countof(respp));
                bufrd = 0;
                    _h, (LPVOID)respp, _countof(respp) - 1, &bufrd)) {
                    return false; }
                if(bufrd == 0) {
                    break; }
                for(DWORD d = 0; d < bufrd; d++) {
                    response += respp[d]; }
            } while(bufrd != 0);
            response += (BYTE)'\0';
            response += (BYTE)'\0';
            return true; }

Everything is encapsulated - in this example, in the _execute_request(data, rpath) call. That was the initial purpose - to have a simple way to do HTTP client requests using only simple Win32 calls and minimalistic classes.

(A note on the support classes, pointer_t and vector_t - they have for sure better equivalents on STL and boost universe for sure, but for my project, minimal dependencies (minus Operating System and the VC runtime) is a must and they serve their purpose for now.)


  • Version 1.0 - 24 July, 2011.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Cristian Amarie
Team Leader BitDefender
Romania Romania
No Biography provided

Comments and Discussions

QuestionDenver limousine Pin
Member 1081038011-May-14 6:13
MemberMember 1081038011-May-14 6:13 
GeneralMy vote of 5 Pin
2374125-Jul-11 10:06
Member2374125-Jul-11 10:06 
GeneralRe: My vote of 5 Pin
Cristian Amarie26-Jul-11 8:47
MemberCristian Amarie26-Jul-11 8:47 
QuestionI would have given you a '5' alone ... Pin
Garth J Lancaster25-Jul-11 1:26
professionalGarth J Lancaster25-Jul-11 1:26 
AnswerRe: I would have given you a '5' alone ... Pin
Cristian Amarie25-Jul-11 1:28
MemberCristian Amarie25-Jul-11 1:28 
GeneralRe: I would have given you a '5' alone ... Pin
Garth J Lancaster25-Jul-11 1:35
professionalGarth J Lancaster25-Jul-11 1:35 
GeneralRe: I would have given you a '5' alone ... Pin
Cristian Amarie25-Jul-11 2:39
MemberCristian Amarie25-Jul-11 2:39 
GeneralRe: I would have given you a '5' alone ... Pin
Teashirt24-Aug-11 18:21
MemberTeashirt24-Aug-11 18:21 
QuestionWhat has this to do with "Basic internet requests"? Pin
Little Indian24-Jul-11 19:39
MemberLittle Indian24-Jul-11 19:39 
AnswerRe: What has this to do with "Basic internet requests"? Pin
Cristian Amarie24-Jul-11 19:46
MemberCristian Amarie24-Jul-11 19:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Posted 24 Jul 2011

Tagged as


13 bookmarked