<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Joe Freeman&#039;s Weblog &#187; MochiWeb</title>
	<atom:link href="http://joefreeman.co.uk/blog/category/erlang/mochiweb/feed/" rel="self" type="application/rss+xml" />
	<link>http://joefreeman.co.uk/blog</link>
	<description>Musings on Software Development, etc</description>
	<lastBuildDate>Sat, 27 Mar 2010 15:16:35 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Handling Multipart Uploads with MochiWeb</title>
		<link>http://joefreeman.co.uk/blog/2009/12/handling-multipart-uploads-with-mochiweb/</link>
		<comments>http://joefreeman.co.uk/blog/2009/12/handling-multipart-uploads-with-mochiweb/#comments</comments>
		<pubDate>Sat, 12 Dec 2009 00:02:40 +0000</pubDate>
		<dc:creator>Joe</dc:creator>
				<category><![CDATA[Erlang]]></category>
		<category><![CDATA[MochiWeb]]></category>

		<guid isPermaLink="false">http://joefreeman.co.uk/blog/?p=262</guid>
		<description><![CDATA[An explanation of how to handle file uploads with the MochiWeb Erlang library. The article includes a brief introduction to setting up MochiWeb and an explanation of how to handle file uploads and save them to the /tmp directory. I've also put together a very simple photo gallery system to show how to make use of this feature.]]></description>
			<content:encoded><![CDATA[<p>I was getting along fairly well with my own custom-built, lightweight Erlang web server, until I needed to handle file uploading. At this point, I decided it was time to stop trying to re-invent the wheel (or take the lazy approach—whichever way you choose to look at it), and take another look at MochiWeb, which implements this feature.</p>
<p>However, MochiWeb&#8217;s documentation is non-existent (unless I&#8217;m missing something—<em>please</em> let me know if I am). I came across <a href="http://jimmyg.org/blog/2007/multipart-post-with-erlang-and-mochiweb.html">James Gardner&#8217;s post</a> on handling file uploads, which helped me out. But after digging through the MochiWeb source-code I discovered a slightly easier way of handling file uploads. It may be that this method has been added since James&#8217; post in 2007, or maybe it&#8217;s just less appropriate to James&#8217; requirements.</p>
<p>I&#8217;m going to quickly run over how to setup MochiWeb. I know this has been covered quite a lot by other people, but it&#8217;s something a found a little daunting when I started out, so I want to emphasise that it&#8217;s a lot easier to setup than maybe first appears. Then I&#8217;ll post and explain a short chunk of code for handling uploads, and saving them to <code>/tmp</code>. Finally, I&#8217;ll provide an example of using this technique to provide a <em>very</em> simple photo gallery system.</p>
<h2>Setting up MochiWeb</h2>
<p>There&#8217;s a pretty good tutorial <a href="http://beebole.com/en/blog/erlang/how-to-quickly-set-up-ubuntu-804-loaded-with-erlang-mochiweb-and-nginx/">on the BeeBole blog</a>, but I&#8217;ll cover the basics here.</p>
<p>First step is to check out the code from the Google Code repository. Make sure you have subversion installed, and then:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">svn</span> checkout http:<span style="color: #000000; font-weight: bold;">//</span>mochiweb.googlecode.com<span style="color: #000000; font-weight: bold;">/</span>svn<span style="color: #000000; font-weight: bold;">/</span>trunk<span style="color: #000000; font-weight: bold;">/</span> mochiweb</pre></div></div>

<p>Now, make sure that you have Erlang installed, and:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">cd</span> mochiweb
<span style="color: #c20cb9; font-weight: bold;">make</span>
<span style="color: #c20cb9; font-weight: bold;">chmod</span> +x scripts<span style="color: #000000; font-weight: bold;">/</span>new_mochiweb.erl
.<span style="color: #000000; font-weight: bold;">/</span>scripts<span style="color: #000000; font-weight: bold;">/</span>new_mochiweb.erl mochiweb_uploads ..<span style="color: #000000; font-weight: bold;">/</span>.</pre></div></div>

<p>This will build the MochiWeb system and then create a new MochiWeb project. You can repeat this process whenever you&#8217;re starting a new project. Note that <code>mochiweb_uploads</code> is the project&#8217;s name. MochiWeb is a bit picky about project names: they must be valid module names, so (it seems) you can&#8217;t use hyphens.</p>
<p>Next, we should make sure that the project builds and runs before we start coding:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">cd</span> ..<span style="color: #000000; font-weight: bold;">/</span>mochiweb_uploads
<span style="color: #c20cb9; font-weight: bold;">make</span>
.<span style="color: #000000; font-weight: bold;">/</span>start-dev.sh</pre></div></div>

<p>By default, your MochiWeb project is setup as a lightweight web server that serves files from the <code>priv/www</code> directory on port 8000. All being well, you should now be able to point your browser at <code>http://localhost:8000/</code> and see the &#8216;MochiWeb is running.&#8217; message.</p>
<p>If you have any problems, you&#8217;ll need to wade through the progress reports on the console to try and figure out where things are going wrong. The clues will be in any &#8216;crash reports&#8217;.</p>
<p>You can stop the server with Ctrl+C, then entering &#8216;a&#8217;, and hitting return. Or you can just hit Ctrl+C twice.</p>
<h2>Handling File Uploads</h2>
<p>First of all, we need to put together a page that we can test our uploading with. We&#8217;ll just replace the <code>index.html</code> file in <code>priv/www</code> with something straight-forward:</p>

<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">html</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">head</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">title</span>&gt;</span>MochiWeb Upload Test<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">title</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">head</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">body</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">form</span> <span style="color: #000066;">action</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;upload_photo&quot;</span> <span style="color: #000066;">method</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;post&quot;</span> <span style="color: #000066;">enctype</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;multipart/form-data&quot;</span>&gt;</span>
    <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">input</span> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;file&quot;</span> <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;photo&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span>
    <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">input</span> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;submit&quot;</span> <span style="color: #000066;">value</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;Upload&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">form</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">body</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">html</span>&gt;</span></pre></div></div>

<h3>Routing the Request</h3>
<p>The code for starting the web server is in <code>src/mochiweb_uploads_web.erl</code>. Open up this file and take a look at the <code>loop/2</code> function. The function is split up into two parts by the outer <code>case</code> construct: the first part is for HTTP GET (and HEAD) requests, the second is for POST requests. We&#8217;re going to be handling the file uploads in the POST clause. Like so:</p>

<div class="wp_syntax"><div class="code"><pre class="erlang" style="font-family:monospace;"><span style="">'POST'</span> <span style="color: #6bb810;">-&gt;</span>
    <span style="color: #186895;">case</span> <span style="color: #45b3e6;">Path</span> <span style="color: #186895;">of</span>
        <span style="color: #ff7800;">&quot;upload_photo&quot;</span> <span style="color: #6bb810;">-&gt;</span>
            <span style="color: #ff3c00;">upload_photo</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">Req</span><span style="color: #109ab8;">&#41;</span><span style="color: #6bb810;">;</span>
        <span style="color: #45b3e6;">_</span> <span style="color: #6bb810;">-&gt;</span>
            <span style="color: #45b3e6;">Req</span>:<span style="color: #ff3c00;">not_found</span><span style="color: #109ab8;">&#40;</span><span style="color: #109ab8;">&#41;</span>
    <span style="color: #186895;">end</span><span style="color: #6bb810;">;</span></pre></div></div>

<p>All we are doing here, is delegating responsibility for handling the &#8216;upload_photo&#8217; request to a function called &#8216;upload_photo&#8217;, which we can add to the bottom of <code>mochiweb_uploads_web.erl</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="erlang" style="font-family:monospace;"><span style="color: #ff3c00;">upload_photo</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">Req</span><span style="color: #109ab8;">&#41;</span> <span style="color: #6bb810;">-&gt;</span>
    <span style="color: #45b3e6;">Req</span>:<span style="color: #ff3c00;">ok</span><span style="color: #109ab8;">&#40;</span><span style="color: #109ab8;">&#123;</span><span style="color: #ff7800;">&quot;text/html&quot;</span><span style="color: #6bb810;">,</span> <span style="color: #109ab8;">&#91;</span><span style="color: #109ab8;">&#93;</span><span style="color: #6bb810;">,</span> <span style="color: #ff7800;">&quot;&lt;p&gt;Hello, world!&lt;/p&gt;&quot;</span><span style="color: #109ab8;">&#125;</span><span style="color: #109ab8;">&#41;</span><span style="color: #6bb810;">.</span></pre></div></div>

<p>That&#8217;s going to just return a &#8216;Hello, world!&#8217; message so we can check the request is getting routed correctly. If we try out the system (<code>make</code>, <code>./start-dev.sh</code>, go to <code>localhost:8000</code>), we should initially see the form, then after submitting the form our message should appear.</p>
<h3>Handling the POSTed multipart data</h3>
<p>Now onto actually handling the POSTed multipart data. We&#8217;ll replace our <code>upload_photo/1</code> function with this:</p>

<div class="wp_syntax"><div class="code"><pre class="erlang" style="font-family:monospace;"><span style="color: #ff3c00;">upload_photo</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">Req</span><span style="color: #109ab8;">&#41;</span> <span style="color: #6bb810;">-&gt;</span>
    <span style="color: #45b3e6;">FileHandler</span> <span style="color: #014ea4;">=</span> <span style="color: #ff3c00;">fun</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">Filename</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">ContentType</span><span style="color: #109ab8;">&#41;</span> <span style="color: #6bb810;">-&gt;</span> <span style="color: #ff3c00;">handle_file</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">Filename</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">ContentType</span><span style="color: #109ab8;">&#41;</span> <span style="color: #186895;">end</span><span style="color: #6bb810;">,</span>
    <span style="color: #45b3e6;">Files</span> <span style="color: #014ea4;">=</span> mochiweb_multipart:<span style="color: #ff3c00;">parse_form</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">Req</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">FileHandler</span><span style="color: #109ab8;">&#41;</span><span style="color: #6bb810;">,</span>
    <span style="color: #45b3e6;">Photo</span> <span style="color: #014ea4;">=</span> <span style="color: #ff4e18;">proplists</span>:<span style="color: #ff3c00;">get_value</span><span style="color: #109ab8;">&#40;</span><span style="color: #ff7800;">&quot;photo&quot;</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">Files</span><span style="color: #109ab8;">&#41;</span><span style="color: #6bb810;">,</span>
    <span style="color: #666666; font-style: italic;">% TODO: handle the photo here</span>
    <span style="color: #45b3e6;">Req</span>:<span style="color: #ff3c00;">ok</span><span style="color: #109ab8;">&#40;</span><span style="color: #109ab8;">&#123;</span><span style="color: #ff7800;">&quot;text/html&quot;</span><span style="color: #6bb810;">,</span> <span style="color: #109ab8;">&#91;</span><span style="color: #109ab8;">&#93;</span><span style="color: #6bb810;">,</span> <span style="color: #ff7800;">&quot;&lt;p&gt;Thank you. &lt;a href=<span style="color: #000099; font-weight: bold;">\&quot;</span>index.html<span style="color: #000099; font-weight: bold;">\&quot;</span>&gt;Upload another?&lt;/a&gt;&lt;/p&gt;&quot;</span><span style="color: #109ab8;">&#125;</span><span style="color: #109ab8;">&#41;</span><span style="color: #6bb810;">.</span></pre></div></div>

<p>Let&#8217;s examine this line-by-line.</p>
<p>First of all, we&#8217;re specifying a function that we pass to the <code>mochiweb_multipart:parse_form/2</code> function. The function that we&#8217;re passing will get called <strong>once for every file that is present in the POST data</strong> (i.e., that is in the form)—don&#8217;t forget that multiple files may be being uploaded.</p>
<p>The file will be split into &#8216;chunks&#8217;. So it&#8217;s the job of this &#8216;FileHandler&#8217; function to return <em>another</em> function that will be used to consume each chunk of the file (and then, finally, the &#8216;eof&#8217; atom). We&#8217;ll come back to this in a moment.</p>
<p>The <code>parse_form/2</code> function will then return a list (in fact, a <a href="http://www.erlang.org/doc/man/proplists.html">property list</a>) of all the files. There will be a mapping from the name of the input to the value finally returned from our file handler.</p>
<p>Let&#8217;s take a look at the <code>handle_file/2</code> function:</p>

<div class="wp_syntax"><div class="code"><pre class="erlang" style="font-family:monospace;"><span style="color: #ff3c00;">handle_file</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">Filename</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">ContentType</span><span style="color: #109ab8;">&#41;</span> <span style="color: #6bb810;">-&gt;</span>
    <span style="color: #45b3e6;">TempFilename</span> <span style="color: #014ea4;">=</span> <span style="color: #ff7800;">&quot;/tmp/&quot;</span> <span style="color: #014ea4;">++</span> <span style="color: #ff3c00;">atom_to_list</span><span style="color: #109ab8;">&#40;</span>?<span style="color: #6941fd;">MODULE</span><span style="color: #109ab8;">&#41;</span> <span style="color: #014ea4;">++</span> <span style="color: #ff3c00;">integer_to_list</span><span style="color: #109ab8;">&#40;</span><span style="color: #ff4e18;">erlang</span>:<span style="color: #ff3c00;">phash2</span><span style="color: #109ab8;">&#40;</span><span style="color: #ff3c00;">make_ref</span><span style="color: #109ab8;">&#40;</span><span style="color: #109ab8;">&#41;</span><span style="color: #109ab8;">&#41;</span><span style="color: #109ab8;">&#41;</span><span style="color: #6bb810;">,</span>
    <span style="color: #109ab8;">&#123;</span>ok<span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">File</span><span style="color: #109ab8;">&#125;</span> <span style="color: #014ea4;">=</span> <span style="color: #ff4e18;">file</span>:<span style="color: #ff3c00;">open</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">TempFilename</span><span style="color: #6bb810;">,</span> <span style="color: #109ab8;">&#91;</span>raw<span style="color: #6bb810;">,</span> write<span style="color: #109ab8;">&#93;</span><span style="color: #109ab8;">&#41;</span><span style="color: #6bb810;">,</span>
    <span style="color: #ff3c00;">chunk_handler</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">Filename</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">ContentType</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">TempFilename</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">File</span><span style="color: #109ab8;">&#41;</span><span style="color: #6bb810;">.</span></pre></div></div>

<p>We use <a href="http://www.erlang.org/doc/man/erlang.html#erlang:phash2-2"><code>erlang:phash2/2</code></a> and <a href="http://www.erlang.org/doc/man/erlang.html#make_ref-0"><code>make_ref/0</code></a> together with a (hopefully) application-specific prefix to construct a random filename which will reside in &#8216;/tmp&#8217;. A couple of points to make here: collisions aren&#8217;t impossible and this is platform-dependent. We could get the <a href="http://en.wikipedia.org/wiki/Temporary_folder">temporary directory</a> from the operating system, and we could generate <a href="http://stackoverflow.com/questions/1222084/how-do-i-create-a-temp-filename-in-erlang">better filenames</a>.</p>
<p>We open a file for writing to and pass it to our &#8216;chunk handler&#8217; ready for consuming the first chunk. Note that <code>chunk_handler/4</code> is <strong>a function that returns a function</strong>. We return this generated function back to the MochiWeb code, which will use it to handle the first chunk.</p>
<p>Before I go on to explain the &#8216;chunk_handler&#8217;, I should point out that in theory we could use this opportunity to filter the input. If (for some reason) we wanted to handle different types of file in different ways, we could do this based on the <code>ContentType</code>. Annoyingly, there&#8217;s no way to inspect the name of the field (i.e., the name of the HTML input) that we&#8217;re handling at this stage.</p>
<p>As I mentioned, the <code>chunk_handler/4</code> function simply returns another function (which will accept one parameter) that MochiWeb will call once it has fetched a chunk. I&#8217;m using the term &#8216;chunk&#8217; casually: it can be <em>either</em> a raw chunk of data from the socket, <em>or</em> the <code>eof</code> atom. <strong>If the chunk being passed is not the <code>eof</code> atom, the function must return another function which will be used to handle the next chunk.</strong> However, if the function is passed the <code>eof</code> atom, we will return a value that we want to associate with this part of the multipart data. The value returned here will be the value that is stored in the property list we mentioned earlier (in <code>upload_photo/1</code>).</p>
<p>Here&#8217;s our <code>chunk_handler/4</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="erlang" style="font-family:monospace;"><span style="color: #ff3c00;">chunk_handler</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">Filename</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">ContentType</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">TempFilename</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">File</span><span style="color: #109ab8;">&#41;</span> <span style="color: #6bb810;">-&gt;</span>
    <span style="color: #ff3c00;">fun</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">Next</span><span style="color: #109ab8;">&#41;</span> <span style="color: #6bb810;">-&gt;</span>
        <span style="color: #186895;">case</span> <span style="color: #45b3e6;">Next</span> <span style="color: #186895;">of</span>
            eof <span style="color: #6bb810;">-&gt;</span>
                <span style="color: #ff4e18;">file</span>:<span style="color: #ff3c00;">close</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">File</span><span style="color: #109ab8;">&#41;</span><span style="color: #6bb810;">,</span>
                <span style="color: #109ab8;">&#123;</span><span style="color: #45b3e6;">Filename</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">ContentType</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">TempFilename</span><span style="color: #109ab8;">&#125;</span><span style="color: #6bb810;">;</span>
            <span style="color: #45b3e6;">Data</span> <span style="color: #6bb810;">-&gt;</span>
                <span style="color: #ff4e18;">file</span>:<span style="color: #ff3c00;">write</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">File</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">Data</span><span style="color: #109ab8;">&#41;</span><span style="color: #6bb810;">,</span>
                <span style="color: #ff3c00;">chunk_handler</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">Filename</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">ContentType</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">TempFilename</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">File</span><span style="color: #109ab8;">&#41;</span>
        <span style="color: #186895;">end</span>
    <span style="color: #186895;">end</span><span style="color: #6bb810;">.</span></pre></div></div>

<p>So, don&#8217;t forget we&#8217;re returning a function here, which will get executed later on. There are two cases, as we&#8217;ve discussed:</p>
<ul>
<li>The <code>eof</code> case involves closing the file, and returning a tuple containing the original filename, the content-type and the temporary filename. We could return this in record form, or we may choose just to return the temporary filename if we didn&#8217;t care about the other parameters.</li>
<li>The non-<code>eof</code> case involves writing the chunk of data to the file, and then returning a function to handle the next chunk of data.</li>
</ul>
<p>This concludes the data-handling code. At this point you may wish to refer back to the <code>upload_photo/1</code>—this is where you would then be able to reference each of the uploaded files in the property list by it&#8217;s HTML input&#8217;s name. The value in the property list would be the <code>{Filename, ContentType, TempFilename}</code> tuple being returned by <code>chunk_handler/4</code>.</p>
<h2>A Semi-practical Example</h2>
<p>To turn this into something &#8216;useful&#8217;, I&#8217;ve put together a rudimentary photo gallery system.</p>
<p>We will adapt our <code>upload_photo/1</code> function to take another two parameters (the directory for the photos and a list of valid file extensions; the function will hence become <code>upload_photo/3</code>).</p>
<p>The total of our security features will be to check that the extension of the file corresponds to a recognised image type. Anyone will be able to upload files.</p>
<p>Here&#8217;s our function:</p>

<div class="wp_syntax"><div class="code"><pre class="erlang" style="font-family:monospace;"><span style="color: #ff3c00;">upload_photo</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">Req</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">PhotoDir</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">ValidExtensions</span><span style="color: #109ab8;">&#41;</span> <span style="color: #6bb810;">-&gt;</span>
    <span style="color: #45b3e6;">FileHandler</span> <span style="color: #014ea4;">=</span> <span style="color: #ff3c00;">fun</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">Filename</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">ContentType</span><span style="color: #109ab8;">&#41;</span> <span style="color: #6bb810;">-&gt;</span> <span style="color: #ff3c00;">handle_file</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">Filename</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">ContentType</span><span style="color: #109ab8;">&#41;</span> <span style="color: #186895;">end</span><span style="color: #6bb810;">,</span>
    <span style="color: #45b3e6;">Files</span> <span style="color: #014ea4;">=</span> mochiweb_multipart:<span style="color: #ff3c00;">parse_form</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">Req</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">FileHandler</span><span style="color: #109ab8;">&#41;</span><span style="color: #6bb810;">,</span>
    <span style="color: #109ab8;">&#123;</span><span style="color: #45b3e6;">OriginalFilename</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">_</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">TempFilename</span><span style="color: #109ab8;">&#125;</span> <span style="color: #014ea4;">=</span> <span style="color: #ff4e18;">proplists</span>:<span style="color: #ff3c00;">get_value</span><span style="color: #109ab8;">&#40;</span><span style="color: #ff7800;">&quot;photo&quot;</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">Files</span><span style="color: #109ab8;">&#41;</span><span style="color: #6bb810;">,</span>
    <span style="color: #186895;">case</span> <span style="color: #ff4e18;">lists</span>:<span style="color: #ff3c00;">member</span><span style="color: #109ab8;">&#40;</span><span style="color: #ff4e18;">filename</span>:<span style="color: #ff3c00;">extension</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">OriginalFilename</span><span style="color: #109ab8;">&#41;</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">ValidExtensions</span><span style="color: #109ab8;">&#41;</span> <span style="color: #186895;">of</span>
        true <span style="color: #6bb810;">-&gt;</span>
            <span style="color: #45b3e6;">Destination</span> <span style="color: #014ea4;">=</span> <span style="color: #45b3e6;">PhotoDir</span> <span style="color: #014ea4;">++</span> <span style="color: #45b3e6;">OriginalFilename</span><span style="color: #6bb810;">,</span>
            <span style="color: #186895;">case</span> <span style="color: #ff4e18;">file</span>:<span style="color: #ff3c00;">rename</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">TempFilename</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">Destination</span><span style="color: #109ab8;">&#41;</span> <span style="color: #186895;">of</span>
                ok <span style="color: #6bb810;">-&gt;</span>
                    <span style="color: #45b3e6;">Url</span> <span style="color: #014ea4;">=</span> <span style="color: #ff7800;">&quot;/&quot;</span><span style="color: #6bb810;">,</span>
                    <span style="color: #45b3e6;">Req</span>:<span style="color: #ff3c00;">respond</span><span style="color: #109ab8;">&#40;</span><span style="color: #109ab8;">&#123;</span><span style="color: #ff9600;">302</span><span style="color: #6bb810;">,</span> <span style="color: #109ab8;">&#91;</span><span style="color: #109ab8;">&#123;</span><span style="color: #ff7800;">&quot;Location&quot;</span><span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">Url</span><span style="color: #109ab8;">&#125;</span><span style="color: #109ab8;">&#93;</span><span style="color: #6bb810;">,</span> <span style="color: #ff7800;">&quot;Redirecting to &quot;</span> <span style="color: #014ea4;">++</span> <span style="color: #45b3e6;">Url</span><span style="color: #109ab8;">&#125;</span><span style="color: #109ab8;">&#41;</span><span style="color: #6bb810;">;</span>
                <span style="color: #109ab8;">&#123;</span>error<span style="color: #6bb810;">,</span> <span style="color: #45b3e6;">Reason</span><span style="color: #109ab8;">&#125;</span> <span style="color: #6bb810;">-&gt;</span>
                    <span style="color: #ff4e18;">file</span>:<span style="color: #ff3c00;">delete</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">TempFilename</span><span style="color: #109ab8;">&#41;</span><span style="color: #6bb810;">,</span>
                    <span style="color: #ff3c00;">html_response</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">Req</span><span style="color: #6bb810;">,</span> <span style="color: #ff7800;">&quot;An error occured whilst trying to move your file: &quot;</span> <span style="color: #014ea4;">++</span> <span style="color: #ff3c00;">atom_to_list</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">Reason</span><span style="color: #109ab8;">&#41;</span> <span style="color: #014ea4;">++</span> <span style="color: #ff7800;">&quot;. Does the destination directory exist?&quot;</span><span style="color: #109ab8;">&#41;</span>
            <span style="color: #186895;">end</span><span style="color: #6bb810;">;</span>
        false <span style="color: #6bb810;">-&gt;</span>
            <span style="color: #ff4e18;">file</span>:<span style="color: #ff3c00;">delete</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">TempFilename</span><span style="color: #109ab8;">&#41;</span><span style="color: #6bb810;">,</span>
            <span style="color: #ff3c00;">html_response</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">Req</span><span style="color: #6bb810;">,</span> <span style="color: #ff7800;">&quot;Invalid file type. File extension must be one of: &quot;</span> <span style="color: #014ea4;">++</span> <span style="color: #ff4e18;">string</span>:<span style="color: #ff3c00;">join</span><span style="color: #109ab8;">&#40;</span><span style="color: #45b3e6;">ValidExtensions</span><span style="color: #6bb810;">,</span> <span style="color: #ff7800;">&quot;, &quot;</span><span style="color: #109ab8;">&#41;</span> <span style="color: #014ea4;">++</span> <span style="color: #ff7800;">&quot;. &lt;a href=<span style="color: #000099; font-weight: bold;">\&quot;</span>/<span style="color: #000099; font-weight: bold;">\&quot;</span>&gt;Try again?&lt;/a&gt;&quot;</span><span style="color: #109ab8;">&#41;</span>
    <span style="color: #186895;">end</span><span style="color: #6bb810;">.</span></pre></div></div>

<p>You can <a href="http://joefreeman.co.uk/blog/wp-content/uploads/2009/12/mochiweb_uploads.zip">download</a> the rest of the code. It&#8217;s not very elegant, but I was keen to put together something for you to take home.</p>
<p>Obviously this isn&#8217;t the sort of thing you should consider making available to the world wide web, but hopefully it&#8217;ll be useful in explaining how to handle file uploads.</p>
]]></content:encoded>
			<wfw:commentRss>http://joefreeman.co.uk/blog/2009/12/handling-multipart-uploads-with-mochiweb/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
