ferrum 0.10.1 → 0.12
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/LICENSE +1 -1
- data/README.md +261 -28
- data/lib/ferrum/browser/binary.rb +46 -0
- data/lib/ferrum/browser/client.rb +15 -12
- data/lib/ferrum/browser/command.rb +7 -8
- data/lib/ferrum/browser/options/base.rb +1 -7
- data/lib/ferrum/browser/options/chrome.rb +17 -10
- data/lib/ferrum/browser/options/firefox.rb +11 -4
- data/lib/ferrum/browser/process.rb +41 -35
- data/lib/ferrum/browser/subscriber.rb +1 -3
- data/lib/ferrum/browser/web_socket.rb +9 -12
- data/lib/ferrum/browser/xvfb.rb +4 -8
- data/lib/ferrum/browser.rb +49 -12
- data/lib/ferrum/context.rb +12 -4
- data/lib/ferrum/contexts.rb +13 -9
- data/lib/ferrum/cookies.rb +10 -9
- data/lib/ferrum/errors.rb +115 -0
- data/lib/ferrum/frame/runtime.rb +20 -17
- data/lib/ferrum/frame.rb +32 -24
- data/lib/ferrum/headers.rb +2 -2
- data/lib/ferrum/keyboard.rb +11 -11
- data/lib/ferrum/mouse.rb +8 -7
- data/lib/ferrum/network/auth_request.rb +7 -2
- data/lib/ferrum/network/exchange.rb +14 -10
- data/lib/ferrum/network/intercepted_request.rb +10 -8
- data/lib/ferrum/network/request.rb +5 -0
- data/lib/ferrum/network/response.rb +4 -4
- data/lib/ferrum/network.rb +124 -35
- data/lib/ferrum/node.rb +98 -40
- data/lib/ferrum/page/animation.rb +15 -0
- data/lib/ferrum/page/frames.rb +46 -15
- data/lib/ferrum/page/screenshot.rb +53 -67
- data/lib/ferrum/page/stream.rb +38 -0
- data/lib/ferrum/page/tracing.rb +71 -0
- data/lib/ferrum/page.rb +88 -34
- data/lib/ferrum/proxy.rb +58 -0
- data/lib/ferrum/{rbga.rb → rgba.rb} +4 -2
- data/lib/ferrum/target.rb +1 -0
- data/lib/ferrum/utils/attempt.rb +20 -0
- data/lib/ferrum/utils/elapsed_time.rb +27 -0
- data/lib/ferrum/utils/platform.rb +28 -0
- data/lib/ferrum/version.rb +1 -1
- data/lib/ferrum.rb +4 -140
- metadata +65 -50
@@ -0,0 +1,115 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ferrum
|
4
|
+
class Error < StandardError; end
|
5
|
+
class NoSuchPageError < Error; end
|
6
|
+
class NoSuchTargetError < Error; end
|
7
|
+
class NotImplementedError < Error; end
|
8
|
+
class BinaryNotFoundError < Error; end
|
9
|
+
class EmptyPathError < Error; end
|
10
|
+
|
11
|
+
class StatusError < Error
|
12
|
+
def initialize(url, message = nil)
|
13
|
+
super(message || "Request to #{url} failed to reach server, check DNS and server status")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class PendingConnectionsError < StatusError
|
18
|
+
attr_reader :pendings
|
19
|
+
|
20
|
+
def initialize(url, pendings = [])
|
21
|
+
@pendings = pendings
|
22
|
+
|
23
|
+
message = "Request to #{url} reached server, but there are still pending connections: #{pendings.join(', ')}"
|
24
|
+
|
25
|
+
super(url, message)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class TimeoutError < Error
|
30
|
+
def message
|
31
|
+
"Timed out waiting for response. It's possible that this happened " \
|
32
|
+
"because something took a very long time (for example a page load " \
|
33
|
+
"was slow). If so, setting the :timeout option to a higher value might " \
|
34
|
+
"help."
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class ScriptTimeoutError < Error
|
39
|
+
def message
|
40
|
+
"Timed out waiting for evaluated script to return a value"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class ProcessTimeoutError < Error
|
45
|
+
attr_reader :output
|
46
|
+
|
47
|
+
def initialize(timeout, output)
|
48
|
+
@output = output
|
49
|
+
super("Browser did not produce websocket url within #{timeout} seconds, try to increase `:process_timeout`. See https://github.com/rubycdp/ferrum#customization")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class DeadBrowserError < Error
|
54
|
+
def initialize(message = "Browser is dead or given window is closed")
|
55
|
+
super
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class NodeMovingError < Error
|
60
|
+
def initialize(node, prev, current)
|
61
|
+
@node = node
|
62
|
+
@prev = prev
|
63
|
+
@current = current
|
64
|
+
super(message)
|
65
|
+
end
|
66
|
+
|
67
|
+
def message
|
68
|
+
"#{@node.inspect} that you're trying to click is moving, hence " \
|
69
|
+
"we cannot. Previously it was at #{@prev.inspect} but now at " \
|
70
|
+
"#{@current.inspect}."
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class CoordinatesNotFoundError < Error
|
75
|
+
def initialize(message = "Could not compute content quads")
|
76
|
+
super
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class BrowserError < Error
|
81
|
+
attr_reader :response
|
82
|
+
|
83
|
+
def initialize(response)
|
84
|
+
@response = response
|
85
|
+
super(response["message"])
|
86
|
+
end
|
87
|
+
|
88
|
+
def code
|
89
|
+
response["code"]
|
90
|
+
end
|
91
|
+
|
92
|
+
def data
|
93
|
+
response["data"]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class NodeNotFoundError < BrowserError; end
|
98
|
+
|
99
|
+
class NoExecutionContextError < BrowserError
|
100
|
+
def initialize(response = nil)
|
101
|
+
response ||= { "message" => "There's no context available" }
|
102
|
+
super(response)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class JavaScriptError < BrowserError
|
107
|
+
attr_reader :class_name, :message, :stack_trace
|
108
|
+
|
109
|
+
def initialize(response, stack_trace = nil)
|
110
|
+
@class_name, @message = response.values_at("className", "description")
|
111
|
+
@stack_trace = stack_trace
|
112
|
+
super(response.merge("message" => @message))
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
data/lib/ferrum/frame/runtime.rb
CHANGED
@@ -46,7 +46,7 @@ module Ferrum
|
|
46
46
|
JS
|
47
47
|
|
48
48
|
def evaluate(expression, *args)
|
49
|
-
expression = "function() { return %s }"
|
49
|
+
expression = format("function() { return %s }", expression)
|
50
50
|
call(expression: expression, arguments: args)
|
51
51
|
end
|
52
52
|
|
@@ -66,12 +66,12 @@ module Ferrum
|
|
66
66
|
}
|
67
67
|
JS
|
68
68
|
|
69
|
-
expression = template
|
69
|
+
expression = format(template, wait * 1000, expression)
|
70
70
|
call(expression: expression, arguments: args, awaitPromise: true)
|
71
71
|
end
|
72
72
|
|
73
73
|
def execute(expression, *args)
|
74
|
-
expression = "function() { %s }"
|
74
|
+
expression = format("function() { %s }", expression)
|
75
75
|
call(expression: expression, arguments: args, handle: false, returnByValue: true)
|
76
76
|
true
|
77
77
|
end
|
@@ -82,7 +82,7 @@ module Ferrum
|
|
82
82
|
|
83
83
|
def evaluate_on(node:, expression:, by_value: true, wait: 0)
|
84
84
|
options = { handle: true }
|
85
|
-
expression = "function() { return %s }"
|
85
|
+
expression = format("function() { return %s }", expression)
|
86
86
|
options = { handle: false, returnByValue: true } if by_value
|
87
87
|
call(expression: expression, on: node, wait: wait, **options)
|
88
88
|
end
|
@@ -119,9 +119,10 @@ module Ferrum
|
|
119
119
|
|
120
120
|
def call(expression:, arguments: [], on: nil, wait: 0, handle: true, **options)
|
121
121
|
errors = [NodeNotFoundError, NoExecutionContextError]
|
122
|
-
|
122
|
+
sleep = INTERMITTENT_SLEEP
|
123
|
+
attempts = INTERMITTENT_ATTEMPTS
|
123
124
|
|
124
|
-
|
125
|
+
Utils::Attempt.with_retry(errors: errors, max: attempts, wait: sleep) do
|
125
126
|
params = options.dup
|
126
127
|
|
127
128
|
if on
|
@@ -141,7 +142,7 @@ module Ferrum
|
|
141
142
|
handle_error(response)
|
142
143
|
response = response["result"]
|
143
144
|
|
144
|
-
handle ? handle_response(response) : response
|
145
|
+
handle ? handle_response(response) : response["value"]
|
145
146
|
end
|
146
147
|
end
|
147
148
|
|
@@ -154,7 +155,7 @@ module Ferrum
|
|
154
155
|
when /\AError: timed out promise/
|
155
156
|
raise ScriptTimeoutError
|
156
157
|
else
|
157
|
-
raise JavaScriptError.new(result)
|
158
|
+
raise JavaScriptError.new(result, response.dig("exceptionDetails", "stackTrace"))
|
158
159
|
end
|
159
160
|
end
|
160
161
|
|
@@ -171,16 +172,17 @@ module Ferrum
|
|
171
172
|
|
172
173
|
case response["subtype"]
|
173
174
|
when "node"
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
175
|
+
# We cannot store object_id in the node because page can be reloaded
|
176
|
+
# and node destroyed so we need to retrieve it each time for given id.
|
177
|
+
# Though we can try to subscribe to `DOM.childNodeRemoved` and
|
178
|
+
# `DOM.childNodeInserted` in the future.
|
179
|
+
node_id = @page.command("DOM.requestNode", objectId: object_id)["nodeId"]
|
180
|
+
description = @page.command("DOM.describeNode", nodeId: node_id)["node"]
|
181
|
+
Node.new(self, @page.target_id, node_id, description)
|
181
182
|
when "array"
|
182
183
|
reduce_props(object_id, []) do |memo, key, value|
|
183
|
-
next(memo) unless
|
184
|
+
next(memo) unless Integer(key, exception: false)
|
185
|
+
|
184
186
|
value = value["objectId"] ? handle_response(value) : value["value"]
|
185
187
|
memo.insert(key.to_i, value)
|
186
188
|
end.compact
|
@@ -212,11 +214,12 @@ module Ferrum
|
|
212
214
|
|
213
215
|
def reduce_props(object_id, to)
|
214
216
|
if cyclic?(object_id).dig("result", "value")
|
215
|
-
|
217
|
+
to.is_a?(Array) ? [cyclic_object] : cyclic_object
|
216
218
|
else
|
217
219
|
props = @page.command("Runtime.getProperties", ownProperties: true, objectId: object_id)
|
218
220
|
props["result"].reduce(to) do |memo, prop|
|
219
221
|
next(memo) unless prop["enumerable"]
|
222
|
+
|
220
223
|
yield(memo, prop["name"], prop["value"])
|
221
224
|
end
|
222
225
|
end
|
data/lib/ferrum/frame.rb
CHANGED
@@ -5,21 +5,28 @@ require "ferrum/frame/runtime"
|
|
5
5
|
|
6
6
|
module Ferrum
|
7
7
|
class Frame
|
8
|
-
include DOM
|
8
|
+
include DOM
|
9
|
+
include Runtime
|
10
|
+
|
11
|
+
STATE_VALUES = %i[
|
12
|
+
started_loading
|
13
|
+
navigated
|
14
|
+
stopped_loading
|
15
|
+
].freeze
|
9
16
|
|
10
|
-
attr_reader :page, :parent_id, :state
|
11
17
|
attr_accessor :id, :name
|
18
|
+
attr_reader :page, :parent_id, :state
|
12
19
|
|
13
20
|
def initialize(id, page, parent_id = nil)
|
14
|
-
@
|
15
|
-
@
|
21
|
+
@id = id
|
22
|
+
@page = page
|
23
|
+
@parent_id = parent_id
|
24
|
+
@execution_id = Concurrent::MVar.new
|
16
25
|
end
|
17
26
|
|
18
|
-
# Can be one of:
|
19
|
-
# * started_loading
|
20
|
-
# * navigated
|
21
|
-
# * stopped_loading
|
22
27
|
def state=(value)
|
28
|
+
raise ArgumentError unless STATE_VALUES.include?(value)
|
29
|
+
|
23
30
|
@state = value
|
24
31
|
end
|
25
32
|
|
@@ -35,7 +42,7 @@ module Ferrum
|
|
35
42
|
@parent_id.nil?
|
36
43
|
end
|
37
44
|
|
38
|
-
def
|
45
|
+
def content=(html)
|
39
46
|
evaluate_async(%(
|
40
47
|
document.open();
|
41
48
|
document.write(arguments[0]);
|
@@ -43,29 +50,30 @@ module Ferrum
|
|
43
50
|
arguments[1](true);
|
44
51
|
), @page.timeout, html)
|
45
52
|
end
|
46
|
-
|
47
|
-
def execution_id?(execution_id)
|
48
|
-
@execution_id == execution_id
|
49
|
-
end
|
53
|
+
alias set_content content=
|
50
54
|
|
51
55
|
def execution_id
|
52
|
-
|
53
|
-
|
54
|
-
rescue NoExecutionContextError
|
55
|
-
@page.event.reset
|
56
|
-
@page.event.wait(@page.timeout) ? retry : raise
|
57
|
-
end
|
56
|
+
value = @execution_id.borrow(@page.timeout, &:itself)
|
57
|
+
raise NoExecutionContextError if value.instance_of?(Object)
|
58
58
|
|
59
|
-
|
60
|
-
@execution_id ||= value
|
59
|
+
value
|
61
60
|
end
|
62
61
|
|
63
|
-
def
|
64
|
-
|
62
|
+
def execution_id=(value)
|
63
|
+
if value.nil?
|
64
|
+
@execution_id.try_take!
|
65
|
+
else
|
66
|
+
@execution_id.try_put!(value)
|
67
|
+
end
|
65
68
|
end
|
66
69
|
|
67
70
|
def inspect
|
68
|
-
|
71
|
+
"#<#{self.class} " \
|
72
|
+
"@id=#{@id.inspect} " \
|
73
|
+
"@parent_id=#{@parent_id.inspect} " \
|
74
|
+
"@name=#{@name.inspect} " \
|
75
|
+
"@state=#{@state.inspect} " \
|
76
|
+
"@execution_id=#{@execution_id.inspect}>"
|
69
77
|
end
|
70
78
|
end
|
71
79
|
end
|
data/lib/ferrum/headers.rb
CHANGED
@@ -39,12 +39,12 @@ module Ferrum
|
|
39
39
|
private
|
40
40
|
|
41
41
|
def set_overrides(user_agent: nil, accept_language: nil, platform: nil)
|
42
|
-
options =
|
42
|
+
options = {}
|
43
43
|
options[:userAgent] = user_agent || @page.browser.default_user_agent
|
44
44
|
options[:acceptLanguage] = accept_language if accept_language
|
45
45
|
options[:platform] if platform
|
46
46
|
|
47
|
-
@page.command("Network.setUserAgentOverride", **options)
|
47
|
+
@page.command("Network.setUserAgentOverride", **options) unless options.empty?
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
data/lib/ferrum/keyboard.rb
CHANGED
@@ -4,14 +4,14 @@ require "json"
|
|
4
4
|
|
5
5
|
module Ferrum
|
6
6
|
class Keyboard
|
7
|
-
KEYS = JSON.parse(File.read(File.expand_path("
|
7
|
+
KEYS = JSON.parse(File.read(File.expand_path("keyboard.json", __dir__)))
|
8
8
|
MODIFIERS = { "alt" => 1, "ctrl" => 2, "control" => 2,
|
9
|
-
"meta" => 4, "command" => 4, "shift" => 8 }
|
9
|
+
"meta" => 4, "command" => 4, "shift" => 8 }.freeze
|
10
10
|
KEYS_MAPPING = {
|
11
11
|
cancel: "Cancel", help: "Help", backspace: "Backspace", tab: "Tab",
|
12
12
|
clear: "Clear", return: "Enter", enter: "Enter", shift: "Shift",
|
13
13
|
ctrl: "Control", control: "Control", alt: "Alt", pause: "Pause",
|
14
|
-
escape: "Escape", space: "Space",
|
14
|
+
escape: "Escape", space: "Space", pageup: "PageUp", page_up: "PageUp",
|
15
15
|
pagedown: "PageDown", page_down: "PageDown", end: "End", home: "Home",
|
16
16
|
left: "ArrowLeft", up: "ArrowUp", right: "ArrowRight",
|
17
17
|
down: "ArrowDown", insert: "Insert", delete: "Delete",
|
@@ -23,8 +23,8 @@ module Ferrum
|
|
23
23
|
separator: "NumpadDecimal", subtract: "NumpadSubtract",
|
24
24
|
decimal: "NumpadDecimal", divide: "NumpadDivide", f1: "F1", f2: "F2",
|
25
25
|
f3: "F3", f4: "F4", f5: "F5", f6: "F6", f7: "F7", f8: "F8", f9: "F9",
|
26
|
-
f10: "F10", f11: "F11", f12: "F12", meta: "Meta", command: "Meta"
|
27
|
-
}
|
26
|
+
f10: "F10", f11: "F11", f12: "F12", meta: "Meta", command: "Meta"
|
27
|
+
}.freeze
|
28
28
|
|
29
29
|
def initialize(page)
|
30
30
|
@page = page
|
@@ -77,25 +77,25 @@ module Ferrum
|
|
77
77
|
pressed_keys.last.push(key)
|
78
78
|
nil
|
79
79
|
else
|
80
|
-
|
81
|
-
|
82
|
-
to_options(
|
80
|
+
key = KEYS.fetch(KEYS_MAPPING[key.to_sym] || key.to_sym)
|
81
|
+
key[:modifiers] = pressed_keys.flatten.map { |k| MODIFIERS[k] }.reduce(0, :|)
|
82
|
+
to_options(key)
|
83
83
|
end
|
84
84
|
when String
|
85
85
|
pressed = pressed_keys.flatten
|
86
86
|
keys.each_char.map do |char|
|
87
|
+
key = KEYS[char] || {}
|
88
|
+
|
87
89
|
if pressed.empty?
|
88
|
-
key = KEYS[char] || {}
|
89
90
|
key = key.merge(text: char, unmodifiedText: char)
|
90
91
|
[to_options(key)]
|
91
92
|
else
|
92
|
-
key = KEYS[char] || {}
|
93
93
|
text = pressed == ["shift"] ? char.upcase : char
|
94
94
|
key = key.merge(
|
95
95
|
text: text,
|
96
96
|
unmodifiedText: text,
|
97
97
|
isKeypad: key["location"] == 3,
|
98
|
-
modifiers: pressed.map { |k| MODIFIERS[k] }.reduce(0, :|)
|
98
|
+
modifiers: pressed.map { |k| MODIFIERS[k] }.reduce(0, :|)
|
99
99
|
)
|
100
100
|
|
101
101
|
modifiers = pressed.map { |k| to_options(KEYS.fetch(KEYS_MAPPING[k.to_sym])) }
|
data/lib/ferrum/mouse.rb
CHANGED
@@ -33,12 +33,14 @@ module Ferrum
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def move(x:, y:, steps: 1)
|
36
|
-
from_x
|
37
|
-
|
36
|
+
from_x = @x
|
37
|
+
from_y = @y
|
38
|
+
@x = x
|
39
|
+
@y = y
|
38
40
|
|
39
41
|
steps.times do |i|
|
40
|
-
new_x = from_x + (@x - from_x) * ((i + 1) / steps.to_f)
|
41
|
-
new_y = from_y + (@y - from_y) * ((i + 1) / steps.to_f)
|
42
|
+
new_x = from_x + ((@x - from_x) * ((i + 1) / steps.to_f))
|
43
|
+
new_y = from_y + ((@y - from_y) * ((i + 1) / steps.to_f))
|
42
44
|
|
43
45
|
@page.command("Input.dispatchMouseEvent",
|
44
46
|
slowmoable: true,
|
@@ -61,9 +63,8 @@ module Ferrum
|
|
61
63
|
|
62
64
|
def validate_button(button)
|
63
65
|
button = button.to_s
|
64
|
-
unless VALID_BUTTONS.include?(button)
|
65
|
-
|
66
|
-
end
|
66
|
+
raise "Invalid button: #{button}" unless VALID_BUTTONS.include?(button)
|
67
|
+
|
67
68
|
button
|
68
69
|
end
|
69
70
|
end
|
@@ -6,7 +6,8 @@ module Ferrum
|
|
6
6
|
attr_accessor :request_id, :frame_id, :resource_type
|
7
7
|
|
8
8
|
def initialize(page, params)
|
9
|
-
@page
|
9
|
+
@page = page
|
10
|
+
@params = params
|
10
11
|
@request_id = params["requestId"]
|
11
12
|
@frame_id = params["frameId"]
|
12
13
|
@resource_type = params["resourceType"]
|
@@ -55,7 +56,11 @@ module Ferrum
|
|
55
56
|
end
|
56
57
|
|
57
58
|
def inspect
|
58
|
-
|
59
|
+
"#<#{self.class} " \
|
60
|
+
"@request_id=#{@request_id.inspect} " \
|
61
|
+
"@frame_id=#{@frame_id.inspect} " \
|
62
|
+
"@resource_type=#{@resource_type.inspect} " \
|
63
|
+
"@request=#{@request.inspect}>"
|
59
64
|
end
|
60
65
|
end
|
61
66
|
end
|
@@ -4,11 +4,11 @@ module Ferrum
|
|
4
4
|
class Network
|
5
5
|
class Exchange
|
6
6
|
attr_reader :id
|
7
|
-
attr_accessor :intercepted_request
|
8
|
-
attr_accessor :request, :response, :error
|
7
|
+
attr_accessor :intercepted_request, :request, :response, :error
|
9
8
|
|
10
9
|
def initialize(page, id)
|
11
|
-
@
|
10
|
+
@id = id
|
11
|
+
@page = page
|
12
12
|
@intercepted_request = nil
|
13
13
|
@request = @response = @error = nil
|
14
14
|
end
|
@@ -23,7 +23,7 @@ module Ferrum
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def blocked?
|
26
|
-
|
26
|
+
intercepted? && intercepted_request.status?(:aborted)
|
27
27
|
end
|
28
28
|
|
29
29
|
def finished?
|
@@ -34,17 +34,21 @@ module Ferrum
|
|
34
34
|
!finished?
|
35
35
|
end
|
36
36
|
|
37
|
+
def intercepted?
|
38
|
+
intercepted_request
|
39
|
+
end
|
40
|
+
|
37
41
|
def to_a
|
38
42
|
[request, response, error]
|
39
43
|
end
|
40
44
|
|
41
45
|
def inspect
|
42
|
-
"#<#{self.class} "\
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
46
|
+
"#<#{self.class} " \
|
47
|
+
"@id=#{@id.inspect} " \
|
48
|
+
"@intercepted_request=#{@intercepted_request.inspect} " \
|
49
|
+
"@request=#{@request.inspect} " \
|
50
|
+
"@response=#{@response.inspect} " \
|
51
|
+
"@error=#{@error.inspect}>"
|
48
52
|
end
|
49
53
|
end
|
50
54
|
end
|
@@ -9,7 +9,8 @@ module Ferrum
|
|
9
9
|
|
10
10
|
def initialize(page, params)
|
11
11
|
@status = nil
|
12
|
-
@page
|
12
|
+
@page = page
|
13
|
+
@params = params
|
13
14
|
@request_id = params["requestId"]
|
14
15
|
@frame_id = params["frameId"]
|
15
16
|
@resource_type = params["resourceType"]
|
@@ -30,15 +31,12 @@ module Ferrum
|
|
30
31
|
end
|
31
32
|
|
32
33
|
def respond(**options)
|
33
|
-
has_body = options.
|
34
|
+
has_body = options.key?(:body)
|
34
35
|
headers = has_body ? { "content-length" => options.fetch(:body, "").length } : {}
|
35
36
|
headers = headers.merge(options.fetch(:responseHeaders, {}))
|
36
37
|
|
37
|
-
options = {responseCode: 200}.merge(options)
|
38
|
-
options = options.merge(
|
39
|
-
requestId: request_id,
|
40
|
-
responseHeaders: header_array(headers),
|
41
|
-
})
|
38
|
+
options = { responseCode: 200 }.merge(options)
|
39
|
+
options = options.merge(requestId: request_id, responseHeaders: header_array(headers))
|
42
40
|
options = options.merge(body: Base64.strict_encode64(options.fetch(:body, ""))) if has_body
|
43
41
|
|
44
42
|
@status = :responded
|
@@ -77,7 +75,11 @@ module Ferrum
|
|
77
75
|
end
|
78
76
|
|
79
77
|
def inspect
|
80
|
-
|
78
|
+
"#<#{self.class} " \
|
79
|
+
"@request_id=#{@request_id.inspect} " \
|
80
|
+
"@frame_id=#{@frame_id.inspect} " \
|
81
|
+
"@resource_type=#{@resource_type.inspect} " \
|
82
|
+
"@request=#{@request.inspect}>"
|
81
83
|
end
|
82
84
|
|
83
85
|
private
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Ferrum
|
4
4
|
class Network
|
5
5
|
class Response
|
6
|
-
attr_reader :body_size
|
6
|
+
attr_reader :body_size, :params
|
7
7
|
|
8
8
|
def initialize(page, params)
|
9
9
|
@page = page
|
@@ -34,7 +34,7 @@ module Ferrum
|
|
34
34
|
def headers_size
|
35
35
|
@response["encodedDataLength"]
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
def type
|
39
39
|
@params["type"]
|
40
40
|
end
|
@@ -55,8 +55,8 @@ module Ferrum
|
|
55
55
|
def body
|
56
56
|
@body ||= begin
|
57
57
|
body, encoded = @page
|
58
|
-
|
59
|
-
|
58
|
+
.command("Network.getResponseBody", requestId: id)
|
59
|
+
.values_at("body", "base64Encoded")
|
60
60
|
encoded ? Base64.decode64(body) : body
|
61
61
|
end
|
62
62
|
end
|