Nurzhan Aitbayev
Nurzhan Aitbayev

Reputation: 807

How to make HTTPS calls (POST requests) using WinHTTP on C++?

I'm writing program on C++ to make calls (POST requests) to Java Servlets using WinHTTP. When I request POST via HTTP everything is OK, problem occurs when I request via HTTPS. It sends empty requests to the server but cuts off request body (but it has content)

int sendPostRequest(char *pszPostData, LPCTSTR servletUrl, char* resultBuffer, ofstream &outputFile) {

    outputFile << "====================================== SENDING REEQUEST ======================================" << endl;

    HINTERNET hSession = WinHttpOpen(
        userAgent,
        WINHTTP_ACCESS_TYPE_NO_PROXY,
        WINHTTP_NO_PROXY_NAME,
        WINHTTP_NO_PROXY_BYPASS,
        0);
    if (!hSession)
    {
        _tprintf(_TEXT("Failed to open WinHTTP session: %ld\n"), GetLastError());
        outputFile << "Failed to open WinHTTP session: %ld\n" << GetLastError() << endl;
        return NULL;
    }
    else {
        _tprintf(_TEXT("Oppening WinHTTP session successful: %ld\n"), GetLastError());
        outputFile << "Oppening WinHTTP session successful: %ld\n" << GetLastError() << endl;
    }

    HINTERNET hConnect = WinHttpConnect(
        hSession,
        serverIP,
        serverPort,
        0);
    if (!hConnect)
    {
        _tprintf(_TEXT("Failed to connect to server: %ld\n"), GetLastError());
        outputFile << "Failed to connect to server: %ld\n" << GetLastError() << endl;
        WinHttpCloseHandle(hSession);
        return NULL;
    }
    else {
        _tprintf(_TEXT("Connection to server successful: %ld\n"), GetLastError());
        outputFile << "Connection to server successful: %ld\n" << GetLastError() << endl;
    }

    _tprintf(_TEXT("Post data : %ld\n"), pszPostData);
    outputFile << "Post data : %ld\n" << pszPostData << endl;
    DWORD dwDataLen = strlen(pszPostData);

    HINTERNET hRequest = WinHttpOpenRequest(
        hConnect,
        _TEXT("POST"),
        servletUrl,
        NULL,
        WINHTTP_NO_REFERER,
        WINHTTP_DEFAULT_ACCEPT_TYPES,
        WINHTTP_FLAG_REFRESH);
    if (!hRequest)
    {
        _tprintf(_TEXT("Failed to open request: %ld\n"), GetLastError());
        outputFile << "Failed to open request: %ld\n" << GetLastError() << endl;
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return -1;
    }
    else {
        _tprintf(_TEXT("Opening request successful: %ld\n"), GetLastError());
        outputFile << "Opening request successful: %ld\n" << GetLastError() << endl;
    }

    DWORD dwReqOpts = 0;
    DWORD dwSize = sizeof(DWORD);
    WinHttpSetOption(
        hRequest,
        WINHTTP_OPTION_SECURITY_FLAGS,
        &dwReqOpts,
        sizeof(DWORD));

    BOOL done = false;
    BOOL rc = WinHttpSendRequest(
        hRequest,
        contentTypeHeader,
        -1,
        (LPVOID)pszPostData,
        dwDataLen,
        dwDataLen,
        NULL);

    if (rc) {
        rc = WinHttpReceiveResponse(hRequest, NULL);
        _tprintf(_TEXT("Sending request successful: %ld\n"), GetLastError());
        outputFile << "Sending request successful: %ld\n" << GetLastError() << endl;
    }
    else
    {
        _tprintf(_TEXT("Send request failed: %ld\n"), GetLastError());
        outputFile << "Send request failed: %ld\n" << GetLastError() << endl;
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return -1;
    }

    // Get the status from the server
    DWORD dwCode = 0;
    if (rc)
    {
        rc = WinHttpQueryHeaders(
            hRequest,
            WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
            NULL,
            &dwCode,
            &dwSize,
            NULL);
    }

    if (dwCode != HTTP_STATUS_OK)
    {
        _tprintf(_TEXT("HTTP Request failed: %ld\n"), dwCode);
        outputFile << "HTTP Request failed: %ld\n" << dwCode << endl;
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
    }
    else
    {
        _tprintf(_TEXT("HTTP Request is ok: %ld\n"), dwCode);
        outputFile << "HTTP Request is ok : %ld\n" << dwCode << endl;

        // Keep reading from the remote server until there's nothing left to read
        DWORD dwBytesToBeRead = 0, dwBytesRead = 0;
        //char szBuffer[8192] = { 0 };
        //strcpy(resultBuffer, "");
        do
        {
            if (!WinHttpQueryDataAvailable(hRequest, &dwBytesToBeRead))
            {
                _tprintf(_TEXT("No data available from server? %ld"), GetLastError());
                outputFile << "No data available from server? %ld" << GetLastError() << endl;

                WinHttpCloseHandle(hRequest);
                WinHttpCloseHandle(hConnect);
                WinHttpCloseHandle(hSession);
                return -1;
            }

            if (!WinHttpReadData(
                hRequest,

                //szBuffer,
                resultBuffer,

                //sizeof(szBuffer),
                RESULT_BUFFER_SIZE,

                &dwBytesRead))
            {
                _tprintf(_TEXT("Failed to read data from server: %ld"), GetLastError());
                outputFile << "Failed to read data from server: %ld" << GetLastError() << endl;

                WinHttpCloseHandle(hRequest);
                WinHttpCloseHandle(hConnect);
                WinHttpCloseHandle(hSession);
                return -1;
            }
            if (dwBytesRead > 0)
            {
                //szBuffer[dwBytesRead] = 0;
                resultBuffer[dwBytesRead] = 0; // NULL-terminated returned buffer
            }
        } while (dwBytesRead > 0);
        WinHttpCloseHandle(hRequest);
        WinHttpCloseHandle(hConnect);
        WinHttpCloseHandle(hSession);
        return 0;
    }
    return -1;
}

Where pszPostData - content of request body, servletUrl - url to Servlet (endpoint), resultBuffer - call result will be written to this buffer, outputFile - file for logs.

So how to make HTTPS calls without cutting of request body?

Upvotes: 3

Views: 8998

Answers (3)

JHag
JHag

Reputation: 1

Even if it is an old question, this might be helpful:
Add WINHTTP_FLAG_SECURE to the WinHttpOpenRequest, and it should work.

...
HINTERNET hRequest = WinHttpOpenRequest(
        hConnect,
        _TEXT("POST"),
        servletUrl,
        NULL,
        WINHTTP_NO_REFERER,
        WINHTTP_DEFAULT_ACCEPT_TYPES,
        WINHTTP_FLAG_REFRESH+WINHTTP_FLAG_SECURE); /// Here
...

Upvotes: 0

user756659
user756659

Reputation: 3512

I came across this today as I was facing a very similar issue. In WinHttpConnect() I was sending pswzServerName as 'example.com'. Problem is, in Apache, I was forcing a redirect on domain.com to www.domain.com and also http to https. This redirect was causing no POST data to be sent, wrong content-length header, and wrong content-type header because I had specified example.com in WinHttpConnect().

Two solutions worked with the last being the best choice :

Removing my htaccess non-www to www and http to https redirect

OR

just changing `pswzServerName` to 'www.example.com' (including the www.) in WinHttpConnect()

Spent a long time trying to figure out why winhttp wasn't working as this was easily overlooked so hopefully it helps someone else that might be in the same boat.

Upvotes: 0

OhadM
OhadM

Reputation: 4803

Regarding WinHttpSendRequest method, at the 2nd paramaet insert: L"content-type:application/x-www-form-urlencoded" and on the 3rd paramer -1 which is according to w3.

It should work with this correction.

Also, check the encoding of your .php file, gave me a trouble once.

Upvotes: 5

Related Questions