puppeteer-ruby 0.0.11 → 0.0.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +0 -12
  3. data/.github/workflows/docs.yml +45 -0
  4. data/.github/workflows/reviewdog.yml +15 -0
  5. data/README.md +54 -1
  6. data/lib/puppeteer.rb +39 -13
  7. data/lib/puppeteer/browser.rb +22 -25
  8. data/lib/puppeteer/cdp_session.rb +3 -19
  9. data/lib/puppeteer/concurrent_ruby_utils.rb +12 -2
  10. data/lib/puppeteer/connection.rb +3 -15
  11. data/lib/puppeteer/define_async_method.rb +23 -0
  12. data/lib/puppeteer/dom_world.rb +51 -65
  13. data/lib/puppeteer/element_handle.rb +15 -44
  14. data/lib/puppeteer/emulation_manager.rb +2 -6
  15. data/lib/puppeteer/event_callbackable.rb +11 -0
  16. data/lib/puppeteer/execution_context.rb +1 -6
  17. data/lib/puppeteer/frame.rb +34 -39
  18. data/lib/puppeteer/frame_manager.rb +7 -25
  19. data/lib/puppeteer/js_handle.rb +3 -12
  20. data/lib/puppeteer/keyboard.rb +6 -27
  21. data/lib/puppeteer/launcher.rb +6 -6
  22. data/lib/puppeteer/launcher/chrome.rb +10 -8
  23. data/lib/puppeteer/mouse.rb +5 -25
  24. data/lib/puppeteer/network_manager.rb +163 -5
  25. data/lib/puppeteer/page.rb +230 -177
  26. data/lib/puppeteer/page/pdf_options.rb +166 -0
  27. data/lib/puppeteer/remote_object.rb +2 -5
  28. data/lib/puppeteer/request.rb +336 -0
  29. data/lib/puppeteer/response.rb +113 -0
  30. data/lib/puppeteer/target.rb +1 -1
  31. data/lib/puppeteer/touch_screen.rb +2 -7
  32. data/lib/puppeteer/version.rb +1 -1
  33. data/lib/puppeteer/wait_task.rb +2 -4
  34. data/lib/puppeteer/web_socket_transport.rb +8 -8
  35. data/puppeteer-ruby.gemspec +1 -1
  36. data/puppeteer-ruby.png +0 -0
  37. metadata +11 -105
  38. data/Dockerfile +0 -6
  39. data/docker-compose.yml +0 -15
  40. data/docs/Puppeteer.html +0 -2020
  41. data/docs/Puppeteer/AsyncAwaitBehavior.html +0 -105
  42. data/docs/Puppeteer/Browser.html +0 -2258
  43. data/docs/Puppeteer/BrowserContext.html +0 -809
  44. data/docs/Puppeteer/BrowserFetcher.html +0 -214
  45. data/docs/Puppeteer/BrowserRunner.html +0 -914
  46. data/docs/Puppeteer/BrowserRunner/BrowserProcess.html +0 -477
  47. data/docs/Puppeteer/CDPSession.html +0 -813
  48. data/docs/Puppeteer/CDPSession/Error.html +0 -124
  49. data/docs/Puppeteer/ConcurrentRubyUtils.html +0 -430
  50. data/docs/Puppeteer/Connection.html +0 -964
  51. data/docs/Puppeteer/Connection/MessageCallback.html +0 -434
  52. data/docs/Puppeteer/Connection/ProtocolError.html +0 -216
  53. data/docs/Puppeteer/Connection/RequestDebugPrinter.html +0 -217
  54. data/docs/Puppeteer/Connection/ResponseDebugPrinter.html +0 -244
  55. data/docs/Puppeteer/ConsoleMessage.html +0 -565
  56. data/docs/Puppeteer/ConsoleMessage/Location.html +0 -433
  57. data/docs/Puppeteer/DOMWorld.html +0 -2219
  58. data/docs/Puppeteer/DOMWorld/DetachedError.html +0 -124
  59. data/docs/Puppeteer/DOMWorld/DocumentEvaluationError.html +0 -124
  60. data/docs/Puppeteer/DebugPrint.html +0 -233
  61. data/docs/Puppeteer/Device.html +0 -470
  62. data/docs/Puppeteer/Devices.html +0 -139
  63. data/docs/Puppeteer/ElementHandle.html +0 -2542
  64. data/docs/Puppeteer/ElementHandle/BoundingBox.html +0 -507
  65. data/docs/Puppeteer/ElementHandle/BoxModel.html +0 -404
  66. data/docs/Puppeteer/ElementHandle/ElementNotFoundError.html +0 -206
  67. data/docs/Puppeteer/ElementHandle/ElementNotVisibleError.html +0 -206
  68. data/docs/Puppeteer/ElementHandle/Point.html +0 -492
  69. data/docs/Puppeteer/ElementHandle/ScrollIntoViewError.html +0 -124
  70. data/docs/Puppeteer/EmulationManager.html +0 -454
  71. data/docs/Puppeteer/EventCallbackable.html +0 -433
  72. data/docs/Puppeteer/EventCallbackable/EventListeners.html +0 -435
  73. data/docs/Puppeteer/ExecutionContext.html +0 -998
  74. data/docs/Puppeteer/ExecutionContext/EvaluationError.html +0 -124
  75. data/docs/Puppeteer/ExecutionContext/JavaScriptExpression.html +0 -357
  76. data/docs/Puppeteer/ExecutionContext/JavaScriptFunction.html +0 -389
  77. data/docs/Puppeteer/FileChooser.html +0 -455
  78. data/docs/Puppeteer/Frame.html +0 -3813
  79. data/docs/Puppeteer/FrameManager.html +0 -2410
  80. data/docs/Puppeteer/FrameManager/NavigationError.html +0 -124
  81. data/docs/Puppeteer/IfPresent.html +0 -222
  82. data/docs/Puppeteer/JSHandle.html +0 -1352
  83. data/docs/Puppeteer/Keyboard.html +0 -1557
  84. data/docs/Puppeteer/Keyboard/KeyDefinition.html +0 -831
  85. data/docs/Puppeteer/Keyboard/KeyDescription.html +0 -603
  86. data/docs/Puppeteer/Launcher.html +0 -237
  87. data/docs/Puppeteer/Launcher/Base.html +0 -385
  88. data/docs/Puppeteer/Launcher/Base/ExecutablePathNotFound.html +0 -124
  89. data/docs/Puppeteer/Launcher/BrowserOptions.html +0 -441
  90. data/docs/Puppeteer/Launcher/Chrome.html +0 -669
  91. data/docs/Puppeteer/Launcher/Chrome/DefaultArgs.html +0 -382
  92. data/docs/Puppeteer/Launcher/ChromeArgOptions.html +0 -531
  93. data/docs/Puppeteer/Launcher/LaunchOptions.html +0 -893
  94. data/docs/Puppeteer/LifecycleWatcher.html +0 -834
  95. data/docs/Puppeteer/LifecycleWatcher/ExpectedLifecycle.html +0 -363
  96. data/docs/Puppeteer/LifecycleWatcher/FrameDetachedError.html +0 -206
  97. data/docs/Puppeteer/LifecycleWatcher/TerminatedError.html +0 -124
  98. data/docs/Puppeteer/Mouse.html +0 -1095
  99. data/docs/Puppeteer/Mouse/Button.html +0 -136
  100. data/docs/Puppeteer/NetworkManager.html +0 -901
  101. data/docs/Puppeteer/NetworkManager/Credentials.html +0 -385
  102. data/docs/Puppeteer/Page.html +0 -5970
  103. data/docs/Puppeteer/Page/FileChooserTimeoutError.html +0 -206
  104. data/docs/Puppeteer/Page/ScreenshotOptions.html +0 -845
  105. data/docs/Puppeteer/Page/ScriptTag.html +0 -555
  106. data/docs/Puppeteer/Page/StyleTag.html +0 -448
  107. data/docs/Puppeteer/Page/TargetCrashedError.html +0 -124
  108. data/docs/Puppeteer/RemoteObject.html +0 -1087
  109. data/docs/Puppeteer/Target.html +0 -1336
  110. data/docs/Puppeteer/Target/InitializeFailure.html +0 -124
  111. data/docs/Puppeteer/Target/TargetInfo.html +0 -729
  112. data/docs/Puppeteer/TimeoutError.html +0 -135
  113. data/docs/Puppeteer/TimeoutSettings.html +0 -496
  114. data/docs/Puppeteer/TouchScreen.html +0 -464
  115. data/docs/Puppeteer/Viewport.html +0 -837
  116. data/docs/Puppeteer/WaitTask.html +0 -637
  117. data/docs/Puppeteer/WaitTask/TerminatedError.html +0 -124
  118. data/docs/Puppeteer/WaitTask/TimeoutError.html +0 -206
  119. data/docs/Puppeteer/WebSocket.html +0 -673
  120. data/docs/Puppeteer/WebSocket/DriverImpl.html +0 -412
  121. data/docs/Puppeteer/WebSocket/TransportError.html +0 -124
  122. data/docs/Puppeteer/WebSocketTransport.html +0 -600
  123. data/docs/Puppeteer/WebSocktTransportError.html +0 -124
  124. data/docs/_index.html +0 -816
  125. data/docs/class_list.html +0 -51
  126. data/docs/css/common.css +0 -1
  127. data/docs/css/full_list.css +0 -58
  128. data/docs/css/style.css +0 -496
  129. data/docs/file.README.html +0 -123
  130. data/docs/file_list.html +0 -56
  131. data/docs/frames.html +0 -17
  132. data/docs/index.html +0 -123
  133. data/docs/js/app.js +0 -314
  134. data/docs/js/full_list.js +0 -216
  135. data/docs/js/jquery.js +0 -4
  136. data/docs/method_list.html +0 -4091
  137. data/docs/top-level-namespace.html +0 -126
  138. data/lib/puppeteer/async_await_behavior.rb +0 -38
@@ -0,0 +1,166 @@
1
+ require 'mime/types'
2
+
3
+ class Puppeteer::Page
4
+ # /**
5
+ # * @typedef {Object} PDFOptions
6
+ # * @property {number=} scale
7
+ # * @property {boolean=} displayHeaderFooter
8
+ # * @property {string=} headerTemplate
9
+ # * @property {string=} footerTemplate
10
+ # * @property {boolean=} printBackground
11
+ # * @property {boolean=} landscape
12
+ # * @property {string=} pageRanges
13
+ # * @property {string=} format
14
+ # * @property {string|number=} width
15
+ # * @property {string|number=} height
16
+ # * @property {boolean=} preferCSSPageSize
17
+ # * @property {!{top?: string|number, bottom?: string|number, left?: string|number, right?: string|number}=} margin
18
+ # * @property {string=} path
19
+ # */
20
+ class PDFOptions
21
+ # @params options [Hash]
22
+ def initialize(options)
23
+ unless options[:path]
24
+ # Original puppeteer allows path = nil, however nothing to do without path actually.
25
+ # Also in most case, users forget to specify path parameter. So let's raise ArgumentError.
26
+ raise ArgumentError('"path" parameter must be specified.')
27
+ end
28
+
29
+ @scale = options[:scale]
30
+ @display_header_footer = options[:display_header_footer]
31
+ @header_template = options[:header_template]
32
+ @footer_template = options[:footer_template]
33
+ @print_background = options[:print_background]
34
+ @landscape = options[:landscape]
35
+ @page_ranges = options[:page_ranges]
36
+ @format = options[:format]
37
+ @width = options[:width]
38
+ @height = options[:height]
39
+ @prefer_css_page_size = options[:prefer_css_page_size]
40
+ @margin = Margin.new(options[:margin] || {})
41
+ @path = options[:path]
42
+ end
43
+
44
+ attr_reader :path
45
+
46
+ class PaperSize
47
+ def initialize(width:, height:)
48
+ @width = width
49
+ @height = height
50
+ end
51
+ attr_reader :width, :height
52
+ end
53
+
54
+ PAPER_FORMATS = {
55
+ letter: PaperSize.new(width: 8.5, height: 11),
56
+ legal: PaperSize.new(width: 8.5, height: 14),
57
+ tabloid: PaperSize.new(width: 11, height: 17),
58
+ ledger: PaperSize.new(width: 17, height: 11),
59
+ a0: PaperSize.new(width: 33.1, height: 46.8),
60
+ a1: PaperSize.new(width: 23.4, height: 33.1),
61
+ a2: PaperSize.new(width: 16.54, height: 23.4),
62
+ a3: PaperSize.new(width: 11.7, height: 16.54),
63
+ a4: PaperSize.new(width: 8.27, height: 11.7),
64
+ a5: PaperSize.new(width: 5.83, height: 8.27),
65
+ a6: PaperSize.new(width: 4.13, height: 5.83),
66
+ }
67
+
68
+ UNIT_TO_PIXELS = {
69
+ px: 1,
70
+ in: 96,
71
+ cm: 37.8,
72
+ mm: 3.78,
73
+ }
74
+
75
+ # @param parameter [String|Integer|nil]
76
+ private def convert_print_parameter_to_inches(parameter)
77
+ return nil if parameter.nil?
78
+
79
+ pixels =
80
+ if parameter.is_a?(Numeric)
81
+ parameter.to_i
82
+ elsif parameter.is_a?(String)
83
+ unit = parameter[-2..-1].downcase
84
+ value =
85
+ if UNIT_TO_PIXELS.has_key?(unit)
86
+ parameter[0...-2].to_i
87
+ else
88
+ unit = 'px'
89
+ parameter.to_i
90
+ end
91
+
92
+ value * UNIT_TO_PIXELS[unit]
93
+ else
94
+ raise ArgumentError.new("page.pdf() Cannot handle parameter type: #{parameter.class}")
95
+ end
96
+
97
+ pixels / 96
98
+ end
99
+
100
+ private def paper_size
101
+ @paper_size ||= calc_paper_size
102
+ end
103
+
104
+ # @return [PaperSize]
105
+ private def calc_paper_size
106
+ if @format
107
+ PAPER_FORMATS[@format.downcase] or raise ArgumentError.new("Unknown paper format: #{@format}")
108
+ else
109
+ PaperSize.new(
110
+ width: convert_print_parameter_to_inches(@width) || 8.5,
111
+ height: convert_print_parameter_to_inches(@height) || 11.0,
112
+ )
113
+ end
114
+ end
115
+
116
+ class Margin
117
+ def initialize(options)
118
+ @top = options[:top]
119
+ @bottom = options[:bottom]
120
+ @left = options[:left]
121
+ @right = options[:right]
122
+ end
123
+
124
+ def translate(&block)
125
+ new_margin ={
126
+ top: block.call(@top),
127
+ bottom: block.call(@bottom),
128
+ left: block.call(@left),
129
+ right: block.call(@right),
130
+ }
131
+ Margin.new(new_margin)
132
+ end
133
+ attr_reader :top, :bottom, :left, :right
134
+ end
135
+
136
+ private def margin
137
+ @__margin ||= calc_margin
138
+ end
139
+
140
+ private def calc_margin
141
+ @margin.translate do |value|
142
+ convert_print_parameter_to_inches(value) || 0
143
+ end
144
+ end
145
+
146
+ def page_print_args
147
+ {
148
+ transferMode: 'ReturnAsStream',
149
+ landscape: @landscape || false,
150
+ displayHeaderFooter: @display_header_footer || false,
151
+ headerTemplate: @header_template || '',
152
+ footerTemplate: @footer_template || '',
153
+ printBackground: @print_background || false,
154
+ scale: @scale || 1,
155
+ paperWidth: paper_size.width,
156
+ paperHeight: paper_size.height,
157
+ marginTop: margin.top,
158
+ marginBottom: margin.bottom,
159
+ marginLeft: margin.left,
160
+ marginRight: margin.right,
161
+ pageRanges: @page_ranges || '',
162
+ preferCSSPageSize: @prefer_css_page_size || false,
163
+ }
164
+ end
165
+ end
166
+ end
@@ -1,7 +1,7 @@
1
1
  # providing #valueFromRemoteObject, #releaseObject
2
2
  class Puppeteer::RemoteObject
3
3
  include Puppeteer::DebugPrint
4
- using Puppeteer::AsyncAwaitBehavior
4
+ using Puppeteer::DefineAsyncMethod
5
5
 
6
6
  # @param payload [Hash]
7
7
  def initialize(payload)
@@ -111,10 +111,7 @@ class Puppeteer::RemoteObject
111
111
  nil
112
112
  end
113
113
 
114
- # @param client [Puppeteer::CDPSession]
115
- async def async_release(client)
116
- release(client)
117
- end
114
+ define_async_method :async_release
118
115
 
119
116
  def converted_arg
120
117
  # ported logic from ExecutionContext#convertArgument
@@ -0,0 +1,336 @@
1
+ class Puppeteer::Request
2
+ include Puppeteer::DebugPrint
3
+ include Puppeteer::IfPresent
4
+
5
+ # defines some methods used only in NetworkManager, Response
6
+ class InternalAccessor
7
+ def initialize(request)
8
+ @request = request
9
+ end
10
+
11
+ def request_id
12
+ @request.instance_variable_get(:@request_id)
13
+ end
14
+
15
+ def interception_id
16
+ @request.instance_variable_get(:@interception_id)
17
+ end
18
+
19
+ # @param response [Puppeteer::Response]
20
+ def response=(response)
21
+ @request.instance_variable_set(:@response, response)
22
+ end
23
+
24
+ def redirect_chain
25
+ @request.instance_variable_get(:@redirect_chain)
26
+ end
27
+
28
+ def failure_text=(failure_text)
29
+ @request.instance_variable_set(:@failure_text, failure_text)
30
+ end
31
+
32
+ def from_memory_cache=(from_memory_cache)
33
+ @request.instance_variable_set(:@from_memory_cache, from_memory_cache)
34
+ end
35
+
36
+ def from_memory_cache?
37
+ @request.instance_variable_get(:@from_memory_cache)
38
+ end
39
+ end
40
+
41
+ # @param client [Puppeteer::CDPSession]
42
+ # @param frame [Puppeteer::Frame]
43
+ # @param interception_id [string|nil]
44
+ # @param allow_interception [boolean]
45
+ # @param event [Hash]
46
+ # @param redirect_chain Array<Request>
47
+ def initialize(client, frame, interception_id, allow_interception, event, redirect_chain)
48
+ @client = client
49
+ @request_id = event['requestId']
50
+ @is_navigation_request = event['requestId'] == event['loaderId'] && event['type'] == 'Document'
51
+ @interception_id = interception_id
52
+ @allow_interception = allow_interception
53
+ @url = event['request']['url']
54
+ @resource_type = event['type'].downcase
55
+ @method = event['request']['method']
56
+ @post_data = event['request']['postData']
57
+ @frame = frame
58
+ @redirect_chain = redirect_chain
59
+ @headers = {}
60
+ event['request']['headers'].each do |key, value|
61
+ @headers[key.downcase] = value
62
+ end
63
+ @from_memory_cache = false
64
+
65
+ @internal = InternalAccessor.new(self)
66
+ end
67
+
68
+ attr_reader :internal
69
+ attr_reader :url, :resource_type, :method, :post_data, :headers, :response, :frame
70
+
71
+ def navigation_request?
72
+ @is_navigation_request
73
+ end
74
+
75
+ def redirect_chain
76
+ @redirect_chain.dup
77
+ end
78
+
79
+ def failure
80
+ if_present(@failure_text) do |failure_text|
81
+ { errorText: @failure_text }
82
+ end
83
+ end
84
+
85
+ private def headers_to_array(headers)
86
+ return nil unless headers
87
+
88
+ headers.map do |key, value|
89
+ { name: key, value: value.to_s }
90
+ end
91
+ end
92
+
93
+ class InterceptionNotEnabledError < StandardError
94
+ def initialize
95
+ super('Request Interception is not enabled!')
96
+ end
97
+ end
98
+
99
+ class AlreadyHandledError < StandardError
100
+ def initialize
101
+ super('Request is already handled!')
102
+ end
103
+ end
104
+
105
+ # proceed request on request interception.
106
+ #
107
+ # Example:
108
+ #
109
+ # ````
110
+ # page.on 'request' do |req|
111
+ # # Override headers
112
+ # headers = req.headers.merge(
113
+ # foo: 'bar', # set "foo" header
114
+ # origin: nil, # remove "origin" header
115
+ # )
116
+ # req.continue(headers: headers)
117
+ # end
118
+ # ```
119
+ #`
120
+ # @param error_code [String|Symbol]
121
+ def continue(url: nil, method: nil, post_data: nil, headers: nil)
122
+ # Request interception is not supported for data: urls.
123
+ return if @url.start_with?('data:')
124
+
125
+ unless @allow_interception
126
+ raise InterceptionNotEnabledError.new
127
+ end
128
+ if @interception_handled
129
+ raise AlreadyHandledError.new
130
+ end
131
+ @interception_handled = true
132
+
133
+ overrides = {
134
+ url: url,
135
+ method: method,
136
+ post_data: post_data,
137
+ headers: headers_to_array(headers),
138
+ }.compact
139
+ begin
140
+ @client.send_message('Fetch.continueRequest',
141
+ requestId: @interception_id,
142
+ **overrides,
143
+ )
144
+ rescue => err
145
+ # In certain cases, protocol will return error if the request was already canceled
146
+ # or the page was closed. We should tolerate these errors.
147
+ debug_puts(err)
148
+ end
149
+ end
150
+
151
+ # Mocking response.
152
+ #
153
+ # Example:
154
+ #
155
+ # ```
156
+ # page.on 'request' do |req|
157
+ # req.respond(
158
+ # status: 404,
159
+ # content_type: 'text/plain',
160
+ # body: 'Not Found!'
161
+ # )
162
+ # end
163
+ # ````
164
+ #
165
+ # @param status [Integer]
166
+ # @param headers [Hash<String, String>]
167
+ # @param content_type [String]
168
+ # @param body [String]
169
+ def respond(status: nil, headers: nil, content_type: nil, body: nil)
170
+ # Mocking responses for dataURL requests is not currently supported.
171
+ return if @url.start_with?('data:')
172
+
173
+ unless @allow_interception
174
+ raise InterceptionNotEnabledError.new
175
+ end
176
+ if @interception_handled
177
+ raise AlreadyHandledError.new
178
+ end
179
+ @interception_handled = true
180
+
181
+ mock_response_headers = {}
182
+ headers&.each do |key, value|
183
+ mock_response_headers[key.downcase] = value
184
+ end
185
+ if content_type
186
+ mock_response_headers['content-type'] = content_type
187
+ end
188
+ if body
189
+ mock_response_headers['content-length'] = body.length
190
+ end
191
+
192
+ mock_response = {
193
+ responseCode: status || 200,
194
+ responsePhrase: STATUS_TEXTS[(status || 200).to_s],
195
+ responseHeaders: headers_to_array(mock_response_headers),
196
+ body: if_present(body) { |mock_body| Base64.strict_encode64(mock_body) },
197
+ }.compact
198
+ begin
199
+ @client.send_message('Fetch.fulfillRequest',
200
+ requestId: @interception_id,
201
+ **mock_response,
202
+ )
203
+ rescue => err
204
+ # In certain cases, protocol will return error if the request was already canceled
205
+ # or the page was closed. We should tolerate these errors.
206
+ debug_puts(err)
207
+ end
208
+ end
209
+
210
+ # abort request on request interception.
211
+ #
212
+ # Example:
213
+ #
214
+ # ````
215
+ # page.on 'request' do |req|
216
+ # if req.url.include?("porn")
217
+ # req.abort
218
+ # else
219
+ # req.continue
220
+ # end
221
+ # end
222
+ # ```
223
+ #`
224
+ # @param error_code [String|Symbol]
225
+ def abort(error_code: :failed)
226
+ # Request interception is not supported for data: urls.
227
+ return if @url.start_with?('data:')
228
+
229
+ error_reason = ERROR_REASONS[error_code.to_s]
230
+ unless error_reason
231
+ raise ArgumentError.new("Unknown error code: #{error_code}")
232
+ end
233
+ unless @allow_interception
234
+ raise InterceptionNotEnabledError.new
235
+ end
236
+ if @interception_handled
237
+ raise AlreadyHandledError.new
238
+ end
239
+ @interception_handled = true
240
+
241
+ begin
242
+ @client.send_message('Fetch.failRequest',
243
+ requestId: @interception_id,
244
+ errorReason: error_reason,
245
+ )
246
+ rescue => err
247
+ # In certain cases, protocol will return error if the request was already canceled
248
+ # or the page was closed. We should tolerate these errors.
249
+ debug_puts(err)
250
+ end
251
+ end
252
+
253
+ ERROR_REASONS = {
254
+ 'aborted' => 'Aborted',
255
+ 'accessdenied' => 'AccessDenied',
256
+ 'addressunreachable' => 'AddressUnreachable',
257
+ 'blockedbyclient' => 'BlockedByClient',
258
+ 'blockedbyresponse' => 'BlockedByResponse',
259
+ 'connectionaborted' => 'ConnectionAborted',
260
+ 'connectionclosed' => 'ConnectionClosed',
261
+ 'connectionfailed' => 'ConnectionFailed',
262
+ 'connectionrefused' => 'ConnectionRefused',
263
+ 'connectionreset' => 'ConnectionReset',
264
+ 'internetdisconnected' => 'InternetDisconnected',
265
+ 'namenotresolved' => 'NameNotResolved',
266
+ 'timedout' => 'TimedOut',
267
+ 'failed' => 'Failed',
268
+ }.freeze
269
+
270
+ # List taken from https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml with extra 306 and 418 codes.
271
+ STATUS_TEXTS = {
272
+ '100' => 'Continue',
273
+ '101' => 'Switching Protocols',
274
+ '102' => 'Processing',
275
+ '103' => 'Early Hints',
276
+ '200' => 'OK',
277
+ '201' => 'Created',
278
+ '202' => 'Accepted',
279
+ '203' => 'Non-Authoritative Information',
280
+ '204' => 'No Content',
281
+ '205' => 'Reset Content',
282
+ '206' => 'Partial Content',
283
+ '207' => 'Multi-Status',
284
+ '208' => 'Already Reported',
285
+ '226' => 'IM Used',
286
+ '300' => 'Multiple Choices',
287
+ '301' => 'Moved Permanently',
288
+ '302' => 'Found',
289
+ '303' => 'See Other',
290
+ '304' => 'Not Modified',
291
+ '305' => 'Use Proxy',
292
+ '306' => 'Switch Proxy',
293
+ '307' => 'Temporary Redirect',
294
+ '308' => 'Permanent Redirect',
295
+ '400' => 'Bad Request',
296
+ '401' => 'Unauthorized',
297
+ '402' => 'Payment Required',
298
+ '403' => 'Forbidden',
299
+ '404' => 'Not Found',
300
+ '405' => 'Method Not Allowed',
301
+ '406' => 'Not Acceptable',
302
+ '407' => 'Proxy Authentication Required',
303
+ '408' => 'Request Timeout',
304
+ '409' => 'Conflict',
305
+ '410' => 'Gone',
306
+ '411' => 'Length Required',
307
+ '412' => 'Precondition Failed',
308
+ '413' => 'Payload Too Large',
309
+ '414' => 'URI Too Long',
310
+ '415' => 'Unsupported Media Type',
311
+ '416' => 'Range Not Satisfiable',
312
+ '417' => 'Expectation Failed',
313
+ '418' => 'I\'m a teapot',
314
+ '421' => 'Misdirected Request',
315
+ '422' => 'Unprocessable Entity',
316
+ '423' => 'Locked',
317
+ '424' => 'Failed Dependency',
318
+ '425' => 'Too Early',
319
+ '426' => 'Upgrade Required',
320
+ '428' => 'Precondition Required',
321
+ '429' => 'Too Many Requests',
322
+ '431' => 'Request Header Fields Too Large',
323
+ '451' => 'Unavailable For Legal Reasons',
324
+ '500' => 'Internal Server Error',
325
+ '501' => 'Not Implemented',
326
+ '502' => 'Bad Gateway',
327
+ '503' => 'Service Unavailable',
328
+ '504' => 'Gateway Timeout',
329
+ '505' => 'HTTP Version Not Supported',
330
+ '506' => 'Variant Also Negotiates',
331
+ '507' => 'Insufficient Storage',
332
+ '508' => 'Loop Detected',
333
+ '510' => 'Not Extended',
334
+ '511' => 'Network Authentication Required',
335
+ }.freeze
336
+ end