I have an application which run 2 concurrent threads which call a code like
this:
InternetOpen( ... )
InternetOpenUrl("http://www......", ... )
while (...)
{
...
InternetReadFile( ... );
...
}
I pass these flags to InternetOpenUrl:
INTERNET_FLAG_NO_CACHE_WRITE
INTERNET_FLAG_RELOAD
INTERNET_FLAG_PRAGMA_NOCACHE
INTERNET_FLAG_KEEP_CONNECTION
INTERNET_FLAG_NO_AUTH
Since the URLs require authentication, in the lpszHeaders parameter of
InternetOpenUrl I pass a string like this:
"Authorization: Basic Xxxxxxxxxx\r\n\r\n" (login:password Base64-encoded)
Credentials are different in each thread but it seems that the server only
picks the first authentication for both
threads, so the first thread succeeds but the second one fails because of
bad authentication.
When credentials are the same for both threads this code works fine and both
threads succeed.
Is there something wrong in this? Are there any other flags required?
Your help would be very appreciated. Thank you.
--
Noël
ICQ# 81812737
http://noeld.com
//HINTERNET hOpen, hConnect;
DWORD WINAPI ThreadFunc( LPVOID lpParam )
{
HINTERNET hOpen, hConnect, hRequest;
char User[25];
char Pass[25];
cout << "Start thread" << GetCurrentThreadId() << endl;
if (*(DWORD*)lpParam == 0)
{
strcpy(User, "Bob");
strcpy(Pass, "Password1");
}
else
{
strcpy(User, "badname");
strcpy(Pass, "Password1");
} //end if
char szObject[100] = "";
if(!(hOpen = InternetOpen("Connection Limit Test",
INTERNET_OPEN_TYPE_PRECONFIG , NULL, NULL, 0)))
{
cout << GetLastError() << " InternetOpen error" << endl;
return 0;
}
if(!(hConnect = InternetConnect(hOpen,
"yourboxnamegoeshere",INTERNET_INVALID_PORT_NUMBER , User,Pass,
INTERNET_SERVICE_HTTP ,0,0)))
{
cout << GetLastError() << " InternetConnect error" << endl;
}
strcpy(szObject, "test/post.asp");
if(!(hRequest = HttpOpenRequest(hConnect, "GET", szObject , NULL, NULL,
NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0)))
{
cout << GetLastError() << " OpenRequest error" << endl;
return 1;
}
if(!HttpSendRequest(hRequest, NULL, 0, NULL, 0))
{
cout << GetLastError() << " SendRequest error" << endl;
}
// First time we will find out the size of the headers.
char *lpBuffer = NULL;
DWORD dwSize = 0;
HttpQueryInfo (hRequest,HTTP_QUERY_RAW_HEADERS_CRLF, NULL, &dwSize, NULL);
lpBuffer = new char [dwSize + 1 ];
// Now we call HttpQueryInfo again to get the headers.
if (!HttpQueryInfo (hRequest,HTTP_QUERY_RAW_HEADERS_CRLF, (LPVOID)
lpBuffer,
&dwSize, NULL))
{
cout <<"HttpQueryInfo" << GetLastError()<< endl;
return 0;
}
cout << lpBuffer << endl;
char buffer[1024] = "";
DWORD dwBufSize = 0;
if(!InternetReadFile(hRequest, buffer, 1024, &dwBufSize))
{
cout << GetLastError() << " ReadFile error" << endl;
}
cout << buffer << endl;
cout << "end thread" << GetCurrentThreadId() << endl;
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hOpen);
return 0;
}
void main()
{
DWORD dwConnections = 2;
DWORD dwSizeOfConnections = sizeof(DWORD);
DWORD dwThreadId, dwThrdParam[2];
HANDLE hThread[2];
int i ;
for(i = 0; i< 2; i++)
{
dwThrdParam[i] = i;
hThread[i] = CreateThread(
NULL, // no security attributes
0, // use default stack size
ThreadFunc, // thread function
&dwThrdParam[i], // argument to thread function
0, // use default creation flags
&dwThreadId); // returns the thread identifier
// Check the return value for success.
Sleep(500);
if (hThread[i] == NULL)
{
cout << "CreateThread failed. " << i << endl;
}
}
DWORD dwWait = WaitForMultipleObjects(10, hThread, TRUE, 60000);
for (i = 0; i < 2; i++)
{
CloseHandle( hThread[i] );
}
}
Thanks
Brian [MS]
Microsoft Developer Support
This posting is provided "AS IS" with no warranties, and confers no rights.
--------------------
| From: "Noël Danjou" <no...@noeld.com>
| Subject: InternetOpenUrl, threads and authentication
| Date: Thu, 24 Apr 2003 19:31:15 +0200
| Lines: 52
| X-Priority: 3
| X-MSMail-Priority: Normal
| X-Newsreader: Microsoft Outlook Express 6.00.2800.1158
| X-MIMEOLE: Produced By Microsoft MimeOLE V6.00.2800.1165
| Message-ID: <uP6mJeoC...@TK2MSFTNGP11.phx.gbl>
| Newsgroups: microsoft.public.inetsdk.programming.wininet
| NNTP-Posting-Host: mix-caen-111-4-124.abo.wanadoo.fr 80.9.119.124
| Path: cpmsftngxa06.phx.gbl!TK2MSFTNGP08.phx.gbl!TK2MSFTNGP11.phx.gbl
| Xref: cpmsftngxa06.phx.gbl
microsoft.public.inetsdk.programming.wininet:9865
| X-Tomcat-NG: microsoft.public.inetsdk.programming.wininet
Thank you very much for your tests.
I tried your code and it seems indeed to work even with two valid users.
I created a sample showuser.asp page which shows the logged user and with
your code both users are shown as expected.
But I think your code send the login and password in clear text while I have
to send a Basic Authentication header instead.
So I slightly modified your code to use InternetOpenUrl like in the code of
my application and the behavior is different, the first user is
authenticated correctly but for the second one, I always get 401 even if the
user and password are valid. Could you please explain this or tell me what's
wrong in my code?
I included both codes (wininet.cpp & showuser.asp) below.
Thank you.
--
Noël
ICQ# 81812737
http://noeld.com
WININET.CPP
// Auth.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#define USE_INTERNETOPENURL
#if defined(USE_INTERNETOPENURL)
#include <atlenc.h>
#endif
DWORD WINAPI ThreadFunc( LPVOID lpParam )
{
HINTERNET hOpen, hRequest;
#if !defined(USE_INTERNETOPENURL)
HINTERNET hConnect;
#endif
char User[25];
char Pass[25];
cout << "Start thread " << GetCurrentThreadId() << endl;
if (*(DWORD*)lpParam == 0)
{
strcpy(User, "user1");
strcpy(Pass, "Password1");
}
else
{
strcpy(User, "user2");
strcpy(Pass, "Password2");
} //end if
char szObject[100] = "";
if(!(hOpen = InternetOpen("Connection Limit Test",
INTERNET_OPEN_TYPE_PRECONFIG , NULL, NULL, 0)))
{
cout << GetLastError() << " InternetOpen error" << endl;
return 0;
}
#if defined(USE_INTERNETOPENURL)
char auth[80];
char encoded[80];
char header[255];
int nLen = sizeof(encoded);
strcpy(auth, User);
strcat(auth, ":");
strcat(auth, Pass);
Base64Encode((const BYTE *)auth, (int)strlen(auth), encoded, &nLen);
encoded[nLen] = 0;
strcpy(header, "Authorization: Basic ");
strcat(header, encoded);
strcat(header, "\r\n\r\n");
if (!(hRequest = InternetOpenUrl(hOpen, "http://192.168.0.4/showuser.asp",
header, (DWORD)strlen(header),
INTERNET_FLAG_NO_CACHE_WRITE |
INTERNET_FLAG_RELOAD |
INTERNET_FLAG_PRAGMA_NOCACHE |
INTERNET_FLAG_KEEP_CONNECTION |
INTERNET_FLAG_NO_COOKIES |
INTERNET_FLAG_NO_UI |
INTERNET_FLAG_NO_AUTH,
0)))
{
cout << GetLastError() << " InternetOpenUrl error" << endl;
return 0;
}
#else
if(!(hConnect = InternetConnect(hOpen,
// "yourboxnamegoeshere",INTERNET_INVALID_PORT_NUMBER , User,Pass,
"192.168.0.4",INTERNET_INVALID_PORT_NUMBER , User,Pass,
INTERNET_SERVICE_HTTP ,0,0)))
{
cout << GetLastError() << " InternetConnect error" << endl;
return 0;
}
// strcpy(szObject, "test/post.asp");
strcpy(szObject, "/showuser.asp");
if(!(hRequest = HttpOpenRequest(hConnect, "GET", szObject , NULL, NULL,
NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0)))
{
cout << GetLastError() << " OpenRequest error" << endl;
return 0;
}
if(!HttpSendRequest(hRequest, NULL, 0, NULL, 0))
{
cout << GetLastError() << " SendRequest error" << endl;
}
#endif
// First time we will find out the size of the headers.
char *lpBuffer = NULL;
DWORD dwSize = 0;
HttpQueryInfo (hRequest,HTTP_QUERY_RAW_HEADERS_CRLF, NULL, &dwSize, NULL);
lpBuffer = new char [dwSize + 1 ];
// Now we call HttpQueryInfo again to get the headers.
if (!HttpQueryInfo (hRequest,HTTP_QUERY_RAW_HEADERS_CRLF, (LPVOID)
lpBuffer,&dwSize, NULL))
{
cout << "HttpQueryInfo " << GetLastError()<< endl;
return 0;
}
cout << lpBuffer << endl;
char buffer[1024] = "";
DWORD dwBufSize = 0;
if(!InternetReadFile(hRequest, buffer, 1024, &dwBufSize))
{
cout << GetLastError() << " ReadFile error" << endl;
}
cout << buffer << endl;
cout << "end thread " << GetCurrentThreadId() << endl;
InternetCloseHandle(hRequest);
#if !defined(USE_INTERNETOPENURL)
InternetCloseHandle(hConnect);
#endif
InternetCloseHandle(hOpen);
return 0;
}
void main()
{
DWORD dwConnections = 2;
DWORD dwSizeOfConnections = sizeof(DWORD);
DWORD dwThreadId, dwThrdParam[2];
HANDLE hThread[2];
int i ;
for(i = 0; i< 2; i++)
{
dwThrdParam[i] = i;
hThread[i] = CreateThread(
NULL, // no security attributes
0, // use default stack size
ThreadFunc, // thread function
&dwThrdParam[i], // argument to thread function
0, // use default creation flags
&dwThreadId); // returns the thread identifier
// Check the return value for success.
Sleep(500);
if (hThread[i] == NULL)
{
cout << "CreateThread failed. " << i << endl;
}
}
DWORD dwWait = WaitForMultipleObjects(2, hThread, TRUE, 60000);
for (i = 0; i < 2; i++)
{
CloseHandle( hThread[i] );
}
cout << "done.";
}
SHOWUSER.ASP
<% @Language=JScript %>
<html>
<head>
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Show logged user</title>
</head>
<body>
The user is <%= Request.ServerVariables("LOGON_USER") %>.
</body>
</html>
If you want to see what is happening you should get a network trace to see
what the differences are. Remember InternetOpenURL has to wrap
InternetConnect, HttpOpenRequest and HttpSendRequest. So you lose some
control.
Thanks
Brian [MS]
Microsoft Developer Support
This posting is provided "AS IS" with no warranties, and confers no rights.
--------------------
| From: "Noël Danjou" <no...@noeld.com>
| References: <uP6mJeoC...@TK2MSFTNGP11.phx.gbl>
<Dtt1UXOE...@cpmsftngxa06.phx.gbl>
| Subject: Re: InternetOpenUrl, threads and authentication
| Date: Sat, 3 May 2003 19:17:14 +0200
| Lines: 347
| X-Priority: 3
| X-MSMail-Priority: Normal
| X-Newsreader: Microsoft Outlook Express 6.00.2800.1158
| X-MIMEOLE: Produced By Microsoft MimeOLE V6.00.2800.1165
| Message-ID: <exKz6fZE...@TK2MSFTNGP11.phx.gbl>
| Newsgroups: microsoft.public.inetsdk.programming.wininet
| NNTP-Posting-Host: mix-caen-104-3-101.abo.wanadoo.fr 193.249.228.101
| Path: cpmsftngxa06.phx.gbl!TK2MSFTNGP08.phx.gbl!TK2MSFTNGP11.phx.gbl
| Xref: cpmsftngxa06.phx.gbl
microsoft.public.inetsdk.programming.wininet:9884
| X-Tomcat-NG: microsoft.public.inetsdk.programming.wininet
I used a simple webserver implementation I made to try the authentication
support in WinInet and indeed it uses the Basic authentication header. But I
cannot use it in my case because two requests are sent for each request, a
first one unauthenticated and a second one authenticated. The owners of the
servers that I use require the first request to be (basic) authenticated to
limit bandwidth usage and lower their costs.
Sending my own Basic authentication header seems OK though. I identified one
of the problems I was having, the authentication fails only when there are
some accentuated letters in the user name.
I created some sample accounts without accentuated letters and I modified
the code to run 4 threads concurrently and this worked just fine.
Thanks for your support.
--
Noël
Thanks
Brian [MS]
Microsoft Developer Support
This posting is provided "AS IS" with no warranties, and confers no rights.
--------------------
| From: "Noël Danjou" <no...@noeld.com>
| References: <uP6mJeoC...@TK2MSFTNGP11.phx.gbl>
<Dtt1UXOE...@cpmsftngxa06.phx.gbl>
<exKz6fZE...@TK2MSFTNGP11.phx.gbl>
<GnSxiexE...@cpmsftngxa06.phx.gbl>
| Subject: Re: InternetOpenUrl, threads and authentication
| Date: Tue, 6 May 2003 17:17:52 +0200
| Lines: 21
| X-Priority: 3
| X-MSMail-Priority: Normal
| X-Newsreader: Microsoft Outlook Express 6.00.2800.1158
| X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1165
| Message-ID: <ef60Tn#EDHA...@TK2MSFTNGP10.phx.gbl>
| Newsgroups: microsoft.public.inetsdk.programming.wininet
| NNTP-Posting-Host: mix-caen-111-2-88.abo.wanadoo.fr 80.9.117.88
| Path: cpmsftngxa06.phx.gbl!TK2MSFTNGP08.phx.gbl!TK2MSFTNGP10.phx.gbl
| Xref: cpmsftngxa06.phx.gbl
microsoft.public.inetsdk.programming.wininet:9893
| X-Tomcat-NG: microsoft.public.inetsdk.programming.wininet