Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add raise_on_missing_assets and exceptions on missing assets #1094

Merged
merged 5 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading