0

I am looking to download a PDF directly from a blob URL using Ruby code. The URL appears like this:

blob:https://dev.myapp.com/ba853441-d1f7-4595-9227-1b0e445b188b

I am able to visit the link in a web browser and have the PDF appear in a new tab. On inspection, other than the GET request there are some request headers related to browser/user agent.

I've attempted to use OpenURI but it detects the url as not an HTTP URI. Open URI works just fine with files from URLs that look like https://.../invoice.pdf

I've also tried to go the JS route with this snippet but this is returning 0 for me, as others have also reported.

Any automated solutions that require a download onClick and then navigating the local disk is not sufficient for my project. I am looking to retrieve files directly from the URL in the same fashion that OpenURI works for a file on a server. Thanks in advance.

Phil
  • 886
  • 7
  • 20

1 Answers1

0

I was able to get the Javascript snippet to work. The piece that I was missing was that the blob URL needed to be opened/visited in the browser first (in this case, Chrome). Here's a code snippet that might work for others.

def get_file_content_in_base64(uri)
  result = page.evaluate_async_script("
    var uri = arguments[0];
    var callback = arguments[1];
    var toBase64 = function(buffer){for(var r,n=new Uint8Array(buffer),t=n.length,a=new Uint8Array(4*Math.ceil(t/3)),i=new Uint8Array(64),o=0,c=0;64>c;++c)i[c]='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.charCodeAt(c);for(c=0;t-t%3>c;c+=3,o+=4)r=n[c]<<16|n[c+1]<<8|n[c+2],a[o]=i[r>>18],a[o+1]=i[r>>12&63],a[o+2]=i[r>>6&63],a[o+3]=i[63&r];return t%3===1?(r=n[t-1],a[o]=i[r>>2],a[o+1]=i[r<<4&63],a[o+2]=61,a[o+3]=61):t%3===2&&(r=(n[t-2]<<8)+n[t-1],a[o]=i[r>>10],a[o+1]=i[r>>4&63],a[o+2]=i[r<<2&63],a[o+3]=61),new TextDecoder('ascii').decode(a)};
    var xhr = new XMLHttpRequest();
    xhr.responseType = 'arraybuffer';
    xhr.onload = function(){ callback(toBase64(xhr.response)) };
    xhr.onerror = function(){ callback(xhr.status) };
    xhr.open('GET', uri);
    xhr.send();
    ", uri)
  if result.is_a? Integer
    fail 'Request failed with status %s' % result
  end
  return result
end

def get_pdf_from_blob
  yield # Yield to whatever Click actions that trigger the file download
  sleep 3 # Wait for direct download to complete
  visit 'chrome://downloads'
  sleep 3
  file_name = page.text.split("\n")[3]
  blob_url = page.text.split("\n")[4]
  visit blob_url
  sleep 3 # Wait for PDF to load
  base64_str = get_file_content_in_base64(blob_url)
  decoded_content = Base64.decode64(base64_str)
  file_path = "./tmp/#{file_name}"
  File.open(file_path, "wb") do |f|
    f.write(decoded_content)
  end
  return file_path
end

From here you can send file_path to S3, send to PDF Reader, etc.

Phil
  • 886
  • 7
  • 20