16
$\begingroup$

I have to submit a form like as follows:

<input type="file" name="jpgFile">

I can't seem to find any instructions on sending this in URLExecute. If I specify the file name as the parameter it fails. If I try Import[filename, "JPG"] of the image it also fails as invalid.

I thought his might work, but I get an error "Iteration limit of 4096 exceeded". This suggests it might be working as test file is 451,107 bytes.

URLExecute[ url,
 "Method" -> "POST",
 "Headers" -> {
   "Accept" -> "application/json; charset=UTF-8"
   },
 "MultipartElements" -> { 
   {"jpgFile", "file"} -> "test.jpg"
  }
 ]

So this is another example. In this instance I am sending a text file and this appears to work.

testData = Import["test.txt","Text"];

URLExecute[
 url,
 "Method" -> "POST",
 "Headers" -> {
   "Accept" -> "application/json; charset=UTF-8"
   },
 "MultipartElements" -> { 
   {"textData", "text/plain"} -> testData
   }
 ]

From a Java point of view, the following actually works: https://stackoverflow.com/a/17174260/1167890

I would like not to be forced back into Java/MathLink if possible though.

$\endgroup$
7
  • $\begingroup$ I already have working code. The HTML snippet is what I am trying to mimic in URLExecute. $\endgroup$ Commented Oct 18, 2015 at 21:34
  • $\begingroup$ It should send a jpeg file via a POST to a REST service. I posted further code where sending a text file works. I've also tried sending a Import["test.jpg","JPEG"] but I get errors. $\endgroup$ Commented Oct 21, 2015 at 5:39
  • $\begingroup$ The mime type of JPEG files is image/jpeg, not file. Try changing that. $\endgroup$
    – C. E.
    Commented Oct 22, 2015 at 3:01
  • $\begingroup$ You end up with: The value {{jpgFile,image/jpeg}->Image[RawArray[Byte,<56,75,3>],Byte,<<1>>,<<12>>->True,MetaInformation->{Exif->{ImageWidth->4288,ImageLength->2848,BitsPerSample->{<<3>>},Make->NIKON CORPORATION,<<43>>,FocalLengthIn35mmFilm->34,SceneCaptureType->0,GainControl->1,<<5>>}}]} specified for the option MultipartElements is invalid. $\endgroup$ Commented Oct 22, 2015 at 5:54
  • $\begingroup$ Specifying text I instead of Jpeg image data does nothing either. $\endgroup$ Commented Oct 22, 2015 at 5:56

2 Answers 2

12
+100
$\begingroup$

As pointed out yesterday by ZachB in answer to another question, there is a hack that makes URLFetch add a filename to the Content-Disposition header as required by RFC 7578 multipart/form-data section 4.2:

URLFetch[url,
    "Method"->"POST",
    "MultipartElements"->{
        {"file\"; filename=\"test.jpg","image/jpeg"}->
            Import["test.jpg", "String"]
     }
]

Here, the Multipart element name is "file" but URLFetch is tricked into adding the filename "test.jpg" by hiding it within a longer element name.

$\endgroup$
9
  • 1
    $\begingroup$ That's a nice, timely hack! +1 $\endgroup$
    – C. E.
    Commented Oct 24, 2015 at 21:38
  • $\begingroup$ This worked perfectly! but I clicked bounty on the wrong person! :( $\endgroup$ Commented Oct 25, 2015 at 6:20
  • $\begingroup$ @SimonO'Doherty I have started a bounty to correct this, I just have to wait 24 hours before I can give it away. $\endgroup$
    – C. E.
    Commented Oct 25, 2015 at 11:37
  • $\begingroup$ Cheers for that. :) $\endgroup$ Commented Oct 25, 2015 at 11:38
  • 1
    $\begingroup$ @ChristopherHaydock Sorry, I posted without testing... The Wolfram HTTPClient is using expect: "100-continue", which is not supported by many common load balancers, proxies and other things that might be between you and your server. No browsers use this header. I just tested this with and without a load balancer that does not support "expect 100" and confirmed that it breaks. I've filed a ticket with Wolfram Support. Yet another annoying part of the URLFetch/URLExecute/URLRead changes. $\endgroup$
    – ZachB
    Commented Oct 14, 2016 at 3:07
4
+100
$\begingroup$

This is a comment that is too long to post as a comment. I have marked it community wiki for this reason. Whether I am right or not in my conclusion, it is probably appropriate to report this to WRI as a bug to know for sure. Christopher's answer pretty much confirms that this is a bug in Mathematica, that can only be worked around with an undocumented hack.


Here is a simple PHP script that I created to compare the request generated by a form and the request generated by Mathematica:

<html>
<h1>Form</h1>
<form method="POST" action="<?php echo $_SERVER['PHP_SELF']; ?>" enctype="multipart/form-data">
    <p><input type="file" name="jpgFile"></p>
    <p><input type="submit"></p>
</form>

<h1>Files</h1>
<pre>
<?php
print_r($_FILES);
?>
</pre>

<h1>Request data</h1>
<pre>
<?php
print_r($_REQUEST);
?>
</pre>

<h1>Request meta information</h1>
<pre>
<?php
print_r($_SERVER);
?>
</pre>
</html>

Mathematica code:

SystemOpen@Export["~/Desktop/test.html", URLFetch[
   "http://localhost:8080/upload.php",
   "Method" -> "POST",
   "MultipartElements" -> {
     {"image", "image/jpeg"} -> ExportString[jpgFile, "JPEG"]
     }], "Text"]

The content type of the request is multipart/form-data as it should be, but instead of sending the file as a file, it sends it as a parameter. That is, it shows up in $_REQUEST instead of $_FILES; this will never work regardless of what you do on your end.

The only options I believe are to either build your own procedure that uses Java (or another external tool) like you did, or use a workaround that sends the image as a string. But for those kinds of workarounds you need to have access to the backend so that you can decode the string on the server. For example I recently wrote a Mathematica code that uploaded images by first encoding them as base64 strings and then sending them as string parameters:

ExportString[Import["~/Desktop/example.png", "String"], "Base64"];
$\endgroup$
4
  • $\begingroup$ Thanks. If you changed it to "MultipartData"->{{"image", "multipart/form-data" , Import["test.jpg", "Byte"]}} Do you still get the same results? $\endgroup$ Commented Oct 23, 2015 at 17:08
  • $\begingroup$ @SimonO'Doherty I get error messsages, I can't evaluate that. However I can say that the data is submitted correctly with the header Content-type set to multipart/form-data for the version that is in my post. It's just that for some reason the file is not sent as a file. I can also say that I tried it that but with the image represented by bytes and it didn't work. $\endgroup$
    – C. E.
    Commented Oct 23, 2015 at 18:36
  • $\begingroup$ I'm not familiar with simple PHP script and Mathematica code combinations like that you created in your answer. Would it be correct to assume that upload.php in the URLFetch first argument of your Mathematica code block is in fact the PHP script in your PHP code block? I'm also guessing that with the URLFetch hack present the JPG image file shows up in both dollar-sign_REQUEST and dollar-sign_FILES, instead of just in the dollar-sign_REQUEST variable. Correct? $\endgroup$ Commented Oct 29, 2015 at 18:12
  • $\begingroup$ @ChristopherHaydock Yes, correct, upload.php is the code I have given. Wen it works correctly, as it does with the hack, the file only shows up in the array $_FILES. $\endgroup$
    – C. E.
    Commented Oct 29, 2015 at 18:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.