I tried uploading a file to skydrive with the rest api in java.
Here is my code:
public void UploadFile(File upfile) {
if (upload_loc == null) {
getUploadLocation();
}
HttpClient client = new DefaultHttpClient();
client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
HttpPost post = new HttpPost(upload_loc + "?" + "access_token=" + access_token);
try {
MultipartEntity mpEntity = new MultipartEntity(null,"A300x",null);
ContentBody cbFile = new FileBody(upfile, "multipart/form-data");
mpEntity.addPart("file", cbFile);
post.setEntity(mpEntity);
System.out.println(post.toString());
HttpResponse response = client.execute(post);
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line2 = "";
while ((line2 = rd.readLine()) != null) {
System.out.println(line2);
}
} catch (IOException ex) {
Logger.getLogger(Onlab.class.getName()).log(Level.SEVERE, null, ex);
}
client.getConnectionManager().shutdown();
}
But when I try to run it, I get this error:
{
"error": {
"code": "request_body_invalid",
"message": "The request entity body for multipart form-data POST isn't valid. The expected format is:\u000d\u000a--[boundary]\u000d\u000aContent-Disposition: form-data; name=\"file\"; filename=\"[FileName]\"\u000d\u000aContent-Type: application/octet-stream\u000d\u000a[CR][LF]\u000d\u000a[file contents]\u000d\u000a--[boundary]--[CR][LF]"
}
}
My biggest problem is that I don't see the request itself. I couldn't find any usable toString method for that. I tried this forced boundary format, but I tried it with empty constructor too.
My file is now a txt with some text, and I think the boundary is the main problem or I should be configuring some more parameters. When I see the variables in debugging mode everything looks the same as a guide in the msdn.
I'm new in the rest world and if it possible I want to keep this apache lib with the simple to use HttpClient and HttpPost classes.
Thanks in advance, and sorry for my english.
EDIT:
Ok, after a long sleep I decided to try the PUT method instead of POST. The code work fine with minimal changes:
public void UploadFile(File upfile) {
if (upload_loc == null) {
getUploadLocation();
}
HttpClient client = new DefaultHttpClient();
client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
String fname=upfile.getName();
HttpPut put= new HttpPut(upload_loc +"/"+fname+ "?" + "access_token=" + access_token);
try {
FileEntity reqEntity=new FileEntity(upfile);
put.setEntity(reqEntity);
HttpResponse response = client.execute(put);
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line2 = "";
while ((line2 = rd.readLine()) != null) {
System.out.println(line2);
}
} catch (IOException ex) {
Logger.getLogger(Onlab.class.getName()).log(Level.SEVERE, null, ex);
}
client.getConnectionManager().shutdown();
}
But there is no answer for the first question yet.
Two quick things:
You should not be using the overloaded MultipartEntity constructor unless you really need to. In this case you are setting the charset to null, which is probably not a good idea. Also, your boundary delimiter is not complex enough.
Your file body content type should reflect the content of the actual file being uploaded. `multipart-formdata is normally used for HTML form data, not files. You should change this to 'text/plain', or 'image/jpeg', or whatever reflects the true mime type of the file.
Some great tools for debugging REST requests - REST Console (Chrome), REST Client (Firefox).
Some quick notes on the error message you received, it actually has quite a bit of detail. The service is expecting the following parameters to be set for the file part being sent:
name:
filename:
Content-Type: application/octet-stream
You can have the HTTP client set most of these with this code:
ContentBody cbFile = new FileBody(
upfile,
"yourFileNameHere",
"application/octet-stream",
"UTF-8");
Related
I'm currently using RT 4.4.3 in a project and I'm trying to create a new ticket with an attachment, using Java code.
I tried to follow the instructions provided by this BestPractical resource hosted on GitHub and specified in this list of pulls.
The code fragment that tries to perform the operation is the following:
PostMethod mPost = new PostMethod(TicketListConstants.SEGNALAZIONI_RTIR_URI + "/ticket");
mPost.setRequestHeader("Content-type", "application/json");
mPost.setRequestHeader("Authorization", TicketListConstants.SEGNALAZIONI_RTIR_TOKEN);
/*String json = ;
NameValuePair[] data = {
new NameValuePair("content", json)
};*/
UploadPortletRequest uploadRequest = PortalUtil.getUploadPortletRequest(request);
File file = uploadRequest.getFile("fileName");
String filename = uploadRequest.getFileName("fileName");
byte[] filecontent = this.encodeBase64(file);
mPost.setRequestBody("{ \"Queue\": \"Infosharing\", \"Subject\": \""+subject+"\",\"From\":\""+currentUser.getEmailAddress()+"\",\"To\":\"test#liferay.com\",\"Owner\":\""
+currentUser.getEmailAddress()+"\",\"Requestor\":\""+currentUser.getEmailAddress()+"\",\"Content\":\""+description+"\",\"AttachmentsContents\":[{\"FileName\":\""+filename+"\",\"FileType\":\"application/pdf\",\"FileContent\":\""+filecontent+"\"}]}");
HttpClient cl = new HttpClient();
String result = "";
String newId = "";
try {
cl.executeMethod(mPost);
result = mPost.getResponseBodyAsString();
if (result != null) {
JSONObject json = null;
try {
json = JSONFactoryUtil.createJSONObject(result);
} catch (JSONException e) {
_log.error("Error extracting ticket info: "+e.getMessage());
}
newId = json.getString("id");
}
} catch (UnsupportedEncodingException e){
_log.error("Error in searching tickets: "+e.getMessage());
} catch (IOException io) {
_log.error("Error in searching tickets: "+io.getMessage());
}
So the JSON I'm sending to RT is the following:
{ "Queue": "Infosharing", "Subject": "Tutto in uno","From":"test#liferay.com","To":"test#liferay.com","Owner":"test#liferay.com","Requestor":"test#liferay.com","Content":"Aggiungo tutto in un solo passaggio","AttachmentsContents":[{"FileName":"prova.txt","FileType":"plain/text","FileContent":""}]}
The problem is that the ticket is correctly created but no attachment is added.
I also tried to perform the same using SOAPUI but no attachment is added to the ticket even if the response is without any error.
Could somebody help me what I'm doing wrong?
EDIT 2019-06-10: since it seems that, as reported here, at least till the end of December 2018:
CREATING ATTACHMENTS Currently RT does not allow creating attachments
via their API.
See https://rt-wiki.bestpractical.com/wiki/REST#Ticket_Attachment
but it should be possible, as a temporary workaround, to post attachments to ticket's comments, can anybody help finding a solution to this problem?
Since I cannot test your code, I suggest you to use HttpClient 4, I provide below a sample code snippet. Modify the code as per your requirement and try to check.
HttpPost post = new HttpPost("http://rtserver.com");
FileBody fileBody = new FileBody(file, ContentType.DEFAULT_BINARY);
StringBody stringBody1 = new StringBody("Message 1", ContentType.MULTIPART_FORM_DATA);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addPart("upfile", fileBody);
builder.addPart("text1", stringBody1);
HttpEntity entity = builder.build();
post.setEntity(entity);
HttpResponse response = client.execute(post);
I am making desktop app in java for instagram right now and i don't know how to get code from callback url. My app is desktop so my REDIRECT-URI is http://instagram.com. So in my app i send a request to https://api.instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=REDIRECT-URI&response_type=code and get redirected to instagram.com?code=CODE. And also forgot to mention, I get a code once by my hands a i gave all permissions. So now then i make request i redirected straightly to URL with code.
How do i get code from callback uri in program in java? This is my code:
static void GetCode()
{
try {
String url = "https://api.instagram.com/oauth/authorize/?client_id=" + ClientId + "&redirect_uri=" + BackUri + "&response_type=code&scope=likes+comments+relationships";
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request);
BufferedReader rd = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
StringBuffer result = new StringBuffer();
String line = "";
while ((line = rd.readLine()) != null) {
result.append(line);
}
System.out.println(result.toString());
}
catch(Exception e)
{
System.out.print("GET CODE ERROR->"+e.toString());
}
}
Change REDIRECT_URI to http://localhost. So the actual 'redirection' code should be done on your side. And you can parse value of argument code. Also look at the answers to this question. This will help you to grab URI with the code.
I am using Apache client libs for http client to post some data to my server.
Below is the code, I get the status line response, but I am not getting the contents.
But on wireshark I could see server is responding the with few contents, such content type, location etc. for my code I am getting the following output.
Status :: HTTP/1.1 201 Created Content null
Pls help me to find out where I have gone wrong to read the content , do I need to some proxy related settings ?
HttpClient client = new DefaultHttpClient();
String line = ""; String status = "";
HttpPost post = new HttpPost("http://127.0.0.1/msg");
try {
HttpEntity e = new StringEntity("POSTING TO SERVER FOR TESTING");
post.setEntity(e);
HttpResponse response = client.execute(post);
BufferedReader rd = new BufferedReader(new
InputStreamReader(response.getEntity().getContent()));
status = response.getStatusLine().toString() ;
while ((line = rd.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(" Status :: "+ status + " Content " + line);
The reason for Status :: HTTP/1.1 201 Created Content null is because the last value assigned to line is null (it's how you broke out of the loop). The response may not have any content. You can use the API to examine the headers as you need
Take a look at How to get headers? (java,httpclient 4.X) for an example
I am testing the uploading of files to a dataset on CKAN / datahub.io through a Java client of the API.
public String uploadFile()
throws CKANException {
String returned_json = this._connection.MultiPartPost("", "");
System.out.println("r: " + returned_json);
return returned_json;
}
and
protected String MultiPartPost(String path, String data)
throws CKANException {
URL url = null;
try {
url = new URL(this.m_host + ":" + this.m_port + path);
} catch (MalformedURLException mue) {
System.err.println(mue);
return null;
}
String body = "";
HttpClient httpclient = new DefaultHttpClient();
try {
String fileName = "D:\\test.jpg";
FileBody bin = new FileBody(new File(fileName),"image/jpeg");
StringBody comment = new StringBody("Filename: " + fileName);
MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("bin", bin);
reqEntity.addPart("comment", comment);
HttpPost postRequest = new HttpPost("http://datahub.io/api/storage/auth/form/2013-01-24T130158/test.jpg");
postRequest.setEntity(reqEntity);
postRequest.setHeader("X-CKAN-API-Key", this._apikey);
HttpResponse response = httpclient.execute(postRequest);
int statusCode = response.getStatusLine().getStatusCode();
System.out.println("status code: " + statusCode);
BufferedReader br = new BufferedReader(
new InputStreamReader((response.getEntity().getContent())));
String line;
while ((line = br.readLine()) != null) {
body += line;
}
System.out.println("body: " + body);
} catch (IOException ioe) {
System.out.println(ioe);
} finally {
httpclient.getConnectionManager().shutdown();
}
return body;
}
2 responses I get to my POST request:
a 413 error ("request entity too large") when the jpeg I try to upload is 2.83 Mb. This disappears when I shrink the file to a smaller size. Is there a limit to file size uploads?
a 500 error ("internal server error"). This is where I am stuck. It might have to do with the fact that my dataset on datahub.io is not "datastore enabled"? (I see a disabled "Data API" button next to my resource files in the dataset, with a tooltip saying:
"Data API is unavailable for this resource as DataStore is disabled"
=> is it a possible reason for this 500 error? If so, how could I enable it from the client side? (pointers to Python code would be useful!)
Thx!
PS: the dataset I am using for testing purposes: http://datahub.io/dataset/testapi
Only someone with access to the exception log could tell you why the 500 is occurring.
However, I'd check your request is the same as what you'd get from the python client that was written alongside the datastore: https://github.com/okfn/ckanclient/blob/master/ckanclient/init.py#L546
You're sending the "bin" image buffer and "comment" file_key in your multipart request. Note the file_key must be changed for every upload, so add in a timestamp or something. And maybe you need to add in a Content-Type: for the binary.
I have been going through the same kind of troubles as the poster of this question. After quite a bit of trial and error, I came up with a solution to the problem. In my case, I had some control over the CKAN repository that I wanted to upload to. If you don't, your problem might be impossible to solve...
I assume you are using the 1.8 version of CKAN?
First of all, check whether the CKAN repository has been set up to allow file upload and if not, configure it to allow that. This can be done on the server using the steps posted here: http://docs.ckan.org/en/ckan-1.8/filestore.html#local-file-storage
The 413 error that you mentioned should be adressed next. This has to do with the general configuration of the server. In my case, the CKAN was hosted through nginx. I added a "client_max_body_size 100M" line to the nginx.conf file. See this post for instance: http://recursive-design.com/blog/2009/11/18/nginx-error-413-request-entity-too-large/
Then there is only the 500 error left. At the time of this writing, the api documentation of CKAN is still a little immature... It does indeed say that you have to build a request like you have made for file upload. However, this request is just to ask for permission for the file upload. If your credentials check out for file upload (not every user may be allowed to upload files), the response holds an object telling you where to send your file to... Because of the unclear api, you ended up merging these two requests.
The following scenario shows a follow up of two requests to handle the file upload. It might be that some steps in the scenario work out differently in your case, because of a repository that has been set up a little differently. If you get error messages, please be sure to check the response's body for clues!
Here is the authentication request that I used:
String body = "";
String generatedFilename=null;
HttpClient httpclient = new DefaultHttpClient();
try {
// create new identifier for every file, use time
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyyMMMddHHmmss");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
String date=dateFormatGmt.format(new Date());
generatedFilename=date +"/"+filename;
HttpGet getRequest = new HttpGet(this.CKANrepos+ "/api/storage/auth/form/"+generatedFilename);
getRequest.setHeader(CKANapiHeader, this.CKANapi);
HttpResponse response = httpclient.execute(getRequest);
int statusCode = response.getStatusLine().getStatusCode();
BufferedReader br = new BufferedReader(
new InputStreamReader((response.getEntity().getContent())));
String line;
while ((line = br.readLine()) != null) {
body += line;
}
if(statusCode!=200){
throw new IllegalStateException("File reservation failed, server responded with code: "+statusCode+
"\n\nThe message was: "+body);
}
}finally {
httpclient.getConnectionManager().shutdown();
}
Now, if all goes well, the server responds with a json object holding the parameters to use when doing the actual file upload. In my case, the object looked like:
{file_key:"some-filename-to-use-when-uploading"}
Be sure to check the json object though, as I'm given to understand that there may be custom ckan repositories that require more or different parameters.
These responses can then be used in the actual file upload:
File file = new File("/tmp/file.rdf");
String body = "";
HttpClient httpclient = new DefaultHttpClient();
try {
FileBody bin = new FileBody(file,"application/rdf+xml");
MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("file", bin);
reqEntity.addPart("key", new StringBody(filename));
HttpPost postRequest = new HttpPost(this.CKANrepos+"/storage/upload_handle");
postRequest.setEntity(reqEntity);
postRequest.setHeader(CKANapiHeader, this.CKANapi);
HttpResponse response = httpclient.execute(postRequest);
int statusCode = response.getStatusLine().getStatusCode();
BufferedReader br = new BufferedReader(
new InputStreamReader((response.getEntity().getContent())));
String line;
while ((line = br.readLine()) != null) {
body += line;
}
if(statusCode!=200){
getWindow().showNotification("Upload Statuscode: "+statusCode,
body,
Window.Notification.TYPE_ERROR_MESSAGE);
}
}finally {
httpclient.getConnectionManager().shutdown();
}
as you can see, the file_key property has now been transformed into the simple 'key' property. I don't know why.
This will get your file uploaded. The response to this upload request will hold a json object telling you where the file got uploaded to. edit: actually it seems that my ckan responded with a simple html page to tell me that the file got uploaded... I had to parse the page to confirm that the file was uploaded correctly :(
In my case, the file was at
this.CKANrepos +"/storage/f/"+location
where location is the filename returned in the authentication phase.
In the previous code fragments:
//the location of your ckan repository, including /api and possibly version, e.g.
this.CKANrepos = "http://datahub.io/api/3/";
this.CKANapiHeader="X-CKAN-API-Key";
this.CKANapi = "your ckan api key here";
I'm trying to upload a photo to the popular service Dailybooth via their new API through the method documented here.
The problem is that the server is responding with:
<html><head><title>411 Length Required</title>...
The code I'm using to send this data is here:
// 2: Build request
HttpClient httpclient = new DefaultHttpClient();
SharedPreferences settings = DailyboothShared.getPrefs(DailyboothTakePhoto.this);
String oauth_token = settings.getString("oauth_token", "");
HttpPost httppost = new HttpPost(
"https://api.dailybooth.com/v1/pictures.json?oauth_token=" + oauth_token);
Log.d("upload", "Facebook: " + facebook);
Log.d("upload", "Twitter: " + twitter);
try {
InputStream f = getContentResolver().openInputStream(snap_url);
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
entity.addPart("picture", new InputStreamBody(f, snap_url.getLastPathSegment()));
entity.addPart("blurb", new StringBody(blurb));
entity.addPart("publish_to[facebook]", new StringBody(facebook));
entity.addPart("publish_to[twiter]", new StringBody(twitter));
httppost.setEntity(entity);
HttpResponse response = httpclient.execute(httppost);
Log.d("upload", response.toString());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) {
// do something?
} else {
Log.d("upload", "Something went wrong :/");
}
Log.d("upload", EntityUtils.toString(response.getEntity()));
} catch (Exception ex) {
ex.printStackTrace();
}
I've got no idea what I'm doing wrong.
You are using either StringBody and InputStreamBody classes which describe the content of your MultipartEntity. Looking at the sources, StringBody.getContentLength() returns the length of the string, but InputStreamBody always return -1, and I guess this is done for the case you need to upload some data to the server without knowing the size of it, and start uploading while data comes to the stream.
If you want to be able to set the content length then you need to know the size of your stream beforehand, what you can do if that's the case is to set the InputStreamBody that way:
new InputStreamBody(f, snap_url.getLastPathSegment()) {
public long getContentLength() {
return /*your length*/;
}
}
or dump your stream in a byte[] array and pass ByteArrayInputStream to the InputStreamBody, of course doing so you loose the streaming ability as you need to cache your data in memory before sending it over...
As you said you are working on images, are this images File by any chance? If so you also have FileBody that return the correct content-length.