bidi2pdf 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +21 -0
- data/docker/docker-compose.yml +17 -0
- data/docker/nginx/default.conf +42 -0
- data/docker/nginx/htpasswd +1 -0
- data/lib/bidi2pdf/chromedriver_manager.rb +31 -2
- data/lib/bidi2pdf/process_tree.rb +71 -0
- data/lib/bidi2pdf/session_runner.rb +5 -5
- data/lib/bidi2pdf/version.rb +1 -1
- data/lib/bidi2pdf.rb +1 -0
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a67b40e096dd2b6b73fa65cec7d9d75182b995435c17186d755f89efebb2ab26
|
4
|
+
data.tar.gz: fde0861d58dd30788aa1b54a24d956d3438bd83cc08a5ec9d22e6750a3e646d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52e199c72b902e046140e6d47a9b00a8354e53a88f3af6135f0d7ab587c7d59532a904388e4a62ed4ba29c03609eab3b8c7f3aea0aa131ba8880f8ecb6f9a503
|
7
|
+
data.tar.gz: a83f7091a455e5c8cb5f2b7e8e621c044b2184c2c6e5a6e11aaa4f4ca2f9879ada89eb7951e7ad78e07a2d473396bb529ce5c4dfc771130a40a1977bb6e60575
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.1.1] - 2025-04-01
|
4
|
+
|
5
|
+
### Added
|
6
|
+
|
7
|
+
- Docker Compose setup with Nginx for authentication examples
|
8
|
+
- Sample configurations for different authentication methods:
|
9
|
+
- Basic HTTP authentication
|
10
|
+
- Cookie-based authentication
|
11
|
+
- API key header authentication
|
12
|
+
|
13
|
+
### Fixed
|
14
|
+
|
15
|
+
- HTTP cookie handling issues
|
16
|
+
|
3
17
|
## [0.1.0] - 2025-03-26
|
4
18
|
|
5
19
|
- Initial release
|
data/README.md
CHANGED
@@ -91,6 +91,27 @@ docker run -it --rm -v ./output:/reports bidi2pdf \
|
|
91
91
|
bidi2pdf render --url=https://example.com --output /reports/example.pdf
|
92
92
|
```
|
93
93
|
|
94
|
+
### Test it with docker compose
|
95
|
+
|
96
|
+
```bash
|
97
|
+
docker compose -f docker/docker-compose.yml up -d
|
98
|
+
|
99
|
+
# simple example
|
100
|
+
docker compose -f docker/docker-compose.yml exec app bidi2pdf render --url=http://nginx/sample.html --wait_window_loaded --wait_network_idle --output /reports/simple.pdf
|
101
|
+
|
102
|
+
# basic auth example
|
103
|
+
docker compose -f docker/docker-compose.yml exec app bidi2pdf render --url=http://nginx/basic/sample.html --auth admin:secret --wait_window_loaded --wait_network_idle --output /reports/basic.pdf
|
104
|
+
|
105
|
+
# header example
|
106
|
+
docker compose -f docker/docker-compose.yml exec app bidi2pdf render --url=http://nginx/header/sample.html --header "X-API-KEY=secret" --wait_window_loaded --wait_network_idle --output /reports/header.pdf
|
107
|
+
|
108
|
+
# cookie example
|
109
|
+
docker compose -f docker/docker-compose.yml exec app bidi2pdf render --url=http://nginx/cookie/sample.html --cookie "auth=secret" --wait_window_loaded --wait_network_idle --output /reports/cookie.pdf
|
110
|
+
|
111
|
+
|
112
|
+
docker compose -f docker/docker-compose.yml down
|
113
|
+
```
|
114
|
+
|
94
115
|
## Configuration Options
|
95
116
|
|
96
117
|
| Option | Description |
|
data/docker/docker-compose.yml
CHANGED
@@ -1 +1,18 @@
|
|
1
1
|
name: bidi2pdf
|
2
|
+
services:
|
3
|
+
nginx:
|
4
|
+
image: nginx:1.27-bookworm
|
5
|
+
ports:
|
6
|
+
- "9091:80"
|
7
|
+
volumes:
|
8
|
+
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
|
9
|
+
- ./nginx/htpasswd:/etc/nginx/conf.d/.htpasswd
|
10
|
+
- ../spec/fixtures:/var/www/html
|
11
|
+
|
12
|
+
app:
|
13
|
+
build:
|
14
|
+
context: ..
|
15
|
+
dockerfile: docker/Dockerfile
|
16
|
+
volumes:
|
17
|
+
- ../tmp/reports:/reports
|
18
|
+
command: tail -f /dev/null
|
@@ -0,0 +1,42 @@
|
|
1
|
+
log_format with_headers_and_cookies '
|
2
|
+
$remote_addr - $remote_user [$time_local] "$request" '
|
3
|
+
'status=$status body_bytes_sent=$body_bytes_sent '
|
4
|
+
'cookie="$http_cookie" '
|
5
|
+
'ua="$http_user_agent" '
|
6
|
+
'referer="$http_referer" '
|
7
|
+
'custom-header-x="$http_x_custom_header" ';
|
8
|
+
|
9
|
+
server {
|
10
|
+
# error_log /var/log/nginx/error.log debug;
|
11
|
+
access_log /var/log/nginx/access.log with_headers_and_cookies;
|
12
|
+
|
13
|
+
location / {
|
14
|
+
root /var/www/html;
|
15
|
+
}
|
16
|
+
|
17
|
+
location /basic {
|
18
|
+
alias /var/www/html;
|
19
|
+
try_files $uri $uri/ =404;
|
20
|
+
|
21
|
+
auth_basic "Restricted Area";
|
22
|
+
auth_basic_user_file /etc/nginx/conf.d/.htpasswd;
|
23
|
+
}
|
24
|
+
|
25
|
+
location /cookie {
|
26
|
+
alias /var/www/html;
|
27
|
+
try_files $uri $uri/ =404;
|
28
|
+
|
29
|
+
if ($cookie_auth != "secret") {
|
30
|
+
return 403;
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
location /header {
|
35
|
+
alias /var/www/html;
|
36
|
+
try_files $uri $uri/ =404;
|
37
|
+
|
38
|
+
if ($http_x_api_key != "secret") {
|
39
|
+
return 403;
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
admin:$apr1$wwl1dIH7$Pm2PaGHWNnXhCoLzD1gr2/
|
@@ -42,6 +42,8 @@ module Bidi2pdf
|
|
42
42
|
|
43
43
|
term_chromedriver
|
44
44
|
|
45
|
+
detect_zombie_processes
|
46
|
+
|
45
47
|
return unless process_alive?
|
46
48
|
|
47
49
|
kill_chromedriver timeout: timeout
|
@@ -51,6 +53,33 @@ module Bidi2pdf
|
|
51
53
|
|
52
54
|
private
|
53
55
|
|
56
|
+
# rubocop:disable Metrics/AbcSize
|
57
|
+
def detect_zombie_processes
|
58
|
+
debug_show_all_children
|
59
|
+
|
60
|
+
child_processes = Bidi2pdf::ProcessTree.new(@pid).children(@pid)
|
61
|
+
Bidi2pdf.logger.debug "Found child processes: #{child_processes.map(&:pid).join(", ")}"
|
62
|
+
|
63
|
+
zombie_processes = child_processes.select { |child| process_alive? child.pid }
|
64
|
+
|
65
|
+
return if zombie_processes.empty?
|
66
|
+
|
67
|
+
printable_zombie_processes = zombie_processes.map { |child| "#{child.name}:#{child.pid}" }
|
68
|
+
printable_zombie_processes_str = printable_zombie_processes.join(", ")
|
69
|
+
|
70
|
+
Bidi2pdf.logger.error "Zombie Processes detected #{printable_zombie_processes_str}"
|
71
|
+
end
|
72
|
+
|
73
|
+
# rubocop:enable Metrics/AbcSize
|
74
|
+
|
75
|
+
def debug_show_all_children
|
76
|
+
Bidi2pdf::ProcessTree.new(@pid).traverse do |process, level|
|
77
|
+
indent = " " * level
|
78
|
+
prefix = level.zero? ? "" : "└─ "
|
79
|
+
Bidi2pdf.logger.debug "#{indent}#{prefix}PID #{process.pid} (#{process.name})"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
54
83
|
def close_session
|
55
84
|
Bidi2pdf.logger.info "Closing session"
|
56
85
|
|
@@ -126,8 +155,8 @@ module Bidi2pdf
|
|
126
155
|
|
127
156
|
# rubocop: enable Metrics/AbcSize
|
128
157
|
|
129
|
-
def process_alive?
|
130
|
-
return false unless
|
158
|
+
def process_alive?(pid = @pid)
|
159
|
+
return false unless pid
|
131
160
|
|
132
161
|
begin
|
133
162
|
Process.waitpid(@pid, Process::WNOHANG)
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sys/proctable"
|
4
|
+
module Bidi2pdf
|
5
|
+
class ProcessTree
|
6
|
+
include Sys
|
7
|
+
|
8
|
+
def initialize(root_pid = nil)
|
9
|
+
@root_pid = root_pid
|
10
|
+
@process_map = build_process_map
|
11
|
+
connect_children
|
12
|
+
end
|
13
|
+
|
14
|
+
def children(of_pid)
|
15
|
+
return [] unless @process_map[of_pid]
|
16
|
+
|
17
|
+
direct_children = @process_map[of_pid][:children].map do |child_pid|
|
18
|
+
@process_map[child_pid][:info]
|
19
|
+
end
|
20
|
+
|
21
|
+
(direct_children + direct_children.flat_map { |child| children(child.pid) }).uniq
|
22
|
+
end
|
23
|
+
|
24
|
+
def traverse(&handler)
|
25
|
+
handler = method(:print_handler) unless handler.is_a?(Proc)
|
26
|
+
|
27
|
+
root_pids.each { |pid| traverse_branch(pid, &handler) }
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def print_handler(process, level)
|
33
|
+
indent = " " * level
|
34
|
+
prefix = level.zero? ? "" : "└─ "
|
35
|
+
puts "#{indent}#{prefix}PID #{process.pid} (#{process.name})"
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_process_map
|
39
|
+
ProcTable.ps.each_with_object({}) do |process, map|
|
40
|
+
map[process.pid] = { info: process, children: [] }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def connect_children
|
45
|
+
@process_map.each_value do |entry|
|
46
|
+
parent_pid = entry[:info].ppid
|
47
|
+
@process_map[parent_pid][:children] << entry[:info].pid if parent_pid && @process_map.key?(parent_pid)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def root_pids
|
52
|
+
return [@root_pid] if @root_pid
|
53
|
+
|
54
|
+
@process_map.values
|
55
|
+
.select { |entry| entry[:info].ppid.nil? || !@process_map.key?(entry[:info].ppid) }
|
56
|
+
.map { |entry| entry[:info].pid }
|
57
|
+
end
|
58
|
+
|
59
|
+
def traverse_branch(pid, level = 0, &handler)
|
60
|
+
return unless @process_map[pid]
|
61
|
+
|
62
|
+
process = @process_map[pid][:info]
|
63
|
+
|
64
|
+
handler.call(process, level)
|
65
|
+
|
66
|
+
@process_map[pid][:children].each do |child_pid|
|
67
|
+
traverse_branch(child_pid, level + 1, &handler)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -29,25 +29,25 @@ module Bidi2pdf
|
|
29
29
|
browser = @session.browser
|
30
30
|
user_context = browser.create_user_context
|
31
31
|
|
32
|
-
add_cookies(user_context)
|
33
|
-
|
34
32
|
window = user_context.create_browser_window
|
35
33
|
tab = window.create_browser_tab
|
36
34
|
|
37
35
|
@window = window
|
38
36
|
@tab = tab
|
39
37
|
|
38
|
+
add_cookies(tab)
|
39
|
+
|
40
40
|
add_headers
|
41
41
|
add_basic_auth
|
42
42
|
end
|
43
43
|
|
44
|
-
def add_cookies(
|
44
|
+
def add_cookies(tab)
|
45
45
|
@cookies.each do |name, value|
|
46
|
-
|
46
|
+
tab.set_cookie(
|
47
47
|
name: name,
|
48
48
|
value: value,
|
49
49
|
domain: domain,
|
50
|
-
|
50
|
+
secure: uri.scheme == "https"
|
51
51
|
)
|
52
52
|
end
|
53
53
|
end
|
data/lib/bidi2pdf/version.rb
CHANGED
data/lib/bidi2pdf.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bidi2pdf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dieter S.
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-04-
|
11
|
+
date: 2025-04-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: base64
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '2.4'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sys-proctable
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.3'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.3'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: thor
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -267,6 +281,8 @@ files:
|
|
267
281
|
- Rakefile
|
268
282
|
- docker/Dockerfile
|
269
283
|
- docker/docker-compose.yml
|
284
|
+
- docker/nginx/default.conf
|
285
|
+
- docker/nginx/htpasswd
|
270
286
|
- exe/bidi2pdf
|
271
287
|
- lib/bidi2pdf.rb
|
272
288
|
- lib/bidi2pdf/bidi/add_headers_interceptor.rb
|
@@ -284,6 +300,7 @@ files:
|
|
284
300
|
- lib/bidi2pdf/chromedriver_manager.rb
|
285
301
|
- lib/bidi2pdf/cli.rb
|
286
302
|
- lib/bidi2pdf/launcher.rb
|
303
|
+
- lib/bidi2pdf/process_tree.rb
|
287
304
|
- lib/bidi2pdf/session_runner.rb
|
288
305
|
- lib/bidi2pdf/utils.rb
|
289
306
|
- lib/bidi2pdf/version.rb
|