RestBuilder Plugin. How can I upload a file without creating a file? - grails

Currently, I can upload files(exist) with Grails's RestBuilder.
However, I want to upload a file without creating a file .
I want to create binary data (= Text File) in a program and send it directly
Is it possible?
RestBuilder rest = new RestBuilder()
RestResponse resp = rest.post(url){
contentType("multipart/form-data")
setProperty("dataFile",[filePath])// <- it can
setProperty("dataFile",[ byte[] or inputStream() or String ? ])// <- Is it possible?
}
'''

I'm sure you figured this out already, but you can just use a String reference or a byte[] just as you can use File instances for the multipart request using RestBuilder. It should 'just work' e.g.
RestBuilder rest = new RestBuilder()
RestResponse response = rest.post(url) {
contentType 'multipart/form-data'
stringPart = 'hello' // String
bytePart = '68656c6c6f'.decode64() // byte[]
filePart = new File('/path/to/file.jpg') // File
}

Related

How to convert Office files to PDF using Microsoft Graph

I'm looking for a way to convert Office files to PDF.
I found out that Microsoft Graph could be used.
I'm trying to download converted PDF using Microsoft Graph from OneDrive.
I'd like to convert .docx to .pdf.
However, when I sent the following request, I did not receive a response even if I waited.
GET https://graph.microsoft.com/v1.0/users/{id}/drive/root:/test.docx:/content?format=pdf
Also, the error code is not returned.
If syntax is wrong, an error code will be returned as expected.
It will not return only when it is correct.
In addition, I can download the file if I do not convert.
GET https://graph.microsoft.com/v1.0/users/{id}/drive/root:/test.docx:/content
Is my method wrong or else I need conditions?
If possible, please give me sample code that you can actually do.
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
client.BaseAddress = new Uri(graphUrl);
var result = await client.GetAsync("/v1.0/users/xxxxxxxxxxxxxxxxxxxxxxxxx/drive/root:/test.docx:/content?format=pdf");
:
I would like to elaborate a bit Marc's answer by providing a few examples for HttpClient.
Since by default for HttpClient HttpClientHandler.AllowAutoRedirect property is set to True there is no need to explicitly follow HTTP redirection headers and the content could be downloaded like this:
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
client.BaseAddress = new Uri("https://graph.microsoft.com");
var response = await client.GetAsync($"/v1.0/drives/{driveId}/root:/{filePath}:/content?format=pdf");
//save content into file
using (var file = System.IO.File.Create(fileName))
{
var stream = await response.Content.ReadAsStreamAsync();
await stream.CopyToAsync(file);
}
}
In case if follow HTTP redirection is disabled, to download the converted file, your app must follow the Location header in the response as demonstrated below:
var handler = new HttpClientHandler()
{
AllowAutoRedirect = false
};
using (HttpClient client = new HttpClient(handler))
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
client.BaseAddress = new Uri("https://graph.microsoft.com");
var response = await client.GetAsync($"/v1.0/drives/{driveId}/root:/{filePath}:/content?format=pdf");
if(response.StatusCode == HttpStatusCode.Redirect)
{
response = await client.GetAsync(response.Headers.Location); //get the actual content
}
//save content into file
using (var file = System.IO.File.Create(fileName))
{
var stream = await response.Content.ReadAsStreamAsync();
await stream.CopyToAsync(file);
}
}
The API doesn't return the converted content directly, it returns a link to the converted file. From the documentation:
Returns a 302 Found response redirecting to a pre-authenticated download URL for the converted file.
To download the converted file, your app must follow the Location header in the response.
Pre-authenticated URLs are only valid for a short period of time (a few minutes) and do not require an Authorization header to access.
You need to capture the 302 and make a 2nd call to the URI in the Location header in order to download the converted file.

How can I upload a PDF using Dart's HttpClient?

I need to post a PDF file to a remote REST API, and I can't for the life of me figure it out. No matter what I do, the server responds that I have not yet associated an object with the file parameter. Let's say that I have a PDF called test.pdf. This is what I've been doing so far:
// Using an HttpClientRequest named req
req.headers.contentType = new ContentType('application', 'x-www-form-urlencoded');
StringBuffer sb = new StringBuffer();
String fileData = new File('Test.pdf').readAsStringSync();
sb.write('file=$fileData');
req.write(sb.toString());
return req.close();
Thus far, I've tried virtually every combination and encoding of the data that I write() to the request, but to no avail. I've tried sending it as codeUnits, I've tried encoding it using a UTF8.encode, I've tried encoding it using a Latin1Codec, everything. I'm stumped.
Any help would be greatly appreciated.
You can use MultipartRequest from the http package :
var uri = Uri.parse("http://pub.dartlang.org/packages/create");
var request = new http.MultipartRequest("POST", url);
request.fields['user'] = 'john#doe.com';
request.files.add(new http.MultipartFile.fromFile(
'package',
new File('build/package.tar.gz'),
contentType: new ContentType('application', 'x-tar'));
request.send().then((response) {
if (response.statusCode == 200) print("Uploaded!");
});
Try using the multipart/form-data header rather than x-www-form-urlencoded. This should be used for binary data, also can you show your full req request?
void uploadFile(File file) async {
// string to uri
var uri = Uri.parse("enter here upload URL");
// create multipart request
var request = new http.MultipartRequest("POST", uri);
// if you need more parameters to parse, add those like this. i added "user_id". here this "user_id" is a key of the API request
request.fields["user_id"] = "text";
// multipart that takes file.. here this "idDocumentOne_1" is a key of the API request
MultipartFile multipartFile = await http.MultipartFile.fromPath(
'idDocumentOne_1',
file.path
);
// add file to multipart
request.files.add(multipartFile);
// send request to upload file
await request.send().then((response) async {
// listen for response
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}).catchError((e) {
print(e);
});
}
I used file picker to pick file.
Here is the codes for pick file.
Future getPdfAndUpload(int position) async {
File file = await FilePicker.getFile(
type: FileType.custom,
allowedExtensions: ['pdf','docx'],
);
if(file != null) {
setState(() {
file1 = file; //file1 is a global variable which i created
});
}
}
here file_picker flutter library.

Google docs file upload and move collection issue

Issue #1
When i'm uploading a file to google docs i receive status code "201" created, but when i try to open the file it seems that i'm doing something wrong, because i can't open it, and when i'm trying to download and open it on my PC i see the binary data instead of text or image. Current language is APEX, but i think it's pretty understandable.
First of all i'm getting Upload URL and then putting data to this URL;
public void getUploadURL()
{
Httprequest req = new Httprequest();
req.setEndpoint('https://docs.google.com/feeds/upload/create-session/default/private/full?convert=false');
req.setMethod('POST');
req.setHeader('GData-Version', '3.0');
req.setHeader('Authorization', 'OAuth '+accessToken);
req.setHeader('Content-Length', '359');
req.setHeader('X-Upload-Content-Type', fileType);
req.setHeader('X-Upload-Content-Length', fileSize);
Dom.Document requestDoc = new Dom.Document();
String xml =
'<?xml version=\'1.0\' encoding=\'UTF-8\'?>'
+'<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007">'
+'<title>'+fileName+'</title></entry>';
requestDoc.load(xml);
req.setBodyDocument(requestDoc);
Http h = new Http();
Httpresponse res = h.send(req);
System.debug('response=\n'+res.getHeader('Location'));
uploadFIle(res.getHeader('Location'));
}
public void uploadFIle(String uploadUrl)
{
Httprequest req = new Httprequest();
req.setEndpoint(uploadUrl);
req.setMethod('PUT');
req.setHeader('GData-Version', '3.0');
req.setHeader('Authorization', 'OAuth '+accessToken);
req.setHeader('Host', 'docs.google.com');
req.setHeader('Content-Length', fileSize);
req.setHeader('Content-Type', fileType);
req.setBody(''+binaryData);
Http h = new Http();
Httpresponse res = h.send(req);
System.debug('response=\n'+res.getBody());
}
As for "binaryData" property - i receive it from the page using javascript like this:
<input type="file" id="myuploadfield" onchange="getBinary()"/>
<script>
function getBinary()
{
var file = document.getElementById('myuploadfield').files[0];
fileSizeToController.val(file.size.toString());
fileNameToController.val(file.name.toString());
fileTypeToController.val(file.type.toString());
var r = new FileReader();
r.onload = function(){ binaryToController.val(r.result); };
r.readAsBinaryString(file);
}
</script>
r.onload = function(){ binaryToController.val(r.result); }; - this is the string that sends file binary data to my controller.
Issue #2
I'm trying to move one collection(folder) to another, and using this article (protocol tab instead of .NET). The issue is that i need to move collection instead of copying it and when i add my collection to another using this article, i'm currently adding reference to my collection instead of moving the whole collection from one place to another.
Please tell me what am i doing wrong.
Thank you for consideration.
Your "binary" data is being corrupted, when you are performing '' + binaryData.
In general, I have had more success using slicing of files, here is an example for webkit:
var chunk = this.file.webkitSlice(startByte, startByte + chunkSize, file_type);
// Upload the chunk
uploadChunk(startByte, chunk, callback);

How to remove an attachment from Jira 4.4 using Http

I have been looking for a way to remove an attachment from Jira using the SOAP Api, but it seems that this is not possible natively, and I would prefer not having to implement a new plugin for Jira, as suggested in the accepted answer to this question, or recompiling the existing plugin to support this as mentioned here.
This answer to the abovementioned question seems to do exactly what I want, but alas, I can't get i to work. The response i get is an error stating that:
XSRF Security Token Missing
JIRA could not complete this action due to a missing form token.
You may have cleared your browser cookies, which could have resulted in the expiry of your current form token. A new form token has been reissued.
As I am using Asp.Net MVC C#, I have used the code from the answer, as is, with only the server url adjusted, as well as with different credentials (a Jira user) and the username/password passed through as request parameters using:
os_username=jirausername&os_password=xxxxxxx
The code I am currently using is as follows:
public void RemoveAttachment(string issueid, string attachmentid)
{
using (System.Net.WebClient client = new System.Net.WebClient())
{
//Compute jira server base url from WS url
string baseUrl = _service.Url.Substring(0, _service.Url.IndexOf("/rpc/"));
//Compute complete attachment url
string attachmenturl = baseUrl + "/secure/DeleteAttachment.jspa?id=" +
issueid + "&deleteAttachmentId=" + attachmentid;
client.Credentials = new System.Net.NetworkCredential("jirausername", "xxxxxxx");
string response = client.DownloadString(attachmenturl);
}
}
I ended up using a method that first requests the deletion confirmation form, then extracts a required token from the form, and finally posts something equivalent to the form content in order to delete the attachment. Code below.
public void RemoveAttachment(string issueid, string attachmentid)
{
//Compute jira server base url from WS url
string baseUrl = _service.Url.Substring(0, _service.Url.IndexOf("/rpc/"));
//Compute complete attachment deletion confirm url
string confirmurl = baseUrl + "/secure/DeleteAttachment!default.jspa?id=" +
issueid + "&deleteAttachmentId=" + attachmentid + "&os_username=jirauser&os_password=xxxxxx";
//Create a cookie container to maintain the xsrf security token cookie.
CookieContainer jiracontainer = new CookieContainer();
//Create a get request for the page containing the delete confirmation.
HttpWebRequest confirmrequest = (HttpWebRequest)WebRequest.Create(confirmurl);
confirmrequest.Credentials = System.Net.CredentialCache.DefaultCredentials;
confirmrequest.CookieContainer = jiracontainer;
//Get the response and the responsestream.
WebResponse confirmdeleteresponse = confirmrequest.GetResponse();
Stream ReceiveStream = confirmdeleteresponse.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader confirmreader = new StreamReader(ReceiveStream);
// Read the content.
string confirmresponse = confirmreader.ReadToEnd();
//Create a regex to extract the atl/xsrf token from a hidden field. (Might be nicer to read it from a cookie, which should also be possible).
Regex atl_token_matcher = new Regex("<input[^>]*id=\"atl_token\"[^>]*value=\"(?<token>\\S+)\"[^>]*>", RegexOptions.Singleline);
Match token_match = atl_token_matcher.Match(confirmresponse);
if (token_match.Success)
{
//If we found the token get the value.
string token = token_match.Groups["token"].Value;
//Compute attachment delete url.
string deleteurl = baseUrl + "/secure/DeleteAttachment.jspa";
//Construct form data.
string postdata = "atl_token=" + HttpContext.Current.Server.UrlEncode(token) + "&id=" + issueid + "&deleteAttachmentId=" + attachmentid + "&Delete=Delete&os_username=jirauser&os_password=xxxxxx";
//Create a post request for the deletion page.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(deleteurl);
request.KeepAlive = false;
request.CookieContainer = jiracontainer; // Remember to set the cookiecontainer.
request.ProtocolVersion = HttpVersion.Version10;
request.Method = "POST";
//Turn our request string into a byte stream
byte[] postBytes = Encoding.ASCII.GetBytes(postdata);
//Make sure you specify the proper type.
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postBytes.Length;
Stream requestStream = request.GetRequestStream();
//Send the post.
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();
//Get the response.
WebResponse deleteresponse = request.GetResponse();
// Open the responsestream using a StreamReader for easy access.
StreamReader deleteresponsereader = new StreamReader(deleteresponse.GetResponseStream());
// Read the content.
string deleteresponsecontent = deleteresponsereader.ReadToEnd();
// do whatever validation/reporting with the response...
}
else
{
//We couldn't find the atl_token. Throw an error or something...
}
}
Edit:
Same thing works for removing comments. Replace 'attachment' with 'comment' and 'deleteAttachmentId' with 'commentId' and you should be good to go.

How to forward a 'saved' request stream to another Action within the same controller?

We have a need to chunk-up large http requests sent by our mobile devices. These smaller chunk streams are merged to a file on the server. Once all chunks are received we need a way to submit the saved merged request to an another method(Action) within the same controller that will process this large http request. How can this be done? The code we tried below results in the service hanging. Is there a way to do this without a round-trip?
//Open merged chunked file
FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
//Read steam support variables
int bytesRead = 0;
byte[] buffer = new byte[1024];
//Build New Web Request. The target Action is called "Upload", this method we are in is called "UploadChunk"
HttpWebRequest webRequest;
webRequest = (HttpWebRequest)WebRequest.Create(Request.Url.ToString().Replace("Chunk", string.Empty));
webRequest.Method = "POST";
webRequest.ContentType = "text/xml";
webRequest.KeepAlive = true;
webRequest.Timeout = 600000;
webRequest.ReadWriteTimeout = 600000;
webRequest.Credentials = System.Net.CredentialCache.DefaultCredentials;
Stream webStream = webRequest.GetRequestStream(); //Hangs here, no errors, just hangs
I have looked into using RedirectToAction and RedirecctToRoute but these methods don't fit well with what we are looking to do as we cannot edit the Request.InputStream (as it is read-only) to carry out large request stream.
You can build what you want, save in the TempData, RedirectToAction and there pull it from the 'TempData'
something like this:
public ActionResult DoSomething()
{
var data = GetData();
TempData["Data"] = data;
RedirectToAction("Forward");
}
public ActionResult Forward()
{
var data = TempData["data"];
if (data == null)
throw new ArgumentException("data is null");
// Do your magic.
}
Found what I was looking for here:
Needed to perform the following steps:
1) Create File stream to read the merged chunk from file
2) Create new System.Net.HttpWebRequest with destination URI
3) Copy Header from original request to new requested noted in 2)
4) Copy contents from file stream to new request
5) Set the content-lenght of new request to the lenght of the file stream
6) Close both file stream and new request streams
7) Copy Headers from original to new request
8) Copy Cookies from original to new request
So basically its the same logic one could use when programming ASP.NET stuff.

Resources