Archive for July 2012

HttpListener Series – 2 – Websiting   1 comment

The series index here.

One of the most common uses of IIS is to host websites through a file system folder where relative paths are used for resources. There isn’t much to it but some string prefix handling and some stream copying but I’ll provide a simple implementation of what it needs to be done to run a simple static website.

Let’s say we have a folder containing a website looking like this:

WebSiteFolder

The content of the files is as follows…

Page.htm:

<!DOCTYPE HTML>
<html>
<head>
    <title>HttpListener Demo HTML Page</title>
    <link rel="stylesheet" type="text/css" href="Files/Styles.css" />
</head>
<body>
    <p>
        Here is the HTML page.</p>
    <input type="button" id="aButton" value="Click to Run Script" />
</body>
</html>
<script type="text/javascript" src="Files/Scripts.js"></script>

Files/Styles.css:

p
{
    font-size: 20px;
    font-weight: bold;
}

input
{
    border: 2px solid blue;
    font-style: italic;
}

Files/Scripts.js:

document.getElementById("aButton").onclick = function () {
    alert("You clicked the button");
};

The implementation of this website hosting would be something like so:

string baseFolder = @"C:\WebSite\";

var listener = new HttpListener();
listener.Prefixes.Add("http://+/HLD/");

listener.Start();
Console.WriteLine("Listening ...");

while (true)
{
    var context = listener.GetContext();

    Console.WriteLine("Request received for: " + context.Request.Url.AbsoluteUri);

    var baseUrl = "http://+/HLD/".Replace("+", context.Request.Url.Authority);
    var resourceRelativePath = context.Request.Url.AbsoluteUri.Substring(baseUrl.Length);
    var resourceFullPath = Path.Combine(baseFolder, resourceRelativePath);

    if (File.Exists(resourceFullPath))
    {
        context.Response.StatusCode = 200;
        context.Response.StatusDescription = "OK";

        string contentType = "application/octet-stream"; // just to have a default
        switch (Path.GetExtension(resourceFullPath))
        {
            case ".htm":
                contentType = "text/html";
                break;
            case ".css":
                contentType = "text/css";
                break;
            case ".js":
                contentType = "application/x-javascript";
                break;
        }
        context.Response.ContentType = contentType;

        var fileStream = File.OpenRead(resourceFullPath);
        context.Response.ContentLength64 = fileStream.Length;
        fileStream.CopyTo(context.Response.OutputStream, 64*1024);
        fileStream.Close();
    }
    else
    {
        context.Response.StatusCode = 404;
        context.Response.StatusDescription = "Not Found";
        var writer = new StreamWriter(context.Response.OutputStream);
        writer.Write(string.Format("<!DOCTYPE HTML><html><head><title>Resource Not Found</title></head><body><b>Error 404 - Resource Not Found</b> - There resource ('{0}') requested was not found.</body></html>",
            resourceRelativePath));
        writer.Close();
    }

    context.Response.Close();
}

A little bit of string comparison and we’re all done. Now you can access “http://localhost/HLD/Page.htm”.

Notes:

  • The functionality of a default document can be easily be implemented by responding to an empty resourceRelativePath with a predefined document.
  • Response.ContentType must be set before beginning to send the resource stream, otherwise it will not be taken in account.
  • 64KB (64B * 1024) of buffering to copy the resource stream should be enough. Play with and find what it implies in the speed of the delivery and find your own buffer size.
Advertisements

Posted 2012/07/09 by Bigsby in Hands On

HttpListener Series – 1 – Get It Listening   1 comment

The series index here.

After getting a grip of what HTTP is, we can start playing with the HttpListener class that was presented to the world in .Net 2.0.

HttpListener, provides a wrapper that manages the socket and TCP levels of communication (streaming, buffering and so on) and reads and sets the protocol parameters, i.e, method, headers, status, content, etc..

So, if you want to start your own web server, HttpListener is the best way to start with. Let’s implement the example of the previous post in this series.

Starting a HttpListener couldn’t be simpler.

Instanciate it:

var listener = new HttpListener(); //instanciate it
listener.Prefixes.Add("http://+/HLD/"); //tell it what to listen to

listener.Start();  // start it
Console.WriteLine("Listening...");

while (true)
{
    var context = listener.GetContext();  // get the request

    Console.WriteLine("Request received for: " + context.Request.Url.AbsoluteUri);
   // answer the request
    context.Response.ContentType = "text/html";
    context.Response.StatusCode = 200;
    context.Response.StatusDescription = "OK";

    var writer = new StreamWriter(context.Response.OutputStream);
    writer.Write("<!DOCTYPE HTML><html><head><title>Http Listener demo.</title></head><body><b>Hello</b>, this is the <i>HttpListener</i> responding.</body></html>");
    writer.Close();

    context.Response.Close(); // end the response
}

Notes:

  • In the prefix the“+” wildcard is used for the domain name. This means every domain coming into the machine in the indicated port. So, “localhost” locally, the machine name or network IP will be valid URLs.
  • As this is Http, the port 80 is implicit. If a different port, for instance 8080, is intended just set “http://+:8080/HLD”.
  • An HttpListenerException “Access is denied” exception might be thrown in the listener.Start() statement if the user running the process is not allowed to open the port. Check here.
  • Setting Response.ContentType is very important. Maybe not so in Internet Explorer that “reads” the content and tries to figure what’s in it. Try changing it to “text/plain” and you’ll find IE and Chrome don’t exactly display alike.
  • You must always close the response by calling context.Response.Close(), otherwise the client will never get the response and will, eventually, time out.

You can now go to any Http client, for instance, the internet browser of your choice, access “http://localhost/HLD/&#8221;.

So, this is just what IIS does in the most simplified way. Mostly reading the content from a file system stream, setting the MIME type (context.Reponse.ContentType) according to the file extension. Will get there in the next post of these series.

Posted 2012/07/04 by Bigsby in Hands On

HttpListener Series – 0 – What is HTTP?   2 comments

The series index here.

When I started working in computer programming (not that long ago) I was amazed how developers (not necessarily bad ones) didn’t know, or care to know, about what happens underneath their coding and what standards rule their unconscious processes. As 90% of the computer programming work I see and do is web-base, I find it intriguing, to say the least, the amount of “professionals” that don’t know what HTTP and a HTTP request/repsonse is. I’ll try and make it simple.

This is one of the rare cases where a naming in technology (computer, mainly) didn’t loose it’s meaning with its extended usage.

H.T.T.P. stands for Hypertext Transfer Protocol.

So, it’s a protocol (a set of rules and standards) to communicate data that is not just text. It’s official documentation is set and provided by W3C (World Wide Web Consortium) here.

I won’t go into the deep depths of the bits communication but, you can go there by looking into Sockets or, up one level, TCP. Let’s just say that, for a HTTP communication to occur, a Socket connection based on TCP must be open.

HTTP provides a standardization for a request-response data in a client-server communication. A raw HTTP request and consequent response look like so…

The request:

GET http://localhost/HLD/ HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: en-US
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Host: localhost
Pragma: no-cache

The response:

HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: text/html
Server: Microsoft-HTTPAPI/2.0
Date: Wed, 04 Jul 2012 15:04:59 GMT

<!DOCTYPE HTML><html><head><title>Http Listener demo.</title></head><body>Hello, this is the HttpListener responding.</body></html>

Simple, no? A first line defining:

– in the request: the type “GET” (or method, we’ll get there); the resource to retrieve “http://localhost/HLD/”; and the protocol version “HTTP/1.1”

– in the response; the procotol version “HTTP/1.1”; the repsonse status code “200”; and the status description “OK”.

A bunch of, so called, headers. “New line” separated values in the form of name:value.

And, in this case just in the response, some content which, in this case, happens to be HTML.

In the end, the protocol provides a way a of, in a commonly known manner,  communicate data with some extra information that helps each side deal with the data in an organize and predictable way.

There really isn’t much more to say about the protocol but it is, IMO, vital to know this happens to understand what goes on underneath every client (e.g., a web-browser) request. Of course, the protocol provides, though methods, headers and statuses ton’s of standardized functionalities. I’ll go through some of those along these series.

See ya!

Posted 2012/07/04 by Bigsby in Hands On

Tagged with ,

HttpListener Series   Leave a comment

In this series, all about HttpListener class will thoroughly explained and exemplified. After this, any one will be able to self-host web-based scenarios without the need of an IIS and everything that comes with it.

The series is divided in the following topics (links will be provided along completion of each topic):

0 – What is HTTP? – Overview of HT.T. Protocol

1 – Get it listening

2 – Websiting – Simple web site hosting

3 – Windows Authentication – Using Windows provided authentication

4 – "Manual" Authentication – Handling HTTP authentication

5 – ASPing – Non-static request processing

6 – HTTPS – SSL secure communication

7 – WCF Data Service Hosting – OData is friends with HttpListener

 

As always, if there is any suggestion or unanswered topic about the subject, feel free to comment anywhere. I’ll be delighted to make this series as though and helpful as I can.

A full working solution with all these implementations can be downloaded here: HttpListenerDemo.zip

Posted 2012/07/04 by Bigsby in Hands On

Tagged with , ,