wicked_pdf 1.0.6 → 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 (49) 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 +83 -29
  6. data/CHANGELOG.md +182 -35
  7. data/README.md +188 -30
  8. data/Rakefile +13 -10
  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 +1 -1
  19. data/lib/wicked_pdf/option_parser.rb +229 -0
  20. data/lib/wicked_pdf/pdf_helper.rb +99 -85
  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 +213 -91
  26. data/lib/wicked_pdf/wicked_pdf_helper.rb +29 -26
  27. data/lib/wicked_pdf.rb +37 -272
  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 +27 -9
  33. data/test/functional/wicked_pdf_helper_test.rb +15 -13
  34. data/test/test_helper.rb +16 -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 +11 -149
  38. data/test/unit/wkhtmltopdf_location_test.rb +48 -0
  39. data/wicked_pdf.gemspec +21 -14
  40. metadata +68 -37
  41. data/.travis.yml +0 -66
  42. data/gemfiles/2.3.gemfile +0 -10
  43. data/gemfiles/3.0.gemfile +0 -7
  44. data/gemfiles/3.1.gemfile +0 -8
  45. data/gemfiles/3.2.gemfile +0 -7
  46. data/gemfiles/4.0.gemfile +0 -6
  47. data/gemfiles/4.1.gemfile +0 -6
  48. data/gemfiles/4.2.gemfile +0 -6
  49. data/gemfiles/rails_edge.gemfile +0 -6
@@ -1,120 +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
- "url(#{wicked_pdf_asset_path(Regexp.last_match[1])})"
40
+ Rails.logger.warn("[wicked_pdf] #{response.code} #{response.message}: #{url}")
41
+ nil
25
42
  end
26
- end.html_safe
27
- end
43
+ end
28
44
 
29
- def wicked_pdf_image_tag(img, options = {})
30
- image_tag wicked_pdf_asset_path(img), options
31
- 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
32
59
 
33
- def wicked_pdf_javascript_src_tag(jsfile, options = {})
34
- jsfile = WickedPdfHelper.add_extension(jsfile, 'js')
35
- javascript_include_tag wicked_pdf_asset_path(jsfile), options
36
- end
60
+ def wicked_pdf_stylesheet_pack_tag(*sources)
61
+ return unless defined?(Webpacker)
37
62
 
38
- def wicked_pdf_javascript_include_tag(*sources)
39
- sources.collect do |source|
40
- source = WickedPdfHelper.add_extension(source, 'js')
41
- "<script type='text/javascript'>#{read_asset(source)}</script>"
42
- end.join("\n").html_safe
43
- 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)
44
76
 
45
- def wicked_pdf_asset_path(asset)
46
- if (pathname = asset_pathname(asset).to_s) =~ URI_REGEXP
47
- pathname
48
- else
49
- "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
50
89
  end
51
- end
52
90
 
53
- 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
54
95
 
55
- # borrowed from actionpack/lib/action_view/helpers/asset_url_helper.rb
56
- 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
57
102
 
58
- def asset_pathname(source)
59
- if precompiled_or_absolute_asset?(source)
60
- asset = asset_path(source)
61
- pathname = prepend_protocol(asset)
62
- if pathname =~ URI_REGEXP
63
- # 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
64
105
  pathname
65
106
  else
66
- File.join(Rails.public_path, asset.sub(/\A#{Rails.application.config.action_controller.relative_url_root}/, ''))
107
+ "file:///#{pathname}"
67
108
  end
68
- else
69
- asset = Rails.application.assets.find_asset(source)
70
- asset ? asset.pathname : File.join(Rails.public_path, source)
71
109
  end
72
- end
73
110
 
74
- # will prepend a http or default_protocol to a protocol relative URL
75
- # or when no protcol is set.
76
- def prepend_protocol(source)
77
- protocol = WickedPdf.config[:default_protocol] || 'http'
78
- if source[0, 2] == '//'
79
- source = [protocol, ':', source].join
80
- elsif source[0] != '/' && !source[0, 8].include?('://')
81
- 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
82
119
  end
83
- source
84
- end
85
120
 
86
- def precompiled_or_absolute_asset?(source)
87
- Rails.configuration.assets.compile == false ||
88
- source.to_s[0] == '/' ||
89
- source.to_s.match(/\Ahttps?\:\/\//)
90
- 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
91
146
 
92
- def read_asset(source)
93
- if precompiled_or_absolute_asset?(source)
94
- pathname = asset_pathname(source)
95
- if pathname =~ URI_REGEXP
96
- read_from_uri(pathname)
97
- elsif File.file?(pathname)
98
- IO.read(pathname)
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)
99
154
  end
100
- else
101
- Rails.application.assets.find_asset(source).to_s
102
155
  end
103
- end
104
156
 
105
- def read_from_uri(uri)
106
- encoding = ':UTF-8' if RUBY_VERSION > '1.8'
107
- asset = open(uri, "r#{encoding}", &:read)
108
- asset = gzip(asset) if WickedPdf.config[:expect_gzipped_remote_assets]
109
- asset
110
- 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
168
+
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
111
220
 
112
- def gzip(asset)
113
- stringified_asset = StringIO.new(asset)
114
- gzipper = Zlib::GzipReader.new(stringified_asset)
115
- gzipper.read
116
- rescue Zlib::GzipFile::Error
117
- nil
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
118
240
  end
119
241
  end
120
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