pdfkit 0.8.4 → 0.8.5
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of pdfkit might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.github/workflows/release-drafter.yml +19 -0
- data/.github/workflows/stale.yml +19 -0
- data/.ruby-version +1 -1
- data/.travis.yml +11 -7
- data/CHANGELOG.md +37 -0
- data/Gemfile +1 -1
- data/README.md +18 -6
- data/lib/pdfkit.rb +1 -0
- data/lib/pdfkit/configuration.rb +13 -3
- data/lib/pdfkit/middleware.rb +32 -22
- data/lib/pdfkit/pdfkit.rb +21 -8
- data/lib/pdfkit/source.rb +2 -1
- data/lib/pdfkit/version.rb +1 -1
- data/pdfkit.gemspec +4 -5
- data/spec/configuration_spec.rb +59 -4
- data/spec/middleware_spec.rb +106 -18
- data/spec/pdfkit_spec.rb +22 -1
- data/spec/source_spec.rb +25 -0
- metadata +10 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 709b9d124eeb6e972d0095d078ce39be54ef3335eb57b4042cc5499a423ac3ba
|
4
|
+
data.tar.gz: 7de22b6ec750dc0f4aebe1f0c58b871cba29253a455310b9cc00b5915627ccce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c76d4d622db3fa8250aa396d5782e6b04d3569da187a740fd600b757956226514c01ccee0ab4e9ffc0d1e9ee828a50efb37d92109aa7a461b0ff0de2e2cdf0e6
|
7
|
+
data.tar.gz: a09547f979b4742c9e4d2ddf898fea4ead8c86906ed89c100cbd476c1f022db46ecb3e0d7c6fa614c3f4ea5173699678d5621230706ad0ea3527ef3968b5a989
|
@@ -0,0 +1,19 @@
|
|
1
|
+
name: Release Drafter
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
# branches to consider in the event; optional, defaults to all
|
6
|
+
branches:
|
7
|
+
- master
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
update_release_draft:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
steps:
|
13
|
+
# Drafts your next Release notes as Pull Requests are merged into "master"
|
14
|
+
- uses: release-drafter/release-drafter@v5
|
15
|
+
with:
|
16
|
+
# (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml
|
17
|
+
# config-name: my-config.yml
|
18
|
+
env:
|
19
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
name: Mark stale issues and pull requests
|
2
|
+
|
3
|
+
on:
|
4
|
+
schedule:
|
5
|
+
- cron: "0 0 * * *"
|
6
|
+
|
7
|
+
jobs:
|
8
|
+
stale:
|
9
|
+
|
10
|
+
runs-on: ubuntu-latest
|
11
|
+
|
12
|
+
steps:
|
13
|
+
- uses: actions/stale@v1
|
14
|
+
with:
|
15
|
+
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
16
|
+
stale-issue-message: 'This issue has been marked as stale and will be automatically closed.'
|
17
|
+
stale-pr-message: 'This pull request has been marked as stale and will be automatically closed.'
|
18
|
+
stale-issue-label: 'no-issue-activity'
|
19
|
+
stale-pr-label: 'no-pr-activity'
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.6.4
|
data/.travis.yml
CHANGED
@@ -1,16 +1,20 @@
|
|
1
|
+
language: ruby
|
2
|
+
|
1
3
|
rvm:
|
2
|
-
- 2.2
|
3
|
-
- 2.3
|
4
|
-
- 2.4
|
5
4
|
- 2.5
|
5
|
+
- 2.6
|
6
|
+
|
7
|
+
env:
|
8
|
+
matrix:
|
9
|
+
- RAILS_VERSION="~> 4.1"
|
10
|
+
- RAILS_VERSION="~> 5.2"
|
11
|
+
- RAILS_VERSION="~> 6.0.0"
|
6
12
|
|
7
13
|
before_install:
|
8
14
|
- gem update --system
|
9
15
|
- gem update bundler
|
10
16
|
|
11
17
|
before_script:
|
12
|
-
- "export DISPLAY=:99.0"
|
13
|
-
- "sh -e /etc/init.d/xvfb start"
|
14
18
|
- "sudo apt-get -qq -y install fontconfig libxrender1"
|
15
|
-
- "wget https://
|
16
|
-
- "sudo apt-get install ./wkhtmltox_0.12.5-1.
|
19
|
+
- "wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.xenial_amd64.deb"
|
20
|
+
- "sudo apt-get install ./wkhtmltox_0.12.5-1.xenial_amd64.deb"
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,44 @@
|
|
1
|
+
2021-01-23
|
2
|
+
=================
|
3
|
+
* Bump to 0.8.5
|
4
|
+
* Make `PDFKit::VERSION` public (#484)
|
5
|
+
* Fix to render stylesheets as html safe string on Rails 6 (#483)
|
6
|
+
* Adds support for Rails 6
|
7
|
+
|
8
|
+
2020-08-16
|
9
|
+
=================
|
10
|
+
* Bump to 0.8.4.3.2
|
11
|
+
* Reduce scope of middleware exception handling (#476)
|
12
|
+
|
13
|
+
2020-07-05
|
14
|
+
=================
|
15
|
+
* Bump to 0.8.4.3.1
|
16
|
+
* Don't override request level Content-Disposition header if it exists (#466)
|
17
|
+
* Update rake (#471)
|
18
|
+
* Add missing require statements for tempfile (#467)
|
19
|
+
* Only grab last line of bundle exec which output (#464)
|
20
|
+
* Return 500 status when an exception is caught in middleware (#469)
|
21
|
+
* Update Travis CI URL for wkhtmltopf (#473)
|
22
|
+
|
23
|
+
2020-04-01
|
24
|
+
=================
|
25
|
+
* Bump to 0.8.4.2
|
26
|
+
* Improve path detection feedback (#460)
|
27
|
+
* Fix typos (#444)
|
28
|
+
* Update readme (#439)
|
29
|
+
|
30
|
+
2019-02-22
|
31
|
+
=================
|
32
|
+
* Bump to 0.8.4.1
|
33
|
+
* Make PDFkit threadsafe (#377)
|
34
|
+
* Update activesupport (#434)
|
35
|
+
|
1
36
|
2019-02-21
|
2
37
|
=================
|
3
38
|
* Bump to 0.8.4
|
4
39
|
* Removed support for Ruby < 2.2
|
40
|
+
* Xvfb support (#277)
|
41
|
+
* Remove 'config.protocol' from the README (#389)
|
5
42
|
|
6
43
|
2015-08-26
|
7
44
|
=================
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -2,6 +2,11 @@
|
|
2
2
|
|
3
3
|
Create PDFs using plain old HTML+CSS. Uses [wkhtmltopdf](http://github.com/antialize/wkhtmltopdf) on the back-end which renders HTML using Webkit.
|
4
4
|
|
5
|
+
## Supported versions
|
6
|
+
|
7
|
+
- Ruby 2.5, 2.6
|
8
|
+
- Rails 4.2, 5.2, 6.0
|
9
|
+
|
5
10
|
## Install
|
6
11
|
|
7
12
|
### PDFKit
|
@@ -14,7 +19,7 @@ gem install pdfkit
|
|
14
19
|
|
15
20
|
<https://github.com/pdfkit/pdfkit/wiki/Installing-WKHTMLTOPDF>
|
16
21
|
|
17
|
-
2. Try using the `wkhtmltopdf-binary` gem (mac + linux i386)
|
22
|
+
2. Try using the `wkhtmltopdf-binary-edge` gem (mac + linux i386)
|
18
23
|
```
|
19
24
|
gem install wkhtmltopdf-binary
|
20
25
|
```
|
@@ -34,7 +39,7 @@ pdf = kit.to_pdf
|
|
34
39
|
file = kit.to_file('/path/to/save/pdf')
|
35
40
|
|
36
41
|
# PDFKit.new can optionally accept a URL or a File.
|
37
|
-
# Stylesheets can not be added when source is provided as a URL
|
42
|
+
# Stylesheets can not be added when source is provided as a URL or File.
|
38
43
|
kit = PDFKit.new('http://google.com')
|
39
44
|
kit = PDFKit.new(File.new('/path/to/html'))
|
40
45
|
|
@@ -116,6 +121,13 @@ config.middleware.use PDFKit::Middleware, {}, :except => [%r[^/prawn], %r[^/secr
|
|
116
121
|
# conditions can be strings (either one or an array)
|
117
122
|
config.middleware.use PDFKit::Middleware, {}, :except => ['/secret']
|
118
123
|
```
|
124
|
+
**With conditions to force download**
|
125
|
+
```ruby
|
126
|
+
# force download with attachment disposition
|
127
|
+
config.middleware.use PDFKit::Middleware, {}, :disposition => 'attachment'
|
128
|
+
# conditions can force a filename
|
129
|
+
config.middleware.use PDFKit::Middleware, {}, :disposition => 'attachment; filename=report.pdf'
|
130
|
+
```
|
119
131
|
**Saving the generated .pdf to disk**
|
120
132
|
|
121
133
|
Setting the `PDFKit-save-pdf` header will cause PDFKit to write the generated .pdf to the file indicated by the value of the header.
|
@@ -125,7 +137,7 @@ For example:
|
|
125
137
|
headers['PDFKit-save-pdf'] = 'path/to/saved.pdf'
|
126
138
|
```
|
127
139
|
|
128
|
-
Will cause the .pdf to be saved to `path/to/saved.pdf` in addition to being sent back to the client. If the path is not writable/non-
|
140
|
+
Will cause the .pdf to be saved to `path/to/saved.pdf` in addition to being sent back to the client. If the path is not writable/non-existent the write will fail silently. The `PDFKit-save-pdf` header is never sent back to the client.
|
129
141
|
|
130
142
|
## Troubleshooting
|
131
143
|
|
@@ -140,13 +152,13 @@ Will cause the .pdf to be saved to `path/to/saved.pdf` in addition to being sent
|
|
140
152
|
around this issue you may want to run a server with multiple workers
|
141
153
|
like Passenger or try to embed your resources within your HTML to
|
142
154
|
avoid extra HTTP requests.
|
143
|
-
|
155
|
+
|
144
156
|
Example solution (rails / bundler), add unicorn to the development
|
145
157
|
group in your Gemfile `gem 'unicorn'` then run `bundle`. Next, add a
|
146
158
|
file `config/unicorn.conf` with
|
147
|
-
|
159
|
+
|
148
160
|
worker_processes 3
|
149
|
-
|
161
|
+
|
150
162
|
Then to run the app `unicorn_rails -c config/unicorn.conf` (from rails_root)
|
151
163
|
|
152
164
|
* **Resources aren't included in the PDF:** Images, CSS, or JavaScript
|
data/lib/pdfkit.rb
CHANGED
data/lib/pdfkit/configuration.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
class PDFKit
|
2
2
|
class Configuration
|
3
|
-
attr_accessor :meta_tag_prefix, :
|
3
|
+
attr_accessor :meta_tag_prefix, :root_url
|
4
4
|
attr_writer :use_xvfb, :verbose
|
5
|
+
attr_reader :default_options
|
5
6
|
|
6
7
|
def initialize
|
7
8
|
@verbose = false
|
@@ -24,14 +25,19 @@ class PDFKit
|
|
24
25
|
end
|
25
26
|
|
26
27
|
def default_wkhtmltopdf
|
27
|
-
@default_command_path
|
28
|
+
return @default_command_path if @default_command_path
|
29
|
+
if defined?(Bundler::GemfileError) && File.exists?('Gemfile')
|
30
|
+
@default_command_path = `bundle exec which wkhtmltopdf`.chomp.lines.last
|
31
|
+
end
|
32
|
+
@default_command_path = `which wkhtmltopdf`.chomp if @default_command_path.nil? || @default_command_path.empty?
|
33
|
+
@default_command_path
|
28
34
|
end
|
29
35
|
|
30
36
|
def wkhtmltopdf=(path)
|
31
37
|
if File.exist?(path)
|
32
38
|
@wkhtmltopdf = path
|
33
39
|
else
|
34
|
-
warn "No executable found at #{path}. Will fall back to #{default_wkhtmltopdf}"
|
40
|
+
warn "No executable found at #{path}. Will fall back to #{default_wkhtmltopdf}"
|
35
41
|
@wkhtmltopdf = default_wkhtmltopdf
|
36
42
|
end
|
37
43
|
end
|
@@ -51,6 +57,10 @@ class PDFKit
|
|
51
57
|
def verbose?
|
52
58
|
@verbose
|
53
59
|
end
|
60
|
+
|
61
|
+
def default_options=(options)
|
62
|
+
@default_options.merge!(options)
|
63
|
+
end
|
54
64
|
end
|
55
65
|
|
56
66
|
class << self
|
data/lib/pdfkit/middleware.rb
CHANGED
@@ -9,40 +9,50 @@ class PDFKit
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def call(env)
|
12
|
+
dup._call(env)
|
13
|
+
end
|
14
|
+
|
15
|
+
def _call(env)
|
12
16
|
@request = Rack::Request.new(env)
|
13
17
|
@render_pdf = false
|
14
18
|
|
15
19
|
set_request_to_render_as_pdf(env) if render_as_pdf?
|
16
20
|
status, headers, response = @app.call(env)
|
17
21
|
|
18
|
-
|
19
|
-
|
20
|
-
|
22
|
+
begin
|
23
|
+
if rendering_pdf? && headers['Content-Type'] =~ /text\/html|application\/xhtml\+xml/
|
24
|
+
body = response.respond_to?(:body) ? response.body : response.join
|
25
|
+
body = body.join if body.is_a?(Array)
|
21
26
|
|
22
|
-
|
23
|
-
|
24
|
-
|
27
|
+
root_url = root_url(env)
|
28
|
+
protocol = protocol(env)
|
29
|
+
options = @options.merge(root_url: root_url, protocol: protocol)
|
25
30
|
|
26
|
-
|
27
|
-
|
28
|
-
|
31
|
+
if headers['PDFKit-javascript-delay']
|
32
|
+
options.merge!(javascript_delay: headers.delete('PDFKit-javascript-delay').to_i)
|
33
|
+
end
|
29
34
|
|
30
|
-
|
31
|
-
|
35
|
+
body = PDFKit.new(body, options).to_pdf
|
36
|
+
response = [body]
|
32
37
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
38
|
+
if headers['PDFKit-save-pdf']
|
39
|
+
File.open(headers['PDFKit-save-pdf'], 'wb') { |file| file.write(body) } rescue nil
|
40
|
+
headers.delete('PDFKit-save-pdf')
|
41
|
+
end
|
37
42
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
+
unless @caching
|
44
|
+
# Do not cache PDFs
|
45
|
+
headers.delete('ETag')
|
46
|
+
headers.delete('Cache-Control')
|
47
|
+
end
|
43
48
|
|
44
|
-
|
45
|
-
|
49
|
+
headers['Content-Length'] = (body.respond_to?(:bytesize) ? body.bytesize : body.size).to_s
|
50
|
+
headers['Content-Type'] = 'application/pdf'
|
51
|
+
headers['Content-Disposition'] ||= @conditions[:disposition] || 'inline'
|
52
|
+
end
|
53
|
+
rescue StandardError => e
|
54
|
+
status = 500
|
55
|
+
response = [e.message]
|
46
56
|
end
|
47
57
|
|
48
58
|
[status, headers, response]
|
data/lib/pdfkit/pdfkit.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
require 'shellwords'
|
2
|
+
require 'tempfile'
|
2
3
|
|
3
4
|
class PDFKit
|
4
|
-
class
|
5
|
+
class Error < StandardError; end
|
6
|
+
|
7
|
+
class NoExecutableError < Error
|
5
8
|
def initialize
|
6
9
|
msg = "No wkhtmltopdf executable found at #{PDFKit.configuration.wkhtmltopdf}\n"
|
7
10
|
msg << ">> Please install wkhtmltopdf - https://github.com/pdfkit/PDFKit/wiki/Installing-WKHTMLTOPDF"
|
@@ -9,12 +12,18 @@ class PDFKit
|
|
9
12
|
end
|
10
13
|
end
|
11
14
|
|
12
|
-
class ImproperSourceError <
|
15
|
+
class ImproperSourceError < Error
|
13
16
|
def initialize(msg)
|
14
17
|
super("Improper Source: #{msg}")
|
15
18
|
end
|
16
19
|
end
|
17
20
|
|
21
|
+
class ImproperWkhtmltopdfExitStatus < Error
|
22
|
+
def initialize(invoke)
|
23
|
+
super("Command failed (exitstatus=#{$?.exitstatus}): #{invoke}")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
18
27
|
attr_accessor :source, :stylesheets
|
19
28
|
attr_reader :renderer
|
20
29
|
|
@@ -31,7 +40,7 @@ class PDFKit
|
|
31
40
|
@renderer = WkHTMLtoPDF.new options
|
32
41
|
@renderer.normalize_options
|
33
42
|
|
34
|
-
raise NoExecutableError
|
43
|
+
raise NoExecutableError unless File.exists?(PDFKit.configuration.wkhtmltopdf)
|
35
44
|
end
|
36
45
|
|
37
46
|
def command(path = nil)
|
@@ -70,7 +79,7 @@ class PDFKit
|
|
70
79
|
|
71
80
|
# $? is thread safe per
|
72
81
|
# http://stackoverflow.com/questions/2164887/thread-safe-external-process-in-ruby-plus-checking-exitstatus
|
73
|
-
raise
|
82
|
+
raise ImproperWkhtmltopdfExitStatus, invoke if empty_result?(path, result) || !successful?($?)
|
74
83
|
return result
|
75
84
|
end
|
76
85
|
|
@@ -83,7 +92,7 @@ class PDFKit
|
|
83
92
|
|
84
93
|
def find_options_in_meta(content)
|
85
94
|
# Read file if content is a File
|
86
|
-
content = content.read if content.is_a?(File)
|
95
|
+
content = content.read if content.is_a?(File) || content.is_a?(Tempfile)
|
87
96
|
|
88
97
|
found = {}
|
89
98
|
content.scan(/<meta [^>]*>/) do |meta|
|
@@ -105,7 +114,9 @@ class PDFKit
|
|
105
114
|
end
|
106
115
|
|
107
116
|
def style_tag_for(stylesheet)
|
108
|
-
"<style>#{File.read(stylesheet)}</style>"
|
117
|
+
style = "<style>#{File.read(stylesheet)}</style>"
|
118
|
+
style = style.html_safe if style.respond_to?(:html_safe)
|
119
|
+
style
|
109
120
|
end
|
110
121
|
|
111
122
|
def preprocess_html
|
@@ -116,11 +127,13 @@ class PDFKit
|
|
116
127
|
end
|
117
128
|
|
118
129
|
def append_stylesheets
|
119
|
-
raise ImproperSourceError
|
130
|
+
raise ImproperSourceError, 'Stylesheets may only be added to an HTML source' if stylesheets.any? && !@source.html?
|
120
131
|
|
121
132
|
stylesheets.each do |stylesheet|
|
122
133
|
if @source.to_s.match(/<\/head>/)
|
123
|
-
@source = Source.new(@source.to_s.gsub(/(<\/head>)/) {|s|
|
134
|
+
@source = Source.new(@source.to_s.gsub(/(<\/head>)/) {|s|
|
135
|
+
style_tag_for(stylesheet) + (s.respond_to?(:html_safe) ? s.html_safe : s)
|
136
|
+
})
|
124
137
|
else
|
125
138
|
@source.to_s.insert(0, style_tag_for(stylesheet))
|
126
139
|
end
|
data/lib/pdfkit/source.rb
CHANGED
data/lib/pdfkit/version.rb
CHANGED
data/pdfkit.gemspec
CHANGED
@@ -13,21 +13,20 @@ Gem::Specification.new do |s|
|
|
13
13
|
s.description = "Uses wkhtmltopdf to create PDFs using HTML"
|
14
14
|
s.license = "MIT"
|
15
15
|
|
16
|
-
s.rubyforge_project = "pdfkit"
|
17
|
-
|
18
16
|
s.files = `git ls-files`.split("\n")
|
19
17
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
19
|
s.require_paths = ["lib"]
|
22
20
|
|
21
|
+
s.required_ruby_version = '>= 2.5'
|
22
|
+
|
23
23
|
s.requirements << "wkhtmltopdf"
|
24
24
|
|
25
25
|
# Development Dependencies
|
26
|
-
s.add_development_dependency(%q<activesupport>, [">=
|
26
|
+
s.add_development_dependency(%q<activesupport>, [">= 4.1.11"])
|
27
27
|
s.add_development_dependency(%q<mocha>, [">= 0.9.10"])
|
28
28
|
s.add_development_dependency(%q<rack-test>, [">= 0.5.6"])
|
29
|
-
s.add_development_dependency(%q<
|
30
|
-
s.add_development_dependency(%q<rake>, ["~>0.9.2"])
|
29
|
+
s.add_development_dependency(%q<rake>, ["~>12.3.3"])
|
31
30
|
s.add_development_dependency(%q<rdoc>, ["~> 4.0.1"])
|
32
31
|
s.add_development_dependency(%q<rspec>, ["~> 3.0"])
|
33
32
|
end
|
data/spec/configuration_spec.rb
CHANGED
@@ -3,11 +3,59 @@ require 'spec_helper'
|
|
3
3
|
describe PDFKit::Configuration do
|
4
4
|
subject { PDFKit::Configuration.new }
|
5
5
|
describe "#wkhtmltopdf" do
|
6
|
+
context "when explicitly configured" do
|
7
|
+
it "uses configured value and don't detect" do
|
8
|
+
expect(subject).not_to receive(:default_wkhtmltopdf)
|
9
|
+
subject.wkhtmltopdf = "./Gemfile" # Need a file which exists
|
10
|
+
expect(subject.wkhtmltopdf).to eq("./Gemfile")
|
11
|
+
end
|
12
|
+
|
13
|
+
it "falls back to detected binary if configured path doesn't exists" do
|
14
|
+
expect(subject).to receive(:default_wkhtmltopdf).twice.and_return("/bin/fallback")
|
15
|
+
expect(subject).to receive(:warn).with(/No executable found/)
|
16
|
+
subject.wkhtmltopdf = "./missing-file" # Need a file which doesn't exist
|
17
|
+
expect(subject.wkhtmltopdf).to eq("/bin/fallback")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
6
21
|
context "when not explicitly configured" do
|
7
|
-
|
8
|
-
#
|
9
|
-
|
10
|
-
|
22
|
+
context "when running inside bundler" do
|
23
|
+
# Simulate the presence of bundler even if it's not here
|
24
|
+
before { stub_const("Bundler::GemfileError", Class) }
|
25
|
+
|
26
|
+
it "detects the existance of bundler" do
|
27
|
+
expect(subject).to receive(:`).with('bundle exec which wkhtmltopdf').and_return("c:\\windows\\path.exe\n")
|
28
|
+
expect(subject.wkhtmltopdf).to eq('c:\windows\path.exe')
|
29
|
+
end
|
30
|
+
|
31
|
+
it "falls back if bundler path fails" do
|
32
|
+
# This happens when there is a wrong (buggy) version of bundler for example
|
33
|
+
expect(subject).to receive(:`).with('bundle exec which wkhtmltopdf').and_return("")
|
34
|
+
expect(subject).to receive(:`).with('which wkhtmltopdf').and_return("c:\\windows\\path.exe\n")
|
35
|
+
expect(subject.wkhtmltopdf).to eq('c:\windows\path.exe')
|
36
|
+
end
|
37
|
+
|
38
|
+
it "returns last line of 'bundle exec which' output" do
|
39
|
+
# Happens when the user does not have a HOME directory on their system and runs bundler < 2
|
40
|
+
expect(subject).to receive(:`).with('bundle exec which wkhtmltopdf').and_return(<<~EOT
|
41
|
+
`/home/myuser` is not a directory.
|
42
|
+
Bundler will use `/tmp/bundler/home/myuser' as your home directory temporarily.
|
43
|
+
/usr/bin/wkhtmltopdf
|
44
|
+
EOT
|
45
|
+
)
|
46
|
+
expect(subject.wkhtmltopdf).to eq('/usr/bin/wkhtmltopdf')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when running without bundler" do
|
51
|
+
# Simulate the absence of bundler even if it's there
|
52
|
+
before { hide_const("Bundler::GemfileError") }
|
53
|
+
|
54
|
+
it "detects the existance of bundler" do
|
55
|
+
expect(subject).not_to receive(:`).with('bundle exec which wkhtmltopdf')
|
56
|
+
expect(subject).to receive(:`).with('which wkhtmltopdf').and_return('c:\windows\path.exe')
|
57
|
+
expect(subject.wkhtmltopdf).to eq('c:\windows\path.exe')
|
58
|
+
end
|
11
59
|
end
|
12
60
|
end
|
13
61
|
end
|
@@ -40,6 +88,13 @@ describe PDFKit::Configuration do
|
|
40
88
|
expect(subject.default_options[:quiet]).to eql false
|
41
89
|
expect(subject.default_options[:is_awesome]).to eql true
|
42
90
|
end
|
91
|
+
|
92
|
+
it "merges additional options with existing defaults" do
|
93
|
+
subject.default_options = { quiet: false, is_awesome: true }
|
94
|
+
expect(subject.default_options[:quiet]).to eql false
|
95
|
+
expect(subject.default_options[:is_awesome]).to eql true
|
96
|
+
expect(subject.default_options[:disable_smart_shrinking]).to eql false
|
97
|
+
end
|
43
98
|
end
|
44
99
|
|
45
100
|
describe "#root_url" do
|
data/spec/middleware_spec.rb
CHANGED
@@ -21,6 +21,35 @@ describe PDFKit::Middleware do
|
|
21
21
|
end
|
22
22
|
|
23
23
|
describe "#call" do
|
24
|
+
|
25
|
+
describe 'threadsafety' do
|
26
|
+
before { mock_app }
|
27
|
+
it 'is threadsafe' do
|
28
|
+
n = 30
|
29
|
+
extensions = Array.new(n) { rand > 0.5 ? 'html' : 'pdf' }
|
30
|
+
actual_content_types = Hash.new
|
31
|
+
|
32
|
+
threads = (0...n).map { |i|
|
33
|
+
Thread.new do
|
34
|
+
resp = get("http://www.example.org/public/test.#{extensions[i]}")
|
35
|
+
actual_content_types[i] = resp.content_type
|
36
|
+
end
|
37
|
+
}
|
38
|
+
|
39
|
+
threads.each(&:join)
|
40
|
+
|
41
|
+
extensions.each_with_index do |extension, index|
|
42
|
+
result = actual_content_types[index]
|
43
|
+
case extension
|
44
|
+
when 'html', 'txt', 'csv'
|
45
|
+
expect(result).to eq("text/#{extension}")
|
46
|
+
when 'pdf'
|
47
|
+
expect(result).to eq('application/pdf')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
24
53
|
describe "caching" do
|
25
54
|
let(:headers) do
|
26
55
|
{
|
@@ -312,6 +341,83 @@ describe PDFKit::Middleware do
|
|
312
341
|
end
|
313
342
|
end
|
314
343
|
end
|
344
|
+
|
345
|
+
describe ":disposition" do
|
346
|
+
describe "doesn't overwrite existing value" do
|
347
|
+
let(:headers) do
|
348
|
+
super().merge({
|
349
|
+
'Content-Disposition' => 'attachment; filename=report-20200101.pdf'
|
350
|
+
})
|
351
|
+
end
|
352
|
+
|
353
|
+
specify do
|
354
|
+
mock_app({}, { :disposition => 'inline' })
|
355
|
+
get 'http://www.example.org/public/test.pdf'
|
356
|
+
expect(last_response.headers["Content-Disposition"]).to eq('attachment; filename=report-20200101.pdf')
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
describe "inline or blank" do
|
361
|
+
context "default" do
|
362
|
+
specify do
|
363
|
+
mock_app
|
364
|
+
get 'http://www.example.org/public/test.pdf'
|
365
|
+
expect(last_response.headers["Content-Disposition"]).to eq("inline")
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
context "inline" do
|
370
|
+
specify do
|
371
|
+
mock_app({}, { :disposition => 'inline' })
|
372
|
+
get 'http://www.example.org/public/test.pdf'
|
373
|
+
expect(last_response.headers["Content-Disposition"]).to eq("inline")
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
describe "attachment" do
|
379
|
+
context "attachment" do
|
380
|
+
specify do
|
381
|
+
mock_app({}, { :disposition => 'attachment' })
|
382
|
+
get 'http://www.example.org/public/test.pdf'
|
383
|
+
expect(last_response.headers["Content-Disposition"]).to eq("attachment")
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
context "attachment with filename" do
|
388
|
+
specify do
|
389
|
+
mock_app({}, { :disposition => 'attachment; filename=report.pdf' })
|
390
|
+
get 'http://www.example.org/public/test.pdf'
|
391
|
+
expect(last_response.headers["Content-Disposition"]).to eq("attachment; filename=report.pdf")
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
describe "error handling" do
|
398
|
+
let(:error) { StandardError.new("Something went wrong") }
|
399
|
+
|
400
|
+
context "errors raised by PDF generation" do
|
401
|
+
specify do
|
402
|
+
mock_app
|
403
|
+
allow(PDFKit).to receive(:new).and_raise(error)
|
404
|
+
get 'http://www.example.org/public/test.pdf'
|
405
|
+
expect(last_response.status).to eq(500)
|
406
|
+
expect(last_response.body).to eq(error.message)
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
context "errors raised upstream" do
|
411
|
+
specify do
|
412
|
+
mock_app
|
413
|
+
allow(@app).to receive(:call).and_raise(error)
|
414
|
+
|
415
|
+
expect {
|
416
|
+
get 'http://www.example.org/public/test.pdf'
|
417
|
+
}.to raise_error(error)
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|
315
421
|
end
|
316
422
|
|
317
423
|
describe "remove .pdf from PATH_INFO and REQUEST_URI" do
|
@@ -397,22 +503,4 @@ describe PDFKit::Middleware do
|
|
397
503
|
end
|
398
504
|
end
|
399
505
|
end
|
400
|
-
|
401
|
-
it "does not get stuck rendering each request as pdf" do
|
402
|
-
mock_app
|
403
|
-
# false by default. No requests.
|
404
|
-
expect(@app.send(:rendering_pdf?)).to eq(false)
|
405
|
-
|
406
|
-
# Remain false on a normal request
|
407
|
-
get 'http://www.example.org/public/file'
|
408
|
-
expect(@app.send(:rendering_pdf?)).to eq(false)
|
409
|
-
|
410
|
-
# Return true on a pdf request.
|
411
|
-
get 'http://www.example.org/public/file.pdf'
|
412
|
-
expect(@app.send(:rendering_pdf?)).to eq(true)
|
413
|
-
|
414
|
-
# Restore to false on any non-pdf request.
|
415
|
-
get 'http://www.example.org/public/file'
|
416
|
-
expect(@app.send(:rendering_pdf?)).to eq(false)
|
417
|
-
end
|
418
506
|
end
|
data/spec/pdfkit_spec.rb
CHANGED
@@ -23,6 +23,13 @@ describe PDFKit do
|
|
23
23
|
expect(pdfkit.source.to_s).to eq(file_path)
|
24
24
|
end
|
25
25
|
|
26
|
+
it "accepts a Tempfile as the source" do
|
27
|
+
file_path = File.join(SPEC_ROOT,'fixtures','example.html')
|
28
|
+
pdfkit = PDFKit.new(Tempfile.new(file_path))
|
29
|
+
expect(pdfkit.source).to be_file
|
30
|
+
expect(pdfkit.source.to_s).to match /^#{Dir.tmpdir}/
|
31
|
+
end
|
32
|
+
|
26
33
|
# Options
|
27
34
|
## options keys
|
28
35
|
it "drops options without values" do
|
@@ -252,6 +259,12 @@ describe PDFKit do
|
|
252
259
|
expect(pdfkit.command).to match /#{file_path} -$/
|
253
260
|
end
|
254
261
|
|
262
|
+
it "specifies the path to the source if it is a tempfile" do
|
263
|
+
file_path = File.join(SPEC_ROOT,'fixtures','example.html')
|
264
|
+
pdfkit = PDFKit.new(Tempfile.new(file_path))
|
265
|
+
expect(pdfkit.command).to match /#{Dir.tmpdir}\S+ -$/
|
266
|
+
end
|
267
|
+
|
255
268
|
it "specifies the path for the ouput if a path is given" do
|
256
269
|
file_path = "/path/to/output.pdf"
|
257
270
|
pdfkit = PDFKit.new("html")
|
@@ -488,6 +501,14 @@ describe PDFKit do
|
|
488
501
|
expect(pdfkit.source.to_s).to include("<style>#{File.read(css)}</style></head>")
|
489
502
|
end
|
490
503
|
|
504
|
+
it "can deal with ActiveSupport::SafeBuffer if the HTML doesn't have a head tag" do
|
505
|
+
pdfkit = PDFKit.new(ActiveSupport::SafeBuffer.new "<html><body>Hai!</body></html>")
|
506
|
+
css = File.join(SPEC_ROOT,'fixtures','example.css')
|
507
|
+
pdfkit.stylesheets << css
|
508
|
+
pdfkit.to_pdf
|
509
|
+
expect(pdfkit.source.to_s).to include("<style>#{File.read(css)}</style>")
|
510
|
+
end
|
511
|
+
|
491
512
|
it "escapes \\X in stylesheets" do
|
492
513
|
pdfkit = PDFKit.new("<html><head></head><body>Hai!</body></html>")
|
493
514
|
css = File.join(SPEC_ROOT,'fixtures','example_with_hex_symbol.css')
|
@@ -499,7 +520,7 @@ describe PDFKit do
|
|
499
520
|
#NOTICE: This test is failed if use wkhtmltopdf-binary (0.9.9.1)
|
500
521
|
it "throws an error if it is unable to connect" do
|
501
522
|
pdfkit = PDFKit.new("http://google.com/this-should-not-be-found/404.html")
|
502
|
-
expect { pdfkit.to_pdf }.to raise_error /exitstatus=1/
|
523
|
+
expect { pdfkit.to_pdf }.to raise_error PDFKit::ImproperWkhtmltopdfExitStatus, /exitstatus=1/
|
503
524
|
end
|
504
525
|
|
505
526
|
it "does not throw an error if it is unable to connect", pending: 'this test works for wkhtmltopdf-binary (0.9.9.1)' do
|
data/spec/source_spec.rb
CHANGED
@@ -12,6 +12,11 @@ describe PDFKit::Source do
|
|
12
12
|
expect(source).not_to be_url
|
13
13
|
end
|
14
14
|
|
15
|
+
it "returns false if passed a tempfile" do
|
16
|
+
source = PDFKit::Source.new(::Tempfile.new(__FILE__))
|
17
|
+
expect(source).not_to be_url
|
18
|
+
end
|
19
|
+
|
15
20
|
it "returns false if passed HTML" do
|
16
21
|
source = PDFKit::Source.new('<blink>Oh Hai!</blink>')
|
17
22
|
expect(source).not_to be_url
|
@@ -29,6 +34,11 @@ describe PDFKit::Source do
|
|
29
34
|
expect(source).to be_file
|
30
35
|
end
|
31
36
|
|
37
|
+
it "returns true if passed a tempfile" do
|
38
|
+
source = PDFKit::Source.new(::Tempfile.new(__FILE__))
|
39
|
+
expect(source).to be_file
|
40
|
+
end
|
41
|
+
|
32
42
|
it "returns false if passed a url like string" do
|
33
43
|
source = PDFKit::Source.new('http://google.com')
|
34
44
|
expect(source).not_to be_file
|
@@ -51,6 +61,11 @@ describe PDFKit::Source do
|
|
51
61
|
expect(source).not_to be_html
|
52
62
|
end
|
53
63
|
|
64
|
+
it "returns false if passed a tempfile" do
|
65
|
+
source = PDFKit::Source.new(::Tempfile.new(__FILE__))
|
66
|
+
expect(source).not_to be_html
|
67
|
+
end
|
68
|
+
|
54
69
|
it "returns false if passed a url like string" do
|
55
70
|
source = PDFKit::Source.new('http://google.com')
|
56
71
|
expect(source).not_to be_html
|
@@ -77,6 +92,11 @@ describe PDFKit::Source do
|
|
77
92
|
source = PDFKit::Source.new(::File.new(__FILE__))
|
78
93
|
expect(source.to_input_for_command).to match 'spec/source_spec.rb'
|
79
94
|
end
|
95
|
+
|
96
|
+
it "returns the file path for tempfile sources" do
|
97
|
+
source = PDFKit::Source.new(file = ::Tempfile.new(__FILE__))
|
98
|
+
expect(source.to_input_for_command).to match file.path
|
99
|
+
end
|
80
100
|
end
|
81
101
|
|
82
102
|
describe "#to_s" do
|
@@ -90,6 +110,11 @@ describe PDFKit::Source do
|
|
90
110
|
expect(source.to_s).to eq(__FILE__)
|
91
111
|
end
|
92
112
|
|
113
|
+
it "returns a path if passed a tempfile" do
|
114
|
+
source = PDFKit::Source.new(file = ::Tempfile.new(__FILE__))
|
115
|
+
expect(source.to_s).to eq(file.path)
|
116
|
+
end
|
117
|
+
|
93
118
|
it "returns the url if passed a url like string" do
|
94
119
|
source = PDFKit::Source.new('http://google.com')
|
95
120
|
expect(source.to_s).to eq('http://google.com')
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pdfkit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jared Pace
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-01-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -17,14 +17,14 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version:
|
20
|
+
version: 4.1.11
|
21
21
|
type: :development
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version:
|
27
|
+
version: 4.1.11
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: mocha
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -53,34 +53,20 @@ dependencies:
|
|
53
53
|
- - ">="
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: 0.5.6
|
56
|
-
- !ruby/object:Gem::Dependency
|
57
|
-
name: i18n
|
58
|
-
requirement: !ruby/object:Gem::Requirement
|
59
|
-
requirements:
|
60
|
-
- - "~>"
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
version: 0.6.11
|
63
|
-
type: :development
|
64
|
-
prerelease: false
|
65
|
-
version_requirements: !ruby/object:Gem::Requirement
|
66
|
-
requirements:
|
67
|
-
- - "~>"
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: 0.6.11
|
70
56
|
- !ruby/object:Gem::Dependency
|
71
57
|
name: rake
|
72
58
|
requirement: !ruby/object:Gem::Requirement
|
73
59
|
requirements:
|
74
60
|
- - "~>"
|
75
61
|
- !ruby/object:Gem::Version
|
76
|
-
version:
|
62
|
+
version: 12.3.3
|
77
63
|
type: :development
|
78
64
|
prerelease: false
|
79
65
|
version_requirements: !ruby/object:Gem::Requirement
|
80
66
|
requirements:
|
81
67
|
- - "~>"
|
82
68
|
- !ruby/object:Gem::Version
|
83
|
-
version:
|
69
|
+
version: 12.3.3
|
84
70
|
- !ruby/object:Gem::Dependency
|
85
71
|
name: rdoc
|
86
72
|
requirement: !ruby/object:Gem::Requirement
|
@@ -117,6 +103,8 @@ extensions: []
|
|
117
103
|
extra_rdoc_files: []
|
118
104
|
files:
|
119
105
|
- ".document"
|
106
|
+
- ".github/workflows/release-drafter.yml"
|
107
|
+
- ".github/workflows/stale.yml"
|
120
108
|
- ".gitignore"
|
121
109
|
- ".rspec"
|
122
110
|
- ".ruby-gemset"
|
@@ -160,7 +148,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
160
148
|
requirements:
|
161
149
|
- - ">="
|
162
150
|
- !ruby/object:Gem::Version
|
163
|
-
version: '
|
151
|
+
version: '2.5'
|
164
152
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
165
153
|
requirements:
|
166
154
|
- - ">="
|
@@ -168,8 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
168
156
|
version: '0'
|
169
157
|
requirements:
|
170
158
|
- wkhtmltopdf
|
171
|
-
|
172
|
-
rubygems_version: 2.7.6
|
159
|
+
rubygems_version: 3.0.3
|
173
160
|
signing_key:
|
174
161
|
specification_version: 4
|
175
162
|
summary: HTML+CSS -> PDF
|