MrHu
MrHu

Reputation: 37

WinHttpCrackUrl function gets wrong nScheme

After running the above code, the output result is not https, but Other(2).

Why does this happen?

The execution environment is Windows 10 (64-bit). The code is compiled as C++14.

#include <windows.h>
#include <WinInet.h>
#include <winhttp.h>
#include <iostream>
#include <string>

#pragma comment(lib, "wininet.lib")
#pragma comment(lib, "Winhttp.lib")

int main() {
    std::wstring gitHubApiUrl = L"https://api.github.com";

    URL_COMPONENTSW urlComponents = {};
    urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);

    // Buffers for host and path
    wchar_t hostName[256] = {};
    wchar_t urlPath[1024] = {};
    urlComponents.lpszHostName = hostName;
    urlComponents.dwHostNameLength = ARRAYSIZE(hostName);
    urlComponents.lpszUrlPath = urlPath;
    urlComponents.dwUrlPathLength = ARRAYSIZE(urlPath);

    // Call WinHttpCrackUrl
    if (!WinHttpCrackUrl(gitHubApiUrl.c_str(), static_cast<DWORD>(gitHubApiUrl.size()), 0, &urlComponents)) {
        std::wcerr << L"Failed to parse URL. Error: " << GetLastError() << std::endl;
        return 0;
    }

    // Output parsed components
    std::wcout << L"Scheme: ";
    switch (urlComponents.nScheme) {
    case INTERNET_SCHEME_HTTP: std::wcout << L"HTTP"; break;
    case INTERNET_SCHEME_HTTPS: std::wcout << L"HTTPS"; break;
    default: std::wcout << L"Other (" << urlComponents.nScheme << L")"; break;
    }
    std::wcout << std::endl;

    std::wcout << L"Host Name: " << urlComponents.lpszHostName << std::endl;
    std::wcout << L"URL Path: " << urlComponents.lpszUrlPath << std::endl;
    return 0;
}

Upvotes: 0

Views: 91

Answers (2)

MrHu
MrHu

Reputation: 37

I found the reason, the reason for this problem is so weird. When #include <WinInet.h> is above #include <winhttp.h>, Other(2) will be output.

Otherwise, if #include <winhttp.h> is above #include <WinInet.h>, https will be output normally, because the INTERNET_SCHEME enumeration is defined in both header files.

Code:

#include <windows.h>
#include <WinInet.h>
#include <winhttp.h>
#include <iostream>
#include <string>

#pragma comment(lib, "wininet.lib")
#pragma comment(lib, "Winhttp.lib")

int main() {
    std::wstring gitHubApiUrl = L"https://api.github.com";

    URL_COMPONENTSW urlComponents = {};
    urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);

    // Buffers for host and path
    wchar_t hostName[256] = {};
    wchar_t urlPath[1024] = {};
    urlComponents.lpszHostName = hostName;
    urlComponents.dwHostNameLength = ARRAYSIZE(hostName);
    urlComponents.lpszUrlPath = urlPath;
    urlComponents.dwUrlPathLength = ARRAYSIZE(urlPath);

    // Call WinHttpCrackUrl
    if (!WinHttpCrackUrl(gitHubApiUrl.c_str(), static_cast<DWORD>(gitHubApiUrl.size()), 0, &urlComponents)) {
        std::wcerr << L"Failed to parse URL. Error: " << GetLastError() << std::endl;
        return 0;
    }

    // Output parsed components
    std::wcout << L"Scheme: ";
    switch (urlComponents.nScheme) {
      case INTERNET_SCHEME_HTTP: std::wcout << L"HTTP"; break;
      case INTERNET_SCHEME_HTTPS: std::wcout << L"HTTPS"; break;
      default: std::wcout << L"Other (" << urlComponents.nScheme << L")"; break;
    }
    std::wcout << std::endl;

    std::wcout << L"Host Name: " << urlComponents.lpszHostName << std::endl;
    std::wcout << L"URL Path: " << urlComponents.lpszUrlPath << std::endl;
    return 0;
}

Upvotes: -1

Simon Mourier
Simon Mourier

Reputation: 138950

INTERNET_SCHEME_HTTPS value is in fact 2 as defined in winhttp.h.

Your code is probably using wininet.h value which is 4.

Make sure you don't mix both, both WinINet and WinHTTP serve the same purpose but are quite different: WinINet vs. WinHTTP

Upvotes: 5

Related Questions