3

Im not sure if this is lack of knowledge in msdn or not. i Have the following code:

    #include "stdafx.h"
    #include <iostream>
    #include <string>
    #include <windows.h>
    #include <WinHttp.h>
    #include "myHTTP.h"
int main(){
    WinHTTP newHTTP("test", "test");
        bool myResult;

        newHTTP.httpConnect(L"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36",
        L"https://pages.awscloud.com/awsomedayonlineconference-reg.html",
        1,
        L"GET");

        newHTTP.httpAddHeader(L"Content-Type: application/x-www-form-urlencoded\r\n");
        newHTTP.httpSend();
        myResult = newHTTP.httpReceive();



        newHTTP.closeHandles();
 return 0;
}

I have a class for this and the following line is being executed: // open the request - not connected at this point

hRequest = WinHttpOpenRequest(hConnect, protocol.c_str(), NULL, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);

if (!hRequest) {
    printf("error2: %d", GetLastError());
}

SO basically when i run my software, it returns here because !hrequest is empty when calling winhttpopenrequest. I have added getlasterror to see why this is but the only output i get is:

error2: 6

I then read the msdn for winhttp and i can see the errors returned from the function here: https://msdn.microsoft.com/en-us/library/windows/desktop/aa384099(v=vs.85).aspx but this mysterious error 6 is making no sense to me.

Any help on seeing why the handle is invalid?

full class code:

#pragma once
// WinHTTP wrapper for web protocol -- windows 8.1+
class WinHTTP {

private:
    std::string siteUsername, sitePassword;
    std::wstring UA, URL;
    bool bResult = false;
    DWORD dwSize = sizeof(DWORD); // used to handle reading data in bytes
    LPSTR pszOutBuffer; // used to Allocate space for the buffer.
    DWORD dwDownloaded = 0; // set to null if using asynchronously and use in callback function only
    HINTERNET hSession = NULL, hConnect = NULL, hRequest = NULL;

public:
    WinHTTP(std::string myuser = "", std::string mypass = "") {
        siteUsername = myuser;
        sitePassword = mypass;
    }

    // TODO: update to be able to add proxy details either here or before. do check if proxy has been detected in here and open/connect accordingly 
    void httpConnect(std::wstring userAgent, std::wstring myURL, int isHTTPS, std::wstring protocol) {

        UA = userAgent;
        URL = myURL;

        std::wstring acceptTypes = L"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8";

        int portToUse;
        if (isHTTPS == 1) {
            portToUse = 443;
        }
        else {
            portToUse = 80;
        }

        //initialize http and return session handle -- use c_str to convert wstring to LPCWSTR
        hSession = WinHttpOpen(UA.c_str(),
            WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);

        //make the connection request
        if (hSession) {
            hConnect = WinHttpConnect(hSession, URL.c_str(), portToUse, 0);
        }
        else {
            std::cout << "winhttpconnect error " << GetLastErrorAsString();
        }

        // open the request - not connected at this point
        hRequest = WinHttpOpenRequest(hConnect, protocol.c_str(), NULL, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);

        if (!hRequest) {
            std::cout << "winhttpopenrequest error " << GetLastErrorAsString();
        }

    }

    std::string GetLastErrorAsString()
    {
        //Get the error message, if any.
        DWORD errorMessageID = ::GetLastError();
        if (errorMessageID == 0)
            return std::string(); //No error message has been recorded

        LPSTR messageBuffer = nullptr;
        size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);

        std::string message(messageBuffer, size);

        //Free the buffer.
        LocalFree(messageBuffer);

        return message;
    }

    void httpAddHeader(std::wstring myheader) {

        if (hRequest) {
            bResult = WinHttpAddRequestHeaders(hRequest, myheader.c_str(), (ULONG)-1L, WINHTTP_ADDREQ_FLAG_ADD);
        }

    }

    bool httpSend() {
        if (hRequest) {
            bResult = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
        }

        if (!bResult) {
            std::cout << "winhttpsendrequest error " << GetLastErrorAsString();
            return false;
        }
        else {
            return true;
        }
    }

    bool httpReceive() {

        if (bResult) {
            bResult = WinHttpReceiveResponse(hRequest, NULL);
        }

        if (bResult) {

            do
            {
                // Check for available data.
                dwSize = 0; //query data available looks for data in bytes
                if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
                {
                    std::cout << "WinHttpQueryDataAvailable error " << GetLastErrorAsString();
                    break;
                }

                // No more available data.
                if (!dwSize)
                    return false;

                // Allocate space for the buffer. as dwSize now holds the size of the request
                pszOutBuffer = new char[dwSize + 1];  // just a way of freeing up memory 
                if (!pszOutBuffer)
                {
                    printf("Out of memory\n"); // couldnt allocate enough
                    return false;
                }

                ZeroMemory(pszOutBuffer, dwSize + 1); // fills a block of memory with 0s

                                                      // we know the expect size and have the pszoutbffer to write to - read the Data.
                if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer,
                    dwSize, &dwDownloaded))
                {
                        std::cout << "WinHttpReadData error " << GetLastErrorAsString();
                    return false;
                }
                else
                {
                    printf("%s", pszOutBuffer);
                }

                // Free the memory allocated to the buffer.
                delete[] pszOutBuffer;
                return true;

                // This condition should never be reached since WinHttpQueryDataAvailable
                // reported that there are bits to read.
                if (!dwDownloaded)
                    return false;

            } while (dwSize > 0);

        }

        return false;

    }

    void closeHandles() {
        if (hRequest) WinHttpCloseHandle(hRequest);
        if (hConnect) WinHttpCloseHandle(hConnect);
        if (hSession) WinHttpCloseHandle(hSession);
    }

};
Max Vollmer
  • 8,412
  • 9
  • 28
  • 43
jimmy
  • 73
  • 1
  • 7
  • 1
    Is `hConnect` valid? – Hatted Rooster Jun 05 '18 at 09:01
  • `GetLastError` returns a `DWORD`, so 6 is a correct value. Error code https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx Example usage, https://msdn.microsoft.com/en-us/library/windows/desktop/aa384091(v=vs.85).aspx – Hello Everyone Jun 05 '18 at 09:04
  • @SombreroChicken thanks, see update question, any reason why hconnect would be invalid? – jimmy Jun 05 '18 at 09:08
  • 1
    We can't tell you that. You need to check the `hConnect` and `GetLastError()` after `WinHttpConnect`, the same way you do after `WinHttpOpen` and after `WinHttpOpenRequest`. – Max Vollmer Jun 05 '18 at 09:15
  • it is not generating any errors as you can see on my code otherwise it would have said @MaxVollmer – jimmy Jun 05 '18 at 09:16
  • 1
    *"as you can see on my code"* I see in your code that you do not check for errors after calling `WinHttpConnect`. – Max Vollmer Jun 05 '18 at 09:16
  • @MaxVollmer sorry i added it after, but again its returning nothing, its empty. – jimmy Jun 05 '18 at 09:20
  • I can only comment on the code you show us. – Max Vollmer Jun 05 '18 at 09:22
  • @MaxVollmer im litterely telling you i added the code from your answer. it is returning no errors – jimmy Jun 05 '18 at 09:23
  • 2
    I compiled and ran your code here: after this line `hConnect = WinHttpConnect(hSession, URL.c_str(), portToUse, 0);`, `hConnect` contains `NULL`, and `GetLastError()` returns 12005 which is `Invalid URL` – Jabberwocky Jun 05 '18 at 09:26
  • @Jabberwocky but this doesnt make sense, why would the url be invalid? – jimmy Jun 05 '18 at 09:29
  • @jimmy _why would it be invalid?_ Good question, I don't know and I don't have time to search any further now, but that's what is actually happening here. – Jabberwocky Jun 05 '18 at 09:31
  • @Jabberwocky figured it out, its because the url should not contain http:// – jimmy Jun 05 '18 at 09:32
  • @jimmy you should answer your own question. – Jabberwocky Jun 05 '18 at 09:33
  • `WinHttpConnect` expects a servername, not a URL. I've updated my answer. – Max Vollmer Jun 05 '18 at 09:44

1 Answers1

3

Why you get error code 6

Error code 6 is the System Error Code ERROR_INVALID_HANDLE.

It tells you that the hConnect you pass into WinHttpOpenRequest is invalid.

You only check hSession after your call to WinHttpOpen, and hRequest after your call to WinHttpOpenRequest. But you never check if hConnect is valid.

You need to check the hConnect returned by WinHttpConnect as well, and if it's invalid check GetLastError() before calling another WINAPI method:

hSession = WinHttpOpen(UA.c_str(), WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);

if (hSession) {
    hConnect = WinHttpConnect(hSession, URL.c_str(), portToUse, 0);

    if (hConnect) {
        hRequest = WinHttpOpenRequest(hConnect, protocol.c_str(), NULL, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);

        if (!hRequest) {
            std::cout << "WinHttpOpenRequest error " << GetLastErrorAsString();
        }
    }
    else {
        std::cout << "WinHttpConnect error " << GetLastErrorAsString();
    }
}
else {
    std::cout << "WinHttpOpen error " << GetLastErrorAsString();
}

Why your call to WinHttpConnect fails

The docs tell us that WinHttpConnect expects a server name, not a URL:

pswzServerName [in]
Pointer to a null-terminated string that contains the host name of an HTTP server. Alternately, the string can contain the IP address of the site in ASCII, for example, 10.0.1.45.

However the string you provide contains a URL, which is not valid. You need to change "https://pages.awscloud.com/awsomedayonlineconference-reg.html" to "pages.awscloud.com", and then provide the path to the page as parameter in WinHttpOpenRequest:

hRequest = WinHttpOpenRequest(hConnect, protocol.c_str(), path.c_str(), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);

where path is a string containing "/awsomedayonlineconference-reg.html".

You could split your URL into parts for this, or change your httpConnect method to get servername and path as separate parameters.

Max Vollmer
  • 8,412
  • 9
  • 28
  • 43