0

This HttpHandler does not send a response if con.Open() throws an exception, for example if faultyConnectionString has an invalid database name. Why?

public void ProcessRequest(HttpContext context)
{
    int status = 400;
    string message = "Test error!";
    string faultyConnectionString = "Data Source=LOCALHOST\\SQLEXPRESS;Initial Catalog=XXX;User ID=XXX;Password=XXX";
    try
    {
        using (SqlConnection con = new SqlConnection(faultyConnectionString))
        {
            //throw new Exception("This works as expected, and is returned to client");
            con.Open();
        }
    }
    catch (Exception ex)
    {
        status = 500;
        message = "Test Exception: " + ex.Message;
    }

    context.Response.StatusCode = status;
    context.Response.StatusDescription = message;
}

Here is how I am handling the call in the client:

function GetContacts() {
  $.ajax({
    type: "POST",
    url: "xxx.ashx",
    data: "",
    contentType: "application/x-www-form-urlencoded; charset=utf-8",
    dataType: "text", // "json",
    success: function (response, a, b) {
        alert(response.status + " " + response.statusText);
    },
    error: function (response, a, b) {
        alert(response.status + " " + response.statusText);
    }
  });
}

If I F12 in FireFox it shows me that there is no Response received after the request is sent. In IE it shows me "SCRIPT7002: XMLHttpRequest: Network Error 0x2ef3, Could not complete the operation due to error 00002ef3.". In both cases the jquery ajax call returns status=0 and statusText="error".

If I comment out the two lines inside the catch block then it works as expected, sending the 403 code to the client and ignoring the exception.

Different types of exceptions do not have the same problem. If I throw a new Exception() before con.Open() then it also works as expected. What is different with SqlException?

UPDATE: The very first time I hit ProcessRequest it gets called 5 times in succession before the client shows the status=0 result (breakpoint on first line is hit 5 times).

FIDDLER: If I fire up Fiddler it (fiddler) intercepts the transaction and sends "504 Fiddler - Receive Failure" to my ajax call. Looks like the initial repetition may be a retry mechanism, when fiddler is active it does it 13 times. Fiddler reports: "Session #xxx raised exception System.Net.Sockets.SocketException An existing connection was forcibly closed by the remote host".

Etherman
  • 1,777
  • 1
  • 21
  • 34

1 Answers1

1

I believe the way your client (browser) handles 404 errors is what is causing this, and each browser type is handling the error differently. 404 errors are specific to "Not Found" so you may want to use a different error code such as a 500 error. More info on error codes is available here: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

Please keep in mind that passing back detailed error messages to a client could be a security issue due to information leakage. You may be better off passing back a generic error to the client and logging detailed error information on the server side.

Edit: Testing this locally, the way you are setting context.Response.StatusDescription to contain ex.Message is producing an invalid HTTP response. Try only placing text such as Internal Server Error in there. Additional details can be added to the body of the response using context.Response.Write(bodyText) but please keep the security implications of this in mind.

Andre Oporto
  • 1,236
  • 9
  • 8
  • I can put whatever codes I like in there, the problem is the server does not send anything back to the client if I have any code inside the catch block (presumably commenting out the code causes a subtle difference in the compiled code). – Etherman Mar 04 '15 at 21:30
  • What happens if you put 403 inside the catch block, and put 200 at the top in place of 403? You might want to examine the HTTP response when the catch block is used vs unused to see exactly what is being communicated by the server. In addition to F12 tools, Fiddler is also helpful for HTTP troubleshooting. – Andre Oporto Mar 04 '15 at 21:40
  • I have tried all combinations. Even if I put 200 in both places. The problem is after an SqlException there is no HTTP response, so there is nothing to inspect. If SqlConnection throws an ArgumentException on a bogus connection string then it works as expected. But as soon as the con.Open() throws an SqlException (e.g. non-existent DB name) then it fails. – Etherman Mar 04 '15 at 21:55
  • This may be due to the con.open statement being wrapped in a using statement which limits the scope/lifetime of the con object. This article may also help you: http://stackoverflow.com/questions/4495961/how-to-send-a-status-code-500-in-asp-net-and-still-write-to-the-response – Andre Oporto Mar 04 '15 at 22:16
  • I get the same results if I remove the "using" clause. I saw that article in my earlier googles, but I seem to be able to set the response code and custom message text just fine, which I pick up in the ajax call, its only after trying to catch a SqlException that it seems like maybe something kills the output stream and the client gets nothing at all. – Etherman Mar 05 '15 at 07:36
  • Please see my updated answer, I was able to reproduce this locally and address the issue by changing _StatusDescription_. – Andre Oporto Mar 05 '15 at 13:30
  • Ah dammit you're right! I'm tripping myself up with my own debug messages that I put in there for some other unrelated problem! – Etherman Mar 05 '15 at 17:59