3

I have some code (its actually for sending SMS messages via a web interface, but that's not relevant). The code works fine in the absence of a proxy server, but one customer wants to use this configuration. I've been testing with our proxy, but can't get it working. When slogging through the help, I found MSKB article 195650 (How To Handle Proxy Authorization with WinInet), which contains this pearl of wisdom:

There are several ways to handle HTTP_STATUS_PROXY_AUTH_REQ without
displaying a user interface. By far the easiest way to do this is by 
using the InternetSetOption function with the flags
INTERNET_OPTION_PROXY_PASSWORD and INTERNET_OPTION_PROXY_USERNAME...

...The same functionality can be accomplished in an MFC application 
by detecting HTTP_STATUS_PROXY_AUTH_REQ, calling 
CHttpConnection::SetOption, then re-calling CHttpFile::SendRequest. 

So I implemented this solution in my code, detecting the 407 error from a proxy requiring authentication, and then supplying the basic authentication via SetOption calls:

     if (AfxParseURL (m_csServerUrl, dwServiceType, csServerName, csObjectName, nPort))
     {
        CString csProxy = m_pOwner->GetProxyServerSetting();
        if (csProxy.GetLength() > 0)
        {
           pSession  = new CMyInternetSession (TEXT("SmGen"),
                                               1,
                                               INTERNET_OPEN_TYPE_PROXY,
                                               csProxy,
                                               NULL,
                                               INTERNET_FLAG_KEEP_CONNECTION);
        }
        else
        {
           pSession  = new CMyInternetSession (TEXT("SmGen"),
                                               1,
                                               INTERNET_OPEN_TYPE_PRECONFIG,
                                               NULL,
                                               NULL,
                                               0);
        }
        if (pSession)
        {
           pSession->SetOwnerDialog (m_pOwner);
           pHttpConn = pSession->GetHttpConnection (csServerName, (INTERNET_PORT)nPort, NULL, NULL);

           if (pHttpConn)
           {
              dwFlags = INTERNET_FLAG_RELOAD | 
                        INTERNET_FLAG_DONT_CACHE;    
              pHttpFile = pHttpConn->OpenRequest (CHttpConnection::HTTP_VERB_GET, 
                                                  csObjectName + TEXT("?") + csHTTP,
                                                  NULL,
                                                  1,
                                                  NULL,
                                                  NULL, 
                                                  dwFlags);
              if (pHttpFile)
              {
                 pHttpFile->AddRequestHeaders (csHeaders);

                 if (pHttpFile->SendRequest ())
                 {
                    pHttpFile->QueryInfoStatusCode (dwResult);
                    bRetryWithAuth = FALSE;

                    switch (dwResult)
                    {
                       case HTTP_STATUS_OK:
                          // log success
                          break;

                       case HTTP_STATUS_PROXY_AUTH_REQ:
                          bRetryWithAuth = TRUE;
                          break;

                       default:
                          // log failure
                          break;
                    }

                    if (bRetryWithAuth)
                    {
                       csProxyUsr = m_pOwner->GetProxyUsername();
                       csProxyPwd = m_pOwner->GetProxyPassword();

                       pHttpConn->SetOption (INTERNET_OPTION_PROXY_USERNAME,
                                             csProxyUsr.GetBuffer(1),
                                             csProxyUsr.GetLength());
                       csProxyUsr.ReleaseBuffer();

                       pHttpConn->SetOption (INTERNET_OPTION_PROXY_PASSWORD,
                                             csProxyPwd.GetBuffer(1),
                                             csProxyPwd.GetLength());
                       csProxyPwd.ReleaseBuffer();

                       if (pHttpFile->SendRequest ())
                       {
                          // ... TIMEOUT

Now for the problem. The issue is that the second SendRequest doesn't fail or throw another error, it just times out. After a little while I get CInternetException 12002 (timeout) thrown via my wrapper handler. This is a little annoying. Needless to say, the SMS never arrives.

The proxy server address is of the form a.b.c.d:8080 to eliminate DNS as a causative factor. My MIS department assures me that the username and password I'm supplying are valid (if I pass a bad uid/pwd it simply reverts to a 407 error, so I know they're getting to the proxy, at least).

I've been through everything I can find both on here and online, and I'm getting nowhere. Simply using INTERNET_OPEN_TYPE_PRECONFIG and hoping that the system will fetch everything it needs automagically doesn't work if all you have is a proxy, sadly.

Remember, there's nothing wrong with the non-proxy-related functionality of the code, because if I eliminate the proxy by wiping the registry entry that supplies the server ip:port, it all leaps into life again.

I'm completely stumped. Has anyone seen this before? I'm not hopeful, given the number of queries about proxy authentication with no replies...

Edit:

I've converted this code to use WinHttp, since there is an MS sample which covers proxy (with authentication), and WinInet is deprecated anyway. All works fine now.

Bob Moore
  • 6,788
  • 3
  • 29
  • 42
  • If you know you're getting to the proxy ... maybe snooping around with Wireshark would yield some useful info? Or maybe Fiddler? – dgnorton Jul 28 '11 at 18:12

1 Answers1

-1

Usually a HTTP connection is closed after the client received a response. So by the time you send your second request with auth details the proxy will have closed the connection (or at least stopped receiving).

So you'll have to call OpenRequest again to establish a new connection.

pezcode
  • 5,490
  • 2
  • 24
  • 37
  • That contradicts MSDN docs which say I only have to resend, but it's easy enough to try, so I'll give it a go tomorrow morning and report back. – Bob Moore Jul 31 '11 at 21:00
  • The HTTP connection is _not_ closed upon receiving a response. That would make web communication a lot slower if it were true. – Tim Cooper Dec 16 '11 at 01:57