In this assignment you are supposed to program you own HTTP server, also known as a web server.
Your will implement an HTTP server which implements a down scaled version of the original HTTP/1.0 protocol http://www.faqs.org/rfcs/rfc1945.html
However, your HTTP server should (although simple) work with ordinary browsers like Internet Explorer, Google Chrome, Mozilla Firefox, Opera, etc.
The assignment is divided into a number of small steps. It is important that you try to complete step N before proceeding to step N + 1 - at least for the first steps.
Note that you probably solved some of steps already in the socket programming exercises. These projects could be used as a starting point.
All code must be properly tested. You are free to write the test before or after the code. However, it is important that you write the test code during each step.
All code must be properly documented with /// comments.
You can use Git with a remote repository for version control.
The repository must be hosted on GitHub https://github.com/
Rules
The first version of your HTTP server will be a very simple single threaded server: There will only be one thread taking care of everything:
The server must listen on some port like 80, 8080, 8888 or the like.
All TCP servers have the same basic structure. This means that you can start looking at a simple TCP server (like Echo server) that you made in the SODP course.
When sending the response, this must follow the format of a HTTP-response see 'Computer networks' pp. 131-133.
The first version of the server should send back some static content (always return the same text, like "Hello world"). This version should no attempt to open a file, etc. In this version you do not need to read the request.
Your server must send a HTTP/1.0 response, not HTTP/1.1.
Useful C# classes
Make sure all network connections, etc. are closed properly: Use using or finally statements.
Run your server and use it from an ordinary browser.
Use Microsoft Internet Explorer to send the request. Press F12 to open a monitoring window: Find the network like icon, and press the Green record button. Send some requests, and they will be recorded, so that you can check the details later. Very useful for debugging.
In the next version the server should send some dynamic content back to the client, like "You requested /someFile.html". This version should no attempt to open a file, etc.
In this version you must read the request send from the browser to the server - but reading the first line is enough.
The first line should look like GET /someFile.html HTTP/1.1
. You must extract the URI (middle) part of the request line (/someFile.html
in this case) and include the URI in the response.
Useful C# API
In this version the server should send the contents of the resource (read "file") from the requests URI.
In the previous version of the server you extracted the URI from the request line. Now you must define where on the servers disk to look for this file. The place to start looking is called the RootCatalog.
Some examples
Declare your root catalog like private static readonly string RootCatalog = "c:/temp";
Useful C# API
Make sure the file stream is closed properly in a using or finally statement.
You should unit test your server (and its individual parts) before and after each of the steps in this exercise.
Testing a server is different from the unit testing you done in the ordinary socket exercises. To test at server you send a request to the server, and then you assert something about the response:
Now it's time to clean and document your code:
The next version of your HTTP server will spin off multiple threads: One request generates one new thread.
The server still accepts request and then creates a new thread to handle the request and send the response.
Advantages: If one client is slow in sending the request it does not block other clients.
Use a thread pool
Useful C# API:
Run the unit test to see that the server still works. VERY IMPORTANT
Do the cleaning and documentation again
Insert Trace statements to monitor important events in the "life" of the server:
The HTTP client (browser) needs to be informed about the status of the HTTP response. This is done using the status response header.
http://www.faqs.org/rfcs/rfc1945.html section 6.1 shows the status response headers.
Check the response status codes with your test. You may have to add more test cases.
All browsers can show plain HTML files, but most browsers can show other kinds of files as well. Examples: GIF and JPEG files.
Some browsers can call external viewers like Adobe Acrobat Readers for PDF files.
If the browser does not know about the file type it will show a "Where to save this file?" dialog.
The server must inform the client (in the HTTP response) about the content type to make all this work. Content-Type is a header in the HTTP response. http://www.faqs.org/rfcs/rfc1945.html section 10.5
The content type can be inferred from the extension of the file name. Some examples
Filename extension | Content type |
html | text/html |
htm | text/html |
doc | application/msword |
gif | image/gif |
jpg | image/jpeg |
application/pdf | |
css | text/css |
xml | text/xml |
jar | application/x-java-archive |
The default content type is application/octet-stream. Use it if no other content types are applicable, i.e. if you have a filename without extension or with an "unknown" extension.
More content types (sometimes called media types) can be found on http://www.iana.org/assignments/media-types/
Useful C# APIMake the content type related methods in a separate class (not inside the general HttpServer class). Make a method like
public static String GetContentType(String filename)
When it works you can copy the method to your server.
Check the response status code with unit testing.
You might also include other headers in the response. Take a look at RFC1945, section 10.
The Content-Length header should be fairly easy ... inspiration.
Maybe some of the other response headers are just as easy?
Until now we've shutdown the HTTP server by typing Ctrl-C in the console window running the server. That is not a very nice way to end a program, especially not if the program needs to do some clean-up before closing.
Ideas for graceful shutdown: The client sends a special stop request like STOP or QUIT (not part of the HTTP/1.0 protocol). When the server receives this request the server must stop.
The C# keyword volatile might be handy.
In the present version the server must be started before you execute the unit test.
It would be better if the unit test started the server (in a separate thread), ran the test cases, and finally stopped the server.
Helpful Unit test fragment:
[ClassInitialize] public static void StartServer(TestContext context) { ... } [ClassCleanup] public static void StopServer() { ... }
Choose what you want to do next: