wicked_pdf 1.0.3 → 2.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +5 -5
  2. data/.github/issue_template.md +15 -0
  3. data/.github/workflows/ci.yml +56 -0
  4. data/.rubocop.yml +60 -0
  5. data/.rubocop_todo.yml +84 -37
  6. data/CHANGELOG.md +230 -0
  7. data/README.md +188 -30
  8. data/Rakefile +13 -9
  9. data/gemfiles/5.0.gemfile +8 -0
  10. data/gemfiles/5.1.gemfile +8 -0
  11. data/gemfiles/5.2.gemfile +9 -0
  12. data/gemfiles/6.0.gemfile +10 -0
  13. data/gemfiles/6.1.gemfile +12 -0
  14. data/gemfiles/7.0.gemfile +12 -0
  15. data/generators/wicked_pdf/templates/wicked_pdf.rb +9 -0
  16. data/lib/generators/wicked_pdf_generator.rb +5 -9
  17. data/lib/wicked_pdf/binary.rb +65 -0
  18. data/lib/wicked_pdf/middleware.rb +3 -3
  19. data/lib/wicked_pdf/option_parser.rb +229 -0
  20. data/lib/wicked_pdf/pdf_helper.rb +101 -88
  21. data/lib/wicked_pdf/progress.rb +33 -0
  22. data/lib/wicked_pdf/railtie.rb +6 -33
  23. data/lib/wicked_pdf/tempfile.rb +38 -7
  24. data/lib/wicked_pdf/version.rb +1 -1
  25. data/lib/wicked_pdf/wicked_pdf_helper/assets.rb +212 -88
  26. data/lib/wicked_pdf/wicked_pdf_helper.rb +29 -26
  27. data/lib/wicked_pdf.rb +37 -274
  28. data/test/fixtures/database.yml +4 -0
  29. data/test/fixtures/manifest.js +3 -0
  30. data/test/fixtures/wicked.js +1 -0
  31. data/test/functional/pdf_helper_test.rb +74 -5
  32. data/test/functional/wicked_pdf_helper_assets_test.rb +86 -25
  33. data/test/functional/wicked_pdf_helper_test.rb +15 -13
  34. data/test/test_helper.rb +22 -7
  35. data/test/unit/wicked_pdf_binary_test.rb +26 -0
  36. data/test/unit/wicked_pdf_option_parser_test.rb +128 -0
  37. data/test/unit/wicked_pdf_test.rb +14 -168
  38. data/test/unit/wkhtmltopdf_location_test.rb +48 -0
  39. data/wicked_pdf.gemspec +20 -14
  40. metadata +69 -38
  41. data/.travis.yml +0 -57
  42. data/CHANGLOG.md +0 -48
  43. data/gemfiles/2.3.gemfile +0 -10
  44. data/gemfiles/3.0.gemfile +0 -7
  45. data/gemfiles/3.1.gemfile +0 -8
  46. data/gemfiles/3.2.gemfile +0 -7
  47. data/gemfiles/4.0.gemfile +0 -6
  48. data/gemfiles/4.1.gemfile +0 -6
  49. data/gemfiles/4.2.gemfile +0 -6
  50. data/gemfiles/rails_edge.gemfile +0 -6
@@ -1,118 +1,242 @@
1
- require 'open-uri'
1
+ require 'net/http'
2
+ require 'delegate'
2
3
 
3
- module WickedPdfHelper
4
- module Assets
5
- ASSET_URL_REGEX = /url\(['"]?([^'"]+?)['"]?\)/
4
+ class WickedPdf
5
+ module WickedPdfHelper
6
+ module Assets
7
+ ASSET_URL_REGEX = /url\(['"]?([^'"]+?)['"]?\)/
6
8
 
7
- def wicked_pdf_asset_base64(path)
8
- asset = Rails.application.assets.find_asset(path)
9
- throw "Could not find asset '#{path}'" if asset.nil?
10
- base64 = Base64.encode64(asset.to_s).gsub(/\s+/, '')
11
- "data:#{asset.content_type};base64,#{Rack::Utils.escape(base64)}"
12
- end
9
+ class PropshaftAsset < SimpleDelegator
10
+ def content_type
11
+ super.to_s
12
+ end
13
+
14
+ def to_s
15
+ content
16
+ end
17
+
18
+ def filename
19
+ path.to_s
20
+ end
21
+ end
22
+
23
+ def wicked_pdf_asset_base64(path)
24
+ asset = find_asset(path)
25
+ raise "Could not find asset '#{path}'" if asset.nil?
13
26
 
14
- def wicked_pdf_stylesheet_link_tag(*sources)
15
- stylesheet_contents = sources.collect do |source|
16
- source = WickedPdfHelper.add_extension(source, 'css')
17
- "<style type='text/css'>#{read_asset(source)}</style>"
18
- end.join("\n")
27
+ base64 = Base64.encode64(asset.to_s).gsub(/\s+/, '')
28
+ "data:#{asset.content_type};base64,#{Rack::Utils.escape(base64)}"
29
+ end
30
+
31
+ # Using `image_tag` with URLs when generating PDFs (specifically large PDFs with lots of pages) can cause buffer/stack overflows.
32
+ #
33
+ def wicked_pdf_url_base64(url)
34
+ response = Net::HTTP.get_response(URI(url))
19
35
 
20
- stylesheet_contents.gsub(ASSET_URL_REGEX) do
21
- if Regexp.last_match[1].starts_with?('data:')
22
- "url(#{Regexp.last_match[1]})"
36
+ if response.is_a?(Net::HTTPSuccess)
37
+ base64 = Base64.encode64(response.body).gsub(/\s+/, '')
38
+ "data:#{response.content_type};base64,#{Rack::Utils.escape(base64)}"
23
39
  else
24
- asset = Regexp.last_match[1]
25
- "url(#{wicked_pdf_asset_path(asset)})" if asset_exists?(asset)
40
+ Rails.logger.warn("[wicked_pdf] #{response.code} #{response.message}: #{url}")
41
+ nil
26
42
  end
27
- end.html_safe
28
- end
43
+ end
29
44
 
30
- def wicked_pdf_image_tag(img, options = {})
31
- image_tag wicked_pdf_asset_path(img), options
32
- end
45
+ def wicked_pdf_stylesheet_link_tag(*sources)
46
+ stylesheet_contents = sources.collect do |source|
47
+ source = WickedPdfHelper.add_extension(source, 'css')
48
+ "<style type='text/css'>#{read_asset(source)}</style>"
49
+ end.join("\n")
50
+
51
+ stylesheet_contents.gsub(ASSET_URL_REGEX) do
52
+ if Regexp.last_match[1].starts_with?('data:')
53
+ "url(#{Regexp.last_match[1]})"
54
+ else
55
+ "url(#{wicked_pdf_asset_path(Regexp.last_match[1])})"
56
+ end
57
+ end.html_safe
58
+ end
33
59
 
34
- def wicked_pdf_javascript_src_tag(jsfile, options = {})
35
- jsfile = WickedPdfHelper.add_extension(jsfile, 'js')
36
- javascript_include_tag wicked_pdf_asset_path(jsfile), options
37
- end
60
+ def wicked_pdf_stylesheet_pack_tag(*sources)
61
+ return unless defined?(Webpacker)
38
62
 
39
- def wicked_pdf_javascript_include_tag(*sources)
40
- sources.collect do |source|
41
- source = WickedPdfHelper.add_extension(source, 'js')
42
- "<script type='text/javascript'>#{read_asset(source)}</script>"
43
- end.join("\n").html_safe
44
- end
63
+ if running_in_development?
64
+ stylesheet_pack_tag(*sources)
65
+ else
66
+ css_text = sources.collect do |source|
67
+ source = WickedPdfHelper.add_extension(source, 'css')
68
+ wicked_pdf_stylesheet_link_tag(webpacker_source_url(source))
69
+ end.join("\n")
70
+ css_text.respond_to?(:html_safe) ? css_text.html_safe : css_text
71
+ end
72
+ end
73
+
74
+ def wicked_pdf_javascript_pack_tag(*sources)
75
+ return unless defined?(Webpacker)
45
76
 
46
- def wicked_pdf_asset_path(asset)
47
- if (pathname = asset_pathname(asset).to_s) =~ URI_REGEXP
48
- pathname
49
- else
50
- "file:///#{pathname}"
77
+ if running_in_development?
78
+ javascript_pack_tag(*sources)
79
+ else
80
+ sources.collect do |source|
81
+ source = WickedPdfHelper.add_extension(source, 'js')
82
+ "<script type='text/javascript'>#{read_asset(webpacker_source_url(source))}</script>"
83
+ end.join("\n").html_safe
84
+ end
85
+ end
86
+
87
+ def wicked_pdf_image_tag(img, options = {})
88
+ image_tag wicked_pdf_asset_path(img), options
51
89
  end
52
- end
53
90
 
54
- private
91
+ def wicked_pdf_javascript_src_tag(jsfile, options = {})
92
+ jsfile = WickedPdfHelper.add_extension(jsfile, 'js')
93
+ javascript_include_tag wicked_pdf_asset_path(jsfile), options
94
+ end
55
95
 
56
- # borrowed from actionpack/lib/action_view/helpers/asset_url_helper.rb
57
- URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//}
96
+ def wicked_pdf_javascript_include_tag(*sources)
97
+ sources.collect do |source|
98
+ source = WickedPdfHelper.add_extension(source, 'js')
99
+ "<script type='text/javascript'>#{read_asset(source)}</script>"
100
+ end.join("\n").html_safe
101
+ end
58
102
 
59
- def asset_pathname(source)
60
- if precompiled_asset?(source)
61
- if (pathname = set_protocol(asset_path(source))) =~ URI_REGEXP
62
- # asset_path returns an absolute URL using asset_host if asset_host is set
103
+ def wicked_pdf_asset_path(asset)
104
+ if (pathname = asset_pathname(asset).to_s) =~ URI_REGEXP
63
105
  pathname
64
106
  else
65
- File.join(Rails.public_path, asset_path(source).sub(/\A#{Rails.application.config.action_controller.relative_url_root}/, ''))
107
+ "file:///#{pathname}"
66
108
  end
67
- else
68
- Rails.application.assets.find_asset(source).pathname
69
109
  end
70
- end
71
110
 
72
- # will prepend a http or default_protocol to a protocol relative URL
73
- # or when no protcol is set.
74
- def set_protocol(source)
75
- protocol = WickedPdf.config[:default_protocol] || 'http'
76
- if source[0, 2] == '//'
77
- source = [protocol, ':', source].join
78
- elsif source[0] != '/' && !source[0, 8].include?('://')
79
- source = [protocol, '://', source].join
111
+ def wicked_pdf_asset_pack_path(asset)
112
+ return unless defined?(Webpacker)
113
+
114
+ if running_in_development?
115
+ asset_pack_path(asset)
116
+ else
117
+ wicked_pdf_asset_path webpacker_source_url(asset)
118
+ end
80
119
  end
81
- source
82
- end
83
120
 
84
- def precompiled_asset?(source)
85
- Rails.configuration.assets.compile == false || source.to_s[0] == '/'
86
- end
121
+ private
122
+
123
+ # borrowed from actionpack/lib/action_view/helpers/asset_url_helper.rb
124
+ URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//}
125
+
126
+ def asset_pathname(source)
127
+ if precompiled_or_absolute_asset?(source)
128
+ asset = asset_path(source)
129
+ pathname = prepend_protocol(asset)
130
+ if pathname =~ URI_REGEXP
131
+ # asset_path returns an absolute URL using asset_host if asset_host is set
132
+ pathname
133
+ else
134
+ File.join(Rails.public_path, asset.sub(/\A#{Rails.application.config.action_controller.relative_url_root}/, ''))
135
+ end
136
+ else
137
+ asset = find_asset(source)
138
+ if asset
139
+ # older versions need pathname, Sprockets 4 supports only filename
140
+ asset.respond_to?(:filename) ? asset.filename : asset.pathname
141
+ else
142
+ File.join(Rails.public_path, source)
143
+ end
144
+ end
145
+ end
87
146
 
88
- def read_asset(source)
89
- if precompiled_asset?(source)
90
- if set_protocol(asset_path(source)) =~ URI_REGEXP
91
- read_from_uri(source)
92
- elsif asset_exists?(source)
93
- IO.read(asset_pathname(source))
147
+ def find_asset(path)
148
+ if Rails.application.assets.respond_to?(:find_asset)
149
+ Rails.application.assets.find_asset(path, :base_path => Rails.application.root.to_s)
150
+ elsif defined?(Propshaft::Assembly) && Rails.application.assets.is_a?(Propshaft::Assembly)
151
+ PropshaftAsset.new(Rails.application.assets.load_path.find(path))
152
+ else
153
+ Sprockets::Railtie.build_environment(Rails.application).find_asset(path, :base_path => Rails.application.root.to_s)
94
154
  end
95
- else
96
- Rails.application.assets.find_asset(source).to_s
97
155
  end
98
- end
99
156
 
100
- def read_from_uri(source)
101
- encoding = ':UTF-8' if RUBY_VERSION > '1.8'
102
- asset = open(asset_pathname(source), "r#{encoding}") { |f| f.read }
103
- asset = gzip(asset) if WickedPdf.config[:expect_gzipped_remote_assets]
104
- asset
105
- end
157
+ # will prepend a http or default_protocol to a protocol relative URL
158
+ # or when no protcol is set.
159
+ def prepend_protocol(source)
160
+ protocol = WickedPdf.config[:default_protocol] || 'http'
161
+ if source[0, 2] == '//'
162
+ source = [protocol, ':', source].join
163
+ elsif source[0] != '/' && !source[0, 8].include?('://')
164
+ source = [protocol, '://', source].join
165
+ end
166
+ source
167
+ end
106
168
 
107
- def gzip(asset)
108
- stringified_asset = StringIO.new(asset)
109
- gzipper = Zlib::GzipReader.new(stringified_asset)
110
- gzipper.read
111
- rescue Zlib::GzipFile::Error
112
- end
169
+ def precompiled_or_absolute_asset?(source)
170
+ !Rails.configuration.respond_to?(:assets) ||
171
+ Rails.configuration.assets.compile == false ||
172
+ source.to_s[0] == '/' ||
173
+ source.to_s.match(/\Ahttps?\:\/\//)
174
+ end
175
+
176
+ def read_asset(source)
177
+ if precompiled_or_absolute_asset?(source)
178
+ pathname = asset_pathname(source)
179
+ if pathname =~ URI_REGEXP
180
+ read_from_uri(pathname)
181
+ elsif File.file?(pathname)
182
+ IO.read(pathname)
183
+ end
184
+ else
185
+ find_asset(source).to_s
186
+ end
187
+ end
188
+
189
+ def read_from_uri(uri)
190
+ asset = Net::HTTP.get(URI(uri))
191
+ asset.force_encoding('UTF-8') if asset
192
+ asset = gzip(asset) if WickedPdf.config[:expect_gzipped_remote_assets]
193
+ asset
194
+ end
195
+
196
+ def gzip(asset)
197
+ stringified_asset = StringIO.new(asset)
198
+ gzipper = Zlib::GzipReader.new(stringified_asset)
199
+ gzipper.read
200
+ rescue Zlib::GzipFile::Error
201
+ nil
202
+ end
203
+
204
+ def webpacker_source_url(source)
205
+ return unless webpacker_version
206
+
207
+ # In Webpacker 3.2.0 asset_pack_url is introduced
208
+ if webpacker_version >= '3.2.0'
209
+ if (host = Rails.application.config.asset_host)
210
+ asset_pack_path(source, :host => host)
211
+ else
212
+ asset_pack_url(source)
213
+ end
214
+ else
215
+ source_path = asset_pack_path(source)
216
+ # Remove last slash from root path
217
+ root_url[0...-1] + source_path
218
+ end
219
+ end
113
220
 
114
- def asset_exists?(source)
115
- Rails.application.assets.find_asset(source).present?
221
+ def running_in_development?
222
+ return unless webpacker_version
223
+
224
+ # :dev_server method was added in webpacker 3.0.0
225
+ if Webpacker.respond_to?(:dev_server)
226
+ Webpacker.dev_server.running?
227
+ else
228
+ Rails.env.development? || Rails.env.test?
229
+ end
230
+ end
231
+
232
+ def webpacker_version
233
+ return unless defined?(Webpacker)
234
+
235
+ # If webpacker is used, need to check for version
236
+ require 'webpacker/version'
237
+
238
+ Webpacker::VERSION
239
+ end
116
240
  end
117
241
  end
118
242
  end
@@ -1,33 +1,36 @@
1
- module WickedPdfHelper
2
- def self.root_path
3
- String === Rails.root ? Pathname.new(Rails.root) : Rails.root
4
- end
1
+ class WickedPdf
2
+ module WickedPdfHelper
3
+ def self.root_path
4
+ String === Rails.root ? Pathname.new(Rails.root) : Rails.root
5
+ end
5
6
 
6
- def self.add_extension(filename, extension)
7
- filename.to_s.split('.').include?(extension) ? filename : "#{filename}.#{extension}"
8
- end
7
+ def self.add_extension(filename, extension)
8
+ filename.to_s.split('.').include?(extension) ? filename : "#{filename}.#{extension}"
9
+ end
9
10
 
10
- def wicked_pdf_stylesheet_link_tag(*sources)
11
- css_dir = WickedPdfHelper.root_path.join('public', 'stylesheets')
12
- css_text = sources.collect do |source|
13
- source = WickedPdfHelper.add_extension(source, 'css')
14
- "<style type='text/css'>#{File.read(css_dir.join(source))}</style>"
15
- end.join("\n")
16
- css_text.respond_to?(:html_safe) ? css_text.html_safe : css_text
17
- end
11
+ def wicked_pdf_stylesheet_link_tag(*sources)
12
+ css_dir = WickedPdfHelper.root_path.join('public', 'stylesheets')
13
+ css_text = sources.collect do |source|
14
+ source = WickedPdfHelper.add_extension(source, 'css')
15
+ "<style type='text/css'>#{File.read(css_dir.join(source))}</style>"
16
+ end.join("\n")
17
+ css_text.respond_to?(:html_safe) ? css_text.html_safe : css_text
18
+ end
18
19
 
19
- def wicked_pdf_image_tag(img, options = {})
20
- image_tag "file:///#{WickedPdfHelper.root_path.join('public', 'images', img)}", options
21
- end
20
+ def wicked_pdf_image_tag(img, options = {})
21
+ image_tag "file:///#{WickedPdfHelper.root_path.join('public', 'images', img)}", options
22
+ end
22
23
 
23
- def wicked_pdf_javascript_src_tag(jsfile, options = {})
24
- jsfile = WickedPdfHelper.add_extension(jsfile, 'js')
25
- src = "file:///#{WickedPdfHelper.root_path.join('public', 'javascripts', jsfile)}"
26
- content_tag('script', '', { 'type' => Mime::JS, 'src' => path_to_javascript(src) }.merge(options))
27
- end
24
+ def wicked_pdf_javascript_src_tag(jsfile, options = {})
25
+ jsfile = WickedPdfHelper.add_extension(jsfile, 'js')
26
+ type = ::Mime.respond_to?(:[]) ? ::Mime[:js] : ::Mime::JS # ::Mime[:js] cannot be used in Rails 2.3.
27
+ src = "file:///#{WickedPdfHelper.root_path.join('public', 'javascripts', jsfile)}"
28
+ content_tag('script', '', { 'type' => type, 'src' => path_to_javascript(src) }.merge(options))
29
+ end
28
30
 
29
- def wicked_pdf_javascript_include_tag(*sources)
30
- js_text = sources.collect { |source| wicked_pdf_javascript_src_tag(source, {}) }.join("\n")
31
- js_text.respond_to?(:html_safe) ? js_text.html_safe : js_text
31
+ def wicked_pdf_javascript_include_tag(*sources)
32
+ js_text = sources.collect { |source| wicked_pdf_javascript_src_tag(source, {}) }.join("\n")
33
+ js_text.respond_to?(:html_safe) ? js_text.html_safe : js_text
34
+ end
32
35
  end
33
36
  end