Link to home
Start Free TrialLog in
Avatar of Rothmans
Rothmans

asked on

WebException thrown on a HttpWebRequest.GetResponse() call

Hi,

I have a problem using HttpWebRequest class.
I create an application, which communicates with a network device (not a PC), which has a built in HTTP 1.1 server listening on port 80. For some requests, which I send to the server it answers with a short byte sequence:

HTTP/1.1 200 OK\r\n

and that's it, no more data (I check network traffic using Ethereal network monitor).
In case of such response from the server, I get a WebException on a call to HttWebRequest.GetResponse() method saying: "The underlying connection was closed: An unexpected error occured on a receive". If there are some data coming from server, then GetResponse() method returns instance of HttpWebResponse properly.

here is a code, where I get a WebException:

HttpWebRequest hwr = (HttpWebRequest) WebRequest.Create(TargetUriString);
hwr.Timeout = 10000;
hwr.Method = "POST";
hwr.UserAgent = "AddressEditor";
hwr.ContentLength = buf.Length;
hwr.KeepAlive = true;
HttpWebResponse hwResponse = null;
Stream sr = null;
try
{
        // Write data
      Stream s = hwr.GetRequestStream();
      s.Write(buf,0,buf.Length);
      s.Close();
      // Read response
      hwResponse = (HttpWebResponse) hwr.GetResponse();     // WebException is thrown here !!!
      if(hwResponse.StatusCode == HttpStatusCode.OK)
      {
            if(hwr.HaveResponse)
            {
                  sr = hwResponse.GetResponseStream();
                  int offset=0;
                  int remaining = buf.Length;
                  while (remaining > 0)
                  {
                        int read = sr.Read(buf, offset, remaining);
                        if (read <= 0)
                              break;
                        remaining -= read;
                        offset += read;
                  }
            }
      }
}
catch(WebException we)
{
      Console.WriteLine(we.Message);
}
finally
{
      if(sr != null)
            sr.Close();
      if(hwResponse != null)
            hwResponse.Close();
}

Actually, I am not completely sure, whether the problem is im my code, .NET framework or device HTTP server, because exception occurs immediately after a call to GetResponse() and the device usually answers with "HTTP/1.1 200 OK\r\n" after a approximately 5 seconds timeout, because of processing of input data. So the GetResponse() does not wait for response and just throws exception. It does not happen with this code when the server returns some data.
Could you please give me a hint:
1) Am I correctly using HttpWebrequest to write data to the remote server?
2) How to make my code block and wait untill "HTTP/1.1 200 OK\r\n" response comes from the server? (The server becomes unavailable untill it processes all input data sent by me and I can not send next requests to it untill this one ends with 200 OK)

Thank you for any help, it is really apreciated.

Sergey
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Are you communicating with your own server, or someone else's?

Bob
Avatar of Rothmans
Rothmans

ASKER

The server in the device is written not by me and I have almost no information describing it's behaviour and no access to the code.

Sergey.
Well, it sounds like you are not forming the WebRequest correctly, and unless you can find the right format, then it will be virtually impossible to fix.

You did say that you are getting some requests back successfully.  What is different between the requests that succeed and the ones that fail?

Bob
Well, there are two entry points for me in the device HTTP server:
1) /cgi-bin/get.cgi
This script (?) returns data describing device settings
2) /cgi-bin/set.cgi
This script accepts settings (same as for get.cgi), which I (user) want to propagate to the device

Format of request to the first script is:
<method POST>
<HTTP Headers>
User-Agent: <user agent name>
Content-Length: <length of >
\r\n
<binary data defining settings, which I want to retireve>
<two trailing zeros>
Server response for this case is:
HTTP/1.1 200 OK\r\n
\r\n
<binary data describing device settings>
<two trailing zeros>

Format of request to the second script is:
<method POST>
<HTTP Headers>
User-Agent: <user agent name>
Content-Length: <length of >
\r\n
<binary data describing settings, which I want to set>
<two trailing zeros>
Server response for this case is:
HTTP/1.1 200 OK\r\n

I use the same code (see above) for both cases.
For the first case GetResponse() returns HttpResponse instance, from where I can get response binary data, properly, no exception is thrown.

For the second case settings ARE ACCEPTED by the device and ARE PROCESSED properly, but GetResponse throws mentioned above exception.

Of course, I could just ignore this exception, because I do not need actually response data, but...
I need to send several requests of second type to the device in order to complete my task.
It happens that the device processes input data several seconds and during this period device is unavailable. Any attempt to establish HTTP connection to it fails with HTTP server response "503 Service Unavailable". Therefore, I can not proceed with next requests.
That's why I acctually need to know when the device finishes accepting and processing input data (returning 200 OK Status Line), because otherwise next calls will fail and timeouts (how much time the device needs to process data) are undefined and may vary.

PS: It seems that "Expect: 100-Continue" mode is not supported by the device HTTP server.
After some reading HTTP RFC I came to one suspicion.
RFC says that in case when there is no data returned by the server the response should be "204 No Content".
Could it be that GetResponse waits for a data because "200 OK" response acquired and for the second described scenario "200 OK" is not the right answer because there are no data following this response?
ASKER CERTIFIED SOLUTION
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
That would be a solution if I would not need to make several requests one after another.
If I put WebRequest into try&catch block, then the next request will fail because device is busy.

Sergey
I mean something like this:

HttpWebRequest hwr = (HttpWebRequest) WebRequest.Create(TargetUriString);
hwr.Timeout = 10000;
hwr.Method = "POST";
hwr.UserAgent = "AddressEditor";
hwr.ContentLength = buf.Length;
hwr.KeepAlive = true;
HttpWebResponse hwResponse = null;
Stream sr = null;
try
{
        // Write data
     Stream s = hwr.GetRequestStream();
     s.Write(buf,0,buf.Length);
     s.Close();
     // Read response

    try {
         hwResponse = (HttpWebResponse) hwr.GetResponse();     // WebException is thrown here !!!
    }
    catch {}

     if(hwResponse.StatusCode == HttpStatusCode.OK)
     {
          if(hwr.HaveResponse)
          {
               sr = hwResponse.GetResponseStream();
               int offset=0;
               int remaining = buf.Length;
               while (remaining > 0)
               {
                    int read = sr.Read(buf, offset, remaining);
                    if (read <= 0)
                         break;
                    remaining -= read;
                    offset += read;
               }
          }
     }
}
catch(WebException we)
{
     Console.WriteLine(we.Message);
}
finally
{
     if(sr != null)
          sr.Close();
     if(hwResponse != null)
          hwResponse.Close();
}


Bob
Anyway thank you for a hint.
I try now to catch "503 Service Unavailable" response and repeat a request attempt in this case. Seems it is possible.

Sergey.
I succeeded to avoid the problem handling "503 Service Unavaible" response.
Thenk you, Bob, for your help.

Sergey.