1

I'm trying to upload an image to the PushBullet API with retrofit.

After the upload-request I fire the multipart upload.

With retrofit I get this error:

{"error":{"code":"invalid_request","type":"invalid_request","message":"Invalid multipart body.","cat":"o(^・x・^)o"},"error_code":"invalid_request"}

The problem only occurs in my java code and not with the PAW HTTP-Client.

# PAW generated Request
POST /upload-legacy/bcSWXnBjNIwpkej7CxfIHFz0ugXO6yhf HTTP/1.1
Content-Type: multipart/form-data; charset=utf-8; boundary=__X_PAW_BOUNDARY__
Host: upload.pushbullet.com
Connection: close
User-Agent: Paw/3.0.12 (Macintosh; OS X/10.11.6) GCDHTTPRequest
Content-Length: 34508

--__X_PAW_BOUNDARY__
Content-Disposition: form-data; name="file"; filename="cat.jpg"
Content-Type: image/jpeg

...

# Retrofit generated Request
POST https://upload.pushbullet.com/upload-legacy/ZZ4fLcqt2WFQmlbKTDlgcYXtB3KiCs3M http/1.1
Content-Type: multipart/form-data; charset=utf-8
Content-Length: 2012
Content-Disposition: form-data; name="file"; filename="1475501429665_motion_detected.jpg"
Content-Type: image/jpeg; charset=utf-8
Content-Length: 1772

...

The important difference I think is the Content-Length in the Part. I found this issue, but that would mean the PushBullet API is non-compliant with the HTTP specification?

Any help would be appreciated.

Cir0X
  • 446
  • 4
  • 11
  • 1
    The only thing that stands out to me is that the Content-Length is significantly smaller in your Retrofit upload attempt. I would try using the same jpg for both methods to rule out that as an issue. – Simon Trigona Oct 03 '16 at 21:20
  • @Trigona That's right, because I've send a significant smaller image with Retrofit :) – Cir0X Oct 03 '16 at 21:23

1 Answers1

0

I was experiencing this same issue in Google Apps Script, which is JavaScript based, but I'm hoping my solution could help anyone else experiencing this issue. I used TANAIKE's method of building the multipart request here: https://gist.github.com/tanaikech/d595d30a592979bbf0c692d1193d260c

My successful end result looked like this for successfully uploading a JPEG:


    // https://docs.pushbullet.com/v8/#upload-request
    // Assuming var picResponseJSON is your JSON results from successful upload-request
    var uploadJSON = {
      awsaccesskeyid: picResponseJSON.data.awsaccesskeyid,
      acl: picResponseJSON.data.acl,
      key: picResponseJSON.data.key,
      signature: picResponseJSON.data.signature,
      policy: picResponseJSON.data.policy,
      "content-type": picResponseJSON.data["content-type"],
    };

    // https://gist.github.com/tanaikech/d595d30a592979bbf0c692d1193d260c
    var boundary = "xxxxxxxxxx";
    var data = "";
    for (var i in uploadJSON) {
      data += "--" + boundary + "\r\n";
      data +=
        'Content-Disposition: form-data; name="' +
        i +
        '"; \r\n\r\n' +
        uploadJSON[i] +
        "\r\n";
    }
    data += "--" + boundary + "\r\n";
    data +=
      'Content-Disposition: form-data; name="file"; filename="' +
      fileTitle +
      '"\r\n';
    data += "Content-Type:" + mimeType + "\r\n\r\n";
    var payload = Utilities.newBlob(data)
      .getBytes()
      .concat(DriveApp.getFileById(fileID).getBlob().getBytes())
      .concat(Utilities.newBlob("\r\n--" + boundary + "--").getBytes());
    var options3 = {
      method: "post",
      contentType: "multipart/form-data; boundary=" + boundary,
      payload: payload,
      muteHttpExceptions: true,
    };

    // Send request
    var uploadResponse = UrlFetchApp.fetch(picResponseJSON.upload_url, options3);

    // Confirm it's successful
    if (uploadResponse.getResponseCode() == 204) {
      console.log("Success! File: " + picResponseJSON.file_url);
    }

Please note the Blob functions in the payload are part of Google Apps Script so modify accordingly for your language.

rjmccallumbigl
  • 385
  • 4
  • 10