Thursday, March 31, 2011

The File Server

I was recently tasked with sending a friend a file the other day.  It was too large for email, he was on Windows and I on Ubuntu, so we couldn't netcat it, and the network we were on disallowed SMB (windows share) traffic.  So I pulled out my trusty USB drive, and gave him the file.  Honestly though, I don't want strange USB drives being stuck in my computer.

Solution:  Build a python web-server that can upload and download files :)


A while back I built a CGI Python webserver by hand, this is not the story of that, but rather of my personal file server.

First things first, I needed a way to upload files, index.py would work:

self.send_200()
self.wfile.write('''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Upload/Download</title>
<style TYPE="text/css">
body {
background-color:#ADD8E6;
text-align:center;
margin:0px;
padding:0px;
font-family:airal,helvetica;
}
.main{
display:block;
background-color:#E5E5E5;
margin-left:auto;
margin-right:auto;
padding:10px;
width:800px;
}

</style>

<script type="text/javascript">
function getNameFromPath(strFilepath) {
var objRE = new RegExp(/([^\\/\\\\]+)$/);
var strName = objRE.exec(strFilepath);

if (strName == null) {
return null;
}
else {
return strName[0];
}
}

function setName()
{
document.getElementById('filename').value = getNameFromPath(document.getElementById('up').value);
}
</script>
</head>

<body>
<div class="main">
<H1>Upload / Download Files</H1>
<form action="upload.py" enctype="multipart/form-data" method="post">
<input type="file" name="myfile" size="chars" id="up">
<input name="filename" id="filename" type="hidden"></input>
<input type="submit" value="Send" onclick="setName()">
</form>


<hr>
<h2>Download</h2>
<ul>
''')

import os
j = os.listdir("Downloads")
for item in j:
self.wfile.write("<li><a href='download.py?f=%s'>%s</a></li>" % (item,item))


self.wfile.write('''
</ul>

</div>
</body>
</html>''')

Essentially all of the HTML is echoed back to the user, however there is also a list of previously uploaded files that needed to be available for download, so that was auto-generated from a directory (not web accessible).

Next I needed the upload script to actually save files that people uplodad:
if POST_DICT:
try:
print POST_DICT.keys()
print POST_DICT['filename']
path = os.path.join("Downloads", POST_DICT['filename'])
print path

with open(path, 'wb') as f:
f.write(POST_DICT['myfile'])
except Exception, e:
print e

self.redirect("index.py")

This script checks to see if the POST variable is set, if so it saves the file as the filename (remember to do it binary otherwise we could get a mess when non text files are uploaded). Then redirect the user back to the index so they can instantly see their newly uploaded file.

Download.py
The last, and most difficult part was the download script:
import os
import mimetypes

if QUERY_DICT:
filename = QUERY_DICT['f'][0]

mime = mimetypes.guess_type(filename)

path = os.path.join("Downloads", filename)
head={'Content-Disposition':'attachment; filename="%s"' %(filename)}
self.send_200(mime_type=mime, headers=head)
with open(path) as f:
self.wfile.write(f.read())

else:
self.redirect("index.py")

This was because unless the content-type was set properly, and the proper filename was given, a file would be saved to the drive every time named "download.py".

Finished Product

No comments:

Post a Comment