Class: Puppeteer::Request

Inherits:
Object
  • Object
show all
Includes:
DebugPrint, IfPresent
Defined in:
lib/puppeteer/request.rb

Defined Under Namespace

Classes: AlreadyHandledError, InterceptionNotEnabledError, InternalAccessor

Constant Summary collapse

ERROR_REASONS =
{
  'aborted' => 'Aborted',
  'accessdenied' => 'AccessDenied',
  'addressunreachable' => 'AddressUnreachable',
  'blockedbyclient' => 'BlockedByClient',
  'blockedbyresponse' => 'BlockedByResponse',
  'connectionaborted' => 'ConnectionAborted',
  'connectionclosed' => 'ConnectionClosed',
  'connectionfailed' => 'ConnectionFailed',
  'connectionrefused' => 'ConnectionRefused',
  'connectionreset' => 'ConnectionReset',
  'internetdisconnected' => 'InternetDisconnected',
  'namenotresolved' => 'NameNotResolved',
  'timedout' => 'TimedOut',
  'failed' => 'Failed',
}.freeze
STATUS_TEXTS =

List taken from www.iana.org/assignments/http-status-codes/http-status-codes.xhtml with extra 306 and 418 codes.

{
  '100' => 'Continue',
  '101' => 'Switching Protocols',
  '102' => 'Processing',
  '103' => 'Early Hints',
  '200' => 'OK',
  '201' => 'Created',
  '202' => 'Accepted',
  '203' => 'Non-Authoritative Information',
  '204' => 'No Content',
  '205' => 'Reset Content',
  '206' => 'Partial Content',
  '207' => 'Multi-Status',
  '208' => 'Already Reported',
  '226' => 'IM Used',
  '300' => 'Multiple Choices',
  '301' => 'Moved Permanently',
  '302' => 'Found',
  '303' => 'See Other',
  '304' => 'Not Modified',
  '305' => 'Use Proxy',
  '306' => 'Switch Proxy',
  '307' => 'Temporary Redirect',
  '308' => 'Permanent Redirect',
  '400' => 'Bad Request',
  '401' => 'Unauthorized',
  '402' => 'Payment Required',
  '403' => 'Forbidden',
  '404' => 'Not Found',
  '405' => 'Method Not Allowed',
  '406' => 'Not Acceptable',
  '407' => 'Proxy Authentication Required',
  '408' => 'Request Timeout',
  '409' => 'Conflict',
  '410' => 'Gone',
  '411' => 'Length Required',
  '412' => 'Precondition Failed',
  '413' => 'Payload Too Large',
  '414' => 'URI Too Long',
  '415' => 'Unsupported Media Type',
  '416' => 'Range Not Satisfiable',
  '417' => 'Expectation Failed',
  '418' => 'I\'m a teapot',
  '421' => 'Misdirected Request',
  '422' => 'Unprocessable Entity',
  '423' => 'Locked',
  '424' => 'Failed Dependency',
  '425' => 'Too Early',
  '426' => 'Upgrade Required',
  '428' => 'Precondition Required',
  '429' => 'Too Many Requests',
  '431' => 'Request Header Fields Too Large',
  '451' => 'Unavailable For Legal Reasons',
  '500' => 'Internal Server Error',
  '501' => 'Not Implemented',
  '502' => 'Bad Gateway',
  '503' => 'Service Unavailable',
  '504' => 'Gateway Timeout',
  '505' => 'HTTP Version Not Supported',
  '506' => 'Variant Also Negotiates',
  '507' => 'Insufficient Storage',
  '508' => 'Loop Detected',
  '510' => 'Not Extended',
  '511' => 'Network Authentication Required',
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from IfPresent

#if_present

Methods included from DebugPrint

#debug_print, #debug_puts

Constructor Details

#initialize(client, frame, interception_id, allow_interception, event, redirect_chain) ⇒ Request

Returns a new instance of Request.

Parameters:



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/puppeteer/request.rb', line 47

def initialize(client, frame, interception_id, allow_interception, event, redirect_chain)
  @client = client
  @request_id = event['requestId']
  @is_navigation_request = event['requestId'] == event['loaderId'] && event['type'] == 'Document'
  @interception_id = interception_id
  @allow_interception = allow_interception
  @url = event['request']['url']
  @resource_type = event['type'].downcase
  @method = event['request']['method']
  @post_data = event['request']['postData']
  @frame = frame
  @redirect_chain = redirect_chain
  @headers = {}
  event['request']['headers'].each do |key, value|
    @headers[key.downcase] = value
  end
  @from_memory_cache = false

  @internal = InternalAccessor.new(self)
end

Instance Attribute Details

#frameObject (readonly)

Returns the value of attribute frame.



69
70
71
# File 'lib/puppeteer/request.rb', line 69

def frame
  @frame
end

#headersObject (readonly)

Returns the value of attribute headers.



69
70
71
# File 'lib/puppeteer/request.rb', line 69

def headers
  @headers
end

#internalObject (readonly)

Returns the value of attribute internal.



68
69
70
# File 'lib/puppeteer/request.rb', line 68

def internal
  @internal
end

#methodObject (readonly)

Returns the value of attribute method.



69
70
71
# File 'lib/puppeteer/request.rb', line 69

def method
  @method
end

#post_dataObject (readonly)

Returns the value of attribute post_data.



69
70
71
# File 'lib/puppeteer/request.rb', line 69

def post_data
  @post_data
end

#resource_typeObject (readonly)

Returns the value of attribute resource_type.



69
70
71
# File 'lib/puppeteer/request.rb', line 69

def resource_type
  @resource_type
end

#responseObject (readonly)

Returns the value of attribute response.



69
70
71
# File 'lib/puppeteer/request.rb', line 69

def response
  @response
end

#urlObject (readonly)

Returns the value of attribute url.



69
70
71
# File 'lib/puppeteer/request.rb', line 69

def url
  @url
end

Instance Method Details

#abort(error_code: :failed) ⇒ Object

abort request on request interception.

Example:

page.on 'request' do |req|
  if req.url.include?("porn")
    req.abort
  else
    req.continue
  end
end

Parameters:

  • error_code (String|Symbol) (defaults to: :failed)


219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/puppeteer/request.rb', line 219

def abort(error_code: :failed)
  # Request interception is not supported for data: urls.
  return if @url.start_with?('data:')

  error_reason = ERROR_REASONS[error_code.to_s]
  unless error_reason
    raise ArgumentError.new("Unknown error code: #{error_code}")
  end
  unless @allow_interception
    raise InterceptionNotEnabledError.new
  end
  if @interception_handled
    raise AlreadyHandledError.new
  end
  @interception_handled = true

  begin
    @client.send_message('Fetch.failRequest',
      requestId: @interception_id,
      errorReason: error_reason,
    )
  rescue => err
    # In certain cases, protocol will return error if the request was already canceled
    # or the page was closed. We should tolerate these errors.
    debug_puts(err)
  end
end

#continue(url: nil, method: nil, post_data: nil, headers: nil) ⇒ Object

proceed request on request interception.

Example:

page.on 'request' do |req|
  # Override headers
  headers = req.headers.merge(
    foo: 'bar', # set "foo" header
    origin: nil, # remove "origin" header
  )
  req.continue(headers: headers)
end

Parameters:

  • error_code (String|Symbol)


119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/puppeteer/request.rb', line 119

def continue(url: nil, method: nil, post_data: nil, headers: nil)
  # Request interception is not supported for data: urls.
  return if @url.start_with?('data:')

  unless @allow_interception
    raise InterceptionNotEnabledError.new
  end
  if @interception_handled
    raise AlreadyHandledError.new
  end
  @interception_handled = true

  overrides = {
    url: url,
    method: method,
    post_data: post_data,
    headers: headers_to_array(headers),
  }.compact
  begin
    @client.send_message('Fetch.continueRequest',
      requestId: @interception_id,
      **overrides,
    )
  rescue => err
    # In certain cases, protocol will return error if the request was already canceled
    # or the page was closed. We should tolerate these errors.
    debug_puts(err)
  end
end

#failureObject



79
80
81
82
83
# File 'lib/puppeteer/request.rb', line 79

def failure
  if_present(@failure_text) do |failure_text|
    { errorText: @failure_text }
  end
end

Returns:

  • (Boolean)


71
72
73
# File 'lib/puppeteer/request.rb', line 71

def navigation_request?
  @is_navigation_request
end

#redirect_chainObject



75
76
77
# File 'lib/puppeteer/request.rb', line 75

def redirect_chain
  @redirect_chain.dup
end

#respond(status: nil, headers: nil, content_type: nil, body: nil) ⇒ Object

Mocking response.

Example:

page.on 'request' do |req|
  req.respond(
    status: 404,
    content_type: 'text/plain',
    body: 'Not Found!'
  )
end

Parameters:

  • status (Integer) (defaults to: nil)
  • headers (Hash<String, String>) (defaults to: nil)
  • content_type (String) (defaults to: nil)
  • body (String) (defaults to: nil)


165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/puppeteer/request.rb', line 165

def respond(status: nil, headers: nil, content_type: nil, body: nil)
  # Mocking responses for dataURL requests is not currently supported.
  return if @url.start_with?('data:')

  unless @allow_interception
    raise InterceptionNotEnabledError.new
  end
  if @interception_handled
    raise AlreadyHandledError.new
  end
  @interception_handled = true

  mock_response_headers = {}
  headers&.each do |key, value|
    mock_response_headers[key.downcase] = value
  end
  if content_type
    mock_response_headers['content-type'] = content_type
  end
  if body
    mock_response_headers['content-length'] = body.length
  end

  mock_response = {
    responseCode: status || 200,
    responsePhrase: STATUS_TEXTS[(status || 200).to_s],
    responseHeaders: headers_to_array(mock_response_headers),
    body: if_present(body) { |mock_body| Base64.strict_encode64(mock_body) },
  }.compact
  begin
    @client.send_message('Fetch.fulfillRequest',
      requestId: @interception_id,
      **mock_response,
    )
  rescue => err
    # In certain cases, protocol will return error if the request was already canceled
    # or the page was closed. We should tolerate these errors.
    debug_puts(err)
  end
end