Bug 1186932 - Implement support for form submission of a picked directory - part 2 - Form submission with directory support, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 14 Jul 2016 09:01:58 +0200
changeset 330068 8105df56b23209b8cb3389dfe483214472e0bb3f
parent 330067 3ac9e026e72eff099c8deba43370b95907140492
child 330069 e3e3c703163d06dcaf97b5db6448a19eb7efb736
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1186932
milestone50.0a1
Bug 1186932 - Implement support for form submission of a picked directory - part 2 - Form submission with directory support, r=smaug
dom/html/HTMLFormSubmission.cpp
dom/html/HTMLFormSubmission.h
--- a/dom/html/HTMLFormSubmission.cpp
+++ b/dom/html/HTMLFormSubmission.cpp
@@ -65,16 +65,29 @@ RetrieveFileName(Blob* aBlob, nsAString&
   }
 
   RefPtr<File> file = aBlob->ToFile();
   if (file) {
     file->GetName(aFilename);
   }
 }
 
+void
+RetrieveDirectoryName(Directory* aDirectory, nsAString& aDirname)
+{
+  MOZ_ASSERT(aDirectory);
+
+  ErrorResult rv;
+  aDirectory->GetName(aDirname, rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    rv.SuppressException();
+    aDirname.Truncate();
+  }
+}
+
 // --------------------------------------------------------------------------
 
 class FSURLEncoded : public EncodingFormSubmission
 {
 public:
   /**
    * @param aCharset the charset of the form as a string
    * @param aMethod the method of the submit (either NS_FORM_METHOD_GET or
@@ -196,18 +209,21 @@ FSURLEncoded::AddNameBlobOrNullPair(cons
   RetrieveFileName(aBlob, filename);
   return AddNameValuePair(aName, filename);
 }
 
 nsresult
 FSURLEncoded::AddNameDirectoryPair(const nsAString& aName,
                                    Directory* aDirectory)
 {
-  // TODO
-  return NS_OK;
+  // No warning about because Directory objects are never sent via form.
+
+  nsAutoString dirname;
+  RetrieveDirectoryName(aDirectory, dirname);
+  return AddNameValuePair(aName, dirname);
 }
 
 void
 HandleMailtoSubject(nsCString& aPath)
 {
   // Walk through the string and see if we have a subject already.
   bool hasSubject = false;
   bool hasParams = false;
@@ -474,16 +490,19 @@ FSMultipartFormData::AddNameValuePair(co
 nsresult
 FSMultipartFormData::AddNameBlobOrNullPair(const nsAString& aName, Blob* aBlob)
 {
   // Encode the control name
   nsAutoCString nameStr;
   nsresult rv = EncodeVal(aName, nameStr, true);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  ErrorResult error;
+
+  uint64_t size = 0;
   nsAutoCString filename;
   nsAutoCString contentType;
   nsCOMPtr<nsIInputStream> fileStream;
 
   if (aBlob) {
     nsAutoString filename16;
 
     RefPtr<File> file = aBlob->ToFile();
@@ -511,80 +530,119 @@ FSMultipartFormData::AddNameBlobOrNullPa
     }
 
     contentType.Adopt(nsLinebreakConverter::
                       ConvertLineBreaks(NS_ConvertUTF16toUTF8(contentType16).get(),
                                         nsLinebreakConverter::eLinebreakAny,
                                         nsLinebreakConverter::eLinebreakSpace));
 
     // Get input stream
-    ErrorResult error;
     aBlob->GetInternalStream(getter_AddRefs(fileStream), error);
     if (NS_WARN_IF(error.Failed())) {
       return error.StealNSResult();
     }
 
+    // Get size
+    size = aBlob->GetSize(error);
+    if (error.Failed()) {
+      error.SuppressException();
+      fileStream = nullptr;
+    }
+
     if (fileStream) {
       // Create buffered stream (for efficiency)
       nsCOMPtr<nsIInputStream> bufferedStream;
       rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
                                      fileStream, 8192);
       NS_ENSURE_SUCCESS(rv, rv);
 
       fileStream = bufferedStream;
     }
   } else {
     contentType.AssignLiteral("application/octet-stream");
   }
 
+  AddDataChunk(nameStr, filename, contentType, fileStream, size);
+  return NS_OK;
+}
+
+nsresult
+FSMultipartFormData::AddNameDirectoryPair(const nsAString& aName,
+                                          Directory* aDirectory)
+{
+  if (!Directory::WebkitBlinkDirectoryPickerEnabled(nullptr, nullptr)) {
+    return NS_OK;
+  }
+
+  // Encode the control name
+  nsAutoCString nameStr;
+  nsresult rv = EncodeVal(aName, nameStr, true);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoCString dirname;
+  nsAutoString dirname16;
+
+  ErrorResult error;
+  nsAutoString path;
+  aDirectory->GetPath(path, error);
+  if (NS_WARN_IF(error.Failed())) {
+    error.SuppressException();
+  } else {
+    dirname16 = path;
+  }
+
+  if (dirname16.IsEmpty()) {
+    RetrieveDirectoryName(aDirectory, dirname16);
+  }
+
+  rv = EncodeVal(dirname16, dirname, true);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  AddDataChunk(nameStr, dirname,
+               NS_LITERAL_CSTRING("application/octet-stream"),
+               nullptr, 0);
+  return NS_OK;
+}
+
+void
+FSMultipartFormData::AddDataChunk(const nsACString& aName,
+                                  const nsACString& aFilename,
+                                  const nsACString& aContentType,
+                                  nsIInputStream* aInputStream,
+                                  uint64_t aInputStreamSize)
+{
   //
   // Make MIME block for name/value pair
   //
   // more appropriate than always using binary?
   mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
                  + NS_LITERAL_CSTRING(CRLF);
   // XXX: name/filename parameter should be encoded per RFC 2231
   // RFC 2388 specifies that RFC 2047 be used, but I think it's not
   // consistent with the MIME standard.
   mPostDataChunk +=
          NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
-       + nameStr + NS_LITERAL_CSTRING("\"; filename=\"")
-       + filename + NS_LITERAL_CSTRING("\"" CRLF)
+       + aName + NS_LITERAL_CSTRING("\"; filename=\"")
+       + aFilename + NS_LITERAL_CSTRING("\"" CRLF)
        + NS_LITERAL_CSTRING("Content-Type: ")
-       + contentType + NS_LITERAL_CSTRING(CRLF CRLF);
+       + aContentType + NS_LITERAL_CSTRING(CRLF CRLF);
 
   // We should not try to append an invalid stream. That will happen for example
   // if we try to update a file that actually do not exist.
-  if (fileStream) {
-    ErrorResult error;
-    uint64_t size = aBlob->GetSize(error);
-    if (error.Failed()) {
-      error.SuppressException();
-    } else {
-      // We need to dump the data up to this point into the POST data stream
-      // here, since we're about to add the file input stream
-      AddPostDataStream();
+  if (aInputStream) {
+    // We need to dump the data up to this point into the POST data stream
+    // here, since we're about to add the file input stream
+    AddPostDataStream();
 
-      mPostDataStream->AppendStream(fileStream);
-      mTotalLength += size;
-    }
+    mPostDataStream->AppendStream(aInputStream);
+    mTotalLength += aInputStreamSize;
   }
 
   // CRLF after file
   mPostDataChunk.AppendLiteral(CRLF);
-
-  return NS_OK;
-}
-
-nsresult
-FSMultipartFormData::AddNameDirectoryPair(const nsAString& aName,
-                                          Directory* aDirectory)
-{
-  // TODO
-  return NS_OK;
 }
 
 nsresult
 FSMultipartFormData::GetEncodedSubmission(nsIURI* aURI,
                                           nsIInputStream** aPostDataStream)
 {
   nsresult rv;
 
@@ -672,17 +730,19 @@ FSTextPlain::AddNameBlobOrNullPair(const
   AddNameValuePair(aName, filename);
   return NS_OK;
 }
 
 nsresult
 FSTextPlain::AddNameDirectoryPair(const nsAString& aName,
                                   Directory* aDirectory)
 {
-  // TODO
+  nsAutoString dirname;
+  RetrieveDirectoryName(aDirectory, dirname);
+  AddNameValuePair(aName, dirname);
   return NS_OK;
 }
 
 nsresult
 FSTextPlain::GetEncodedSubmission(nsIURI* aURI,
                                   nsIInputStream** aPostDataStream)
 {
   nsresult rv = NS_OK;
--- a/dom/html/HTMLFormSubmission.h
+++ b/dom/html/HTMLFormSubmission.h
@@ -206,16 +206,21 @@ public:
 protected:
 
   /**
    * Roll up the data we have so far and add it to the multiplexed data stream.
    */
   nsresult AddPostDataStream();
 
 private:
+  void AddDataChunk(const nsACString& aName,
+                    const nsACString& aFilename,
+                    const nsACString& aContentType,
+                    nsIInputStream* aInputStream,
+                    uint64_t aInputStreamSize);
   /**
    * The post data stream as it is so far.  This is a collection of smaller
    * chunks--string streams and file streams interleaved to make one big POST
    * stream.
    */
   nsCOMPtr<nsIMultiplexInputStream> mPostDataStream;
 
   /**