From 113e2470627629cb4555d83715d37ba814ca4031 Mon Sep 17 00:00:00 2001
From: Joshua Pinter <joshuapinter@gmail.com>
Date: Wed, 21 Oct 2020 16:21:47 -0600
Subject: [PATCH] Add `wicked_pdf_url_base64`.

Using URLs to reference images can cause a lot of problems with wkhtmltopdf, particularly when used in the header and footer. It produces errors such as "Too many open files" as well as buffer/stack overflows.

A good solution to this is providing the image encoded as base64. This helper method takes a URL of an image, opens the URL, reads the image data and encodes it to base64.

If the URL does not have a successful response (`response.is_a?(Net::HTTPSuccess) == false`), it will log a warning and return `nil`. We could optionally make this raise but that should be a project-wide change.

TODO:

- [ ] Better placement (since this is not technically part of the asset pipeline)?
- [ ] Better naming?
- [ ] Tests.
---
 lib/wicked_pdf/wicked_pdf_helper/assets.rb | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/lib/wicked_pdf/wicked_pdf_helper/assets.rb b/lib/wicked_pdf/wicked_pdf_helper/assets.rb
index 6692fe1d..58b0e6a6 100644
--- a/lib/wicked_pdf/wicked_pdf_helper/assets.rb
+++ b/lib/wicked_pdf/wicked_pdf_helper/assets.rb
@@ -15,6 +15,20 @@ def wicked_pdf_asset_base64(path)
         "data:#{asset.content_type};base64,#{Rack::Utils.escape(base64)}"
       end
 
+      # Using `image_tag` with URLs when generating PDFs (specifically large PDFs with lots of pages) can cause buffer/stack overflows.
+      #
+      def wicked_pdf_url_base64(url)
+        response = Net::HTTP.get_response(URI(url))
+
+        if response.is_a?(Net::HTTPSuccess)
+          base64 = Base64.encode64(response.body).gsub(/\s+/, '')
+          "data:#{response.content_type};base64,#{Rack::Utils.escape(base64)}"
+        else
+          Rails.logger.warn("[wicked_pdf] #{response.code} #{response.message}: #{url}")
+          nil
+        end
+      end
+
       def wicked_pdf_stylesheet_link_tag(*sources)
         stylesheet_contents = sources.collect do |source|
           source = WickedPdfHelper.add_extension(source, 'css')