Grails Base64 to PDF - render a PDF inline - grails

I have a Grails controller action that calls a service that will return XML that contains a base64 representation of a PDF. Here is an (abbreviated) example sample.
<response status="Success"><messages/><values><pages>8</pages></values><xml/><files><pdf name="FitnessApplication" content-type="application/pdf"><![CDATA[JVBERi0xLjQKJeL ... </files></response>
After we parse that out I want to display that PDF in the browser. So far I am able to decode the string and render it using the file attribute of the render method. This serves up the PDF correctly as a download but I want it to display in the browser (inline) and NOT as a file download.
Map responseMap = new XmlParserHelper().parse( formsResponse.payload )
byte[] decoded = responseMap.files.pdf.decodeBase64()
render( file: decoded, fileName: "${document}.pdf", contentType: "application/pdf", )
I tried setting the content disposition as both an option to render and in the header map but neither seem to do the trick. Does anyone know how I can serve this PDF to the user in the browser?

Just send it in the response. But you need to add the headers on your own. E.g. something like:
response.contentType = "application/pdf"
response.contentLength = FileUtils.copyFile(pdfFile, response.outputStream)

To build on what cfrick said here is the final solution I went with.
// response data
byte[] pdfData = responseMap.files.pdf.decodeBase64()
response.contentType = "application/pdf"
response.setHeader("Content-disposition", "inline; filename='dan.pdf'")
// write to output
OutputStream output = response.outputStream
output.write(pdfData);
output.close();

Related

Upload Attachment to ServiceNow using SOAP and Base64 via BluePrism

I am trying to upload a file into ServiceNow using the WSDL <https://instanceName.Service-now.com/ecc_queue.do?WSDL>
I am converting the file to Base64 using Powershell. The upload via SOAPUI works fine, however the same file when downloaded is corrupted. If I upload an Excel file with data on downloading the file the Excel file is Empty
Source File Name is tp-certification-guide.pdf (Source PDF: - https://www.servicenow.com/content/dam/servicenow/other-documents/training/tp-certification-guide.pdf)
However, when I convert the file to Base64 using a portal (https://www.browserling.com/tools/file-to-base64/), I am able to upload and download the file without any issues. Again the file uploaded to ServiceNow does not get corrupted nor does it download an Empty File.
My SoapUI code: -
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ecc="http://www.service-now.com/ecc_queue">
<soapenv:Header/>
<soapenv:Body>
<ecc:insert>
<agent>AttachmentUploader</agent>
<name>problem_data.pdf:application/pdf</name>
<payload>AAAAIGZ0eXBxdCrG[..truncated..]</payload>;
<source>incident:[sysid is here]</source>
<topic>AttachmentUploader</topic>
</ecc:insert>
</soapenv:Body>
</soapenv:Envelope>
Above Code taken from https://www.servicenowguru.com/integration/sending-attachment-servicenow/
My PowerShell code is as below
$InputFile = "D:\02_Downloads\ChromeDLs\tp-certification-guide.pdf"
# Read the file as text
$Text = [System.IO.File]::ReadAllText($InputFile)
# Convert the string to UTF-8 bytes
$UTF8Bytes = [System.Text.Encoding]::UTF8.GetBytes($Text)
# Encode the UTF-8 bytes as a Base64 string
$Base64String = [System.Convert]::ToBase64String($UTF8Bytes)
$Base64String | Out-File "D:\02_Downloads\ChromeDLs\tp-certification-guide.txt"
The file should uploaded to ServiceNow using the WSDL and the same file when downloaded should not be corrupted or empty.
I feel there is something wrong in the generation of Base64 using Powershell compared to the Online Edition which would need assistance.
I can't help you with the base64 problem, but if you're interested, then here's my dotnet code to upload attachment to SNOW using REST.
Dim request As WebRequest = WebRequest.Create(REST_Address)
request.UseDefaultCredentials = True
request.Credentials = new NetworkCredential(SNOW_Username, SNOW_Password)
request.Method = "POST"
request.ContentType = ContentType
Dim byteArray As Byte() = System.IO.File.ReadAllBytes(Filename)
request.ContentLength = byteArray.Length
Dim RequestStream As System.IO.Stream = request.GetRequestStream()
RequestStream.Write(byteArray, 0, byteArray.Length)
RequestStream.close()
Dim response As WebResponse = request.GetResponse
Dim responseStream As IO.Stream = response.GetResponseStream
Dim sr As New IO.StreamReader(responseStream)
resultData = sr.ReadToEnd
response.Close
REST address example: https://instance.service-now.com/api/now/attachment/file?table_name=SNOWTable&table_sys_id=32charsysid&file_name=test.pdf
content type: application/pdf

Convert paperclip pdf from S3 to base64 (Rails)

I'm sending a base64 of a PDF to an external API endpoint in a Rails app.
This occurs regularly with different PDFs for different users. I'm currently using the Paperclip gem.
The problem is getting the PDF into a format that I can then convert to base64.
Below works if I start with a PDF locally and .read it, but not when it comes from S3.
Code:
def self.get_pdf(upload_id)
# get URL for file in S3 (for directly accessing the PDF in browser)
# `.generic` implemented via `has_attached_file :generic` in model
# `.expiring_url` is paperclip syntax for generating a URL
s3_url = Upload
.find(upload_id)
.generic
.expiring_url(100)
# open file from URL
file = open(s3_url)
# read file
pdf = File.read(file)
# convert to base64
base64 = Base64.encode64(File.open(pdf, "rb").read)
end
Error:
OpenURI::HTTPError (404 Not Found):
Ideally this can just occur in memory instead of actually download the file.
Streaming-in a base64 from S3 while streaming out the API request would be awesome but I don't think thats an option here.
UPDATE:
signed URLs from Cyberduck + Michael's answer will work
paperclip URLs fail + Michael's answer results in below error
Error:
The specified key does not exist.
Unfortunately I need to use Paperclip so I can generate links and download PDFs on the fly, based on the uploads table records in my db.
Is there is a technicality about paperclip links I don't understand?
base64 = Base64.encode64( get_me(s3_url).body ).gsub("\n", '')
def get_me(url)
uri = URI(url)
req = Net::HTTP::Get.new(uri)
req['Any_header_you_might_need'] = 'idem'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
return res
end

Classic ASP: Emit Response with charset UTF-16

I need to do a script in classic ASP to generate a CSV file for the user to download. It needs to be encoded in "classic Windows Unicode", ie., UTF-16.
I tried this:
Response.Clear
Response.ContentType = "text/csv"
Response.Charset = "utf-16"
Response.Codepage = 1200
Response.AddHeader "Content-Disposition", "attachment; filename=export.csv"
but I get the error
ERROR -2147467259: 006~ASP 0204~Invalid CodePage Value~An invalid CodePage value was specified.
which makes sense, because according to the documentation, code page 1200 is only available to managed (ASP.NET) applications.
But then, how can I set the Response's charset to UTF-16?
Well, I “solved” it using an ADODB.Stream. The disadvantage of this is that I need to accumulate the full output in memory before I send it to the user. Basically,
dim s
set s = Server.CreateObject("ADODB.Stream")
s.Type = 2 ' text '
s.Open
do while <getting data>
s.WriteText <data>
loop
s.Flush
s.Position = 1
s.Type = 1 ' binary '
Response.Clear
Response.ContentType = "application/csv"
Response.AddHeader "Content-Disposition", "attachment; filename=export.csv"
Response.BinaryWrite s.Read
This makes use the fact that ADODB.Stream uses Unicode by default to store text.

Ruby: Open URI. Get file name from the remote url

I have a remote URL, that doesn't have any reference to filename.
https://example.site.com/sadfasfsadfasdfasfdsafas/
But on downloading it gives file as 'Intro.pdf'
I would like to get that filename in my ruby code so that I can use it to create the file or send file in requests. As of now, I am sending the hardcode name as attachment.pdf
obj = open(url, :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE)
data = obj.read
send_data data, :disposition => 'attachment', :filename=>"attachment.pdf"
Pls Advice.
Thanks
Check result of meta method:
p obj.meta
probably it have Content-Disposition header. In this case it can have file name as optional parameter.

BinaryContent Stream wrapper in Grails

I am trying to write a simple wrapper in grails that will read a binary file from a non-public back-end web-server and makes it available as a stream to a public server.
The first question is what is the best method to handle such a solution considering that the Grails will attempt to render views by default.
I am attempting a solution which leads to an "Attempted read from closed stream." which apparently looks to avoid the view rendering by invoking response but I am not sure if this is a good solution anyway.
I am reading the back-end file through the following code:
def http = new HTTPBuilder(baseUrl)
http.request(method, ContentType.BINARY) {
uri.path = path
uri.query = query
response.success = { resp, inputstream ->
log.info "response status: ${resp.statusLine}"
resp.headers.each { h -> log.info " ${h.name} : ${h.value}" }
return inputstream
}
and later attempt to push it to the client through the following method in a controller:
def binary(){
response.outputStream << getBinaryContent("http://aaa" );
response.flush()
}
Error: "Attempted read from closed stream."
If I'm not mistaken << will close the response so response.flush() is invalid.
Here's the snippet that I use for CSV, just replace with your content type:
byte[] bytes = fileGenerated.getBytes() //fileGenerated is a File
response.setContentType("text/csv")
response.setContentLength(bytes.length)
response.setHeader("Content-Disposition", "attachment; filename=" + fileGenerated.getName())
response.outputStream << bytes

Resources