Skip to content

Commit

Permalink
Merge pull request #1094 from d4rky-pl/patch-remote-assets
Browse files Browse the repository at this point in the history
Add raise_on_missing_assets and exceptions on missing assets
  • Loading branch information
unixmonkey committed Feb 5, 2024
2 parents 549e00c + 9adfa7a commit fe3f8b3
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 12 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ class ThingsController < ApplicationController
viewport_size: 'TEXT', # available only with use_xserver or patched QT
extra: '', # directly inserted into the command to wkhtmltopdf
raise_on_all_errors: nil, # raise error for any stderr output. Such as missing media, image assets
raise_on_missing_assets: nil, # raise when trying to access a missing asset
log_level: 'info', # Available values: none, error, warn, or info - only available with wkhtmltopdf 0.12.5+
quiet: false, # `false` is same as `log_level: 'info'`, `true` is same as `log_level: 'none'`
outline: { outline: true,
Expand Down
93 changes: 81 additions & 12 deletions lib/wicked_pdf/wicked_pdf_helper/assets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,27 @@ module WickedPdfHelper
module Assets
ASSET_URL_REGEX = /url\(['"]?([^'"]+?)['"]?\)/

class MissingAsset < StandardError; end

class MissingLocalAsset < MissingAsset
attr_reader :path

def initialize(path)
@path = path
super("Could not find asset '#{path}'")
end
end

class MissingRemoteAsset < MissingAsset
attr_reader :url, :response

def initialize(url, response)
@url = url
@response = response
super("Could not fetch asset '#{url}': server responded with #{response.code} #{response.message}")
end
end

class PropshaftAsset < SimpleDelegator
def content_type
super.to_s
Expand All @@ -21,9 +42,39 @@ def filename
end
end

class SprocketsEnvironment
def self.instance
@instance ||= Sprockets::Railtie.build_environment(Rails.application)
end

def self.find_asset(*args)
instance.find_asset(*args)
end
end

class LocalAsset
attr_reader :path

def initialize(path)
@path = path
end

def content_type
Mime::Type.lookup_by_extension(File.extname(path).delete('.'))
end

def to_s
IO.read(path)
end

def filename
path.to_s
end
end

def wicked_pdf_asset_base64(path)
asset = find_asset(path)
raise "Could not find asset '#{path}'" if asset.nil?
raise MissingLocalAsset, path if asset.nil?

base64 = Base64.encode64(asset.to_s).gsub(/\s+/, '')
"data:#{asset.content_type};base64,#{Rack::Utils.escape(base64)}"
Expand Down Expand Up @@ -150,8 +201,11 @@ def find_asset(path)
Rails.application.assets.find_asset(path, :base_path => Rails.application.root.to_s)
elsif defined?(Propshaft::Assembly) && Rails.application.assets.is_a?(Propshaft::Assembly)
PropshaftAsset.new(Rails.application.assets.load_path.find(path))
elsif Rails.application.respond_to?(:assets_manifest)
asset_path = File.join(Rails.application.assets_manifest.dir, Rails.application.assets_manifest.assets[path])
LocalAsset.new(asset_path) if File.file?(asset_path)
else
Sprockets::Railtie.build_environment(Rails.application).find_asset(path, :base_path => Rails.application.root.to_s)
SprocketsEnvironment.find_asset(path, :base_path => Rails.application.root.to_s)
end
end

Expand All @@ -175,20 +229,35 @@ def precompiled_or_absolute_asset?(source)
end

def read_asset(source)
if precompiled_or_absolute_asset?(source)
pathname = asset_pathname(source)
if pathname =~ URI_REGEXP
read_from_uri(pathname)
elsif File.file?(pathname)
IO.read(pathname)
end
else
find_asset(source).to_s.force_encoding('UTF-8')
asset = find_asset(source)
return asset.to_s.force_encoding('UTF-8') if asset

unless precompiled_or_absolute_asset?(source)
raise MissingLocalAsset, source if WickedPdf.config[:raise_on_missing_assets]

return
end

pathname = asset_pathname(source)
if pathname =~ URI_REGEXP
read_from_uri(pathname)
elsif File.file?(pathname)
IO.read(pathname)
elsif WickedPdf.config[:raise_on_missing_assets]
raise MissingLocalAsset, pathname if WickedPdf.config[:raise_on_missing_assets]
end
end

def read_from_uri(uri)
asset = Net::HTTP.get(URI(uri))
response = Net::HTTP.get_response(URI(uri))

unless response.is_a?(Net::HTTPSuccess)
raise MissingRemoteAsset.new(uri, response) if WickedPdf.config[:raise_on_missing_assets]

return
end

asset = response.body
asset.force_encoding('UTF-8') if asset
asset = gzip(asset) if WickedPdf.config[:expect_gzipped_remote_assets]
asset
Expand Down
61 changes: 61 additions & 0 deletions test/functional/wicked_pdf_helper_assets_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@
class WickedPdfHelperAssetsTest < ActionView::TestCase
include WickedPdf::WickedPdfHelper::Assets

setup do
@saved_config = WickedPdf.config
WickedPdf.config = {}
end

teardown do
WickedPdf.config = @saved_config
end

if Rails::VERSION::MAJOR > 3 || (Rails::VERSION::MAJOR == 3 && Rails::VERSION::MINOR > 0)
test 'wicked_pdf_asset_base64 returns a base64 encoded asset' do
assert_match %r{data:text\/css;base64,.+}, wicked_pdf_asset_base64('wicked.css')
Expand All @@ -15,6 +24,58 @@ class WickedPdfHelperAssetsTest < ActionView::TestCase
wicked_pdf_stylesheet_link_tag('wicked')
end

test 'wicked_pdf_stylesheet_link_tag should raise if the stylesheet is not available and config is set' do
Rails.configuration.assets.expects(:compile => true)
WickedPdf.config[:raise_on_missing_assets] = true
assert_raise WickedPdf::WickedPdfHelper::Assets::MissingLocalAsset do
wicked_pdf_stylesheet_link_tag('non_existent')
end
end

test 'wicked_pdf_stylesheet_link_tag should return empty if the stylesheet is not available' do
Rails.configuration.assets.expects(:compile => true)
assert_equal "<style type='text/css'></style>",
wicked_pdf_stylesheet_link_tag('non_existent')
end

test 'wicked_pdf_stylesheet_link_tag should raise if the absolute path stylesheet is not available and config is set' do
Rails.configuration.assets.expects(:compile => true)
WickedPdf.config[:raise_on_missing_assets] = true
expects(:precompiled_or_absolute_asset? => true).twice
assert_raise WickedPdf::WickedPdfHelper::Assets::MissingLocalAsset do
wicked_pdf_stylesheet_link_tag('/non_existent')
end
end

test 'wicked_pdf_stylesheet_link_tag should return empty if the absolute path stylesheet is not available' do
Rails.configuration.assets.expects(:compile => true).twice
assert_equal "<style type='text/css'></style>",
wicked_pdf_stylesheet_link_tag('/non_existent')
end

test 'wicked_pdf_stylesheet_link_tag should inline the stylesheets passed in when assets are remote' do
stub_request(:get, 'https://www.example.com/wicked.css').to_return(:status => 200, :body => '/* Wicked styles */')
expects(:precompiled_or_absolute_asset? => true).twice
assert_equal "<style type='text/css'>/* Wicked styles */</style>",
wicked_pdf_stylesheet_link_tag('https://www.example.com/wicked.css')
end

test 'wicked_pdf_stylesheet_link_tag should raise if remote assets are not available and config is set' do
WickedPdf.config[:raise_on_missing_assets] = true
stub_request(:get, 'https://www.example.com/wicked.css').to_return(:status => 404, :body => 'File not found')
expects(:precompiled_or_absolute_asset? => true).twice
assert_raise WickedPdf::WickedPdfHelper::Assets::MissingRemoteAsset do
wicked_pdf_stylesheet_link_tag('https://www.example.com/wicked.css')
end
end

test 'wicked_pdf_stylesheet_link_tag should return empty if remote assets are not available' do
stub_request(:get, 'https://www.example.com/wicked.css').to_return(:status => 404, :body => 'File not found')
expects(:precompiled_or_absolute_asset? => true).twice
assert_equal "<style type='text/css'></style>",
wicked_pdf_stylesheet_link_tag('https://www.example.com/wicked.css')
end

test 'wicked_pdf_image_tag should return the same as image_tag when passed a full path' do
Rails.configuration.assets.expects(:compile => true)
assert_equal image_tag("file:///#{Rails.root.join('public', 'pdf')}"),
Expand Down
1 change: 1 addition & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
require 'mocha'
require 'rails/test_help'
require 'mocha/test_unit'
require 'webmock/minitest'

require 'wicked_pdf'

Expand Down
1 change: 1 addition & 0 deletions wicked_pdf.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ DESC
spec.add_development_dependency 'rubocop', '~> 1.46'
spec.add_development_dependency 'sqlite3', '~> 1.3'
spec.add_development_dependency 'test-unit'
spec.add_development_dependency 'webmock', '~> 3.19'
end

0 comments on commit fe3f8b3

Please sign in to comment.