ferrum 0.10.1 → 0.12
Sign up to get free protection for your applications and to get access to all the features.
- 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
|