Trying to upload files to Cloudinary, immediately get Code 3

6 posts, 0 answers
  1. Artie
    Artie avatar
    29 posts
    Member since:
    May 2015

    Posted 18 Jun 2015 Link to this post

    I've run into an issue that is very similar to this post:

     http://www.telerik.com/forums/code-3-upload-error-on-android-4-3-when-uploading-to-s3

    We are developing an iPad app that requires us to take pictures and upload them to Cloudinary, using their REST API.  In order to accomplish this, we are trying to leverage Cordova's Camera and FileTransfer functionality.  Taking the picture works okay, but whenever we try upload the files we are immediately getting a FileTransferError with code 3, just like the post described above.  We have verified that the request is never actually issued.  This problem exists on both the simulator using the native Windows client and on the iPad itself.  According to the docs, the FileTransfer plugin is supported on the simulator for the windows client, so that's our starting point.

    Here's what we're doing:

    var ft = new FileTransfer();
    var options = new FileUploadOptions();
    var params = {
        timestamp: ts,
        signature: signature,
        api_key: apiKey
    };
    options.params = params;
    options.fileKey = "file";
    options.fileName = fileURI.substr(fileURI.lastIndexOf('/') + 1);
    options.mimeType = "image/jpeg";
    options.chunkedMode = false;
    options.headers = {
        Connection: "close"
    };
    ft.upload(fileURI, encodeURI(CLOUDINARY_URL), successCallback, failureCallback, options, false);

    No matter what I try to modify, I always seem to get a FileTransferError that looks like the following:

    {
      body: null,
      code: 3,
      exception: null,
      http_status: 408,
      source: "<image source>"
    }

    I've tried everything I've found around the web regarding similar issues, including:

    • Changing the destinationType on the camera.getPicture call to FILE_URI
    • Adding our removing the Connection header
    • Setting trustAllHosts to true and false
    • Setting chunkedMode to both true and false

    The next thing I will try is to get my FileTransfer plugin updated to version 0.5.0 (my project has 0.4.8) but as far as I can tell there were some known bugs with this stuff that supposedly got fixed many versions ago so I'm doubtful this will work.

  2. Paulo
    Paulo avatar
    1 posts
    Member since:
    Jun 2015

    Posted 19 Jun 2015 Link to this post

    did you solved this problem?
  3. Artie
    Artie avatar
    29 posts
    Member since:
    May 2015

    Posted 19 Jun 2015 Link to this post

    Not yet, still holding out for one of the admins or developers to take a look =]
  4. Tina Stancheva
    Admin
    Tina Stancheva avatar
    3298 posts

    Posted 22 Jun 2015 Link to this post

    Hello guys,

    I was also able to replicate this issue but it actually throws an "access denied" exception that basically says that the targeted Cloudinary url cannot be accessed. I checked the Cloudinary API and it seems that in order to submit a request from JavaScript, you can use their jQuery plugin. In order to avoid setting authentication, you can take advantage of their Direct unsigned upload. I tested this approach and it works as expected - but I only tested it with an <input> tag. I haven't tried integrating their jQuery API with the Cordova Camera plugin, but if you decide to test such an implementation, this post might help.

    I also found an iOS Cordova plugin, which I tested in AppBuilder and it works as expected. You can give it a try on your side as well.

    If you have any further questions on the Cloudinary API and its integration with the Cordova plugins, I would recommend posting them in the Cloudinary support channels as they should be able to provide you with more in-depth response.

    Please note that Telerik Platform also includes a cloud-based data storage and if you decide to give it a try, you can examine the file upload API described here. You can easily use the FileTransfer plugin API to upload images in the Telerik Backend Services storage.

    Regards,
    Tina Stancheva
    Telerik
     

    Visit the Telerik Verified Plugins Marketplace and get the custom Cordova plugin you need, already tweaked to work seamlessly with AppBuilder.

     
  5. Artie
    Artie avatar
    29 posts
    Member since:
    May 2015

    Posted 23 Jun 2015 in reply to Tina Stancheva Link to this post

    I eventually did manage to solve this problem using the base-64 encoding technique that Tina mentioned.  The solution is posted below, although I have some follow-up questions below the solution.

     The fundamental problem to get around when using pure Javascript to upload a file is that you are not allowed to directly modify the value of an <input type="file">, and in my case I don't have one of these inputs that the user can click on, nor do I have drag/drop support since we're using an app.  What we want to do is simply take a picture with the camera and then upload it to a server, I think the fact that we're using Cloudinary is irrelevant at least in terms of the issue.

    The first step is to have your camera return your image as base-64 encoded data, instead of a file URI:

    navigator.camera.getPicture(successFunction, errorFunction, {
        destinationType: navigator.camera.DestinationType.DATA_URL
    });

    You can then use the technique specified in one of Tina's links to bolt the encoded image onto the uploader:

    var params = {
        timestamp: ts,
        signature: signature,
        api_key: apiKey
    };
     
    // You will need to add the base-64 encoding prefix to the encoded string you get back from the camera for this to work
    var encodedFileData = "data:image/jpeg;base64," + imageData;
     
    var input = $("#fileUpload");
    input.attr("data-form-data", JSON.stringify(params));
    input.bind("fileuploaddone", function(e, data) {
        successCallback(data);
    });
    input.cloudinary_fileupload();
    input.fileupload('option', 'formData').file = encodedFileData;
    input.fileupload('add', { files: [ encodedFileData ] });

    What wasn't immediately obvious to me based on the Cloudinary documentation was exactly how to physically trigger the upload when doing this without user interaction, it turns out that the last line with the "add" command is what actually triggers it.  This functionality is exposed by the underlying jQuery FileUpload plugin:

    https://github.com/blueimp/jQuery-File-Upload/wiki/API#programmatic-file-upload

    Based on the docs I didn't think that both the "options" and the "add" call to .fileupload() were both needed, but it turns out that they are...Cloudinary will complain if you are missing the "options".file property but the upload won't actually start until you invoke "add".

    I'm still not sure why the FileTransfer method didn't work, I intend on exploring that further once I have the time.  The puzzling part to me was why the FileTransfer plugin never even tried to physically make a request, if it had at least attempted a connection to Cloudinary I would have been able to figure out the issues from there.  I will also try to perform the exact same call except to a Telerik cloud storage instance, but my instincts are telling me I will see the same problem.

  6. Tina Stancheva
    Admin
    Tina Stancheva avatar
    3298 posts

    Posted 26 Jun 2015 Link to this post

    Hello Artie,

    I am still not sure why the FileTransfer plugin can't make the request but I suppose that the native implementation of the plugin doesn't match the Cloudinary requirements for a post request from a native mobile API.

    As for using the FileTransfer plugin to upload the files in the Telerik Backend Services file storage, you shouldn't have any troubles with that. Still if you do have any questions or issues on that front, don't hesitate to let us know.

    Regards,
    Tina Stancheva
    Telerik
     

    Visit the Telerik Verified Plugins Marketplace and get the custom Cordova plugin you need, already tweaked to work seamlessly with AppBuilder.

     
Back to Top