diff --git a/rhizome.h b/rhizome.h
index 580149de..94588cee 100644
--- a/rhizome.h
+++ b/rhizome.h
@@ -346,6 +346,25 @@ typedef struct rhizome_http_request {
   /* Boundary string for POST multipart form requests */
   char boundary_string[1024];
   int boundary_string_length;
+  /* File currently being written to while decoding POST multipart form */
+  FILE *field_file;
+  /* Which fields have been seen in POST multipart form */
+  int fields_seen;
+  /* The seen fields bitmap above shares values with the actual Rhizome Direct
+     state machine.  The state numbers (and thus bitmap values for the various
+     fields) are listed here.
+     
+     To avoid confusion, we should not use single bit values for states that do
+     not correspond directly to a particular field.
+     Doesn't really matter what they are apart from not having exactly one bit set.
+     In fact, the only reason to not have exactly one bit set is so that we keep as
+     many bits available for field types as possible.
+  */
+#define RD_MIME_STATE_MANIFESTHEADERS (1<<0)
+#define RD_MIME_STATE_DATAHEADERS (1<<1)
+#define RD_MIME_STATE_INITIAL 0
+#define RD_MIME_STATE_PARTHEADERS 0xffff0000
+#define RD_MIME_STATE_BODY 0xffff0001
 
   /* The source specification data which are used in different ways by different 
    request types */
diff --git a/rhizome_direct.c b/rhizome_direct.c
index 5dfb9d7d..a9055c2b 100644
--- a/rhizome_direct.c
+++ b/rhizome_direct.c
@@ -119,11 +119,6 @@ int rhizome_direct_form_received(rhizome_http_request *r)
   return rhizome_server_simple_http_response(r, 204, "Move along. Nothing to see.");
 }
 
-#define RD_MIME_STATE_INITIAL 0
-#define RD_MIME_STATE_PARTHEADERS 1
-#define RD_MIME_STATE_MANIFESTHEADERS 2
-#define RD_MIME_STATE_DATAHEADERS 3
-#define RD_MIME_STATE_BODY 99
 
 int rhizome_direct_process_mime_line(rhizome_http_request *r,char *buffer)
 {
@@ -149,7 +144,6 @@ int rhizome_direct_process_mime_line(rhizome_http_request *r,char *buffer)
      then.  In the meantime, we will have something that meets our immediate
      needs for Rhizome Direct and a variety of use cases.
   */
-  DEBUGF("mime line: %s",buffer);
 
   /* Regardless of the state of the parser, the presence of boundary lines
      is significant, so lets just check once, and remember the result.
@@ -165,22 +159,28 @@ int rhizome_direct_process_mime_line(rhizome_http_request *r,char *buffer)
   int blankLine=0;
   if (!strcmp(buffer,"\r\n")) blankLine=1;
 
+  DEBUGF("mime state: 0x%x, blankLine=%d, EOF=%d",
+	 r->source_flags,blankLine,endOfForm);
   switch(r->source_flags) {
   case RD_MIME_STATE_INITIAL:
+    DEBUGF("mime line: %s",r->request);
     if (boundaryLine) r->source_flags=RD_MIME_STATE_PARTHEADERS;
     break;
   case RD_MIME_STATE_PARTHEADERS:
   case RD_MIME_STATE_MANIFESTHEADERS:
   case RD_MIME_STATE_DATAHEADERS:
+    DEBUGF("mime line: %s",r->request);
     if (blankLine) {
       /* End of headers */
       if (r->source_flags!=RD_MIME_STATE_PARTHEADERS) {
 	/* Open manifest or data file handle, and begin writing to
 	   it. */
+	/* XXX not implemented */
+	r->source_flags=RD_MIME_STATE_BODY;
       } else {
 	/* unknown part: complain */
 	rhizome_server_simple_http_response
-	  (r, 400, "<html><h1>Unsupported form field</h1></html>\r\n");
+	  (r, 400, "<html><h1>Unsupported form field or missing content-disposition line in mime part</h1></html>\r\n");
 	return -1;
       }
     } else {
@@ -190,12 +190,30 @@ int rhizome_direct_process_mime_line(rhizome_http_request *r,char *buffer)
 		 "Content-Disposition: form-data; name=\"%[^\"]\";"
 		 " filename=\"%[^\"]\"",field,name)==2)
 	{
+	  if (r->source_flags!=RD_MIME_STATE_PARTHEADERS)
+	    {
+	      /* Multiple content-disposition lines.  This is very naughty. */
+	      rhizome_server_simple_http_response
+		(r, 400, "<html><h1>Malformed multi-part form POST: Multiple content-disposition lines in single MIME encoded part.</h1></html>\r\n");
+	      return -1;
+	    }
 	  DEBUGF("Found form part '%s' name '%s'",field,name);
 	  if (!strcasecmp(field,"manifest")) 
 	    r->source_flags=RD_MIME_STATE_MANIFESTHEADERS;
 	  if (!strcasecmp(field,"data")) 
 	    r->source_flags=RD_MIME_STATE_DATAHEADERS;
-	}
+	  if (r->source_flags!=RD_MIME_STATE_PARTHEADERS)
+	    r->fields_seen|=r->source_flags;
+	} else if (blankLine) {
+	  if (r->source_flags==RD_MIME_STATE_PARTHEADERS)
+	    {
+	      /* Multiple content-disposition lines.  This is very naughty. */
+	      rhizome_server_simple_http_response
+		(r, 400, "<html><h1>Malformed multi-part form POST: Missing content-disposition lines in MIME encoded part.</h1></html>\r\n");
+	      return -1;
+	    }
+	  r->source_flags=RD_MIME_STATE_BODY;
+      }	
     }
     break;
   case RD_MIME_STATE_BODY: