0

Since there is no official support for Unity3d and Dropbox I'm using the HTTP API. I was able to do both the oauth2/authorize with the code flow (by using Application.OpenURL in Unity3d), and the oauth2/token Post part (so I was able to login and get the code that I got from the oauth2/authorize).

Problem is I don't really know how to upload and download files. What I tried (this code is inside a Coroutine):

Dictionary<string, string> postHeader = new Dictionary<string, string>();
postHeader.Add("Authorization", "Bearer <code>");
postHeader.Add("Dropbox-API-Arg", "{\"path\": \"/uploadtry.json\",\"mode\": \"overwrite\",\"autorename\": true,\"mute\": false}");
postHeader.Add("Content-Type", "application/octet-stream");
byte[] myData = System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(Application.persistentDataPath + "/" + "uploadtry.json"));
using (WWW www = new WWW("https://content.dropboxapi.com/2/files/upload", myData, postHeader)) {
  yield return www;
  if (www.error != null) {
    Debug.Log(www.error);
  } else {
    Debug.Log("Success! " + www.text);
  }
}

I get Error 400 from this.

Dropbox docs say

curl -X POST https://content.dropboxapi.com/2/files/upload \
--header "Authorization: Bearer <code>" \
--header "Dropbox-API-Arg: {\"path\": \"/Homework/math/Matrices.txt\",\"mode\": \"add\",\"autorename\": true,\"mute\": false}" \
--header "Content-Type: application/octet-stream" \
--data-binary @local_file.txt

I'm sure that my post is right because I've done the same for the login part. I'm sure that the bearer header is right. I'm not sure that the path part of Dropbox-API-Arg is right... my app only got access to it's own folder but I don't really know if I should always use the full path... I tried it anyway but I got the same error (I copied the path from "Applicazioni" italian for Applications created automatically after the authorization part and MyAppName... I have not tried to add /home/ to the path). I'm not sure if overwrite is compatible with autorename true. I'm not sure if I have to use application/octet-stream or application/json but I tried both and got the same Error 400.

So I think the problem can be that --data-binary. Right now I read all file text and I convert it to an array of byte... usually this works for -d (data) but maybe this is wrong for --data-binary.

I also tried to generate the access token from dropbox (the temporary solution to avoid the authorization part the only work with your own account... Because I don't know if the bearer code can expire) but this was not helpful. I still got error 400.

With download:

https://content.dropboxapi.com/2/files/download

I don't get any error. But I have no idea how to decide the download folder so I don't get any file.

https://www.dropbox.com/developers/documentation/http/documentation#files-download

I don't understand how can I specify the download folder in the (GET?)? I'm really confused.

EDIT. I tried curl from a linux terminal (at home I use Windows so I don't have curl), and I was able to upload and download with curl (I was right about the path it start from the application folder so /uploadtry.json is good. the Bearer works. overwrite is compatible with autorename true and Content-type application/octet-stream is good. Also the get only print the file so I don't really know why it didn't work with no errors (but it was late, maybe for the download the problem was an error in the code, I will try again today).

The only real difference is that in Unity I read the file as a text->convert to an array of byte->send in the body... In curl I use --data-binary @path/to/file.json Maybe it's because there is no name if I pass a simple array of bytes... I don't really know. I will update if I found a solution, but if you have an idea I appreciate.

EDIT2. Tried the download again still not working. Error 400 Bad request

from curl

curl -X POST https://content.dropboxapi.com/2/files/download     --header "Authorization: Bearer <code>" --header "Dropbox-API-Arg: {\"path\": \"/prova.json\"}"

this is working and return a string to the terminal.

on Unity3d

Dictionary<string, string> postHeader = new Dictionary<string, string>();
postHeader.Add("Authorization", "Bearer <code>");
postHeader.Add("Dropbox-API-Arg", "{\"path\": \"/prova.json\"}");
using (WWW www = new WWW("https://content.dropboxapi.com/2/files/download", null, postHeader)){
    yield return www;
    if (www.error != null){
        Debug.Log(www.error);
    }else{
        Debug.Log("Success! " + www.text);
    }
}

this is not working.

I don't really know what I'm doing wrong here.

EDIT3.

For some reason the upload code is actually working. Maybe it's the OS, or maybe it's the unity version (they updated it yesterday, but at home I'm still using the old version...) anyway, right now the only problem is that I still don't know how to download.

EDIT4.

Ok New problem. I tried with the UnityWebRequest class (that for Post does not work) and I changed to a Get (since with curl is still working. With this code the download return Success.... but with an empty file

using (UnityWebRequest www = UnityWebRequest.Get("https://content.dropboxapi.com/2/files/download"))
    {
        www.SetRequestHeader("Authorization", "Bearer <code>");
        www.SetRequestHeader("Dropbox-API-Arg", "{\"path\": \"/prova.json\"}");
        yield return www;
        if (www.error != null)
        {
            Debug.Log(www.error);
        }
        else
        {
            Debug.Log("Success! " + www.downloadHandler.data.Length);
        }
    }
LiefLayer
  • 977
  • 1
  • 12
  • 29
  • 1
    Whenever you get an error response, such as with the 400 status code you mentioned, print out the response body itself for a more specific error message. – Greg Jul 11 '18 at 17:02
  • @Programmer You should be able to get the bearer code with a simple dropbox account->create app (in the site)-> Generate. I cannot share that code because it upload everything to my personal account. Sorry. Anyway I tried the upload at home and it works (I don't really know what I did different yesterday). Now I only have to understand how to get the download working. – LiefLayer Jul 11 '18 at 17:18
  • @Greg Thank you for your suggestion – LiefLayer Jul 11 '18 at 17:22

1 Answers1

1

Ok, thanks to Greg suggesion I was able to think about something to seach on google for the download problem. Like I said the upload works (even on the 2018.1 version of Unity3d. I will upload after this post to see if 2018.2 still works). I don't really know why yesterday I was not able to upload files (maybe my code was wrong for example in the url and I didn't notice).

Anyway, for the download part I was finally able to understand what was the problem: the Content-Type. Dropbox, for the download, require an empty "" content type (but I don't see it in the docs, I was able to find this information here: Dropbox download file API stopped working with 400 error ).

From there the solution was easy. I used again the WWW class (UnityWebRequest Post is still broken for some reason), and with this code I was able to get the text of my json file (just added an header):

Dictionary<string, string> postHeader = new Dictionary<string, string>();
    postHeader.Add("Authorization", "Bearer <code>");
    postHeader.Add("Dropbox-API-Arg", "{\"path\": \"/provaupload.json\"}");
    postHeader.Add("Content-Type", "");
    using (WWW www = new WWW("https://content.dropboxapi.com/2/files/download", null, postHeader)) {
        yield return www;
        if (www.error != null) {
            Debug.Log(www.error + " " + www.text);
        } else {
            Debug.Log("Success! " + www.text);
        }
    }

Finally I can complete my save cloud solution.

LiefLayer
  • 977
  • 1
  • 12
  • 29