pdfkit 0.8.3 → 0.8.4.3.2
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 +8 -8
- data/CHANGELOG.md +35 -0
- data/Gemfile +1 -1
- data/README.md +13 -7
- data/lib/pdfkit/configuration.rb +24 -4
- data/lib/pdfkit/middleware.rb +32 -22
- data/lib/pdfkit/pdfkit.rb +16 -7
- data/lib/pdfkit/source.rb +2 -1
- data/lib/pdfkit/version.rb +1 -1
- data/pdfkit.gemspec +2 -5
- data/spec/configuration_spec.rb +86 -4
- data/spec/middleware_spec.rb +106 -18
- data/spec/pdfkit_spec.rb +32 -1
- data/spec/source_spec.rb +25 -0
- metadata +9 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9763236251a08873c269bb76fa8cbc81e64111a9bd94ea7a167c0e96ad1e0dc
|
4
|
+
data.tar.gz: ab65d5b9648ec671a22191cf7eca7b14d6c4b07917e45adf479046360f7adfd7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ce66b221fce28fb3be395a199fdb4fc3c660a1702302c4b453bc40f39033cadc41fff9ea8a5f0e612f12a1040fbdad31e738823c6d9cf3ea2456a9ebf55b999
|
7
|
+
data.tar.gz: 73827642f8a0d5a87745eb9d853f9a9a9e0d62ea7ab9f31e552be71cba2c4ce7b340da992ab0eabd145a0fbb6395a30d953396fc1bf25f7410db5df9572eb6e1
|
@@ -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,16 @@
|
|
1
|
+
language: ruby
|
2
|
+
|
1
3
|
rvm:
|
2
|
-
-
|
3
|
-
-
|
4
|
-
- 2.
|
5
|
-
- 2.
|
4
|
+
- 2.3
|
5
|
+
- 2.4
|
6
|
+
- 2.5
|
7
|
+
- 2.6
|
6
8
|
|
7
9
|
before_install:
|
8
10
|
- gem update --system
|
9
11
|
- gem update bundler
|
10
12
|
|
11
13
|
before_script:
|
12
|
-
- "export DISPLAY=:99.0"
|
13
|
-
- "sh -e /etc/init.d/xvfb start"
|
14
14
|
- "sudo apt-get -qq -y install fontconfig libxrender1"
|
15
|
-
- "wget
|
16
|
-
- "sudo
|
15
|
+
- "wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.xenial_amd64.deb"
|
16
|
+
- "sudo apt-get install ./wkhtmltox_0.12.5-1.xenial_amd64.deb"
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,38 @@
|
|
1
|
+
2020-08-16
|
2
|
+
=================
|
3
|
+
* Bump to 0.8.4.3.2
|
4
|
+
* Reduce scope of middleware exception handling (#476)
|
5
|
+
|
6
|
+
2020-07-05
|
7
|
+
=================
|
8
|
+
* Bump to 0.8.4.3.1
|
9
|
+
* Don't override request level Content-Disposition header if it exists (#466)
|
10
|
+
* Update rake (#471)
|
11
|
+
* Add missing require statements for tempfile (#467)
|
12
|
+
* Only grab last line of bundle exec which output (#464)
|
13
|
+
* Return 500 status when an exception is caught in middleware (#469)
|
14
|
+
* Update Travis CI URL for wkhtmltopf (#473)
|
15
|
+
|
16
|
+
2020-04-01
|
17
|
+
=================
|
18
|
+
* Bump to 0.8.4.2
|
19
|
+
* Improve path detection feedback (#460)
|
20
|
+
* Fix typos (#444)
|
21
|
+
* Update readme (#439)
|
22
|
+
|
23
|
+
2019-02-22
|
24
|
+
=================
|
25
|
+
* Bump to 0.8.4.1
|
26
|
+
* Make PDFkit threadsafe (#377)
|
27
|
+
* Update activesupport (#434)
|
28
|
+
|
29
|
+
2019-02-21
|
30
|
+
=================
|
31
|
+
* Bump to 0.8.4
|
32
|
+
* Removed support for Ruby < 2.2
|
33
|
+
* Xvfb support (#277)
|
34
|
+
* Remove 'config.protocol' from the README (#389)
|
35
|
+
|
1
36
|
2015-08-26
|
2
37
|
=================
|
3
38
|
* Bump to 0.8.2
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -14,7 +14,7 @@ gem install pdfkit
|
|
14
14
|
|
15
15
|
<https://github.com/pdfkit/pdfkit/wiki/Installing-WKHTMLTOPDF>
|
16
16
|
|
17
|
-
2. Try using the `wkhtmltopdf-binary` gem (mac + linux i386)
|
17
|
+
2. Try using the `wkhtmltopdf-binary-edge` gem (mac + linux i386)
|
18
18
|
```
|
19
19
|
gem install wkhtmltopdf-binary
|
20
20
|
```
|
@@ -34,7 +34,7 @@ pdf = kit.to_pdf
|
|
34
34
|
file = kit.to_file('/path/to/save/pdf')
|
35
35
|
|
36
36
|
# PDFKit.new can optionally accept a URL or a File.
|
37
|
-
# Stylesheets can not be added when source is provided as a URL
|
37
|
+
# Stylesheets can not be added when source is provided as a URL or File.
|
38
38
|
kit = PDFKit.new('http://google.com')
|
39
39
|
kit = PDFKit.new(File.new('/path/to/html'))
|
40
40
|
|
@@ -76,7 +76,6 @@ PDFKit.configure do |config|
|
|
76
76
|
}
|
77
77
|
# Use only if your external hostname is unavailable on the server.
|
78
78
|
config.root_url = "http://localhost"
|
79
|
-
config.protocol = 'http'
|
80
79
|
config.verbose = false
|
81
80
|
end
|
82
81
|
```
|
@@ -117,6 +116,13 @@ config.middleware.use PDFKit::Middleware, {}, :except => [%r[^/prawn], %r[^/secr
|
|
117
116
|
# conditions can be strings (either one or an array)
|
118
117
|
config.middleware.use PDFKit::Middleware, {}, :except => ['/secret']
|
119
118
|
```
|
119
|
+
**With conditions to force download**
|
120
|
+
```ruby
|
121
|
+
# force download with attachment disposition
|
122
|
+
config.middleware.use PDFKit::Middleware, {}, :disposition => 'attachment'
|
123
|
+
# conditions can force a filename
|
124
|
+
config.middleware.use PDFKit::Middleware, {}, :disposition => 'attachment; filename=report.pdf'
|
125
|
+
```
|
120
126
|
**Saving the generated .pdf to disk**
|
121
127
|
|
122
128
|
Setting the `PDFKit-save-pdf` header will cause PDFKit to write the generated .pdf to the file indicated by the value of the header.
|
@@ -126,7 +132,7 @@ For example:
|
|
126
132
|
headers['PDFKit-save-pdf'] = 'path/to/saved.pdf'
|
127
133
|
```
|
128
134
|
|
129
|
-
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-
|
135
|
+
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.
|
130
136
|
|
131
137
|
## Troubleshooting
|
132
138
|
|
@@ -141,13 +147,13 @@ Will cause the .pdf to be saved to `path/to/saved.pdf` in addition to being sent
|
|
141
147
|
around this issue you may want to run a server with multiple workers
|
142
148
|
like Passenger or try to embed your resources within your HTML to
|
143
149
|
avoid extra HTTP requests.
|
144
|
-
|
150
|
+
|
145
151
|
Example solution (rails / bundler), add unicorn to the development
|
146
152
|
group in your Gemfile `gem 'unicorn'` then run `bundle`. Next, add a
|
147
153
|
file `config/unicorn.conf` with
|
148
|
-
|
154
|
+
|
149
155
|
worker_processes 3
|
150
|
-
|
156
|
+
|
151
157
|
Then to run the app `unicorn_rails -c config/unicorn.conf` (from rails_root)
|
152
158
|
|
153
159
|
* **Resources aren't included in the PDF:** Images, CSS, or JavaScript
|
data/lib/pdfkit/configuration.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
class PDFKit
|
2
2
|
class Configuration
|
3
|
-
attr_accessor :meta_tag_prefix, :
|
4
|
-
attr_writer :verbose
|
3
|
+
attr_accessor :meta_tag_prefix, :root_url
|
4
|
+
attr_writer :use_xvfb, :verbose
|
5
|
+
attr_reader :default_options
|
5
6
|
|
6
7
|
def initialize
|
7
8
|
@verbose = false
|
9
|
+
@use_xvfb = false
|
8
10
|
@meta_tag_prefix = 'pdfkit-'
|
9
11
|
@default_options = {
|
10
12
|
:disable_smart_shrinking => false,
|
@@ -23,18 +25,31 @@ class PDFKit
|
|
23
25
|
end
|
24
26
|
|
25
27
|
def default_wkhtmltopdf
|
26
|
-
@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
|
27
34
|
end
|
28
35
|
|
29
36
|
def wkhtmltopdf=(path)
|
30
37
|
if File.exist?(path)
|
31
38
|
@wkhtmltopdf = path
|
32
39
|
else
|
33
|
-
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}"
|
34
41
|
@wkhtmltopdf = default_wkhtmltopdf
|
35
42
|
end
|
36
43
|
end
|
37
44
|
|
45
|
+
def executable
|
46
|
+
using_xvfb? ? "xvfb-run #{wkhtmltopdf}" : wkhtmltopdf
|
47
|
+
end
|
48
|
+
|
49
|
+
def using_xvfb?
|
50
|
+
@use_xvfb
|
51
|
+
end
|
52
|
+
|
38
53
|
def quiet?
|
39
54
|
!@verbose
|
40
55
|
end
|
@@ -42,6 +57,10 @@ class PDFKit
|
|
42
57
|
def verbose?
|
43
58
|
@verbose
|
44
59
|
end
|
60
|
+
|
61
|
+
def default_options=(options)
|
62
|
+
@default_options.merge!(options)
|
63
|
+
end
|
45
64
|
end
|
46
65
|
|
47
66
|
class << self
|
@@ -54,6 +73,7 @@ class PDFKit
|
|
54
73
|
# @example
|
55
74
|
# PDFKit.configure do |config|
|
56
75
|
# config.wkhtmltopdf = '/usr/bin/wkhtmltopdf'
|
76
|
+
# config.use_xvfb = true
|
57
77
|
# config.verbose = true
|
58
78
|
# end
|
59
79
|
|
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)
|
@@ -53,7 +62,7 @@ class PDFKit
|
|
53
62
|
end
|
54
63
|
|
55
64
|
def executable
|
56
|
-
PDFKit.configuration.
|
65
|
+
PDFKit.configuration.executable
|
57
66
|
end
|
58
67
|
|
59
68
|
def to_pdf(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|
|
@@ -116,7 +125,7 @@ class PDFKit
|
|
116
125
|
end
|
117
126
|
|
118
127
|
def append_stylesheets
|
119
|
-
raise ImproperSourceError
|
128
|
+
raise ImproperSourceError, 'Stylesheets may only be added to an HTML source' if stylesheets.any? && !@source.html?
|
120
129
|
|
121
130
|
stylesheets.each do |stylesheet|
|
122
131
|
if @source.to_s.match(/<\/head>/)
|
data/lib/pdfkit/source.rb
CHANGED
data/lib/pdfkit/version.rb
CHANGED
data/pdfkit.gemspec
CHANGED
@@ -13,8 +13,6 @@ 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) }
|
@@ -23,11 +21,10 @@ Gem::Specification.new do |s|
|
|
23
21
|
s.requirements << "wkhtmltopdf"
|
24
22
|
|
25
23
|
# Development Dependencies
|
26
|
-
s.add_development_dependency(%q<activesupport>, [">=
|
24
|
+
s.add_development_dependency(%q<activesupport>, [">= 4.1.11"])
|
27
25
|
s.add_development_dependency(%q<mocha>, [">= 0.9.10"])
|
28
26
|
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"])
|
27
|
+
s.add_development_dependency(%q<rake>, ["~>12.3.3"])
|
31
28
|
s.add_development_dependency(%q<rdoc>, ["~> 4.0.1"])
|
32
29
|
s.add_development_dependency(%q<rspec>, ["~> 3.0"])
|
33
30
|
end
|
data/spec/configuration_spec.rb
CHANGED
@@ -3,12 +3,71 @@ 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
|
11
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
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "#executable" do
|
64
|
+
it "returns wkhtmltopdf by default" do
|
65
|
+
expect(subject.executable).to eql subject.wkhtmltopdf
|
66
|
+
end
|
67
|
+
|
68
|
+
it "uses xvfb-run wrapper when option of using xvfb is configured" do
|
69
|
+
expect(subject).to receive(:using_xvfb?).and_return(true)
|
70
|
+
expect(subject.executable).to include 'xvfb-run'
|
12
71
|
end
|
13
72
|
end
|
14
73
|
|
@@ -29,6 +88,13 @@ describe PDFKit::Configuration do
|
|
29
88
|
expect(subject.default_options[:quiet]).to eql false
|
30
89
|
expect(subject.default_options[:is_awesome]).to eql true
|
31
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
|
32
98
|
end
|
33
99
|
|
34
100
|
describe "#root_url" do
|
@@ -53,6 +119,22 @@ describe PDFKit::Configuration do
|
|
53
119
|
end
|
54
120
|
end
|
55
121
|
|
122
|
+
describe "#using_xvfb?" do
|
123
|
+
it "can be configured to true" do
|
124
|
+
subject.use_xvfb = true
|
125
|
+
expect(subject.using_xvfb?).to eql true
|
126
|
+
end
|
127
|
+
|
128
|
+
it "defaults to false" do
|
129
|
+
expect(subject.using_xvfb?).to eql false
|
130
|
+
end
|
131
|
+
|
132
|
+
it "can be configured to false" do
|
133
|
+
subject.use_xvfb = false
|
134
|
+
expect(subject.using_xvfb?).to eql false
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
56
138
|
describe "#verbose?" do
|
57
139
|
it "can be configured to true" do
|
58
140
|
subject.verbose = true
|
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")
|
@@ -384,6 +397,24 @@ describe PDFKit do
|
|
384
397
|
end
|
385
398
|
end
|
386
399
|
|
400
|
+
it "does not use xvfb-run wrapper by default" do
|
401
|
+
pdfkit = PDFKit.new('html')
|
402
|
+
expect(pdfkit.command).not_to include 'xvfb-run'
|
403
|
+
end
|
404
|
+
|
405
|
+
it "uses xvfb-run wrapper when option of using xvfb is configured" do
|
406
|
+
PDFKit.configure do |config|
|
407
|
+
config.use_xvfb = true
|
408
|
+
end
|
409
|
+
|
410
|
+
pdfkit = PDFKit.new('html')
|
411
|
+
expect(pdfkit.command).to include 'xvfb-run'
|
412
|
+
|
413
|
+
PDFKit.configure do |config|
|
414
|
+
config.use_xvfb = false
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
387
418
|
context "on windows" do
|
388
419
|
before do
|
389
420
|
allow(PDFKit::OS).to receive(:host_is_windows?).and_return(true)
|
@@ -481,7 +512,7 @@ describe PDFKit do
|
|
481
512
|
#NOTICE: This test is failed if use wkhtmltopdf-binary (0.9.9.1)
|
482
513
|
it "throws an error if it is unable to connect" do
|
483
514
|
pdfkit = PDFKit.new("http://google.com/this-should-not-be-found/404.html")
|
484
|
-
expect { pdfkit.to_pdf }.to raise_error /exitstatus=1/
|
515
|
+
expect { pdfkit.to_pdf }.to raise_error PDFKit::ImproperWkhtmltopdfExitStatus, /exitstatus=1/
|
485
516
|
end
|
486
517
|
|
487
518
|
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.3
|
4
|
+
version: 0.8.4.3.2
|
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: 2020-08-16 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"
|
@@ -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
|