Click here to Skip to main content
13,661,823 members
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

11.9K views
457 downloads
23 bookmarked
Posted 31 Dec 2016
Licenced CPOL

Take a REST : A Windows C++ library for quick Web interfaces interaction

, 20 Jan 2017
Rate this:
Please Sign up or sign in to vote.
A few functions and you can call various Web libraries like Google Drive.

Introduction

Too many services are available for the web (Google Drive, Facebook APIs etc) but you only get a Java SDK, a PHP SDK, a Python SDK and never a Windows SDK. Here is a small library that can take care of any REST interface in a quick manner.

I will use this library in my next article, which will provide a Google/Onedrive/Dropbox drive library for Windows.

The ZIP Contains

  • A ready to use Visual Studio solution with the library.
  • TEST.EXE to test immediately a google authentication. To facilitate coding, we also use Hong Jiang's JSON parser and my own ystring.
  • REST.H, the only file you need to use in your projects.

The ihandle wrapper

To facilitate coding, the HINTERNET WinInet handle is wrapped in a ihandle class:

class ihandle
        {
        private:
            HINTERNET hX = 0;
            std::shared_ptr<size_t> ptr = std::make_shared<size_t>();

        public:

            void Close()
                {
                if (!ptr || !ptr.unique())
                    {
                    ptr.reset();
                    return;
                    }
                ptr.reset();
                if (hX != 0)
                    InternetCloseHandle(hX);
                hX = 0;
                }

            ihandle()
                {
                hX = 0;
                }
            ~ihandle()
                {
                Close();
                }
            ihandle(const ihandle& h)
                {
                Dup(h);
                }
            ihandle(ihandle&& h)
                {
                Move(std::forward<ihandle>(h));
                }
            ihandle(HINTERNET hY)
                {
                hX = hY;
                }
            ihandle& operator =(const ihandle& h)
                {
                Dup(h);
                return *this;
                }
            ihandle& operator =(ihandle&& h)
                {
                Move(std::forward<ihandle>(h));
                return *this;
                }

            void Dup(const ihandle& h)
                {
                Close();
                hX = h.hX;
                ptr = h.ptr;
                }
            void Move(ihandle&& h)
                {
                Close();
                hX = h.hX;
                ptr = h.ptr;
                h.ptr.reset();
                h.hX = 0;
                }
            operator HINTERNET() const
                {
                return hX;
                }


        }

This class provides copy/move functions and can be used in place of the standard HINTERNET handle.

The providers

The library must read from or write data to somewhere.  The abstract interface which the library expects to read data is data_provider:

class data_provider
    {
    public:

        virtual size_t s() = 0;
        virtual size_t Read(char* Buff, size_t sz) = 0;
        virtual bool CanOnce() = 0;
        virtual std::tuple<const char*, size_t> Once() = 0;

    };

For convenience, the library provides two implementations of it, memory_data_provider and file_data_provider which provide reading functions from a memory buffer or a file handle respectively.

The abstract interface to write data is data_writer:

class data_writer
    {
    public:

        virtual DWORD Write(const char* Buff, DWORD sz) = 0;
        virtual size_t s() = 0;

    };

In addition, the library provides memory_data_writer and file_data_writer to write to memory or a handle, for convenience. 

The Library

Constructor: Pass the agent name.

REST(const wchar_t* ag = 0);

 

Connect or disconnect:

HRESULT Connect(const wchar_t* host, bool SSL = false, unsigned short Port = 0, DWORD flg = 0,const wchar_t* user= 0,const wchar_t* pass = 0)
void Disconnect();

If SSL is true, the default port is 443 and flags are appended INTERNET_FLAG_SECURE. 

 

Make a request:

ihandle Request2(const wchar_t* url, data_provider& dp, bool Once = true, 
    const wchar_t* verb = L"POST", std::initializer_list<wstring> hdrs = {}, 
    std::function<HRESULT(size_t sent, size_t tot, void*)> fx = nullptr, 
    void* lp = 0, 
    const char* extradata1 = 0, DWORD extradatasize1 = 0,
     const char* extradata2 = 0,DWORD extradatasize2 = 0);

The parameters to this function are:

  • The url to connect.
    • If you pass a full url (like https://accounts.google.com/o/oauth2), then the function:
      • If the request is a GET, takes the entire url with InternetOpenURL and returns that handle without doing anything else (all other parameters are ignored).
      • If the request is a verb other than GET, it cracks the url to it's parts and proceeds to the steps as if you had passed a relative url.
    • If you pass a relative url, then the function uses it to HttpOpenRequest().
  • The data provider to provide more data to the request. This is used when the request requires a HTTP body, for example when passing form data or when uploading a file.
  • Once can  be true to instruct the function to pass the entire data in dp at once. This is ignored unless the data provider is a memory data provider and extradata1.extradata2 are null.
  • verb is the HTTP verb to send, like GET, POST or PUT.
  • hdrs include extra HTTP headers to be sent to the request (for example, in Google Auth, you can use an Authorization: Bearer header).
  • fx and lp specify a function and a custom value, The function is to be called periodically as long as the upload is progressing.
  • extradata1/extradatasize1 are sent, if not null, before the upload of the data in dp.
  • extradata2/extradatasize2 are sent, if not null, after the upload of the data in dp.

The function returns a non-null ihandle on success.

For convenience, the library provides the RequestWithBuffer and RequestWithFile functions.

 

Get any headers related to a request:

long Headers(ihandle& hI3,std::map<wstring,wstring>& t);

It returns all the headers in a map and also the HTTP result code (say, 200 or 404) as a return value.

 

Read the result:

HRESULT Read2(ihandle& hI3, data_writer& dw, 
std::function<HRESULT(unsigned long long, unsigned long long, void*)> fx = nullptr, void* lp = 0);

The parameters to this function are:

  • The handle to read
  • A provider to write the data
  • fx and lp specify a function and a custom value, The function is to be called periodically as long as the download is progressing.

If the size of the download is unknown, the second parameter of the fx function is -1.

For convenience, the library provides the ReadToFile and ReadToMemory functions.

 

Google Authentication

The google authentication flow is demonstrated in text.exe.

  • The app asks for the Client ID and secret. To use it, you must have an application's client ID and secret (created in Google API Console).
  • The app opens a google permission URL which you click "Allow" in order to get a code.
  • The app asks for the code.
  • The app then uses REST to get the access token:
if (FAILED(Connect(L"accounts.google.com", true)))
    return false;

string u;
// Build the thing to be passed as the request body
u = {...} ;

wchar_t au[1000] = { 0 };
swprintf_s(au, 1000, L"Content-Length: %u", (DWORD)u.length());
auto hi = RequestWithBuffer(L"/o/oauth2/token", L"POST",
     { L"Content-Type: application/x-www-form-urlencoded",au }, 
      u.data(), u.size());

The return is then read:

vector<char> out;
ReadToMemory(hi, out);
out.resize(out.size() + 1); // to make it a ASCIIZ
char* p = (char*)out.data();
j.Parse(p);

and parsed with JSON, to provide the refresh and access token.

 

History

21-01-2017: Added user+pass to connect and some minor fixes.
04-01-2017 : Fixed a (serious) bug, duh.
01-01-2017 : Happy new year (and first release).

License

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

Share

About the Author

Michael Chourdakis
Engineer
Greece Greece
I'm working in C++, PHP , Java, Windows, iOS and Android.

I 've a PhD in Digital Signal Processing and I specialize in Pro Audio applications.

My home page: http://www.michaelchourdakis.com

You may also be interested in...

Pro

Comments and Discussions

 
QuestionA virus in the download Pin
ANANDHAN steve24-Jan-17 8:18
memberANANDHAN steve24-Jan-17 8:18 
AnswerRe: A virus in the download Pin
Rick York24-Jan-17 9:41
memberRick York24-Jan-17 9:41 
GeneralRe: A virus in the download Pin
ANANDHAN steve25-Jan-17 8:47
memberANANDHAN steve25-Jan-17 8:47 
GeneralRe: A virus in the download Pin
Michael Chourdakis25-Jan-17 9:01
memberMichael Chourdakis25-Jan-17 9:01 
AnswerRe: A virus in the download Pin
Michael Chourdakis25-Jan-17 8:42
memberMichael Chourdakis25-Jan-17 8:42 
GeneralRe: A virus in the download Pin
ANANDHAN steve25-Jan-17 8:53
memberANANDHAN steve25-Jan-17 8:53 

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.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web01-2016 | 2.8.180810.1 | Last Updated 21 Jan 2017
Article Copyright 2017 by Michael Chourdakis
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid