views:

228

answers:

2

Hi all,
I have a request that works fine when I use the WinInet API. I now want to make that request with the WinHTTP API as I already use it in my project and as it is simply better. My request is used for calling JSON. I already authenticated before calling this. When authenticating I get a SessionID that I send via cookie.
So here is my working WinInet code:

DWORD dwError;
HINTERNET hOpen = NULL, hReq = NULL;
hOpen = InternetOpen(_T(""), INTERNET_OPEN_TYPE_DIRECT, _T(""), _T(""), 0);
if(hOpen == NULL)
{
    dwError = GetLastError();
    return false;
}

CString cstrCookies = _T("Cookie: JSESSIONID=") + cstrSession;
CString cstr = _T("https://") + cstrServer + _T("/list/") + cstrFileOrFolder;
hReq = InternetOpenUrl(hOpen, cstr, cstrCookies, -1L,
    INTERNET_FLAG_SECURE | INTERNET_FLAG_NO_COOKIES, 0); // without NO_COOKIES I'll get a 401
if(hReq == NULL)
{
    dwError = GetLastError();
    InternetCloseHandle(hOpen);
    return false;
}

DWORD dwCode, dwCodeSize;
dwCodeSize = sizeof(DWORD);
if(!HttpQueryInfo(hReq, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwCode, &dwCodeSize, NULL))
{
    dwError = GetLastError();
    InternetCloseHandle(hReq);
    InternetCloseHandle(hOpen);
    return false;
}

InternetCloseHandle(hOpen);
InternetCloseHandle(hReq);
return dwCode == 200;

So I now want to do the same using the WinHTTP API. Here is what I have for the moment:

DWORD dwError = 0;
HINTERNET hConnect = NULL, hRequest = NULL;

hConnect = WinHttpConnect(m_hSession, cstrServer, INTERNET_DEFAULT_HTTPS_PORT, 0);
if (hConnect == NULL)
{
    return false;
}

hRequest = WinHttpOpenRequest(hConnect, NULL, cstrMethod + _T("/list/") + cstrFileOrFolder,
    NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
if (hRequest == NULL)
{
    WinHttpCloseHandle(hConnect);
    return false;
}

DWORD dwOptionValue = WINHTTP_DISABLE_COOKIES;
if (WinHttpSetOption(hRequest, WINHTTP_OPTION_DISABLE_FEATURE, &dwOptionValue,
    sizeof(dwOptionValue)) != TRUE)
{
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hRequest);
    return false;
}

const CString cstrHeaders = _T("Cookie: JSESSIONID=") + cstrSession;
if (WinHttpAddRequestHeaders(hRequest, cstrHeaders, cstrHeaders.GetLength(),
    WINHTTP_ADDREQ_FLAG_ADD) != TRUE)
{
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hRequest);
    return false;
}

if (WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, -1L, WINHTTP_NO_REQUEST_DATA, 0,
    0, 0) != TRUE)
{
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hRequest);
    return false;
}

if (WinHttpReceiveResponse(hRequest, NULL) != TRUE)
{
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hRequest);
    return false;
}

DWORD dwCode, dwCodeSize;
dwCodeSize = sizeof(DWORD);
if(!WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwCode, &dwCodeSize, NULL))
{
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hRequest);
    return false;
}

WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hRequest);
return dwCode == 200;

With that latter call I always receive a 401 but I should get a 200 like I do with the first method. I also found out that I get a 401 with the first call when I don't specify the INTERNET_FLAG_NO_COOKIES flag. So I suspect something with the cookie header is wrong. Do anyone see what I'm doing wrong? Or what is the difference between the two methods?
Thx...

A: 

Looks about right. If I were you I would hook up an HTTP debugging proxy, like Fiddler, and examine and compare the HTTP traffic for the two methods. That might point you to what you need to do.

Cheeso
I already tried that with Wireshark. Problem is that I do have HTTPS and not HTTP, so I cannot read much out of it.
Simon Linder
Fiddler can show you the HTTPS traffic, too. http://www.fiddlertool.com/Fiddler/help/httpsdecryption.asp
Cheeso
Ok, I tried Fiddler but I cannot see traffic from my application. I also tried to filter everything to my process. Sorry new to Fiddler... Any hints?
Simon Linder
Figured out that I can see the traffic when I use localhost as proxy, but then my code doesn't work at all, can't send request...
Simon Linder
A: 

Ok, I found it. Wasn't obvious from the code I posted...
The string cstrMethod contains a user id that I extracted previously from the response header from an authentication call. This id is then used for constructing the method call. Now problem was that the user id comes from a response header so it ends with \r\n. So the constructed method call also contains \r\n and as therefore the user id is wrong I get the 401.
So I had to trim the user id string from the header before I could use it for further calls.
Well it's a little bit odd that the WinInet call accepted the \r\n.

Simon Linder