Overview

You can solve issues encountered when using the HTTP protocol by applying the principles in this article.  By simplifying the issue into a small reproducible problem you can effectively troubleshoot and resolve most problems encountered in code that uses the HTTP protocol.  Crucial steps to troubleshooting code are: Gather Information, Simplify the Problem and Detailed Troubleshooting.

Technologies Covered

WinHttp, WinInet, Internet Explorer, XMLHTTP (MSXML), ServerXMLHTTP, System.Net classes such as WebClient, HttpWebRequest, SOAP classes, WebServices, System.Xml classes such as XmlUrlResolver, SoapHttpClientProtocol.

 

Error Messages Encountered (so search will find this document)

The operation timed out, 80072EE2, -2147954402, ERROR_WINHTTP_TIMEOUT, ERROR_WINHTTP_INVALID_SERVER_RESPONSE, The server name or address could not be resolved, 0x80072EE7, -2147012889, ERROR_WINHTTP_NAME_NOT_RESOLVED, 0x80072EFD

-2147012867, A connection with the server could not be established, -2146697208 (800c0008), The download of the specified resource has failed, Cannot connect to Remote server, Access is Denied, System error: -2146697191, 401, 500, 407, Server refused connection, Http protocol violation, Unauthorized, Cannot find server.

 

Step 1.  Gather Information

You may solve the issue or get close to the root cause quickly by gathering information about the problem.  Then you can continue to the Simplify the Problem section of this document to further isolate the issue and determine where the problem is occurring. Do this only after Gathering the information listed below. 

 

1.       What HTTP Verb are you using (EX: GET, POST, PUT)?

2.       What is the destination URL?

3.       Did this ever work? What changed if it did work previously (moved to production server, applied Service pack or Anti Virus update)?

4.       What technology are you using to reach the URL that fails?

5.       Can you reach the destination URL with another Technology such as Internet Explorer, other Browser, scripted Http Components, a simple console application?

6.       Can you reach ANY URL from the computer (Perhaps DNS is not set, ports blocked, or you need a proxy setting)?

7.       What is the failure (exact error message)?

8.       What is the call stack of the failure?

9.       Is this a Desktop or service based application (ASP and ASP.NET is a service)?

10.   Are you running with the latest Service Packs and fixes etc…(Go to Windows Update)?

 

Step 2. Simplify the Problem

 

Armed with the answers from Step 1, reproduce the problem with the simplest code possible.   In the process of simplifying the issue you may discover the issue is not in the technology you are using but a problem being obscured by your program’s logic or system configuration.  For example, In one case I assisted in, numerous troubleshooting actions had been taken in the ASP pages to determine what was going wrong.  When I was brought in to assist, I simply asked, “Can you hit the target URL in a Browser”?  The answer (“no”) instantly revealed to all of us that the issue was the DNS server setting on that machine and not the code.

 

How to simplify the issue:

 

1.       Duplicate the issue with a technology that is easier to troubleshoot such as the Web Browser or System.Net 2.0 which has the ability to log the HTTPS traffic.

2.       If the problem occurs with HTTPS, see if you can reproduce with HTTP as well then troubleshoot HTTP traffic instead of HTTPS traffic (which is securely encoded).  If you cannot duplicate the issue with HTTP then the problem may lie with your HTTPS configuration.

3.       If this is a service based application, such as ASP or ASP.NET, move the code out of the Service and test.  If it works, then the issue is not with the technology you are using.  The issue is how you have your service configured or the context it is running in.

4.       Try simple code from script or a command line application to see if that succeeds.  Then use that same simple code in your application and test.  If it fails in either case you have a much smaller problem to deal with.

5.       Simplify the code by executing the simplest possible HTTP call in a command line script or console application.  Start with using a HEAD or GET verb to a resource (perhaps an image or static file on the server) and add complexity until you get the failure.

 

Below are some code samples you can use to simplify the problem.  Simplify!  For example if your application is doing a POST verb, start with a GET verb to start your troubleshooting and then only if you cannot duplicate the issue using the GET verb, move to the POST verb.

 

VBScript samples:

 

Dim aRequest

Set aRequest = CreateObject ("Microsoft.XMLHTTP")

aRequest.Open "GET","http://www.microsoft.com/",False

aRequest.Send

Wscript.Echo aRequest.responseText

 

Dim aRequest

set aRequest = CreateObject("Msxml2.ServerXMLHTTP")

aRequest.Open "GET","http://www.microsoft.com/",False

aRequest.Send

Wscript.Echo aRequest.responseText

 

Dim aRequest

set aRequest = CreateObject("WinHttp.WinHttpRequest.5.1")

aRequest.Open "GET","http://www.microsoft.com/",False

aRequest.Send

Wscript.Echo aRequest.responseText

 

 

Dim aRequest

Set aRequest = CreateObject ("Microsoft.XMLHTTP")

aRequest.Open "POST"," http://www.contoso.com/PostAccepter.aspx",False

aRequest.setRequestHeader "Content-Type","application/x-www-form-urlencoded"

aRequest.Send "This is data"

Wscript.Echo aRequest.responseText

 

Dim aRequest

set aRequest = CreateObject("Msxml2.ServerXMLHTTP")

aRequest.Open "POST"," http://www.contoso.com/PostAccepter.aspx",False

aRequest.setRequestHeader "Content-Type","application/x-www-form-urlencoded"

aRequest.Send "This is data"

Wscript.Echo aRequest.responseText

 

Dim aRequest

set aRequest = CreateObject("WinHttp.WinHttpRequest.5.1")

aRequest.Open "POST"," http://www.contoso.com/PostAccepter.aspx",False

aRequest.setRequestHeader "Content-Type","application/x-www-form-urlencoded"

aRequest.Send "This is data"

Wscript.Echo aRequest.responseText

 

 

System.Net 2.0 console application samples:

 

using System;

using System.Net;

 

 

namespace HttpWebRequestConsole

{

 

    class Program

    {

 

        static void Main(string[] args)

        {

            HttpWebResponse aResponse = null;

            try

            {

 

                HttpWebRequest aRequest = WebRequest.Create("http://www.microsoft.com/") as HttpWebRequest;

 

                // if challenged with a 401, use current user's credentials       aRequest.UseDefaultCredentials = true;

 

                aResponse = aRequest.GetResponse() as HttpWebResponse;

 

                Console.WriteLine("Success. HttpStatus: {0}", aResponse.StatusCode);

 

            }

 

            catch (Exception theEx)

            {

                // TODO:  Notify end user of the issue... Perhaps a Dialog or some logging?

                Console.WriteLine(theEx.Message);

 

            }

            finally

            {

                if (aResponse != null)

                {

                    // if you don't close, you will leak connections!

                    aResponse.Close();

                }

            }

 

            Console.ReadKey();

 

        }

 

    }

 

}

 

 

Simple .NET Post example:

http://msdn2.microsoft.com/en-us/library/debx8sh9.aspx

 

ASP samples (use only after trying simpler cases above – and simply embed the VBScript from above samples)

 

ASPX samples (use only after trying simpler cases above - and the .NET 2.0 console app sample):

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

   

    void GreetingBtn_Click(Object sender,

                           EventArgs e)

    {

        // When the button is clicked,

        // change the button text, and disable it.

 

        Button clickedButton = (Button)sender;

        clickedButton.Text = "...button clicked...";

        clickedButton.Enabled = false;

       

        // Display the greeting label text.

        GreetingLabel.Visible = true;

 

        try

        {

            System.Net.WebClient aClient = new System.Net.WebClient();

      //proxy server if needed can be set here! aClient.Proxy = new System.Net.WebProxy("http://mycorpproxy:80" , true);

//bypass proxy for local address = true

            GreetingLabel.Text = aClient.DownloadString("http://www.microsoft.com/");

 

        }

        catch (Exception theEx)

        {

            GreetingLabel.Text = theEx.Message;

        }

    }

 

</script>

 

<html>

<head id="Head1" runat="server">

    <title>Untitled Page</title>

</head>

<body>

    <form id="form1" runat="server">

    <div>

      <h3>Simple Button Example</h3>

    

      <asp:Button id="Button1"

           Text="Click here for greeting..."

           OnClick="GreetingBtn_Click"

           runat="server"/>

      <br />

      <br />

      <asp:Label ID="GreetingLabel" runat="server"

                 Visible="false" Text="Hello World!" />

    </div>

    </form>

</body>

</html>

 

 

Step 3. Detailed Troubleshooting

 

DO NOT troubleshoot until you simplify the problem.  Get the problem isolated first to the simplest possible reproduction of the problem (following Step 2) and then proceed to this step.  For example: If you are having trouble hitting a WebService from ASP.NET and can reproduce the issue with a simple command line application written in .NET, you will be able to troubleshoot this much easier.

 

Volumes of material could be written on this subject.  This document will not give you detailed troubleshooting steps but simply ideas to get you started.

 

Search

Many times after you have simplified the issue, you can search MSDN and use http://Search.Live.Com to find the issue and solution to your particular situation.

 

Compare

In almost every case you can gather data of a successful HTTP request and compare it to the failed case.  From this you can see what the difference is between the successful and failed request and correct the issue.  The problem may be missing or incorrect headers, data or authorization.

 

Two useful tools for gathering HTTP traffic are ‘Network Monitor’ and ‘Fiddler’.  ‘Fiddler’ has the advantage of being able to execute requests you can construct yourself, the ability to see HTTPS traffic using a ‘man in the middle’ approach and will detect HTTP Protocol violations that the .NET classes will report as WebExceptions.  ‘Network Monitor’ has the advantage of showing you not only the HTTP traffic but the underlying TCP transport traffic.  This makes it a useful tool when the issue is the transport (TCP) instead of the protocol (HTTP).

 

Both tools have excellent help documentation built into them.  Familiarize yourself with these help files and practice capturing data with them.

 

Use Logging

Another useful tool is logging.  WinInet and WinHttp as well as the System.Net based technologies have the ability to generate logs.  Often these logs will help you find problems and see exactly what is happening internally.

 

WinHttp logging (also used by ServerXMLHttp): http://msdn2.microsoft.com/en-us/library/aa384119(VS.85).aspx  Vista and Above use netsh: http://msdn2.microsoft.com/en-us/library/bb648687.aspx

 

WinInet logging (also used by XMLHTTP): http://support.microsoft.com/kb/884931 

WinInet logging in Vista: http://blogs.msdn.com/wndp/archive/2006/03/28/wininet-etw-tracing-support-in-windows-vista.aspx

 

System.Net logging:  http://msdn2.microsoft.com/en-us/library/ty48b824(VS.80).aspx

 

See what is happening at the Protocol level

Using Fiddler or Netmon, see if the server is responding.  If it is, what is the HTTP Status code?  A 407 means the Proxy needs credentials for authorization.  Make sure you are sending those credentials after the 407 comes back.  Similarly ensure your application responds to Server Authentication requests (HTTP Status Code 401).  If the server is responding 500 series of status codes, then the issue is on the server side.  Are you sending the correct data to the server?  Does the server work for the same exact query from different clients?  If not then the server programmer needs to resolve the issue.

Capture traffic on the client and server to see if anything is altering or delaying the traffic between the two.

 

Sporadic problems

These are the most difficult to narrow down and a detailed discussion of this could fill a book (or website).  Many times the issue is a resource issue on the client or server.  You need to isolate the issue if possible to a simple repro at the time of failure.  You can try getting trapping 1st chance WebExceptions if using .NET or a .NET log to see what is happening.  Logging and network traces will be your best bet to solve most of these issues.  In the ASP.NET case, you may have to get a manual dump of the w3wp.exe process and engage Microsoft support for assistance.

 

Perfmon counters may show you what is going on as well.  Ultimately you may have to get a Debug Dump and engage Microsoft Support if you cannot isolate the issue yourself.  When the problem occurs you can use DebugDiagnostics to get a couple of hang dumps and then analyze these dumps with that same tool and it will often suggest what the issue is and how to fix it.

 

Other troubleshooting hints:

 

Test the possibility of the Network causing the issue by putting the client and server on the same box.  If the problem goes away, then you may have an issue with the Network or network devices.

 

Temporarily Eliminate load balancing and access a particular server directly so that you can determine if the load balancer is a factor and allow you to monitor a particular server while troubleshooting.

 

Does the request look exactly the same as it left the client when it gets to the server?  Use  Netmon  to determine this.  It is possible that a Network device is altering packets in transit.

 

Can any other client machine make the same request successfully?  It must be a configuration issue on the problem machine if other clients can get there.

 

Is the problem only Http or Https traffic?  Https problems may be certificate related.  Ensure client certificate is installed in the Local Machine store for ASP/ASP.NET apps (see link below "How to call a Web service by using a client certificate for authentication in an ASP.NET Web application") or current user store for non service based apps if required.  Ensure the certificate chain is trusted by viewing the certificate chain in Internet Explorer.

 

Does the request leave the box?  Use Netmon or Fiddler or tracing to determine this.  AntiVirus or firewall applications are suspect so temporarily disable them.

 

Does any response come back from the server?  Use Netmon or Fiddler or tracing to determine this.  Perhaps the server is not responding due to server errors.  Inspect server logs and WebService logs.

 

Some issues I have encountered:

 

Not able to reach URL even with simplified code using different technologies. DNS or Proxy issues on network or on that particular machine could be the cause.  Try a different machine to confirm or narrow this down

 

Can reach URL with one Technology but not another:  Common issues are:  Authorization not done correctly, Proxy settings, Firewall settings, or Antivirus is blocking the outgoing call.  Compare successful vs. failed cases to see what is happening.

 

If you can reach that URL and successfully retrieve data using one technology but not another, then determine:

·         Does the HTTP traffic in both cases look the same?

·         Does the time for the response differ from one client to another?

·         Use various tools to determine the above to include; logging, Netmon 3.2, Fiddler, Simultaneous Netmon traces on client and target machines.  Fiddler can be configured to see the HTTPS traffic as clear text if it is an HTTPS only problem.

·         AntiVirus and Firewall programs can block the traffic and do this differently per process.  Test by turning them off.

 

Sometimes you will see a 401 response in ASP.NET application and not in console app with same code.  The issue commonly is that the credentials passed by default are obtained from the security context that the program was running in and ASP.NET was not using the logged on credentials (search ASP.NET impersonation on MSDN).

 

Helpful Links:

Common ASP.NET issues related to http calls are usually resolved by following this article:  http://support.microsoft.com/?id=821268

Fiddler Web Debugging Proxy - http://www.fiddler2.com/fiddler2/

Current Netmon 3.1 http://www.microsoft.com/downloads/details.aspx?FamilyID=18b1d59d-f4d8-4213-8d17-2f6dde7d7aac&DisplayLang=en

Troubleshooting HTTP 401 errors in IIS - http://support.microsoft.com/kb/907273

Troubleshooting ASP.NET  - http://support.microsoft.com/kb/891032

Troubleshooting common permissions and security-related issues in ASP.NET - http://support.microsoft.com/kb/910449

Troubleshoot Forms Authentication - http://support.microsoft.com/kb/910439

How to call a Web service by using a client certificate for authentication in an ASP.NET Web application http://support.microsoft.com/kb/901183

 

Supplemental info

Network monitor hints:

 

How to get the IP addresses of the client and the server

                a)  ipconfig /all on the client > client.txt

                b)  ipconfig /all on the server > server.txt

 

You can apply a filter to Netmon and see only Http traffic between the client and server (use ip addresses from above hint)

192.168.1.1 //server

AND

192.168.2.2. //client

AND

HTTP  //our target protocol