pdfkit 0.8.0 → 0.8.7.1
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 +5 -5
- data/.github/workflows/release-drafter.yml +19 -0
- data/.github/workflows/stale.yml +19 -0
- data/.github/workflows/test.yml +59 -0
- data/.ruby-version +1 -1
- data/.travis.yml +42 -8
- data/CHANGELOG.md +71 -1
- data/Gemfile +1 -1
- data/README.md +36 -10
- data/lib/pdfkit/configuration.rb +38 -3
- data/lib/pdfkit/html_preprocessor.rb +25 -0
- data/lib/pdfkit/middleware.rb +53 -43
- data/lib/pdfkit/os.rb +21 -0
- data/lib/pdfkit/pdfkit.rb +55 -96
- data/lib/pdfkit/source.rb +36 -7
- data/lib/pdfkit/version.rb +3 -1
- data/lib/pdfkit/wkhtmltopdf.rb +82 -0
- data/lib/pdfkit.rb +6 -0
- data/pdfkit.gemspec +9 -7
- data/spec/configuration_spec.rb +85 -12
- data/spec/html_preprocessor_spec.rb +71 -0
- data/spec/middleware_spec.rb +240 -107
- data/spec/os_spec.rb +67 -0
- data/spec/pdfkit_spec.rb +132 -52
- data/spec/source_spec.rb +67 -13
- data/spec/spec_helper.rb +5 -1
- metadata +45 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: dd9ab1711dcc1f5dc4c9ec2b0f5a203394cc8276291f34bd59230dd832c6b51c
|
4
|
+
data.tar.gz: 0ec141cfe484aea9ae00488c34da32573f8f84d7ae3a5a3d5c954a0d4acfbee5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d8cf1754028c05b1dab1f382c91b86672a8a2808bbabbe66132fdb78501a731b1a651b5d276c0818efba1b537a685d2f55cb2a281935edf8c7b5b58c3aed1f1a
|
7
|
+
data.tar.gz: 93f26e92cc31dd7f4fdaf1d5a20c2b2c5463d66588bc465bfacbfa4aecbbbe19662b1e605c1ac69593e1974fc0d606ff92298cfdace4c55313d977b87d128fc4
|
@@ -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'
|
@@ -0,0 +1,59 @@
|
|
1
|
+
name: Test workflow
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
strategy:
|
8
|
+
fail-fast: false
|
9
|
+
matrix:
|
10
|
+
os: [ubuntu-latest]
|
11
|
+
ruby:
|
12
|
+
- '2.5'
|
13
|
+
- '2.6'
|
14
|
+
- '2.7'
|
15
|
+
- '3.0'
|
16
|
+
- '3.1'
|
17
|
+
rails:
|
18
|
+
- '~> 4.1'
|
19
|
+
- '~> 5.2'
|
20
|
+
- '~> 6.0.0'
|
21
|
+
- '~> 6.1'
|
22
|
+
- '~> 7.0.0'
|
23
|
+
exclude:
|
24
|
+
- ruby: '2.5'
|
25
|
+
rails: '~> 7.0.0'
|
26
|
+
- ruby: '2.6'
|
27
|
+
rails: '~> 7.0.0'
|
28
|
+
- ruby: '2.7'
|
29
|
+
rails: '~> 4.1'
|
30
|
+
- ruby: '3.0'
|
31
|
+
rails: '~> 4.1'
|
32
|
+
- ruby: '3.0'
|
33
|
+
rails: '~> 5.2'
|
34
|
+
- ruby: '3.1'
|
35
|
+
rails: '~> 4.1'
|
36
|
+
- ruby: '3.1'
|
37
|
+
rails: '~> 5.2'
|
38
|
+
- ruby: '3.1'
|
39
|
+
rails: '~> 6.0.0'
|
40
|
+
runs-on: ${{ matrix.os }}
|
41
|
+
env:
|
42
|
+
RAILS_VERSION: ${{ matrix.rails }}
|
43
|
+
steps:
|
44
|
+
- uses: actions/checkout@v2
|
45
|
+
- uses: ruby/setup-ruby@v1
|
46
|
+
with:
|
47
|
+
ruby-version: ${{ matrix.ruby }}
|
48
|
+
rubygems: latest
|
49
|
+
bundler: latest
|
50
|
+
bundler-cache: true
|
51
|
+
|
52
|
+
- name: Setup wkhtmltopdf
|
53
|
+
run: |
|
54
|
+
sudo apt-get install -y xfonts-base xfonts-75dpi
|
55
|
+
wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.bionic_amd64.deb
|
56
|
+
sudo dpkg -i wkhtmltox_0.12.6-1.bionic_amd64.deb
|
57
|
+
|
58
|
+
- name: Run tests
|
59
|
+
run: bundle exec rake
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.6.9
|
data/.travis.yml
CHANGED
@@ -1,12 +1,46 @@
|
|
1
|
+
language: ruby
|
2
|
+
|
1
3
|
rvm:
|
2
|
-
-
|
3
|
-
-
|
4
|
-
- 2.
|
5
|
-
-
|
4
|
+
- 2.5
|
5
|
+
- 2.6
|
6
|
+
- 2.7
|
7
|
+
- 3.0
|
8
|
+
- 3.1
|
9
|
+
|
10
|
+
env:
|
11
|
+
matrix:
|
12
|
+
- RAILS_VERSION="~> 4.1"
|
13
|
+
- RAILS_VERSION="~> 5.2"
|
14
|
+
- RAILS_VERSION="~> 6.0.0"
|
15
|
+
- RAILS_VERSION="~> 6.1"
|
16
|
+
- RAILS_VERSION="~> 7.0.0"
|
17
|
+
|
18
|
+
jobs:
|
19
|
+
exclude:
|
20
|
+
- rvm: 2.5
|
21
|
+
env: RAILS_VERSION="~> 7.0.0"
|
22
|
+
- rvm: 2.6
|
23
|
+
env: RAILS_VERSION="~> 7.0.0"
|
24
|
+
- rvm: 2.7
|
25
|
+
env: RAILS_VERSION="~> 4.1"
|
26
|
+
- rvm: 3.0
|
27
|
+
env: RAILS_VERSION="~> 4.1"
|
28
|
+
- rvm: 3.0
|
29
|
+
env: RAILS_VERSION="~> 5.2"
|
30
|
+
- rvm: 3.1
|
31
|
+
env: RAILS_VERSION="~> 4.1"
|
32
|
+
- rvm: 3.1
|
33
|
+
env: RAILS_VERSION="~> 5.2"
|
34
|
+
- rvm: 3.1
|
35
|
+
env: RAILS_VERSION="~> 6.0.0"
|
36
|
+
|
37
|
+
cache: bundler
|
38
|
+
|
39
|
+
before_install:
|
40
|
+
- gem update --system
|
41
|
+
- gem update bundler
|
6
42
|
|
7
43
|
before_script:
|
8
|
-
- "export DISPLAY=:99.0"
|
9
|
-
- "sh -e /etc/init.d/xvfb start"
|
10
44
|
- "sudo apt-get -qq -y install fontconfig libxrender1"
|
11
|
-
- "wget
|
12
|
-
- "sudo
|
45
|
+
- "wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.xenial_amd64.deb"
|
46
|
+
- "sudo apt-get install ./wkhtmltox_0.12.5-1.xenial_amd64.deb"
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,76 @@
|
|
1
|
+
2022-10-17
|
2
|
+
=================
|
3
|
+
* Bump to 0.8.7.1
|
4
|
+
* Support non-lower-case Content-Type header provided by app (#516)
|
5
|
+
|
6
|
+
2022-10-02
|
7
|
+
=================
|
8
|
+
* Bump to 0.8.7
|
9
|
+
* Lowercase the header names for rack 3 changes (#511)
|
10
|
+
* Partially escaped URLs should be escaped (#509)
|
11
|
+
|
12
|
+
2022-04-11
|
13
|
+
=================
|
14
|
+
* Bump to 0.8.6
|
15
|
+
* Update ruby and rails versions
|
16
|
+
|
17
|
+
2021-01-23
|
18
|
+
=================
|
19
|
+
* Bump to 0.8.5
|
20
|
+
* Make `PDFKit::VERSION` public (#484)
|
21
|
+
* Fix to render stylesheets as html safe string on Rails 6 (#483)
|
22
|
+
* Adds support for Rails 6
|
23
|
+
|
24
|
+
2020-08-16
|
25
|
+
=================
|
26
|
+
* Bump to 0.8.4.3.2
|
27
|
+
* Reduce scope of middleware exception handling (#476)
|
28
|
+
|
29
|
+
2020-07-05
|
30
|
+
=================
|
31
|
+
* Bump to 0.8.4.3.1
|
32
|
+
* Don't override request level Content-Disposition header if it exists (#466)
|
33
|
+
* Update rake (#471)
|
34
|
+
* Add missing require statements for tempfile (#467)
|
35
|
+
* Only grab last line of bundle exec which output (#464)
|
36
|
+
* Return 500 status when an exception is caught in middleware (#469)
|
37
|
+
* Update Travis CI URL for wkhtmltopf (#473)
|
38
|
+
|
39
|
+
2020-04-01
|
40
|
+
=================
|
41
|
+
* Bump to 0.8.4.2
|
42
|
+
* Improve path detection feedback (#460)
|
43
|
+
* Fix typos (#444)
|
44
|
+
* Update readme (#439)
|
45
|
+
|
46
|
+
2019-02-22
|
47
|
+
=================
|
48
|
+
* Bump to 0.8.4.1
|
49
|
+
* Make PDFkit threadsafe (#377)
|
50
|
+
* Update activesupport (#434)
|
51
|
+
|
52
|
+
2019-02-21
|
53
|
+
=================
|
54
|
+
* Bump to 0.8.4
|
55
|
+
* Removed support for Ruby < 2.2
|
56
|
+
* Xvfb support (#277)
|
57
|
+
* Remove 'config.protocol' from the README (#389)
|
58
|
+
|
59
|
+
2015-08-26
|
60
|
+
=================
|
61
|
+
* Bump to 0.8.2
|
62
|
+
* Fix URI errors for users using PDFKit in contexts with 'uri' not
|
63
|
+
already required (thanks christhekeele)
|
64
|
+
|
65
|
+
2015-08-20
|
66
|
+
=================
|
67
|
+
* Bump to 0.8.1
|
68
|
+
* Fix shell escaping issues for Windows (thanks muness)
|
69
|
+
* Fix shell escaping issues for URLs, introduced in 0.5.3 release
|
70
|
+
|
1
71
|
2015-07-08
|
2
72
|
=================
|
3
|
-
* Bump to 0.
|
73
|
+
* Bump to 0.8.0
|
4
74
|
* Support Cover and Table Of Contents options (thanks @nicpillinger)
|
5
75
|
* Fix repeatings keys with string values
|
6
76
|
* Fix caching bug (thanks @jocranford)
|
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, 2.7, 3.0, 3.1
|
8
|
+
- Rails 4.2, 5.2, 6.0, 6.1, 7.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
|
|
@@ -43,8 +48,22 @@ PDFKit.new('<html><head><meta name="pdfkit-page_size" content="Letter"')
|
|
43
48
|
PDFKit.new('<html><head><meta name="pdfkit-cookie cookie_name1" content="cookie_value1"')
|
44
49
|
PDFKit.new('<html><head><meta name="pdfkit-cookie cookie_name2" content="cookie_value2"')
|
45
50
|
```
|
51
|
+
|
52
|
+
### Resolving relative URLs and protocols
|
53
|
+
|
54
|
+
If the source HTML has relative URLs (`/images/cat.png`) or
|
55
|
+
[protocols](https://en.wikipedia.org/wiki/Uniform_Resource_Locator#prurl)
|
56
|
+
(`//example.com/site.css`) that need to be resolved, you can pass `:root_url`
|
57
|
+
and `:protocol` options to PDFKit:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
PDFKit.new(html, root_url: 'http://mysite.com/').to_file
|
61
|
+
# or:
|
62
|
+
PDFKit.new(html, protocol: 'https').to_file
|
63
|
+
```
|
64
|
+
|
46
65
|
### Using cookies in scraping
|
47
|
-
If you want to pass a cookie to
|
66
|
+
If you want to pass a cookie to pdfkit to scrape a website, you can
|
48
67
|
pass it in a hash:
|
49
68
|
```ruby
|
50
69
|
kit = PDFKit.new(url, cookie: {cookie_name: :cookie_value})
|
@@ -102,6 +121,13 @@ config.middleware.use PDFKit::Middleware, {}, :except => [%r[^/prawn], %r[^/secr
|
|
102
121
|
# conditions can be strings (either one or an array)
|
103
122
|
config.middleware.use PDFKit::Middleware, {}, :except => ['/secret']
|
104
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
|
+
```
|
105
131
|
**Saving the generated .pdf to disk**
|
106
132
|
|
107
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.
|
@@ -111,7 +137,7 @@ For example:
|
|
111
137
|
headers['PDFKit-save-pdf'] = 'path/to/saved.pdf'
|
112
138
|
```
|
113
139
|
|
114
|
-
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.
|
115
141
|
|
116
142
|
## Troubleshooting
|
117
143
|
|
@@ -126,13 +152,13 @@ Will cause the .pdf to be saved to `path/to/saved.pdf` in addition to being sent
|
|
126
152
|
around this issue you may want to run a server with multiple workers
|
127
153
|
like Passenger or try to embed your resources within your HTML to
|
128
154
|
avoid extra HTTP requests.
|
129
|
-
|
130
|
-
Example solution (rails / bundler), add unicorn to the development
|
131
|
-
group in your Gemfile `gem 'unicorn'` then run `bundle`. Next, add a
|
155
|
+
|
156
|
+
Example solution (rails / bundler), add unicorn to the development
|
157
|
+
group in your Gemfile `gem 'unicorn'` then run `bundle`. Next, add a
|
132
158
|
file `config/unicorn.conf` with
|
133
|
-
|
159
|
+
|
134
160
|
worker_processes 3
|
135
|
-
|
161
|
+
|
136
162
|
Then to run the app `unicorn_rails -c config/unicorn.conf` (from rails_root)
|
137
163
|
|
138
164
|
* **Resources aren't included in the PDF:** Images, CSS, or JavaScript
|
@@ -146,7 +172,7 @@ Will cause the .pdf to be saved to `path/to/saved.pdf` in addition to being sent
|
|
146
172
|
asset host.
|
147
173
|
|
148
174
|
* **Mangled output in the browser:** Be sure that your HTTP response
|
149
|
-
headers specify "
|
175
|
+
headers specify "content-type: application/pdf"
|
150
176
|
|
151
177
|
## Note on Patches/Pull Requests
|
152
178
|
|
data/lib/pdfkit/configuration.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class PDFKit
|
2
4
|
class Configuration
|
3
|
-
attr_accessor :meta_tag_prefix, :
|
4
|
-
attr_writer :
|
5
|
+
attr_accessor :meta_tag_prefix, :root_url
|
6
|
+
attr_writer :use_xvfb, :verbose
|
7
|
+
attr_reader :default_options
|
5
8
|
|
6
9
|
def initialize
|
7
10
|
@verbose = false
|
11
|
+
@use_xvfb = false
|
8
12
|
@meta_tag_prefix = 'pdfkit-'
|
9
13
|
@default_options = {
|
10
14
|
:disable_smart_shrinking => false,
|
@@ -19,7 +23,33 @@ class PDFKit
|
|
19
23
|
end
|
20
24
|
|
21
25
|
def wkhtmltopdf
|
22
|
-
@wkhtmltopdf ||=
|
26
|
+
@wkhtmltopdf ||= default_wkhtmltopdf
|
27
|
+
end
|
28
|
+
|
29
|
+
def default_wkhtmltopdf
|
30
|
+
return @default_command_path if @default_command_path
|
31
|
+
if defined?(Bundler::GemfileError) && File.exist?('Gemfile')
|
32
|
+
@default_command_path = `bundle exec which wkhtmltopdf`.chomp.lines.last
|
33
|
+
end
|
34
|
+
@default_command_path = `which wkhtmltopdf`.chomp if @default_command_path.nil? || @default_command_path.empty?
|
35
|
+
@default_command_path
|
36
|
+
end
|
37
|
+
|
38
|
+
def wkhtmltopdf=(path)
|
39
|
+
if File.exist?(path)
|
40
|
+
@wkhtmltopdf = path
|
41
|
+
else
|
42
|
+
warn "No executable found at #{path}. Will fall back to #{default_wkhtmltopdf}"
|
43
|
+
@wkhtmltopdf = default_wkhtmltopdf
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def executable
|
48
|
+
using_xvfb? ? "xvfb-run #{wkhtmltopdf}" : wkhtmltopdf
|
49
|
+
end
|
50
|
+
|
51
|
+
def using_xvfb?
|
52
|
+
@use_xvfb
|
23
53
|
end
|
24
54
|
|
25
55
|
def quiet?
|
@@ -29,6 +59,10 @@ class PDFKit
|
|
29
59
|
def verbose?
|
30
60
|
@verbose
|
31
61
|
end
|
62
|
+
|
63
|
+
def default_options=(options)
|
64
|
+
@default_options.merge!(options)
|
65
|
+
end
|
32
66
|
end
|
33
67
|
|
34
68
|
class << self
|
@@ -41,6 +75,7 @@ class PDFKit
|
|
41
75
|
# @example
|
42
76
|
# PDFKit.configure do |config|
|
43
77
|
# config.wkhtmltopdf = '/usr/bin/wkhtmltopdf'
|
78
|
+
# config.use_xvfb = true
|
44
79
|
# config.verbose = true
|
45
80
|
# end
|
46
81
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class PDFKit
|
4
|
+
module HTMLPreprocessor
|
5
|
+
|
6
|
+
# Change relative paths to absolute, and relative protocols to absolute protocols
|
7
|
+
def self.process(html, root_url, protocol)
|
8
|
+
html = translate_relative_paths(html, root_url) if root_url
|
9
|
+
html = translate_relative_protocols(html, protocol) if protocol
|
10
|
+
html
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def self.translate_relative_paths(html, root_url)
|
16
|
+
# Try out this regexp using rubular http://rubular.com/r/hiAxBNX7KE
|
17
|
+
html.gsub(/(href|src)=(['"])\/([^\/"']([^\"']*|[^"']*))?['"]/, "\\1=\\2#{root_url}\\3\\2")
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.translate_relative_protocols(body, protocol)
|
21
|
+
# Try out this regexp using rubular http://rubular.com/r/0Ohk0wFYxV
|
22
|
+
body.gsub(/(href|src)=(['"])\/\/([^\"']*|[^"']*)['"]/, "\\1=\\2#{protocol}://\\3\\2")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/pdfkit/middleware.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class PDFKit
|
2
4
|
class Middleware
|
3
5
|
def initialize(app, options = {}, conditions = {})
|
@@ -9,31 +11,51 @@ class PDFKit
|
|
9
11
|
end
|
10
12
|
|
11
13
|
def call(env)
|
14
|
+
dup._call(env)
|
15
|
+
end
|
16
|
+
|
17
|
+
def _call(env)
|
12
18
|
@request = Rack::Request.new(env)
|
13
19
|
@render_pdf = false
|
14
20
|
|
15
21
|
set_request_to_render_as_pdf(env) if render_as_pdf?
|
16
22
|
status, headers, response = @app.call(env)
|
17
23
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
24
|
+
begin
|
25
|
+
content_type_header = headers.has_key?('Content-Type') ? 'Content-Type' : 'content-type'
|
26
|
+
if rendering_pdf? && headers[content_type_header] =~ /text\/html|application\/xhtml\+xml/
|
27
|
+
body = response.respond_to?(:body) ? response.body : response.join
|
28
|
+
body = body.join if body.is_a?(Array)
|
29
|
+
|
30
|
+
root_url = root_url(env)
|
31
|
+
protocol = protocol(env)
|
32
|
+
options = @options.merge(root_url: root_url, protocol: protocol)
|
33
|
+
|
34
|
+
if headers['PDFKit-javascript-delay']
|
35
|
+
options.merge!(javascript_delay: headers.delete('PDFKit-javascript-delay').to_i)
|
36
|
+
end
|
37
|
+
|
38
|
+
body = PDFKit.new(body, options).to_pdf
|
39
|
+
response = [body]
|
40
|
+
|
41
|
+
if headers['PDFKit-save-pdf']
|
42
|
+
File.open(headers['PDFKit-save-pdf'], 'wb') { |file| file.write(body) } rescue nil
|
43
|
+
headers.delete('PDFKit-save-pdf')
|
44
|
+
end
|
45
|
+
|
46
|
+
unless @caching
|
47
|
+
# Do not cache PDFs
|
48
|
+
headers.delete('etag')
|
49
|
+
headers.delete('cache-control')
|
50
|
+
end
|
51
|
+
|
52
|
+
headers['content-length'] = (body.respond_to?(:bytesize) ? body.bytesize : body.size).to_s
|
53
|
+
headers[content_type_header] = 'application/pdf'
|
54
|
+
headers['content-disposition'] ||= @conditions[:disposition] || 'inline'
|
33
55
|
end
|
34
|
-
|
35
|
-
|
36
|
-
|
56
|
+
rescue StandardError => e
|
57
|
+
status = 500
|
58
|
+
response = [e.message]
|
37
59
|
end
|
38
60
|
|
39
61
|
[status, headers, response]
|
@@ -41,22 +63,12 @@ class PDFKit
|
|
41
63
|
|
42
64
|
private
|
43
65
|
|
44
|
-
|
45
|
-
|
46
|
-
body = translate_relative_paths(body, env)
|
47
|
-
translate_relative_protocols(body, env)
|
66
|
+
def root_url(env)
|
67
|
+
PDFKit.configuration.root_url || "#{env['rack.url_scheme']}://#{env['HTTP_HOST']}/"
|
48
68
|
end
|
49
69
|
|
50
|
-
def
|
51
|
-
|
52
|
-
# Try out this regexp using rubular http://rubular.com/r/hiAxBNX7KE
|
53
|
-
body.gsub(/(href|src)=(['"])\/([^\/"']([^\"']*|[^"']*))?['"]/, "\\1=\\2#{root}\\3\\2")
|
54
|
-
end
|
55
|
-
|
56
|
-
def translate_relative_protocols(body, env)
|
57
|
-
protocol = "#{env['rack.url_scheme']}://"
|
58
|
-
# Try out this regexp using rubular http://rubular.com/r/0Ohk0wFYxV
|
59
|
-
body.gsub(/(href|src)=(['"])\/\/([^\"']*|[^"']*)['"]/, "\\1=\\2#{protocol}\\3\\2")
|
70
|
+
def protocol(env)
|
71
|
+
env['rack.url_scheme']
|
60
72
|
end
|
61
73
|
|
62
74
|
def rendering_pdf?
|
@@ -65,20 +77,18 @@ class PDFKit
|
|
65
77
|
|
66
78
|
def render_as_pdf?
|
67
79
|
request_path = @request.path
|
68
|
-
|
80
|
+
return false unless request_path.end_with?('.pdf')
|
69
81
|
|
70
|
-
if
|
82
|
+
if @conditions[:only]
|
71
83
|
conditions_as_regexp(@conditions[:only]).any? do |pattern|
|
72
|
-
|
84
|
+
pattern === request_path
|
73
85
|
end
|
74
|
-
elsif
|
75
|
-
conditions_as_regexp(@conditions[:except]).
|
76
|
-
|
86
|
+
elsif @conditions[:except]
|
87
|
+
conditions_as_regexp(@conditions[:except]).none? do |pattern|
|
88
|
+
pattern === request_path
|
77
89
|
end
|
78
|
-
|
79
|
-
return true
|
80
90
|
else
|
81
|
-
|
91
|
+
true
|
82
92
|
end
|
83
93
|
end
|
84
94
|
|
@@ -99,8 +109,8 @@ class PDFKit
|
|
99
109
|
end
|
100
110
|
|
101
111
|
def conditions_as_regexp(conditions)
|
102
|
-
|
103
|
-
pattern.is_a?(Regexp) ? pattern : Regexp.new(
|
112
|
+
Array(conditions).map do |pattern|
|
113
|
+
pattern.is_a?(Regexp) ? pattern : Regexp.new("^#{pattern}")
|
104
114
|
end
|
105
115
|
end
|
106
116
|
end
|
data/lib/pdfkit/os.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rbconfig'
|
4
|
+
|
5
|
+
class PDFKit
|
6
|
+
module OS
|
7
|
+
def self.host_is_windows?
|
8
|
+
!(RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince/).nil?
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.shell_escape_for_os(args)
|
12
|
+
if (host_is_windows?)
|
13
|
+
# Windows reserved shell characters are: & | ( ) < > ^
|
14
|
+
# See http://technet.microsoft.com/en-us/library/cc723564.aspx#XSLTsection123121120120
|
15
|
+
args.map { |arg| arg.gsub(/([&|()<>^])/,'^\1') }.join(" ")
|
16
|
+
else
|
17
|
+
args.shelljoin
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|