Information is not knowledge, knowledge is not wisdom, wisdom is not truth. (Frank Zappa)


Found at XKCD
The well-known problem of transferring a file is comparably hard to solve: There are plenty of possibilities for file transferring, and as long as you work with somebody who knows how to use them, you usually find a possibility to do so. The original problem arose from NATs, which do not provide you a direct port for listening.

Meanwhile, with the rise of VoIP, this problem is solved in most cases. Routers can be configured to support UPnP, for example. The main problem is that there are plenty of people not knowing how to use tools like, say, scp. And many people are not willing to use any program that is not already installed on their system. They will try to use filehosters, and if you insist on security, they will compress the whole stuff into an encrypted RAR archive - if they have RAR.

So there is a certain motivation to have at least an own upload server - at least you can (mostly) rely on the person having some sort of webbrowser. Of course, there are plenty of PHP Upload Scripts out there. However, the other person might have a slow internet connection, and the file may be several gigabytes large. Which is mostly out of the bounds of your usual Apache and PHP configuration. And changing this configuration can be a real pain, as relevant configuration options are scattered all over the system, and you are likely to miss one and make the upload fail - and you may not want to configure such an upload site just for the casual use.

So, my approach was to use Clisp with Hunchentoot. Clisp is small, and Hunchentoot is simple but powerfull and gives me full control. I installed the necessary packages with Quicklisp, and produced the following code:

(ql:quickload :cl-base64)
(ql:quickload :hunchentoot)

(hunchentoot:define-easy-handler (index :uri "/index") ()
    "<form enctype=\"multipart/form-data\" action=\"upload\" method=\"POST\">
 Please choose a file: <input name=\"uploaded\" type=\"file\" /><br />
 <input type=\"submit\" value=\"Upload\" />
 </form>")

(hunchentoot:define-easy-handler (upload :uri "/upload") (uploaded)
    (rename-file (car uploaded)
        (concatenate 'string "/tmp/"
        (cl-base64:string-to-base64-string (cadr uploaded))))
    "SUCCESS")

(hunchentoot:start (make-instance 'hunchentoot:easy-acceptor :port 8000))

The uploaded file will be moved to /tmp/, and be named as the base64-representation of the name given by the client (to prevent any exploits). As you may notice, this is a script that is not made for "production use". I can just run it when I need it, let it run until the file is uploaded, and then stop it again. This is exactly what I need.

Well, one possible extension would be to add UPnP-Support, so I do not have to manually forward my router's port to use it.
Update: Notice that you should set LANG=C or something similar, otherwise binary data might be re-encoded.