Returning error codes using HttpListener

Sep 5, 2008 at 9:54 AM
Hi,

I couldn't find any examples that describes how to respond with an error using HttpListener. I tried the following

client.Respond(HttpHelper.HTTP11, HttpStatusCode.NotFound, request.Uri.AbsoluteUri);

The browser receives nothing. If I add a body as the fourth parameter, the body is returned as usually, but no error.

Am I doing this the right way?

Coordinator
Sep 8, 2008 at 7:34 AM
This sounds very strange, since this is the code for Respond:

        /// <summary>
        /// Send a response.
        /// </summary>
        /// <param name="httpVersion">Either HttpHelper.HTTP10 or HttpHelper.HTTP11</param>
        /// <param name="statusCode">http status code</param>
        /// <param name="reason">reason for the status code.</param>
        /// <param name="body">html body contents, can be null or empty.</param>
        /// <exception cref="ArgumentException">If httpVersion is invalid.</exception>
        public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body)
        {
            if (string.IsNullOrEmpty(httpVersion) || !httpVersion.StartsWith("HTTP/1"))
                throw new ArgumentException("Invalid HTTP version");

            byte[] buffer;
            if (string.IsNullOrEmpty(body))
                buffer = Encoding.ASCII.GetBytes(httpVersion + " " + (int) statusCode + " " + reason + "\r\n\r\n");
            else
            {
                buffer =
                    Encoding.ASCII.GetBytes(
                        string.Format("{0} {1} {2}\r\nContent-Type: text/html\r\nContent-Length: {3}\r\n\r\n{4}",
                                      httpVersion, (int) statusCode, reason ?? statusCode.ToString(), body.Length, body));
            }

            Send(buffer);
        }

The last parameter should not be an uri (request.Uri.AbsoluteUri), but a status message telling the client why the request failed.
Sep 8, 2008 at 9:32 AM
The code looks ok, but Firefox or IE7 don't get the response, they just wait until timeout. I tried wget, and it works just fine. Could the message get stuck somewhere on the way. A missing flush or close perhaps? Maybe the browsers expect something more before they consider the response to be complete?

Regarding the third parameter, I thought it would be informative to send the uri back to the user in a NotFound error. But now I see that request.Uri.toString() == "http://localhost/" for "wget http://localhost:11111/123". Shouldn't they be the same?

Sep 8, 2008 at 12:16 PM
Edited Sep 8, 2008 at 12:21 PM
I tried curl as well, and this is the verbose output.

>c:\cygwin\bin\curl.exe -v http://localhost:11111/123

* About to connect() to localhost port 11111 (#0)
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 11111 (#0)
> GET /123 HTTP/1.1
> User-Agent: curl/7.16.3 (i686-pc-cygwin) libcurl/7.16.3 OpenSSL/0.9.8h zlib/1.
2.3 libssh2/0.15-CVS
> Host: localhost:11111
> Accept: */*
>
< HTTP/1.1 404 http://localhost/
<
* Connection #0 to host localhost left intact
* Closing connection #0

>c:\cygwin\bin\curl.exe -v http://localhost:11111/test/123

* About to connect() to localhost port 11111 (#0)
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 11111 (#0)
> GET /test/123 HTTP/1.1
> User-Agent: curl/7.16.3 (i686-pc-cygwin) libcurl/7.16.3 OpenSSL/0.9.8h zlib/1.
2.3 libssh2/0.15-CVS
> Host: localhost:11111
> Accept: */*
>
< HTTP/1.1 404 http://localhost:11111/test/123
<
* Connection #0 to host localhost left intact
* Closing connection #0

request.Uri seems to be wrong in the first case.

Coordinator
Sep 8, 2008 at 12:25 PM
Edited Sep 8, 2008 at 12:33 PM
Add this as a bug in the issue tracker.
Sep 9, 2008 at 8:03 PM
When I use the HttpResponse class, the error messages are properly received by Firefox and IE. I suggest you rewrite HttpClientContextImp to use an internal HttpResponse instance, and you will get rid of the code duplication as you fix the bug.