- Home /
WWW, WWWForm and SoundCloud
I am trying to upload a file to SoundCloud with the WWW class. When i run the code below i get a response '400 Bad Request'. Can someone tell me why or give me some hints what to look for?
Is it even possible to use the WWW class for this?
EDIT: I looked a bit with Fiddler. I get the following message when running the code: 'Content-Length mismatch: Request Header indicated 208.662 bytes, but client sent 0 bytes.'
public IEnumerator UploadFileWebClient(FileInfo file)
{
byte[] fileContents = File.ReadAllBytes(file.FullName);
WWWForm form = new WWWForm();
form.AddField("track[title]", "Some title", System.Text.Encoding.UTF8);
form.AddField("track[sharing]", "private", System.Text.Encoding.UTF8);
form.AddField("oauth_token", soundCloudToken, System.Text.Encoding.UTF8);
form.AddField("format", "json", System.Text.Encoding.UTF8);
form.AddBinaryData("track[asset_data]", fileContents, "0.wav", "application/octet-stream");
foreach(var header in form.headers)
{
Debug.Log ("Header: " + header);
}
WWW download = new WWW("https://api.soundcloud.com/tracks", form);
yield return download;
if(!string.IsNullOrEmpty(download.error))
{
Debug.Log ( "Error downloading: " + download.error );
}
else
{
Debug.Log(download.text);
}
}
UPDATE: the SoundCloud token request (just for the completeness of the question):
public IEnumerator GetTokenAndUploadFile(MonoBehaviour mono, FileInfo file)
{
Debug.Log ( "GetTokenAndUploadFile() started");
ServicePointManager.ServerCertificateValidationCallback = (p1, p2, p3, p4) => true;
var form = new WWWForm ();
form.AddField ("client_id", _clientId);
form.AddField ("client_secret", _clientSecret);
form.AddField ("grant_type", "password");
form.AddField ("username", _username);
form.AddField ("password", _password);
//Authentication
string soundCloudTokenRes = "https://api.soundcloud.com/oauth2/token";
Debug.Log ( "Try to get token");
WWW download = new WWW(soundCloudTokenRes, form);
yield return download;
if(!string.IsNullOrEmpty(download.error))
{
Debug.Log ( "Error downloading: " + download.error );
}
else
{
var tokenInfo = download.text;
tokenInfo = tokenInfo.Remove(0, tokenInfo.IndexOf("token\":\"") + 8);
soundCloudToken = tokenInfo.Remove(tokenInfo.IndexOf("\""));
Debug.Log(string.Format("Token set: {0}", soundCloudToken));
}
}
Answer by hanger · May 18, 2015 at 06:13 AM
A 400 response means the server got the request, but there was something wrong with the format. Usually the response tells you more, but Unity won't let you access the response on anything but a 200. Anyway, as far as I can see, there are two problems.
You need to specify the token in an Authorization header.
You're sending the wrong verb; POST when you want a PUT.
Dictionary<string, string> headers = new Dictionary<string, string>(); headers.Add("Authorization", "Bearer " + token); headers.Add("X-HTTP-Method-Override", "PUT"); WWW download = new WWW(same_url, form, headers);
Bearer is an OAuth thing. Make sure you get a "token" and not a "code"; a "code" is just used to retrieve a token via a server. (I don't think there's any worry of injection attacks here.)
HTTP has several different verbs; ways to call a url. Soundcloud uses GET, POST, PUT and DELETE. The WWW class only supports GET and POST, and you can't set headers for GET. To get around stupid limitations like Unity's WWW class has, SoundCloud supports the fairly common nonstandard header X-HTTP-Method-Override. The value for that header should be the (capitalized) verb you want to use.
You need to use System.Collections.Hashtable instead of System.Collections.Generic.Dictionary<string, string> in older versions of Unity.
Thanks for the response! I'll have a look at it tonight
I can't get it to work, below the code as i have it now.
I have used the token before with other code (http://answers.unity3d.com/questions/966462/webrequest-receives-400-bad-request-on-android.html), it was working here. $$anonymous$$aybe the link will give you some more information about the things i have tried
In that code i use POST. I also tried POST in the code you provided but also didn't work.
public IEnumerator UploadFileWebClient(FileInfo file)
{
ServicePoint$$anonymous$$anager.Expect100Continue = false;
byte[] fileContents = File.ReadAllBytes(file.FullName);
WWWForm form = new WWWForm();
form.AddField("track[title]", "Some title");
form.AddField("track[sharing]", "private");
//form.AddField("oauth_token", soundCloudToken, System.Text.Encoding.UTF8);
form.AddField("format", "json");
form.AddBinaryData("track[asset_data]", fileContents, "3.wav", "application/octet-stream");
Dictionary<string, string> headers = new Dictionary<string, string>();
headers.Add("Authorization", "Bearer " + soundCloudToken);
headers.Add("X-HTTP-$$anonymous$$ethod-Override", "PUT");
//I don't know if this is needed. Doesn't work with or without it.
foreach(var header in form.headers)
{
headers.Add(header.$$anonymous$$ey, header.Value);
}
WWW download = new WWW("https://api.soundcloud.com/tracks", form.data, headers);
yield return download;
if(!string.IsNullOrEmpty(download.error))
{
Debug.Log ( "Error downloading: " + download.error );
}
else
{
Debug.Log(download.text);
}
}
Below the code of the token:
ServicePoint$$anonymous$$anager.ServerCertificateValidationCallback = (p1, p2, p3, p4) => true;
//Authentication data
string postData = "client_id=" + _clientId
+ "&client_secret=" + _clientSecret
+ "&grant_type=password&username=" + _username
+ "&password=" + _password;
//Authentication
string soundCloudTokenRes = "https://api.soundcloud.com/oauth2/token";
string tokenInfo = _webclient.UploadString(soundCloudTokenRes, postData);
//Parse the token
tokenInfo = tokenInfo.Remove(0, tokenInfo.IndexOf("token\":\"") + 8);
soundCloudToken = tokenInfo.Remove(tokenInfo.IndexOf("\""));
Do you think Wireshark/Fiddler could give me some more useful information? I tried looking around but i'm not that experienced with the requests/responses
For my original code (as posted in my question): If i remove the 'form.AddBinaryData(...);' it gives me other errors. For example: If i remove the token 'form.AddField("oauth_token", soundCloudToken);' it gives me an unauthorized exception. With the 'oauth_token' i get some other exception (so it seems to accept the token). Whenever i add the 'form.AddBinaryData(...);' line i get '400 Bad Request' (with or without the 'oauth_token').
If you want me to rephrase this let me know ;)