Simple HTTP Server

Assigned: Friday, Apr 15, 2016

Due: Friday, Apr 22, 2016 at 10:30pm

Collaboration: Complete this assignment with your assigned partner. You are expected to work collaboratively, not divide up the assigned work. You may use your classmates as a resource, but please cite them. Sharing of complete or nearly-complete answers is not permitted.

Submitting Your Work: Submit your answers to me by email before the due date. You can submit your work in the body of the email or in an attachment. Please CC your partner on the email.

Groups

  • David Ca. and Daniel
  • Jerry and Kumar
  • Nick and Marcel
  • Sarah and Alex
  • Moses and Evan
  • Bazil and Reilly
  • Otabek and David Ch.
  • Uzo and Albert
  • Shaun and Dave
  • Helen and Mari
  • Fengyuan and Hamza
  • Aleksandar and Michael

Overview

In this lab you will implement and test a very simple web server using the hypertext transport protocol (HTTP), a text-based application-layer protocol. The basic outline is as follows. Your server will establish a listening socket and wait for connections in an infinite loop (so that it can serve as many as come in while it is waiting). It will then need to accept a connection, then receive and parse the HTTP request. If the request is valid, the server should read the file from the file system and send the file contents (in small chunks, say 2 kilobytes) to the requestor preceded by the appropriate response header lines. If the request is not valid, a 400 error code should be sent instead. If there is some other error reading the file, a 404 error code should be sent.

Implementation

Create a file called wwwserv.py. The port your server listens on should be a clearly identifiable variable; its value should be greater than 5000, where users have rights to establish port listeners. You will want to make it a variable because if you kill the server, the port will remain “in use” for a short while to ensure that no stray requests for the port filter in.

After creating, binding, and listening on the socket, your server body should act like the following:

while True
    Establish connection with a client
    Try
        Read a request
        If the request is invalid
            Send a 400 status code, close the connection, and continue
        Open the requested file (strip the leading '/' for a relative path)
        Send a single response header to the client
        Send the file to the client in small chunks
        Close the file and connection
    Handle IO Error (sending a 404 status code and closing the connection)

In lieu of a proper logging system, your server should report simple messages to the console as it takes these steps.

Testing

Place a simple HTML file, such as example.html in the same directory as your wwwserv.py. Requests to your web server for files will be relative to the server’s directory. For example, if you used port 8765 and were running your program on the machine rosser, you can request the file via a web browser with the url http://rosser.cs.grinnell.edu:8765/example.html or using telnet, as demonstrated in Kurose and Ross. You can even make such a telnet-based request to a “real” web server, as in the following transcript, which you can try yourself.

curtsinger@turing:~$ telnet www.cs.grinnell.edu 80
Trying 132.161.196.27...
Connected to baran.cs.grinnell.edu.
Escape character is ''.
GET /curtsinger/teaching/2016S/CSC216/labs/simple-server/
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
[ ... Lots of intermediate stuff snipped out ...]
</html>
Connection closed by foreign host.
curtsinger@turing:~$ 

Questions

Submit answers to the following questions when you turn in your lab:

  1. What happens if you try to make a second connection to your server while it is still handling another connection? For example, make one telnet connection to your server, but don’t issue a request yet. Make another telnet connection. If it succeeds, issue a GET request. Then go back to your original connection and issue a GET request. What happened? Why?
  2. Note that we use the program’s directory to implicitly specify where the web server should look for files. Does this guarantee that a malicious web client cannot access files outside of the web server’s directory? If so, explain why. If not, give an example of a request a client could make to obtain an unauthorized file.

What to turn in

  • Your wwwserv.py file
  • A transcript of telnet sessions:
    • requsting a short file from your server,
    • making an invalid request, and
    • requesting a nonexistent file.
  • A transcript of your server starting and handling those requests
  • Your answers to the questions above

Python Hints

You can find a basic python tutorial at sthurlow.com/python/. Your textbook includes example Python socket code on pages 159–161 (UDP) and 165–167 (TCP).

Conditionals and looping

if (foo == 1 and 
    bar != ") or 
    baz == "bish":
    print "Success!n"
while 1:
    print "Are we there yet?n"

Simple string operations

myString = "foo bar baz"
myStringSub = myString[2:4] # myStringSub will be "o b"
myStringSub2 = myString[5:] # myStringSub2 will be "ar baz"

Splitting a string on whitespace

myString = "foo bar baz"
myStringParts = myString.split()
# myStringParts[0] is "foo", myStringParts[1] is "bar" and myStringParts[2] is "baz"
# len(myStringParts) is 3

Reading files

try:
    fileHandle = open( "myFilename" ) # Open file and return a file handle (object)
    chunk = fileHandle.read(64) # Read 64 bytes from the file (advancing file pointer)
    if chunk == '':  # Test whether EOF has been reached (no string data from read method)
        print "No more file!"
    fileHandle.close() # Close the file
except IOError:
    print "Something went wrong (like a file not found or bad permissions)!"

Acknowledgements

This assignment was developed by Jerod Weinman, who adapted it from Janet Davis’ Lab 10: A Simple Web Client and Server and Programming Assignment 1: Web Server by James F. Kurose and Keith W. Ross.