15
$\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$
  • $\begingroup$ I already have working code. The HTML snippet is what I am trying to mimic in URLExecute. $\endgroup$ – Simon O'Doherty Oct 18 '15 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$ – Simon O'Doherty Oct 21 '15 at 5:39
  • $\begingroup$ The mime type of JPEG files is image/jpeg, not file. Try changing that. $\endgroup$ – C. E. Oct 22 '15 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$ – Simon O'Doherty Oct 22 '15 at 5:54
  • $\begingroup$ Specifying text I instead of Jpeg image data does nothing either. $\endgroup$ – Simon O'Doherty Oct 22 '15 at 5:56
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$
  • 1
    $\begingroup$ That's a nice, timely hack! +1 $\endgroup$ – C. E. Oct 24 '15 at 21:38
  • $\begingroup$ This worked perfectly! but I clicked bounty on the wrong person! :( $\endgroup$ – Simon O'Doherty Oct 25 '15 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. Oct 25 '15 at 11:37
  • $\begingroup$ Cheers for that. :) $\endgroup$ – Simon O'Doherty Oct 25 '15 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 Oct 14 '16 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$
  • $\begingroup$ Thanks. If you changed it to "MultipartData"->{{"image", "multipart/form-data" , Import["test.jpg", "Byte"]}} Do you still get the same results? $\endgroup$ – Simon O'Doherty Oct 23 '15 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. Oct 23 '15 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$ – Christopher Haydock Oct 29 '15 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. Oct 29 '15 at 18:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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