Lab: Simple Web Server
CSC 364 - Computer Networks - Weinman
- Summary:
- We implement a very simple web server in Python.
- Assigned:
- Friday 14 February
- Due:
- 11:59 PM Thursday 20 February
- Objectives:
-
- Introduce Python programming
- Practice basic UNIX-style socket programming
- Learn a little about the HTTP protocol
- Reinforce knowledge about filesystem security
- Background
-
- Section 2.2 in Kurose and Ross (Computer Networks) details the basics
of the HTTP protocol, with section 2.2.3 highlighting the HTTP message
format for requests and responses.
- Section 2.7 in Kurose and Ross (Computer Networks) demonstrates how
to use Python for socket programming, with 2.7.2 highlighting the
TCP protocol you will use.
- You can find an extremely simple Python tutorial at http://www.sthurlow.com/python/
- Collaboration:
- You will complete this lab in pairs assigned by
the instructor.
Introduction
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(1), 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.
-
weinman@laplace:~$ telnet www.cs.grinnell.edu 80
Trying 132.161.196.27...
Connected to baran.cs.grinnell.edu.
Escape character is ''.
GET /weinman/courses/CSC364/2014S/labs/attribution.html
<!DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN
DTD/xhtml1-transitional.dtd>
<html xmlns=http://www.w3.org/1999/xhtml>
[ ... Lots of intermediate stuff snipped out ...]
</html>
Connection closed by foreign host.
weinman@laplace:~$
Questions
- 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?
- 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 single PDF containing (merged)
- An enscripted version of your wwwserv.py
- A transcript of telnet sessions
- requesting a short file from your server,
- making an invalid request, and
- requesting a non-existant file.
- A transcript of your server starting and handling these requests
- Your answers to the questions
Submissions missing the PDF or files in any other formats will not
be graded.
Python Hints
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)!"
Acknowledgments
This lab was inspired in part by CSC 213, Fall 2006 : Lab 10 : A Simple Web Client and Server,
by Janet Davis, as well as Socket Programming Assignment
1: Web Server, by James F. Kurose and Keith W. Ross.