Lab Handout 6: Networking
The lab checkoff sheet for all students can be found right here.
Get Started
Before starting, go ahead and clone the lab6 folder, which contains the code for the file-server program discussed in Problem 1. This is the main problem you'll be focusing on in section - the second problem is extra, only if there's time.
git clone /usr/class/cs110/repos/lab6/shared lab6
Problem 1: File Server
(Est. 40min)
In class, we built a server that used our subprocess function to run an external program. Using most of the same code (minus the subprocess, timing, caching, and JSON functionality), we can write a file server that sends files from our file system to a client, and also produces directory listings if the client requests a directory. Many World Wide Web servers have this ability built-in, and it is a quick way to access files on your web server. If you cloned the repository, you have all of the code for the file server.
In order to request a file, the client requests the server name and port number, followed by the file path, which has its root wherever the server is running. e.g. http://myth57:13133/filename.
The code for getFilename is shown below:
static string getFilename(iosockstream& ss) {
string method, path, protocol;
ss >> method >> path >> protocol;
string rest;
getline(ss, rest);
cout << "\tPath requested: " << path << endl;
if (path == "/") {
// serve current directory
return (".");
}
size_t pos = path.find("/");
return pos == string::npos ? path : path.substr(pos + 1);
}
- The function populates the
method,path, andprotocolvariables, but only uses thepathvariable. What is the purpose of reading in data we won't use? - What is the purpose of the
getline(ss, rest)statement? - Can you think of any security vulnerabilities in the code above? Hint: what if you ran the server in a directory located at
~/yourHome/SecureServer. Is there any way for the client to be malicious?
The three functions shown below determine whether the file requested by the client is a file or a directory, and format the fileContents appropriately. If the name requested is a directory, the opendir and readdir functions are used to populate an html listing, complete with hyperlinks. For actual files, the file is sent in plain text without any extra formatting.
/**
* Function: listDir
* ------------------------------
* Populates fileContents with a directory listing in HTML
*/
static void listDir(string& fileContents, const string& directoryPath, bool& isHTML) {
isHTML = true;
/* Create a list of all entries in this directory, in (filename, path) pairs
* e.g. (myfile.txt, samples/mydir/files/myfile.txt).
*/
vector<pair<string, string>> containedFiles;
DIR *dir = opendir(directoryPath.c_str());
if (dir != NULL) {
struct dirent *ent = readdir(dir);
// Loop through every entry in this directory
while (ent != NULL) {
string entryFileName = string(ent->d_name);
string pathToFile;
if (entryFileName == ".") {
pathToFile = ".";
} else if (entryFileName == "..") {
// remove up to the final slash
size_t lastSlashIndex = directoryPath.rfind("/");
if (lastSlashIndex != string::npos) {
pathToFile = directoryPath.substr(0, lastSlashIndex);
} else {
pathToFile = "";
}
} else {
pathToFile = directoryPath + "/" + entryFileName;
}
// Add a new (filename, path) pair
containedFiles.push_back(make_pair(entryFileName, pathToFile));
ent = readdir(dir);
}
closedir(dir);
// Fill fileContents with HTML for these pairs (omitted)
makeHTMLForDirectoryContents(fileContents, directoryPath, containedFiles);
} else {
/* could not open directory */
fileContents = "<h1>Could not open directory.</h1>\r\n";
}
}
/**
* Function: showFile
* ------------------------------
* Populates fileContents with the file contents
*/
static void showFile(string& fileContents, const string& fileName, bool& isHtml) {
ifstream t(fileName);
stringstream buffer;
buffer << t.rdbuf();
fileContents = buffer.str();
isHtml = false;
}
/**
* Function: getFileContents
* ------------------------------
* If fileName is a file, populate fileContents with
* the file's data. If fileName is a directory,
* populate fileContents with a directory listing
*/
static void getFileContents(string& fileContents, const string& fileName, bool& isHTML) {
struct stat s;
if (stat(fileName.c_str(), &s) == 0) {
if (s.st_mode & S_IFDIR) {
//it's a directory
listDir(fileContents, fileName, isHTML);
}
else if (s.st_mode & S_IFREG) {
//it's a file
showFile(fileContents, fileName, isHTML);
} else {
fileContents = "<h1>Requested name was not a file or directory.</h1>\r\n";
isHTML = true;
return;
}
} else {
fileContents = "<h1>File \"" + fileName + "\" was not found.</h1>\r\n";
isHTML = true;
return;
}
}
- Explain how the path to the file is generated for the “..” file. Why does it need to be handled as a special case?
- Assuming that the client is using a web browser, some files that the client might request could actually be html files, yet we are displaying them as raw text files. How might you modify
showFileto set theisHTMLflag appropriately for html files?
The sendResponse function is shown below:
static void sendResponse(iosockstream& ss, const string& payload, bool isHTML) {
ss << "HTTP/1.1 200 OK\r\n";
if (isHTML) {
ss << "Content-Type: text/html; charset=UTF-8\r\n";
} else {
ss << "Content-Type: text/plain; charset=UTF-8\r\n";
}
ss << "Content-Length: " << payload.size() << "\r\n";
ss << "\r\n";
ss << payload << flush;
}
- Notice that we use the
isHTMLbool we populated in the file-handling functions to tell the client's browser what type of data we are sending back. The “Content-Type” string, known as a “media type” or “MIME type” is an important identifier for the Internet. We have already used theapplication/javascriptsee here type for the scrabble solver server, but there are many other types. You can find an overwhelming list here. - Why must we declare the character set along with the content type?
- What is the purpose of the
flushon the last line?
You can try out the server by running it and then requesting files using your web browser (if you aren't on the Stanford campus, you should use the Stanford VPN so you can access the myth machines with your browser). There are two directories (subdir and anotherdir) in samples with files in them to test going up and down directories.
Problem 2: Networking, Client/Server, Request/Response
(Est. 15min)
- Explain the differences between a pipe and a socket.
- Explain how system calls are a form of client/server and request/response.
- Describe how networking is just another form of function call and return. What “function” is being called? What are the parameters? And what's the return value? Assume HTTP is the operative protocol.
- Describe the network architecture needed for:
- Email servers and clients
- Peer-to-Peer Text Messaging via cell phone numbers
- Skype
- As it turns out, each of the three network applications above all make use of custom protocols. Which ones could have relied on HTTP and/or HTTPS instead of custom protocols?