pdfkit 0.8.2 → 0.8.4.3.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.

@@ -1,3 +1,4 @@
1
+ require 'tempfile'
1
2
  require 'uri'
2
3
 
3
4
  class PDFKit
@@ -13,7 +14,7 @@ class PDFKit
13
14
  end
14
15
 
15
16
  def file?
16
- @is_file ||= @source.kind_of?(File)
17
+ @is_file ||= @source.kind_of?(File) || @source.kind_of?(Tempfile)
17
18
  end
18
19
 
19
20
  def html?
@@ -1,3 +1,3 @@
1
1
  class PDFKit
2
- VERSION = "0.8.2"
2
+ VERSION = '0.8.4.3.1'
3
3
  end
@@ -0,0 +1,80 @@
1
+ class PDFKit
2
+ class WkHTMLtoPDF
3
+ attr_reader :options
4
+ # Pulled from:
5
+ # https://github.com/wkhtmltopdf/wkhtmltopdf/blob/ebf9b6cfc4c58a31349fb94c568b254fac37b3d3/README_WKHTMLTOIMAGE#L27
6
+ REPEATABLE_OPTIONS = %w[--allow --cookie --custom-header --post --post-file --run-script]
7
+ SPECIAL_OPTIONS = %w[cover toc]
8
+
9
+ def initialize(options)
10
+ @options = options
11
+ end
12
+
13
+ def normalize_options
14
+ # TODO(cdwort,sigmavirus24): Make this method idempotent in a future release so it can be called repeatedly
15
+ normalized_options = {}
16
+
17
+ @options.each do |key, value|
18
+ next if !value
19
+
20
+ # The actual option for wkhtmltopdf
21
+ normalized_key = normalize_arg key
22
+ normalized_key = "--#{normalized_key}" unless SPECIAL_OPTIONS.include?(normalized_key)
23
+
24
+ # If the option is repeatable, attempt to normalize all values
25
+ if REPEATABLE_OPTIONS.include? normalized_key
26
+ normalize_repeatable_value(normalized_key, value) do |normalized_unique_key, normalized_value|
27
+ normalized_options[normalized_unique_key] = normalized_value
28
+ end
29
+ else # Otherwise, just normalize it like usual
30
+ normalized_options[normalized_key] = normalize_value(value)
31
+ end
32
+ end
33
+
34
+ @options = normalized_options
35
+ end
36
+
37
+ def error_handling?
38
+ @options.key?('--ignore-load-errors') ||
39
+ # wkhtmltopdf v0.10.0 beta4 replaces ignore-load-errors with load-error-handling
40
+ # https://code.google.com/p/wkhtmltopdf/issues/detail?id=55
41
+ %w(skip ignore).include?(@options['--load-error-handling'])
42
+ end
43
+
44
+ def options_for_command
45
+ @options.to_a.flatten.compact
46
+ end
47
+
48
+ private
49
+
50
+ def normalize_arg(arg)
51
+ arg.to_s.downcase.gsub(/[^a-z0-9]/,'-')
52
+ end
53
+
54
+ def normalize_value(value)
55
+ case value
56
+ when nil
57
+ nil
58
+ when TrueClass, 'true' #ie, ==true, see http://www.ruby-doc.org/core-1.9.3/TrueClass.html
59
+ nil
60
+ when Hash
61
+ value.to_a.flatten.collect{|x| normalize_value(x)}.compact
62
+ when Array
63
+ value.flatten.collect{|x| x.to_s}
64
+ else
65
+ (OS::host_is_windows? && value.to_s.index(' ')) ? "'#{ value.to_s }'" : value.to_s
66
+ end
67
+ end
68
+
69
+ def normalize_repeatable_value(option_name, value)
70
+ case value
71
+ when Hash, Array
72
+ value.each do |(key, val)|
73
+ yield [[option_name, normalize_value(key)], normalize_value(val)]
74
+ end
75
+ else
76
+ yield [[option_name, normalize_value(value)], nil]
77
+ end
78
+ end
79
+ end
80
+ end
@@ -11,20 +11,20 @@ Gem::Specification.new do |s|
11
11
  s.homepage = "https://github.com/pdfkit/pdfkit"
12
12
  s.summary = "HTML+CSS -> PDF"
13
13
  s.description = "Uses wkhtmltopdf to create PDFs using HTML"
14
-
15
- s.rubyforge_project = "pdfkit"
14
+ s.license = "MIT"
16
15
 
17
16
  s.files = `git ls-files`.split("\n")
18
17
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
19
  s.require_paths = ["lib"]
21
20
 
22
- # Developmnet Dependencies
23
- s.add_development_dependency(%q<activesupport>, [">= 3.0.8"])
21
+ s.requirements << "wkhtmltopdf"
22
+
23
+ # Development Dependencies
24
+ s.add_development_dependency(%q<activesupport>, [">= 4.1.11"])
24
25
  s.add_development_dependency(%q<mocha>, [">= 0.9.10"])
25
26
  s.add_development_dependency(%q<rack-test>, [">= 0.5.6"])
26
- s.add_development_dependency(%q<i18n>, ["~>0.6.11"]) # Ruby 1.9.2 compatibility
27
- s.add_development_dependency(%q<rake>, ["~>0.9.2"])
27
+ s.add_development_dependency(%q<rake>, ["~>12.3.3"])
28
28
  s.add_development_dependency(%q<rdoc>, ["~> 4.0.1"])
29
29
  s.add_development_dependency(%q<rspec>, ["~> 3.0"])
30
30
  end
@@ -3,26 +3,74 @@ require 'spec_helper'
3
3
  describe PDFKit::Configuration do
4
4
  subject { PDFKit::Configuration.new }
5
5
  describe "#wkhtmltopdf" do
6
- it "can be configured" do
7
- subject.wkhtmltopdf = '/my/bin/wkhtmltopdf'
8
- expect(subject.wkhtmltopdf).to eql '/my/bin/wkhtmltopdf'
9
- end
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
10
12
 
11
- # This test documents existing functionality. Feel free to fix.
12
- it "can be poorly configured" do
13
- subject.wkhtmltopdf = 1234
14
- expect(subject.wkhtmltopdf).to eql 1234
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
15
19
  end
16
20
 
17
21
  context "when not explicitly configured" do
18
- it "detects the existance of bundler" do
19
- # Test assumes bundler is installed in your test environment
20
- expect(subject).to receive(:`).with('bundle exec which wkhtmltopdf').and_return('c:\windows\path.exe')
21
- subject.wkhtmltopdf
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
22
59
  end
23
60
  end
24
61
  end
25
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'
71
+ end
72
+ end
73
+
26
74
  describe "#default_options" do
27
75
  it "sets defaults for the command options" do
28
76
  expect(subject.default_options[:disable_smart_shrinking]).to eql false
@@ -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
@@ -64,6 +119,22 @@ describe PDFKit::Configuration do
64
119
  end
65
120
  end
66
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
+
67
138
  describe "#verbose?" do
68
139
  it "can be configured to true" do
69
140
  subject.verbose = true
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+
3
+ describe PDFKit::HTMLPreprocessor do
4
+ describe "#process" do
5
+ let(:preprocessor) { PDFKit::HTMLPreprocessor }
6
+ let(:root_url) { 'http://example.com/' } # This mirrors Middleware#root_url's response
7
+ let(:protocol) { 'http' }
8
+
9
+ it "correctly parses host-relative url with single quotes" do
10
+ original_body = %{<html><head><link href='/stylesheets/application.css' media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' src="/test.png" /></body></html>}
11
+ body = preprocessor.process original_body, root_url, protocol
12
+ expect(body).to eq("<html><head><link href='http://example.com/stylesheets/application.css' media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' src=\"http://example.com/test.png\" /></body></html>")
13
+ end
14
+
15
+ it "correctly parses host-relative url with double quotes" do
16
+ original_body = %{<link href="/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />}
17
+ body = preprocessor.process original_body, root_url, protocol
18
+ expect(body).to eq("<link href=\"http://example.com/stylesheets/application.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />")
19
+ end
20
+
21
+ it "correctly parses protocol-relative url with single quotes" do
22
+ original_body = %{<link href='//fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'>}
23
+ body = preprocessor.process original_body, root_url, protocol
24
+ expect(body).to eq("<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'>")
25
+ end
26
+
27
+ it "correctly parses protocol-relative url with double quotes" do
28
+ original_body = %{<link href="//fonts.googleapis.com/css?family=Open+Sans:400,600" rel='stylesheet' type='text/css'>}
29
+ body = preprocessor.process original_body, root_url, protocol
30
+ expect(body).to eq("<link href=\"http://fonts.googleapis.com/css?family=Open+Sans:400,600\" rel='stylesheet' type='text/css'>")
31
+ end
32
+
33
+ it "correctly parses multiple tags where first one is root url" do
34
+ original_body = %{<a href='/'><img src='/logo.jpg' ></a>}
35
+ body = preprocessor.process original_body, root_url, protocol
36
+ expect(body).to eq "<a href='http://example.com/'><img src='http://example.com/logo.jpg' ></a>"
37
+ end
38
+
39
+ it "returns the body even if there are no valid substitutions found" do
40
+ original_body = "NO MATCH"
41
+ body = preprocessor.process original_body, root_url, protocol
42
+ expect(body).to eq("NO MATCH")
43
+ end
44
+
45
+ context 'when root_url is nil' do
46
+ it "returns the body safely, without interpolating" do
47
+ original_body = %{<link href='//fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'><a href='/'><img src='/logo.jpg'></a>}
48
+ body = preprocessor.process original_body, nil, protocol
49
+ expect(body).to eq(%{<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'><a href='/'><img src='/logo.jpg'></a>})
50
+ end
51
+ end
52
+
53
+ context 'when protocol is nil' do
54
+ it "returns the body safely, without interpolating" do
55
+ original_body = %{<link href='//fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'><a href='/'><img src='/logo.jpg'></a>}
56
+ body = preprocessor.process original_body, root_url, nil
57
+ expect(body).to eq(%{<link href='//fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'><a href='http://example.com/'><img src='http://example.com/logo.jpg'></a>})
58
+ end
59
+ end
60
+
61
+ context 'when root_url and protocol are both nil' do
62
+ it "returns the body safely, without interpolating" do
63
+ original_body = %{<link href='//fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'><a href='/'><img src='/logo.jpg'></a>}
64
+ body = preprocessor.process original_body, nil, nil
65
+ expect(body).to eq original_body
66
+ end
67
+ end
68
+ end
69
+ end
@@ -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
  {
@@ -236,22 +265,22 @@ describe PDFKit::Middleware do
236
265
  end
237
266
 
238
267
  describe "saving generated pdf to disk" do
239
- before do
268
+ before do
240
269
  #make sure tests don't find an old test_save.pdf
241
270
  File.delete('spec/test_save.pdf') if File.exists?('spec/test_save.pdf')
242
271
  expect(File.exists?('spec/test_save.pdf')).to eq(false)
243
- end
272
+ end
244
273
 
245
274
  context "when header PDFKit-save-pdf is present" do
246
275
  it "saves the .pdf to disk" do
247
- headers = { 'PDFKit-save-pdf' => 'spec/test_save.pdf' }
276
+ headers = { 'PDFKit-save-pdf' => 'spec/test_save.pdf' }
248
277
  mock_app({}, {only: '/public'}, headers)
249
- get 'http://www.example.org/public/test_save.pdf'
278
+ get 'http://www.example.org/public/test_save.pdf'
250
279
  expect(File.exists?('spec/test_save.pdf')).to eq(true)
251
- end
280
+ end
252
281
 
253
282
  it "does not raise when target directory does not exist" do
254
- headers = { 'PDFKit-save-pdf' => '/this/dir/does/not/exist/spec/test_save.pdf' }
283
+ headers = { 'PDFKit-save-pdf' => '/this/dir/does/not/exist/spec/test_save.pdf' }
255
284
  mock_app({}, {only: '/public'}, headers)
256
285
  expect {
257
286
  get 'http://www.example.com/public/test_save.pdf'
@@ -262,15 +291,122 @@ describe PDFKit::Middleware do
262
291
  context "when header PDFKit-save-pdf is not present" do
263
292
  it "does not saved the .pdf to disk" do
264
293
  mock_app({}, {only: '/public'}, {} )
265
- get 'http://www.example.org/public/test_save.pdf'
294
+ get 'http://www.example.org/public/test_save.pdf'
266
295
  expect(File.exists?('spec/test_save.pdf')).to eq(false)
267
296
  end
268
297
  end
269
298
  end
299
+
300
+ describe 'javascript delay' do
301
+ context 'when header PDFKit-javascript-delay is present' do
302
+ it 'passes header value through to PDFKit initialiser' do
303
+ expect(PDFKit).to receive(:new).with('Hello world!', {
304
+ root_url: 'http://www.example.com/', protocol: 'http', javascript_delay: 4321
305
+ }).and_call_original
306
+
307
+ headers = { 'PDFKit-javascript-delay' => '4321' }
308
+ mock_app({}, { only: '/public' }, headers)
309
+ get 'http://www.example.com/public/test_save.pdf'
310
+ end
311
+
312
+ it 'handles invalid content in header' do
313
+ expect(PDFKit).to receive(:new).with('Hello world!', {
314
+ root_url: 'http://www.example.com/', protocol: 'http', javascript_delay: 0
315
+ }).and_call_original
316
+
317
+ headers = { 'PDFKit-javascript-delay' => 'invalid' }
318
+ mock_app({}, { only: '/public' }, headers)
319
+ get 'http://www.example.com/public/test_save.pdf'
320
+ end
321
+
322
+ it 'overrides default option' do
323
+ expect(PDFKit).to receive(:new).with('Hello world!', {
324
+ root_url: 'http://www.example.com/', protocol: 'http', javascript_delay: 4321
325
+ }).and_call_original
326
+
327
+ headers = { 'PDFKit-javascript-delay' => '4321' }
328
+ mock_app({ javascript_delay: 1234 }, { only: '/public' }, headers)
329
+ get 'http://www.example.com/public/test_save.pdf'
330
+ end
331
+ end
332
+
333
+ context 'when header PDFKit-javascript-delay is not present' do
334
+ it 'passes through default option' do
335
+ expect(PDFKit).to receive(:new).with('Hello world!', {
336
+ root_url: 'http://www.example.com/', protocol: 'http', javascript_delay: 1234
337
+ }).and_call_original
338
+
339
+ mock_app({ javascript_delay: 1234 }, { only: '/public' }, { })
340
+ get 'http://www.example.com/public/test_save.pdf'
341
+ end
342
+ end
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
+ specify do
399
+ mock_app
400
+ allow(PDFKit).to receive(:new).and_raise(StandardError.new("Something went wrong"))
401
+ get 'http://www.example.org/public/test.pdf'
402
+ expect(last_response.status).to eq(500)
403
+ expect(last_response.body).to eq("Something went wrong")
404
+ end
405
+ end
270
406
  end
271
407
 
272
- describe "remove .pdf from PATH_INFO and REQUEST_URI" do
273
- before { mock_app }
408
+ describe "remove .pdf from PATH_INFO and REQUEST_URI" do
409
+ before { mock_app }
274
410
 
275
411
  context "matching" do
276
412
 
@@ -319,80 +455,37 @@ describe PDFKit::Middleware do
319
455
  end
320
456
  end
321
457
 
322
- describe "#translate_paths" do
458
+ describe "#root_url and #protocol" do
323
459
  before do
324
460
  @pdf = PDFKit::Middleware.new({})
325
461
  @env = { 'REQUEST_URI' => 'http://example.com/document.pdf', 'rack.url_scheme' => 'http', 'HTTP_HOST' => 'example.com' }
326
462
  end
327
463
 
328
- it "correctly parses relative url with single quotes" do
329
- @body = %{<html><head><link href='/stylesheets/application.css' media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' src="/test.png" /></body></html>}
330
- body = @pdf.send :translate_paths, @body, @env
331
- expect(body).to eq("<html><head><link href='http://example.com/stylesheets/application.css' media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' src=\"http://example.com/test.png\" /></body></html>")
332
- end
333
-
334
- it "correctly parses relative url with double quotes" do
335
- @body = %{<link href="/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />}
336
- body = @pdf.send :translate_paths, @body, @env
337
- expect(body).to eq("<link href=\"http://example.com/stylesheets/application.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />")
338
- end
339
-
340
- it "correctly parses relative url with double quotes" do
341
- @body = %{<link href='//fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'>}
342
- body = @pdf.send :translate_paths, @body, @env
343
- expect(body).to eq("<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'>")
344
- end
345
-
346
- it "correctly parses multiple tags where first one is root url" do
347
- @body = %{<a href='/'><img src='/logo.jpg' ></a>}
348
- body = @pdf.send :translate_paths, @body, @env
349
- expect(body).to eq "<a href='http://example.com/'><img src='http://example.com/logo.jpg' ></a>"
350
- end
464
+ context 'when root_url is not configured' do
465
+ it "infers the root_url and protocol from the environment" do
466
+ root_url = @pdf.send(:root_url, @env)
467
+ protocol = @pdf.send(:protocol, @env)
351
468
 
352
- it "returns the body even if there are no valid substitutions found" do
353
- @body = "NO MATCH"
354
- body = @pdf.send :translate_paths, @body, @env
355
- expect(body).to eq("NO MATCH")
469
+ expect(root_url).to eq('http://example.com/')
470
+ expect(protocol).to eq('http')
471
+ end
356
472
  end
357
- end
358
473
 
359
- describe "#translate_paths with root_url configuration" do
360
- before do
361
- @pdf = PDFKit::Middleware.new({})
362
- @env = { 'REQUEST_URI' => 'http://example.com/document.pdf', 'rack.url_scheme' => 'http', 'HTTP_HOST' => 'example.com' }
363
- PDFKit.configure do |config|
364
- config.root_url = "http://example.net/"
474
+ context 'when root_url is configured' do
475
+ before do
476
+ PDFKit.configuration.root_url = 'http://example.net/'
477
+ end
478
+ after do
479
+ PDFKit.configuration.root_url = nil
365
480
  end
366
- end
367
481
 
368
- it "adds the root_url" do
369
- @body = %{<html><head><link href='/stylesheets/application.css' media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' src="/test.png" /></body></html>}
370
- body = @pdf.send :translate_paths, @body, @env
371
- expect(body).to eq("<html><head><link href='http://example.net/stylesheets/application.css' media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' src=\"http://example.net/test.png\" /></body></html>")
372
- end
482
+ it "takes the root_url from the configuration, and infers the protocol from the environment" do
483
+ root_url = @pdf.send(:root_url, @env)
484
+ protocol = @pdf.send(:protocol, @env)
373
485
 
374
- after do
375
- PDFKit.configure do |config|
376
- config.root_url = nil
486
+ expect(root_url).to eq('http://example.net/')
487
+ expect(protocol).to eq('http')
377
488
  end
378
489
  end
379
490
  end
380
-
381
- it "does not get stuck rendering each request as pdf" do
382
- mock_app
383
- # false by default. No requests.
384
- expect(@app.send(:rendering_pdf?)).to eq(false)
385
-
386
- # Remain false on a normal request
387
- get 'http://www.example.org/public/file'
388
- expect(@app.send(:rendering_pdf?)).to eq(false)
389
-
390
- # Return true on a pdf request.
391
- get 'http://www.example.org/public/file.pdf'
392
- expect(@app.send(:rendering_pdf?)).to eq(true)
393
-
394
- # Restore to false on any non-pdf request.
395
- get 'http://www.example.org/public/file'
396
- expect(@app.send(:rendering_pdf?)).to eq(false)
397
- end
398
491
  end